blob: 945bdb7344c284b7f6035d8edf4c1bfa49ad554b [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/camera2/hal/cpp/fidl.h>
#include <fuchsia/camera3/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include "src/camera/bin/device/device_impl.h"
#include "src/camera/bin/device/stream_impl.h"
#include "src/camera/bin/device/test/fake_controller.h"
#include "src/camera/bin/device/util.h"
#include "src/camera/lib/fake_legacy_stream/fake_legacy_stream.h"
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
namespace camera {
// No-op function.
static void nop() {}
class DeviceTest : public gtest::RealLoopFixture {
protected:
DeviceTest() : context_(sys::ComponentContext::Create()) {}
void SetUp() override {
context_->svc()->Connect(allocator_.NewRequest());
allocator_.set_error_handler(MakeErrorHandler("Sysmem Allocator"));
fidl::InterfaceHandle<fuchsia::camera2::hal::Controller> controller;
auto controller_result = FakeController::Create(controller.NewRequest());
ASSERT_TRUE(controller_result.is_ok());
controller_ = controller_result.take_value();
fidl::InterfaceHandle<fuchsia::sysmem::Allocator> allocator;
context_->svc()->Connect(allocator.NewRequest());
auto device_result = DeviceImpl::Create(std::move(controller), std::move(allocator));
ASSERT_TRUE(device_result.is_ok());
device_ = device_result.take_value();
}
void TearDown() override {
device_ = nullptr;
controller_ = nullptr;
allocator_ = nullptr;
RunLoopUntilIdle();
}
static fit::function<void(zx_status_t status)> MakeErrorHandler(std::string server) {
return [server](zx_status_t status) {
ADD_FAILURE() << server << " server disconnected - " << status;
};
}
std::unique_ptr<sys::ComponentContext> context_;
std::unique_ptr<DeviceImpl> device_;
std::unique_ptr<FakeController> controller_;
fuchsia::sysmem::AllocatorPtr allocator_;
};
TEST_F(DeviceTest, CreateStreamNullConnection) { StreamImpl stream(nullptr, nullptr, 0, nop); }
TEST_F(DeviceTest, CreateStreamFakeLegacyStream) {
fidl::InterfaceHandle<fuchsia::camera2::Stream> handle;
auto result = FakeLegacyStream::Create(handle.NewRequest());
ASSERT_TRUE(result.is_ok());
{ StreamImpl stream(std::move(handle), nullptr, 0, nop); }
}
TEST_F(DeviceTest, CreateStreamNoClientBuffers) {
fuchsia::camera3::DevicePtr device;
device_->GetHandler()(device.NewRequest());
device.set_error_handler(MakeErrorHandler("Device"));
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token;
allocator_->AllocateSharedCollection(token.NewRequest());
fuchsia::camera3::StreamPtr stream;
device->ConnectToStream(0, std::move(token), stream.NewRequest());
bool stream_errored = false;
zx_status_t stream_status = ZX_OK;
stream.set_error_handler([&](zx_status_t status) {
stream_status = status;
stream_errored = true;
});
fuchsia::camera3::StreamPtr stream2;
stream->Rebind(stream2.NewRequest());
bool stream2_errored = false;
zx_status_t stream2_status = ZX_OK;
stream2.set_error_handler([&](zx_status_t status) {
stream2_status = status;
stream2_errored = true;
});
while (!HasFailure() && !(stream_errored && stream2_errored)) {
RunLoopUntilIdle();
}
EXPECT_EQ(stream_status, ZX_ERR_NOT_SUPPORTED);
EXPECT_EQ(stream2_status, ZX_ERR_NOT_SUPPORTED);
}
TEST_F(DeviceTest, ConvertConfig) {
auto configs = FakeController::GetDefaultConfigs();
ASSERT_FALSE(configs.empty());
auto& a = configs[0];
ASSERT_FALSE(a.stream_configs.empty());
ASSERT_FALSE(a.stream_configs[0].image_formats.empty());
auto result = Convert(a);
ASSERT_TRUE(result.is_ok());
auto b = result.take_value();
EXPECT_EQ(a.stream_configs.size(), b.streams.size());
ASSERT_FALSE(b.streams[0].supported_resolutions.empty());
EXPECT_EQ(a.stream_configs[0].image_formats[0].bytes_per_row,
b.streams[0].supported_resolutions[0].bytes_per_row);
}
TEST_F(DeviceTest, GetFrames) {
fidl::InterfaceHandle<fuchsia::camera2::Stream> handle;
auto result = FakeLegacyStream::Create(handle.NewRequest());
ASSERT_TRUE(result.is_ok());
auto legacy_stream_fake = result.take_value();
fuchsia::camera3::StreamPtr stream;
stream.set_error_handler(MakeErrorHandler("Stream"));
constexpr uint32_t kMaxCampingBuffers = 2;
constexpr uint32_t kBufferId1 = 42;
constexpr uint32_t kBufferId2 = 17;
auto stream_impl =
std::make_unique<StreamImpl>(std::move(handle), stream.NewRequest(), kMaxCampingBuffers, nop);
bool frame1_received = false;
bool frame2_received = false;
auto callback2 = [&](fuchsia::camera3::FrameInfo info) {
ASSERT_EQ(info.buffer_index, kBufferId2);
frame2_received = true;
};
auto callback1 = [&](fuchsia::camera3::FrameInfo info) {
ASSERT_EQ(info.buffer_index, kBufferId1);
frame1_received = true;
stream->GetNextFrame(std::move(callback2));
};
stream->GetNextFrame(std::move(callback1));
fuchsia::camera2::FrameAvailableInfo frame1_info;
frame1_info.frame_status = fuchsia::camera2::FrameStatus::OK;
frame1_info.buffer_id = kBufferId1;
frame1_info.metadata.set_timestamp(0);
ASSERT_EQ(legacy_stream_fake->SendFrameAvailable(std::move(frame1_info)), ZX_OK);
fuchsia::camera2::FrameAvailableInfo frame2_info;
frame2_info.frame_status = fuchsia::camera2::FrameStatus::OK;
frame2_info.buffer_id = kBufferId2;
frame2_info.metadata.set_timestamp(0);
ASSERT_EQ(legacy_stream_fake->SendFrameAvailable(std::move(frame2_info)), ZX_OK);
while (!HasFailure() && (!frame1_received || !frame2_received)) {
RunLoopUntilIdle();
}
auto client_result = legacy_stream_fake->StreamClientStatus();
EXPECT_TRUE(client_result.is_ok()) << client_result.error();
stream = nullptr;
stream_impl = nullptr;
}
TEST_F(DeviceTest, GetFramesInvalidCall) {
fidl::InterfaceHandle<fuchsia::camera2::Stream> handle;
auto result = FakeLegacyStream::Create(handle.NewRequest());
ASSERT_TRUE(result.is_ok());
auto legacy_stream_fake = result.take_value();
bool stream_errored = false;
fuchsia::camera3::StreamPtr stream;
stream.set_error_handler([&](zx_status_t status) {
EXPECT_EQ(status, ZX_ERR_BAD_STATE);
stream_errored = true;
});
auto stream_impl = std::make_unique<StreamImpl>(std::move(handle), stream.NewRequest(), 0, nop);
stream->GetNextFrame([](fuchsia::camera3::FrameInfo info) {});
stream->GetNextFrame([](fuchsia::camera3::FrameInfo info) {});
while (!HasFailure() && !stream_errored) {
RunLoopUntilIdle();
}
}
} // namespace camera