blob: 58925046164f9ce8af1c99175823d49f0f832faf [file] [log] [blame]
// Copyright 2023 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 <fidl/fuchsia.hardware.powersource.test/cpp/markers.h>
#include <fidl/fuchsia.hardware.powersource/cpp/wire.h>
#include <lib/async-loop/loop.h>
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/testing/cpp/driver_lifecycle.h>
#include <lib/driver/testing/cpp/driver_runtime.h>
#include <lib/driver/testing/cpp/test_environment.h>
#include <lib/driver/testing/cpp/test_node.h>
#include <lib/fdf/env.h>
#include <lib/fdf/testing.h>
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
#include "driver.h"
#include "power_source_protocol_server.h"
namespace fake_powersource::testing {
namespace {
using fuchsia_hardware_powersource::wire::BatteryInfo;
using fuchsia_hardware_powersource::wire::BatteryUnit;
using fuchsia_hardware_powersource::wire::PowerType;
// If the environment needs to run on a background driver dispatcher (for example if the driver
// needs to make sync FIDL calls), we need to run the environment on a background dispatcher while
// keeping the driver on the main thread.
class FakeBatteryDriverTest : public ::testing::Test {
public:
static void RunSyncClientTask(fit::closure task) {
// Spawn a separate thread to run the client task using an async::Loop.
async::Loop loop{&kAsyncLoopConfigNeverAttachToThread};
loop.StartThread();
zx::result result = fdf::RunOnDispatcherSync(loop.dispatcher(), std::move(task));
ASSERT_EQ(ZX_OK, result.status_value());
}
void SetUp() override {
// Create start args
zx::result start_args = node_server_.SyncCall(&fdf_testing::TestNode::CreateStartArgsAndServe);
EXPECT_EQ(ZX_OK, start_args.status_value());
// Start the test environment
zx::result init_result =
test_environment_.SyncCall(&fdf_testing::TestEnvironment::Initialize,
std::move(start_args->incoming_directory_server));
EXPECT_EQ(ZX_OK, init_result.status_value());
zx::result driver = runtime_.RunToCompletion(driver_.Start(std::move(start_args->start_args)));
EXPECT_EQ(ZX_OK, driver.status_value());
}
void TearDown() override {
zx::result result = runtime_.RunToCompletion(driver_.PrepareStop());
EXPECT_EQ(ZX_OK, result.status_value());
}
fdf_testing::DriverUnderTest<fake_powersource::Driver>& driver() { return driver_; }
async_dispatcher_t* env_dispatcher() { return test_env_dispatcher_->async_dispatcher(); }
async_patterns::TestDispatcherBound<fdf_testing::TestNode>& node_server() { return node_server_; }
private:
fdf_testing::DriverRuntime runtime_;
// Env dispatcher. Managed by driver runtime threads because we need to make sync calls into it.
fdf::UnownedSynchronizedDispatcher test_env_dispatcher_ = runtime_.StartBackgroundDispatcher();
async_patterns::TestDispatcherBound<fdf_testing::TestNode> node_server_{
env_dispatcher(), std::in_place, std::string("root")};
// The env_dispatcher is an fdf_dispatcher so we can add driver transport FIDL servers into this
// environment.
async_patterns::TestDispatcherBound<fdf_testing::TestEnvironment> test_environment_{
env_dispatcher(), std::in_place};
fdf_testing::DriverUnderTest<fake_powersource::Driver> driver_;
};
TEST_F(FakeBatteryDriverTest, CanGetInfo) {
// Safe to touch the driver from here since the driver_dispatcher is the default.
// Dispatcher allows sync calls from the driver so we use the sync version.
zx::result device_result = node_server().SyncCall([](fdf_testing::TestNode* root_node) {
return root_node->children().at("fake-battery").ConnectToDevice();
});
ASSERT_EQ(ZX_OK, device_result.status_value());
fidl::ClientEnd<fuchsia_hardware_powersource::Source> device_client_end(
std::move(device_result.value()));
fidl::WireSyncClient<fuchsia_hardware_powersource::Source> client(std::move(device_client_end));
RunSyncClientTask([this_client = std::move(client)]() {
{
fidl::WireResult result = this_client->GetPowerInfo();
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result.value().status, ZX_OK);
const auto& info = result.value().info;
ASSERT_EQ(info.type, PowerType::kBattery);
ASSERT_EQ(info.state, fuchsia_hardware_powersource::kPowerStateCharging |
fuchsia_hardware_powersource::kPowerStateOnline);
}
{
fidl::WireResult result = this_client->GetBatteryInfo();
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result.value().status, ZX_OK);
const auto& info = result.value().info;
ASSERT_EQ(info.present_rate, 2);
}
});
}
TEST_F(FakeBatteryDriverTest, CatGetEvent) {
// Safe to touch the driver from here since the driver_dispatcher is the default.
// Dispatcher allows sync calls from the driver so we use the sync version.
zx::result device_result = node_server().SyncCall([](fdf_testing::TestNode* root_node) {
return root_node->children().at("fake-battery").ConnectToDevice();
});
ASSERT_EQ(ZX_OK, device_result.status_value());
fidl::ClientEnd<fuchsia_hardware_powersource::Source> device_client_end(
std::move(device_result.value()));
fidl::WireSyncClient<fuchsia_hardware_powersource::Source> client(std::move(device_client_end));
device_result = node_server().SyncCall([](fdf_testing::TestNode* root_node) {
return root_node->children().at("battery-source-simulator").ConnectToDevice();
});
ASSERT_EQ(ZX_OK, device_result.status_value());
fidl::ClientEnd<fuchsia_hardware_powersource_test::SourceSimulator> test_client_end(
std::move(device_result.value()));
fidl::WireSyncClient<fuchsia_hardware_powersource_test::SourceSimulator> test_client(
std::move(test_client_end));
RunSyncClientTask([this_client = std::move(client), test_client = std::move(test_client)]() {
{
fidl::WireResult result = this_client->GetBatteryInfo();
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result.value().status, ZX_OK);
const auto& info = result.value().info;
ASSERT_EQ(info.remaining_capacity, 2950u);
}
{
fidl::WireResult result = this_client->GetStateChangeEvent();
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result.value().status, ZX_OK);
auto event = std::move(result.value().handle);
zx_signals_t pending = 0;
ASSERT_EQ(event.wait_one(ZX_USER_SIGNAL_0, zx::time::infinite_past(), &pending),
ZX_ERR_TIMED_OUT);
ASSERT_EQ(pending, 0u);
BatteryInfo battery_info{
/* unit */ BatteryUnit::kMa,
/* design_capacity */ 3000,
/* last_full_capacity */ 2950,
/* design_voltage */ 3000, // mV
/* capacity_warning */ 800,
/* capacity_low */ 500,
/* capacity_granularity_low_warning */ 20,
/* capacity_granularity_warning_full */ 1,
/* present_rate */ 2,
/* remaining_capacity */ 45, // Only changed this value
/* present_voltage */ 2900,
};
auto result2 = test_client->SetBatteryInfo(battery_info);
ASSERT_EQ(result2.status(), ZX_OK);
ASSERT_EQ(event.wait_one(ZX_USER_SIGNAL_0, zx::time::infinite(), &pending), ZX_OK);
ASSERT_EQ(pending, ZX_USER_SIGNAL_0);
}
{
fidl::WireResult result = this_client->GetBatteryInfo();
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result.value().status, ZX_OK);
const auto& info = result.value().info;
ASSERT_EQ(info.remaining_capacity, 45u);
}
});
}
} // namespace
} // namespace fake_powersource::testing