blob: a4062935553f15570e85d885d5935de1aecf6b7a [file]
/*
* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "common/capture_result_sequencer.h"
#include <hardware/camera3.h>
#include <system/camera_metadata.h>
#include <map>
#include <set>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include "common/camera_hal3_helpers.h"
#include "common/stream_manipulator.h"
namespace cros {
namespace {
class CaptureResultSequencerTest : public testing::Test {
protected:
CaptureResultSequencerTest()
: sequencer_(StreamManipulator::Callbacks{
.result_callback =
base::BindRepeating(&CaptureResultSequencerTest::ResultCallback,
base::Unretained(this)),
.notify_callback =
base::BindRepeating(&CaptureResultSequencerTest::NotifyCallback,
base::Unretained(this)),
}) {}
void AddRequest(const Camera3CaptureDescriptor& request) {
sequencer_.AddRequest(request);
}
void AddResult(Camera3CaptureDescriptor result) {
sequencer_.AddResult(std::move(result));
}
void NotifyDeviceError() {
sequencer_.Notify(camera3_notify_msg_t{
.type = CAMERA3_MSG_ERROR,
.message =
{
.error =
camera3_error_msg_t{
.error_code = CAMERA3_MSG_ERROR_DEVICE,
},
},
});
}
void NotifyRequestError(uint32_t frame_number) {
sequencer_.Notify(camera3_notify_msg_t{
.type = CAMERA3_MSG_ERROR,
.message =
{
.error =
camera3_error_msg_t{
.frame_number = frame_number,
.error_code = CAMERA3_MSG_ERROR_REQUEST,
},
},
});
}
void NotifyBufferError(uint32_t frame_number, size_t stream_index) {
sequencer_.Notify(camera3_notify_msg_t{
.type = CAMERA3_MSG_ERROR,
.message =
{
.error =
camera3_error_msg_t{
.frame_number = frame_number,
.error_stream = stream(stream_index),
.error_code = CAMERA3_MSG_ERROR_BUFFER,
},
},
});
}
void Reset() {
sequencer_.Reset();
returned_results_.clear();
notified_messages_.clear();
}
void ValidateReturnedResults(
const std::map<uint32_t /*frame_number*/,
std::set<size_t> /*stream_indices*/>& expected_results)
const {
std::map<const camera3_stream_t*, std::vector<uint32_t>> frame_numbers;
std::map<uint32_t, std::set<size_t>> stream_indices;
for (auto& result : returned_results_) {
for (auto& b : result.GetOutputBuffers()) {
if (b.status() == CAMERA3_BUFFER_STATUS_OK) {
frame_numbers[b.stream()].push_back(result.frame_number());
stream_indices[result.frame_number()].insert(
stream_index(b.stream()));
}
}
}
EXPECT_TRUE(
std::all_of(frame_numbers.begin(), frame_numbers.end(), [](auto& item) {
return std::is_sorted(item.second.begin(), item.second.end());
}));
EXPECT_EQ(stream_indices, expected_results);
}
Camera3CaptureDescriptor MakeRequest(
uint32_t frame_number, const std::vector<size_t>& stream_indices) {
Camera3CaptureDescriptor request(
camera3_capture_result_t{.frame_number = frame_number});
for (size_t i : stream_indices) {
request.AppendOutputBuffer(Camera3StreamBuffer::MakeResultOutput(
camera3_stream_buffer_t{.stream = stream(i)}));
}
return request;
}
Camera3CaptureDescriptor MakeResult(
uint32_t frame_number,
const std::vector<size_t> stream_indices,
int buffer_status = CAMERA3_BUFFER_STATUS_OK,
uint32_t partial_result = 0) {
Camera3CaptureDescriptor result(camera3_capture_result_t{
.frame_number = frame_number,
.partial_result = partial_result,
});
for (size_t i : stream_indices) {
result.AppendOutputBuffer(
Camera3StreamBuffer::MakeResultOutput(camera3_stream_buffer_t{
.stream = stream(i), .status = buffer_status}));
}
return result;
}
const Camera3CaptureDescriptor& LastReturnedResult() const {
CHECK(!returned_results_.empty());
return returned_results_.back();
}
const camera3_notify_msg_t& LastNotifiedMessage() const {
CHECK(!notified_messages_.empty());
return notified_messages_.back();
}
private:
void ResultCallback(Camera3CaptureDescriptor result) {
returned_results_.push_back(std::move(result));
}
void NotifyCallback(camera3_notify_msg_t msg) {
notified_messages_.push_back(msg);
}
camera3_stream_t* stream(size_t index) { return &mock_streams_[index]; }
size_t stream_index(const camera3_stream_t* stream) const {
return std::distance(mock_streams_.begin(), stream);
}
static constexpr const size_t kMaxNumStreams = 10;
std::array<camera3_stream_t, kMaxNumStreams> mock_streams_ = {};
CaptureResultSequencer sequencer_;
std::vector<Camera3CaptureDescriptor> returned_results_;
std::vector<camera3_notify_msg_t> notified_messages_;
};
TEST_F(CaptureResultSequencerTest, OutOfOrderBuffers) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0}));
AddRequest(MakeRequest(3, {0, 1}));
AddRequest(MakeRequest(4, {1}));
AddRequest(MakeRequest(5, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(3, {0, 1}));
AddResult(MakeResult(1, {1}));
AddResult(MakeResult(2, {0}));
AddResult(MakeResult(5, {0}));
AddResult(MakeResult(5, {1}));
ValidateReturnedResults({
{1, {0, 1}},
{2, {0}},
{3, {0, 1}},
{5, {0}},
});
}
TEST_F(CaptureResultSequencerTest, BufferErrors) {
AddRequest(MakeRequest(1, {0}));
AddRequest(MakeRequest(2, {0, 1}));
AddRequest(MakeRequest(3, {0}));
AddRequest(MakeRequest(4, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(2, {0}));
AddResult(MakeResult(3, {0}, /*buffer_status=*/CAMERA3_BUFFER_STATUS_ERROR));
AddResult(MakeResult(4, {0, 1}));
AddResult(MakeResult(2, {1}, /*buffer_status=*/CAMERA3_BUFFER_STATUS_ERROR));
ValidateReturnedResults({
{1, {0}},
{2, {0}},
{4, {0, 1}},
});
}
TEST_F(CaptureResultSequencerTest, NotifyDeviceError) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(2, {0}));
AddResult(MakeResult(1, {1}));
NotifyDeviceError();
ValidateReturnedResults({
{1, {0, 1}},
{2, {0}},
});
const camera3_notify_msg_t& last_msg = LastNotifiedMessage();
ASSERT_EQ(last_msg.type, CAMERA3_MSG_ERROR);
ASSERT_EQ(last_msg.message.error.error_code, CAMERA3_MSG_ERROR_DEVICE);
}
TEST_F(CaptureResultSequencerTest, NotifyRequestError) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0, 1}));
AddRequest(MakeRequest(3, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(3, {0}));
NotifyRequestError(2);
AddResult(MakeResult(2, {0},
/*buffer_status=*/CAMERA3_BUFFER_STATUS_ERROR));
AddResult(MakeResult(3, {1}));
ValidateReturnedResults({
{1, {0}},
{3, {0}},
});
const camera3_notify_msg_t& last_msg = LastNotifiedMessage();
ASSERT_EQ(last_msg.type, CAMERA3_MSG_ERROR);
ASSERT_EQ(last_msg.message.error.error_code, CAMERA3_MSG_ERROR_REQUEST);
EXPECT_EQ(last_msg.message.error.frame_number, 2);
}
TEST_F(CaptureResultSequencerTest, NotifyBufferError) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0, 1}));
AddRequest(MakeRequest(3, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(1, {1}));
NotifyBufferError(2, 0);
AddResult(MakeResult(2, {1}));
AddResult(MakeResult(3, {0}));
ValidateReturnedResults({
{1, {0, 1}},
{2, {1}},
{3, {0}},
});
const camera3_notify_msg_t& last_msg = LastNotifiedMessage();
ASSERT_EQ(last_msg.type, CAMERA3_MSG_ERROR);
ASSERT_EQ(last_msg.message.error.error_code, CAMERA3_MSG_ERROR_BUFFER);
EXPECT_EQ(last_msg.message.error.frame_number, 2);
}
TEST_F(CaptureResultSequencerTest, BypassMetadata) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0, 1}));
AddRequest(MakeRequest(3, {0, 1}));
AddResult(MakeResult(1, {0, 1}));
{
Camera3CaptureDescriptor result =
MakeResult(3, {0},
/*buffer_status=*/CAMERA3_BUFFER_STATUS_OK,
/*partial_result=*/1);
result.UpdateMetadata<int64_t>(ANDROID_SENSOR_TIMESTAMP,
std::array<int64_t, 1>{1'234'567});
AddResult(std::move(result));
}
ValidateReturnedResults({
{1, {0, 1}},
});
const Camera3CaptureDescriptor& last_result = LastReturnedResult();
EXPECT_EQ(last_result.frame_number(), 3);
EXPECT_TRUE(last_result.HasMetadata(ANDROID_SENSOR_TIMESTAMP));
}
TEST_F(CaptureResultSequencerTest, UnexpectedResult) {
AddRequest(MakeRequest(1, {0, 1}));
AddResult(MakeResult(1, {0}));
EXPECT_DEATH(AddResult(MakeResult(2, {1})), "");
}
TEST_F(CaptureResultSequencerTest, Reset) {
AddRequest(MakeRequest(1, {0, 1}));
AddRequest(MakeRequest(2, {0}));
AddRequest(MakeRequest(3, {0}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(2, {0}));
AddResult(MakeResult(1, {1}));
ValidateReturnedResults({
{1, {0, 1}},
{2, {0}},
});
Reset();
AddRequest(MakeRequest(1, {0}));
AddRequest(MakeRequest(2, {0, 1}));
AddResult(MakeResult(1, {0}));
AddResult(MakeResult(2, {0}));
ValidateReturnedResults({
{1, {0}},
{2, {0}},
});
}
} // namespace
} // namespace cros
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}