blob: acab026f2ca7fc131c641f1cb61827ae52bd9bca [file] [log] [blame]
// Copyright 2020 The Chromium OS 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 <memory>
#include <utility>
#include <base/run_loop.h>
#include <base/test/task_environment.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/public/cpp/bindings/binding.h>
#include <mojo/public/cpp/bindings/interface_request.h>
#include <power_manager/proto_bindings/power_supply_properties.pb.h>
#include "diagnostics/common/system/fake_powerd_adapter.h"
#include "diagnostics/cros_healthd/events/power_events_impl.h"
#include "diagnostics/cros_healthd/system/mock_context.h"
#include "mojo/cros_healthd_events.mojom.h"
namespace diagnostics {
namespace {
namespace mojo_ipc = ::chromeos::cros_healthd::mojom;
using ::testing::Invoke;
using ::testing::StrictMock;
class MockCrosHealthdPowerObserver : public mojo_ipc::CrosHealthdPowerObserver {
public:
MockCrosHealthdPowerObserver(
mojo_ipc::CrosHealthdPowerObserverRequest request)
: binding_{this /* impl */, std::move(request)} {
DCHECK(binding_.is_bound());
}
MockCrosHealthdPowerObserver(const MockCrosHealthdPowerObserver&) = delete;
MockCrosHealthdPowerObserver& operator=(const MockCrosHealthdPowerObserver&) =
delete;
MOCK_METHOD(void, OnAcInserted, (), (override));
MOCK_METHOD(void, OnAcRemoved, (), (override));
MOCK_METHOD(void, OnOsSuspend, (), (override));
MOCK_METHOD(void, OnOsResume, (), (override));
private:
mojo::Binding<mojo_ipc::CrosHealthdPowerObserver> binding_;
};
} // namespace
// Tests for the PowerEventsImpl class.
class PowerEventsImplTest : public testing::Test {
protected:
PowerEventsImplTest() = default;
PowerEventsImplTest(const PowerEventsImplTest&) = delete;
PowerEventsImplTest& operator=(const PowerEventsImplTest&) = delete;
void SetUp() override {
ASSERT_TRUE(mock_context_.Initialize());
// Before any observers have been added, we shouldn't have subscribed to
// powerd_adapter.
ASSERT_FALSE(fake_adapter()->HasPowerObserver(&power_events_impl_));
mojo_ipc::CrosHealthdPowerObserverPtr observer_ptr;
mojo_ipc::CrosHealthdPowerObserverRequest observer_request(
mojo::MakeRequest(&observer_ptr));
observer_ = std::make_unique<StrictMock<MockCrosHealthdPowerObserver>>(
std::move(observer_request));
power_events_impl_.AddObserver(std::move(observer_ptr));
// Now that an observer has been added, we should have subscribed to
// powerd_adapter.
ASSERT_TRUE(fake_adapter()->HasPowerObserver(&power_events_impl_));
}
PowerEventsImpl* power_events_impl() { return &power_events_impl_; }
FakePowerdAdapter* fake_adapter() {
return mock_context_.fake_powerd_adapter();
}
MockCrosHealthdPowerObserver* mock_observer() { return observer_.get(); }
base::test::TaskEnvironment* task_environment() { return &task_environment_; }
void DestroyMojoObserver() {
observer_.reset();
// Make sure |power_events_impl_| gets a chance to observe the connection
// error.
task_environment_.RunUntilIdle();
}
private:
base::test::TaskEnvironment task_environment_;
MockContext mock_context_;
std::unique_ptr<StrictMock<MockCrosHealthdPowerObserver>> observer_;
PowerEventsImpl power_events_impl_{&mock_context_};
};
// Test that we can receive AC inserted events from powerd's AC proto.
TEST_F(PowerEventsImplTest, ReceiveAcInsertedEventFromAcProto) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnAcInserted()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::PowerSupplyProperties power_supply;
power_supply.set_external_power(power_manager::PowerSupplyProperties::AC);
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
run_loop.Run();
}
// Test that we can receive AC inserted events from powerd's USB proto.
TEST_F(PowerEventsImplTest, ReceiveAcInsertedEventFromUsbProto) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnAcInserted()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::PowerSupplyProperties power_supply;
power_supply.set_external_power(power_manager::PowerSupplyProperties::USB);
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
run_loop.Run();
}
// Test that we can receive AC removed events.
TEST_F(PowerEventsImplTest, ReceiveAcRemovedEvent) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnAcRemoved()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::PowerSupplyProperties power_supply;
power_supply.set_external_power(
power_manager::PowerSupplyProperties::DISCONNECTED);
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
run_loop.Run();
}
// Test that we can receive OS suspend events from suspend imminent signals.
TEST_F(PowerEventsImplTest, ReceiveOsSuspendEventFromSuspendImminent) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnOsSuspend()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::SuspendImminent suspend_imminent;
fake_adapter()->EmitSuspendImminentSignal(suspend_imminent);
run_loop.Run();
}
// Test that we can receive OS suspend events from dark suspend imminent
// signals.
TEST_F(PowerEventsImplTest, ReceiveOsSuspendEventFromDarkSuspendImminent) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnOsSuspend()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::SuspendImminent suspend_imminent;
fake_adapter()->EmitDarkSuspendImminentSignal(suspend_imminent);
run_loop.Run();
}
// Test that we can receive OS resume events.
TEST_F(PowerEventsImplTest, ReceiveOsResumeEvent) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnOsResume()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
power_manager::SuspendDone suspend_done;
fake_adapter()->EmitSuspendDoneSignal(suspend_done);
run_loop.Run();
}
// Test that powerd events without external power are ignored.
TEST_F(PowerEventsImplTest, IgnorePayloadWithoutExternalPower) {
power_manager::PowerSupplyProperties power_supply;
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
task_environment()->RunUntilIdle();
}
// Test that multiple of the same powerd events in a row are only reported once.
TEST_F(PowerEventsImplTest, MultipleIdenticalPayloadsReportedOnlyOnce) {
base::RunLoop run_loop;
EXPECT_CALL(*mock_observer(), OnAcRemoved()).WillOnce(Invoke([&]() {
run_loop.Quit();
}));
// Make the first call, which should be reported.
power_manager::PowerSupplyProperties power_supply;
power_supply.set_external_power(
power_manager::PowerSupplyProperties::DISCONNECTED);
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
run_loop.Run();
// A second identical call should be ignored.
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
task_environment()->RunUntilIdle();
// Changing the type of external power should again be reported.
base::RunLoop run_loop2;
EXPECT_CALL(*mock_observer(), OnAcInserted()).WillOnce(Invoke([&]() {
run_loop2.Quit();
}));
power_supply.set_external_power(power_manager::PowerSupplyProperties::AC);
fake_adapter()->EmitPowerSupplyPollSignal(power_supply);
run_loop2.Run();
}
// Test that PowerEvents unsubscribes to PowerdAdapter when PowerEvents loses
// all of its mojo observers.
TEST_F(PowerEventsImplTest, UnsubscribeFromPowerdAdapterWhenAllObserversLost) {
DestroyMojoObserver();
// Emit an event, so that PowerEventsImpl has a chance to check for any
// remaining mojo observers.
power_manager::SuspendDone suspend_done;
fake_adapter()->EmitSuspendDoneSignal(suspend_done);
EXPECT_FALSE(fake_adapter()->HasPowerObserver(power_events_impl()));
}
} // namespace diagnostics