Add a compliance tool to ease testing of cameras. In contrast to the unit-tests under test/ that aims to test the internal components of libcamera the compliance tool aims to test application use-cases and to some extent the public API. This change adds the boilerplate code of a simple framework for the creation of tests. The tests aim both to demonstrate the tool and to catch real problems. The tests added are: - Test that if one queues exactly N requests to a camera exactly N requests are eventually completed. - Test that a configured camera can be started and stopped multiple times in an attempt to exercise cleanup code paths otherwise not often tested with 'cam' for example. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
148 lines
2.7 KiB
C++
148 lines
2.7 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2020, Google Inc.
|
|
*
|
|
* main.cpp - lc-compliance - The libcamera compliance tool
|
|
*/
|
|
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
#include <libcamera/libcamera.h>
|
|
|
|
#include "../cam/options.h"
|
|
#include "tests.h"
|
|
|
|
using namespace libcamera;
|
|
|
|
enum {
|
|
OptCamera = 'c',
|
|
OptHelp = 'h',
|
|
};
|
|
|
|
class Harness
|
|
{
|
|
public:
|
|
Harness(const OptionsParser::Options &options);
|
|
~Harness();
|
|
|
|
int exec();
|
|
|
|
private:
|
|
int init();
|
|
void listCameras();
|
|
|
|
OptionsParser::Options options_;
|
|
std::unique_ptr<CameraManager> cm_;
|
|
std::shared_ptr<Camera> camera_;
|
|
};
|
|
|
|
Harness::Harness(const OptionsParser::Options &options)
|
|
: options_(options)
|
|
{
|
|
cm_ = std::make_unique<CameraManager>();
|
|
}
|
|
|
|
Harness::~Harness()
|
|
{
|
|
if (camera_) {
|
|
camera_->release();
|
|
camera_.reset();
|
|
}
|
|
|
|
cm_->stop();
|
|
}
|
|
|
|
int Harness::exec()
|
|
{
|
|
int ret = init();
|
|
if (ret)
|
|
return ret;
|
|
|
|
std::vector<Results> results;
|
|
|
|
results.push_back(testSingleStream(camera_));
|
|
|
|
for (const Results &result : results) {
|
|
ret = result.summary();
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Harness::init()
|
|
{
|
|
int ret = cm_->start();
|
|
if (ret) {
|
|
std::cout << "Failed to start camera manager: "
|
|
<< strerror(-ret) << std::endl;
|
|
return ret;
|
|
}
|
|
|
|
if (!options_.isSet(OptCamera)) {
|
|
std::cout << "No camera specified, available cameras:" << std::endl;
|
|
listCameras();
|
|
return -ENODEV;
|
|
}
|
|
|
|
const std::string &cameraId = options_[OptCamera];
|
|
camera_ = cm_->get(cameraId);
|
|
if (!camera_) {
|
|
std::cout << "Camera " << cameraId << " not found, available cameras:" << std::endl;
|
|
listCameras();
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (camera_->acquire()) {
|
|
std::cout << "Failed to acquire camera" << std::endl;
|
|
return -EINVAL;
|
|
}
|
|
|
|
std::cout << "Using camera " << cameraId << std::endl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Harness::listCameras()
|
|
{
|
|
for (const std::shared_ptr<Camera> &cam : cm_->cameras())
|
|
std::cout << "- " << cam.get()->id() << std::endl;
|
|
}
|
|
|
|
static int parseOptions(int argc, char **argv, OptionsParser::Options *options)
|
|
{
|
|
OptionsParser parser;
|
|
parser.addOption(OptCamera, OptionString,
|
|
"Specify which camera to operate on, by id", "camera",
|
|
ArgumentRequired, "camera");
|
|
parser.addOption(OptHelp, OptionNone, "Display this help message",
|
|
"help");
|
|
|
|
*options = parser.parse(argc, argv);
|
|
if (!options->valid())
|
|
return -EINVAL;
|
|
|
|
if (options->isSet(OptHelp)) {
|
|
parser.usage();
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
OptionsParser::Options options;
|
|
int ret = parseOptions(argc, argv, &options);
|
|
if (ret == -EINTR)
|
|
return EXIT_SUCCESS;
|
|
if (ret < 0)
|
|
return EXIT_FAILURE;
|
|
|
|
Harness harness(options);
|
|
|
|
return harness.exec() ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|