blob: 46b44c293b5a44061b2815c96896cc6e97bfcc6a [file] [log] [blame]
// Copyright 2021 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 "src/camera/bin/virtual_camera/virtual_camera_agent.h"
#include <fuchsia/camera/test/cpp/fidl.h>
#include <fuchsia/camera2/hal/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/sys/cpp/testing/component_context_provider.h>
#include <lib/syslog/cpp/macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/camera/bin/virtual_camera/stream_storage.h"
#include "src/camera/lib/stream_utils/stream_constraints.h"
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
namespace {
class FakeDeviceWatcherTester : public fuchsia::camera::test::DeviceWatcherTester {
public:
MOCK_METHOD(void, InjectDevice, (fidl::InterfaceHandle<fuchsia::hardware::camera::Device>),
(override));
MOCK_METHOD(void, InjectDeviceByPath, (std::string), (override));
FakeDeviceWatcherTester() {
ON_CALL(*this, InjectDevice)
.WillByDefault([this](fidl::InterfaceHandle<fuchsia::hardware::camera::Device> handle) {
device_ptr_.Bind(std::move(handle));
});
}
fidl::InterfaceRequestHandler<fuchsia::camera::test::DeviceWatcherTester> GetInterfaceHandler() {
return bindings_.GetHandler(this);
}
fidl::InterfacePtr<fuchsia::camera2::hal::Controller> GetHalController() {
if (!device_ptr_) {
return nullptr;
}
fidl::InterfacePtr<fuchsia::camera2::hal::Controller> controller;
device_ptr_->GetChannel2(controller.NewRequest());
return controller;
}
private:
fidl::BindingSet<fuchsia::camera::test::DeviceWatcherTester> bindings_;
fidl::InterfacePtr<fuchsia::hardware::camera::Device> device_ptr_;
};
class VirtualCameraAgentTest : public gtest::TestLoopFixture {
protected:
VirtualCameraAgentTest()
: provider_(), stream_storage_(), agent_under_test_(provider_.context(), stream_storage_) {}
void SetUp() override {
gtest::TestLoopFixture::SetUp();
// Create a |DeviceWatchterTester| and publish it.
provider_.service_directory_provider()->AddService<fuchsia::camera::test::DeviceWatcherTester>(
device_watcher_tester_.GetInterfaceHandler());
}
sys::testing::ComponentContextProvider provider_;
camera::StreamStorage stream_storage_;
camera::VirtualCameraAgent agent_under_test_;
FakeDeviceWatcherTester device_watcher_tester_;
};
TEST_F(VirtualCameraAgentTest, TestAddToDeviceWatcher) {
// |InjectDevice| should be called once.
EXPECT_CALL(device_watcher_tester_, InjectDevice(::testing::_)).Times(1);
// Call |AddToDeviceWatcher|. The response should not be an error.
agent_under_test_.AddToDeviceWatcher([](auto result) { EXPECT_TRUE(result.is_response()); });
// Run loop until call to |InjectDevice| completes.
RunLoopUntilIdle();
}
TEST_F(VirtualCameraAgentTest, TestAddToDeviceWatcher_CalledTwice) {
// |InjectDevice| should be called once. The second call should never happen
// as it should fail with an error.
EXPECT_CALL(device_watcher_tester_, InjectDevice(::testing::_)).Times(1);
// Call |AddToDeviceWatcher| twice. The first call should succeed. The second
// call should fail with ALREADY_ADDED_TO_DEVICE_WATCHER.
agent_under_test_.AddToDeviceWatcher([](auto result) { EXPECT_TRUE(result.is_response()); });
agent_under_test_.AddToDeviceWatcher([](auto result) {
EXPECT_TRUE(result.is_err());
EXPECT_EQ(result.err(),
fuchsia::camera::test::virtualcamera::Error::ALREADY_ADDED_TO_DEVICE_WATCHER);
});
// Run loop until call to |InjectDevice| completes.
RunLoopUntilIdle();
}
TEST_F(VirtualCameraAgentTest, TestConnectToHalController) {
// Create a |StreamConfig| and inject the device.
fuchsia::camera::test::virtualcamera::StreamConfig config;
config.set_width(100);
config.set_height(100);
agent_under_test_.AddStreamConfig(0, fidl::Clone(config));
agent_under_test_.AddToDeviceWatcher([](auto result) { EXPECT_TRUE(result.is_response()); });
RunLoopUntilIdle();
// Connect to the HAL controller. Verify it is bound.
fidl::InterfacePtr<fuchsia::camera2::hal::Controller> hal_controller =
device_watcher_tester_.GetHalController();
RunLoopUntilIdle();
EXPECT_TRUE(hal_controller);
// Get the device info.
hal_controller->GetDeviceInfo([](auto device_info) {
EXPECT_EQ(device_info.vendor_name(), "virtual_camera_vendor");
EXPECT_EQ(device_info.product_name(), "virtual_camera_product");
EXPECT_EQ(device_info.vendor_id(), 1);
EXPECT_EQ(device_info.product_id(), 2);
});
RunLoopUntilIdle();
// Get the configs. There should only be one config so the second call should
// return ZX_ERR_STOP
hal_controller->GetNextConfig(
[&config](std::unique_ptr<fuchsia::camera2::hal::Config> next_config, zx_status_t status) {
EXPECT_EQ(status, ZX_OK);
EXPECT_TRUE(next_config);
camera::StreamConstraints constraints(fuchsia::camera2::CameraStreamType::MONITORING);
constraints.AddImageFormat(config.width(), config.height(),
fuchsia::sysmem::PixelFormatType::NV12);
fuchsia::camera2::hal::Config expected_config;
expected_config.stream_configs.push_back(constraints.ConvertToStreamConfig());
EXPECT_TRUE(fidl::Equals(*next_config, expected_config));
});
RunLoopUntilIdle();
hal_controller->GetNextConfig(
[](std::unique_ptr<fuchsia::camera2::hal::Config> next_config, zx_status_t status) {
EXPECT_EQ(status, ZX_ERR_STOP);
EXPECT_FALSE(next_config);
});
RunLoopUntilIdle();
}
} // namespace