diff options
-rw-r--r-- | src/apps/lc-compliance/meson.build | 3 | ||||
-rw-r--r-- | src/apps/lc-compliance/tests/request_test.cpp | 206 |
2 files changed, 208 insertions, 1 deletions
diff --git a/src/apps/lc-compliance/meson.build b/src/apps/lc-compliance/meson.build index c53b2603..ae9596a8 100644 --- a/src/apps/lc-compliance/meson.build +++ b/src/apps/lc-compliance/meson.build @@ -16,7 +16,8 @@ lc_compliance_sources = files([ 'main.cpp', 'tests/capture_test.cpp', 'tests/configure_test.cpp', - 'tests/controls_test.cpp' + 'tests/controls_test.cpp', + 'tests/request_test.cpp' ]) lc_compliance_includes = ([ diff --git a/src/apps/lc-compliance/tests/request_test.cpp b/src/apps/lc-compliance/tests/request_test.cpp new file mode 100644 index 00000000..957db590 --- /dev/null +++ b/src/apps/lc-compliance/tests/request_test.cpp @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023, Ideas On Board Oy + * + * request_test.cpp - Request handling test + */ + +#include <gtest/gtest.h> + +#include <libcamera/libcamera.h> + +#include "environment.h" + +#include "../common/event_loop.h" + +using namespace libcamera; + +class RequestTest : public testing::Test +{ +public: + void setExposureTime(Request *request); + +protected: + void SetUp() override; + void TearDown() override; + + bool controlSupported(const ControlId *) const; + + void configure(Span<const StreamRole> roles); + void start(unsigned int minRequests, unsigned int maxRequests); + void stop(); + + std::unique_ptr<libcamera::FrameBufferAllocator> allocator_; + std::vector<std::unique_ptr<libcamera::Request>> requests_; + std::unique_ptr<libcamera::CameraConfiguration> config_; + std::shared_ptr<Camera> camera_; + EventLoop *loop_; + + bool testPass; + +private: + unsigned int requestCount_; + unsigned int maxRequests_; + unsigned int minRequests_; +}; + +void RequestTest::SetUp() +{ + Environment *env = Environment::get(); + + camera_ = env->cm()->get(env->cameraId()); + + ASSERT_EQ(camera_->acquire(), 0); +} + +void RequestTest::TearDown() +{ + if (!camera_) + return; + + camera_->release(); + camera_.reset(); +} + +bool RequestTest::controlSupported(const ControlId *id) const +{ + auto it = camera_->controls().find(id); + return it != camera_->controls().end(); +} + +void RequestTest::configure(Span<const StreamRole> roles) +{ + config_ = camera_->generateConfiguration(roles); + if (!config_) { + std::cout << "Roles not supported by camera" << std::endl; + GTEST_SKIP(); + } + + if (config_->validate() != CameraConfiguration::Valid) { + config_.reset(); + FAIL() << "Configuration not valid"; + } + + if (camera_->configure(config_.get())) { + config_.reset(); + FAIL() << "Failed to configure camera"; + } + + Stream *stream = config_->at(0).stream(); + allocator_ = (std::make_unique<FrameBufferAllocator>(camera_)); + allocator_->allocate(stream); + + const auto &buffers = allocator_->buffers(stream); + for (const auto &buffer : buffers) { + std::unique_ptr<Request> request = camera_->createRequest(); + request->addBuffer(stream, buffer.get(), 0); + requests_.push_back(std::move(request)); + } +} + +void RequestTest::start(unsigned int minRequests, unsigned int maxRequests) +{ + minRequests_ = minRequests; + maxRequests_ = maxRequests; + requestCount_ = 0; + testPass = true; + + ASSERT_EQ(camera_->start(), 0) << "Failed to start camera"; + + for (const auto &request : requests_) { + if (camera_->queueRequest(request.get())) + return; + } +} + +void RequestTest::stop() +{ + if (!config_ || !allocator_->allocated()) + return; + + camera_->stop(); + + camera_->requestCompleted.disconnect(this); + + requests_.clear(); + + for (auto const &config : *config_) { + Stream *stream = config.stream(); + allocator_->free(stream); + } +} + +void RequestTest::setExposureTime(Request *request) +{ + static unsigned int metadataCounter = 0; + static int expectedResult = 0; + + /* Requests completed after a 'stop()' are returned in error state. */ + if (requestCount_ < maxRequests_) { + EXPECT_EQ(request->status(), Request::Status::RequestComplete) + << "Request didn't complete successfully"; + } + + if (expectedResult) { + std::cout << "CHECK METADATA" << std::endl; + const auto &metadata = request->metadata(); + auto exposureTime = metadata.get<int>(controls::ExposureTime); + if (!exposureTime) { + std::cout << "NO EXPOSURE TIME" << std::endl; + --metadataCounter; + } else if (*exposureTime == expectedResult) { + std::cout << "FOUND EXPOSURE TIME: " << *exposureTime << std::endl; + requestCount_ = maxRequests_; + testPass = true; + } else if (--metadataCounter == 0) { + /* + * The requested exposureTime has not been set in + * less than the expected number of completed requests. + * + * Break the loop and set the test status to failure. + */ + std::cout << "FOUND EXPOSURE TIME: " << *exposureTime << std::endl; + requestCount_ = maxRequests_; + } + } + + /* Wait for a min number of requests to fill the pipeline. */ + if (requestCount_++ > minRequests_ && !expectedResult) { + std::cout << "SET EXPOSURE TIEM TO 100" << std::endl; + + testPass = false; + metadataCounter = 1; + expectedResult = 100; + request->controls().set(controls::ExposureTime, 100); + } + + if (requestCount_ >= maxRequests_) { + loop_->exit(0); + return; + } + + request->reuse(Request::ReuseBuffers); + if (camera_->queueRequest(request)) + loop_->exit(-EINVAL); +} + +TEST_F(RequestTest, ExposureTime) +{ + if (!controlSupported(&controls::ExposureTime)) + GTEST_SKIP() << "ExposureTime control not supported"; + + const std::array<StreamRole, 1> roles{ StreamRole::Viewfinder }; + configure(roles); + + camera_->requestCompleted.connect(dynamic_cast<RequestTest *>(this), + &RequestTest::setExposureTime); + + start(4, 20); + + loop_ = new EventLoop(); + loop_->exec(); + stop(); + delete loop_; + + EXPECT_EQ(testPass, true); +} |