| // Copyright 2018 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 <fcntl.h> |
| #include <poll.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <base/files/file_path.h> |
| #include <base/files/scoped_file.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/logging.h> |
| #include <base/memory/ref_counted.h> |
| #include <base/memory/shared_memory.h> |
| #include <base/message_loop/message_loop.h> |
| #include <base/run_loop.h> |
| #include <base/strings/stringprintf.h> |
| #include <brillo/dbus/async_event_sequencer.h> |
| #include <dbus/wilco_dtc_supportd/dbus-constants.h> |
| #include <dbus/message.h> |
| #include <dbus/mock_bus.h> |
| #include <dbus/mock_exported_object.h> |
| #include <dbus/mock_object_proxy.h> |
| #include <dbus/property.h> |
| #include <gmock/gmock.h> |
| #include <google/protobuf/util/message_differencer.h> |
| #include <gtest/gtest.h> |
| #include <mojo/edk/embedder/embedder.h> |
| #include <mojo/public/cpp/bindings/binding.h> |
| #include <mojo/public/cpp/bindings/interface_ptr.h> |
| |
| #include "diagnostics/common/bind_utils.h" |
| #include "diagnostics/common/file_test_utils.h" |
| #include "diagnostics/common/protobuf_test_utils.h" |
| #include "diagnostics/wilco_dtc_supportd/ec_constants.h" |
| #include "diagnostics/wilco_dtc_supportd/fake_browser.h" |
| #include "diagnostics/wilco_dtc_supportd/fake_wilco_dtc.h" |
| #include "diagnostics/wilco_dtc_supportd/mojo_test_utils.h" |
| #include "diagnostics/wilco_dtc_supportd/mojo_utils.h" |
| #include "diagnostics/wilco_dtc_supportd/system/fake_powerd_adapter.h" |
| #include "diagnostics/wilco_dtc_supportd/system/mock_debugd_adapter.h" |
| #include "diagnostics/wilco_dtc_supportd/telemetry/ec_event_service.h" |
| #include "diagnostics/wilco_dtc_supportd/telemetry/fake_powerd_event_service.h" |
| #include "diagnostics/wilco_dtc_supportd/wilco_dtc_supportd_core.h" |
| #include "mojo/wilco_dtc_supportd.mojom.h" |
| #include "wilco_dtc_supportd.pb.h" // NOLINT(build/include) |
| |
| using testing::_; |
| using testing::Invoke; |
| using testing::Mock; |
| using testing::Return; |
| using testing::SaveArg; |
| using testing::StrictMock; |
| using testing::WithArg; |
| |
| namespace diagnostics { |
| |
| // Templates for the gRPC URIs that should be used for testing. "%s" is |
| // substituted with a temporary directory. |
| const char kWilcoDtcSupportdGrpcUriTemplate[] = |
| "unix:%s/test_wilco_dtc_supportd_socket"; |
| const char kWilcoDtcGrpcUriTemplate[] = "unix:%s/test_wilco_dtc_socket"; |
| const char kUiMessageReceiverWilcoDtcGrpcUriTemplate[] = |
| "unix:%s/test_ui_message_receiver_wilco_dtc_socket"; |
| |
| using EcEvent = EcEventService::EcEvent; |
| using MojomWilcoDtcSupportdService = |
| chromeos::wilco_dtc_supportd::mojom::WilcoDtcSupportdService; |
| using MojomWilcoDtcSupportdServiceFactory = |
| chromeos::wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory; |
| |
| namespace { |
| |
| // Returns a callback that, once called, saves its parameter to |*response| and |
| // quits |*run_loop|. |
| template <typename ValueType> |
| base::Callback<void(std::unique_ptr<ValueType>)> MakeAsyncResponseWriter( |
| std::unique_ptr<ValueType>* response, base::RunLoop* run_loop) { |
| return base::Bind( |
| [](std::unique_ptr<ValueType>* response, base::RunLoop* run_loop, |
| std::unique_ptr<ValueType> received_response) { |
| EXPECT_TRUE(received_response); |
| EXPECT_FALSE(*response); |
| *response = std::move(received_response); |
| run_loop->Quit(); |
| }, |
| base::Unretained(response), base::Unretained(run_loop)); |
| } |
| |
| class FakeWilcoDtcSupportdCoreDelegate : public WilcoDtcSupportdCore::Delegate { |
| public: |
| FakeWilcoDtcSupportdCoreDelegate() |
| : passed_debugd_adapter_( |
| std::make_unique<StrictMock<MockDebugdAdapter>>()), |
| passed_powerd_adapter_(std::make_unique<FakePowerdAdapter>()), |
| passed_powerd_event_service_( |
| std::make_unique<FakePowerdEventService>()), |
| debugd_adapter_(passed_debugd_adapter_.get()), |
| powerd_adapter_(passed_powerd_adapter_.get()), |
| powerd_event_service_(passed_powerd_event_service_.get()) {} |
| |
| std::unique_ptr<mojo::Binding<MojomWilcoDtcSupportdServiceFactory>> |
| BindWilcoDtcSupportdMojoServiceFactory( |
| MojomWilcoDtcSupportdServiceFactory* mojo_service_factory, |
| base::ScopedFD mojo_pipe_fd) override { |
| // Redirect to a separate mockable method to workaround GMock's issues with |
| // move-only types. |
| return std::unique_ptr<mojo::Binding<MojomWilcoDtcSupportdServiceFactory>>( |
| BindWilcoDtcSupportdMojoServiceFactoryImpl(mojo_service_factory, |
| mojo_pipe_fd.get())); |
| } |
| |
| // Must be called no more than once. |
| std::unique_ptr<DebugdAdapter> CreateDebugdAdapter( |
| const scoped_refptr<dbus::Bus>& bus) override { |
| DCHECK(bus); |
| DCHECK(passed_debugd_adapter_); |
| return std::move(passed_debugd_adapter_); |
| } |
| |
| // Must be called no more than once. |
| std::unique_ptr<PowerdAdapter> CreatePowerdAdapter( |
| const scoped_refptr<dbus::Bus>& bus) override { |
| DCHECK(bus); |
| DCHECK(passed_powerd_adapter_); |
| return std::move(passed_powerd_adapter_); |
| } |
| |
| // Must be called no more than once. |
| std::unique_ptr<PowerdEventService> CreatePowerdEventService( |
| PowerdAdapter* powerd_adapter) override { |
| DCHECK(powerd_adapter); |
| DCHECK(passed_powerd_event_service_); |
| return std::move(passed_powerd_event_service_); |
| } |
| |
| StrictMock<MockDebugdAdapter>* debugd_adapter() const { |
| return debugd_adapter_; |
| } |
| |
| FakePowerdEventService* powerd_event_service() const { |
| return powerd_event_service_; |
| } |
| |
| MOCK_METHOD(mojo::Binding<MojomWilcoDtcSupportdServiceFactory>*, |
| BindWilcoDtcSupportdMojoServiceFactoryImpl, |
| (MojomWilcoDtcSupportdServiceFactory*, int)); |
| MOCK_METHOD(void, BeginDaemonShutdown, (), (override)); |
| |
| private: |
| // Mock objects to be transferred by Create* methods. |
| std::unique_ptr<StrictMock<MockDebugdAdapter>> passed_debugd_adapter_; |
| std::unique_ptr<FakePowerdAdapter> passed_powerd_adapter_; |
| std::unique_ptr<FakePowerdEventService> passed_powerd_event_service_; |
| |
| // Pointers to objects originally stored in |passed_*| members. These allow |
| // continued access by tests even after the corresponding Create* method has |
| // been called and ownership has been transferred to |core_|. |
| StrictMock<MockDebugdAdapter>* debugd_adapter_; |
| FakePowerdAdapter* powerd_adapter_; |
| FakePowerdEventService* powerd_event_service_; |
| }; |
| |
| // Tests for the WilcoDtcSupportdCore class. |
| class WilcoDtcSupportdCoreTest : public testing::Test { |
| protected: |
| WilcoDtcSupportdCoreTest() { InitializeMojo(); } |
| |
| void CreateCore(const std::vector<std::string>& grpc_service_uris, |
| const std::string& ui_message_receiver_wilco_dtc_grpc_uri, |
| const std::vector<std::string>& wilco_dtc_grpc_uris) { |
| core_ = std::make_unique<WilcoDtcSupportdCore>( |
| grpc_service_uris, ui_message_receiver_wilco_dtc_grpc_uri, |
| wilco_dtc_grpc_uris, &core_delegate_); |
| } |
| |
| WilcoDtcSupportdCore* core() { |
| DCHECK(core_); |
| return core_.get(); |
| } |
| |
| FakeWilcoDtcSupportdCoreDelegate* core_delegate() { return &core_delegate_; } |
| |
| private: |
| // Initialize the Mojo subsystem. |
| void InitializeMojo() { mojo::edk::Init(); } |
| |
| base::MessageLoop message_loop_; |
| |
| StrictMock<FakeWilcoDtcSupportdCoreDelegate> core_delegate_; |
| |
| std::unique_ptr<WilcoDtcSupportdCore> core_; |
| }; |
| |
| // Test successful shutdown after failed start. |
| TEST_F(WilcoDtcSupportdCoreTest, FailedStartAndSuccessfulShutdown) { |
| // Invalid gRPC service URI. |
| CreateCore({""}, "", {""}); |
| EXPECT_FALSE(core()->Start()); |
| |
| base::RunLoop run_loop; |
| core()->ShutDown(run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| // Tests for the WilcoDtcSupportdCore class which started successfully. |
| class StartedWilcoDtcSupportdCoreTest : public WilcoDtcSupportdCoreTest { |
| protected: |
| void SetUp() override { |
| ASSERT_NO_FATAL_FAILURE(WilcoDtcSupportdCoreTest::SetUp()); |
| |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| |
| wilco_dtc_supportd_grpc_uri_ = base::StringPrintf( |
| kWilcoDtcSupportdGrpcUriTemplate, temp_dir_.GetPath().value().c_str()); |
| ui_message_receiver_wilco_dtc_grpc_uri_ = |
| base::StringPrintf(kUiMessageReceiverWilcoDtcGrpcUriTemplate, |
| temp_dir_.GetPath().value().c_str()); |
| |
| wilco_dtc_grpc_uri_ = base::StringPrintf( |
| kWilcoDtcGrpcUriTemplate, temp_dir_.GetPath().value().c_str()); |
| |
| CreateCore({wilco_dtc_supportd_grpc_uri_}, |
| ui_message_receiver_wilco_dtc_grpc_uri_, {wilco_dtc_grpc_uri_}); |
| core()->set_root_dir_for_testing(temp_dir_.GetPath()); |
| |
| SetUpEcEventService(); |
| |
| ASSERT_TRUE(core()->Start()); |
| |
| SetUpEcEventServiceFifoWriteEnd(); |
| |
| SetUpDBus(); |
| |
| fake_browser_ = |
| std::make_unique<FakeBrowser>(&mojo_service_factory_interface_ptr_, |
| bootstrap_mojo_connection_dbus_method_); |
| } |
| |
| void TearDown() override { |
| SetDBusShutdownExpectations(); |
| |
| base::RunLoop run_loop; |
| core()->ShutDown(run_loop.QuitClosure()); |
| run_loop.Run(); |
| |
| WilcoDtcSupportdCoreTest::TearDown(); |
| } |
| |
| const base::FilePath& temp_dir_path() const { |
| DCHECK(temp_dir_.IsValid()); |
| return temp_dir_.GetPath(); |
| } |
| |
| mojo::InterfacePtr<MojomWilcoDtcSupportdServiceFactory>* |
| mojo_service_factory_interface_ptr() { |
| return &mojo_service_factory_interface_ptr_; |
| } |
| |
| FakeBrowser* fake_browser() { |
| DCHECK(fake_browser_); |
| return fake_browser_.get(); |
| } |
| |
| // Set up mock for BindWilcoDtcSupportdMojoServiceFactory() that simulates |
| // successful Mojo service binding to the given file descriptor. After the |
| // mock gets triggered, |mojo_service_factory_interface_ptr_| become |
| // initialized to point to the tested Mojo service. |
| void SetSuccessMockBindWilcoDtcSupportdMojoService( |
| FakeMojoFdGenerator* fake_mojo_fd_generator) { |
| EXPECT_CALL(*core_delegate(), |
| BindWilcoDtcSupportdMojoServiceFactoryImpl(_, _)) |
| .WillOnce(Invoke( |
| [fake_mojo_fd_generator, this]( |
| MojomWilcoDtcSupportdServiceFactory* mojo_service_factory, |
| int mojo_pipe_fd) { |
| // Verify the file descriptor is a duplicate of an expected one. |
| EXPECT_TRUE(fake_mojo_fd_generator->IsDuplicateFd(mojo_pipe_fd)); |
| // Initialize a Mojo binding that, instead of working through the |
| // given (fake) file descriptor, talks to the test endpoint |
| // |mojo_service_interface_ptr_|. |
| auto mojo_service_factory_binding = std::make_unique< |
| mojo::Binding<MojomWilcoDtcSupportdServiceFactory>>( |
| mojo_service_factory, &mojo_service_factory_interface_ptr_); |
| DCHECK(mojo_service_factory_interface_ptr_); |
| return mojo_service_factory_binding.release(); |
| })); |
| } |
| |
| void WriteEcEventToEcEventFile(const EcEvent& ec_event) const { |
| ASSERT_EQ(write(ec_event_service_fd_.get(), &ec_event, sizeof(ec_event)), |
| sizeof(ec_event)); |
| } |
| |
| dbus::ExportedObject::MethodCallCallback |
| bootstrap_mojo_connection_dbus_method() { |
| return bootstrap_mojo_connection_dbus_method_; |
| } |
| |
| const std::string& wilco_dtc_supportd_grpc_uri() const { |
| DCHECK(!wilco_dtc_supportd_grpc_uri_.empty()); |
| return wilco_dtc_supportd_grpc_uri_; |
| } |
| |
| const std::string& ui_message_receiver_wilco_dtc_grpc_uri() const { |
| DCHECK(!ui_message_receiver_wilco_dtc_grpc_uri_.empty()); |
| return ui_message_receiver_wilco_dtc_grpc_uri_; |
| } |
| |
| const std::string& wilco_dtc_grpc_uri() const { |
| DCHECK(!wilco_dtc_grpc_uri_.empty()); |
| return wilco_dtc_grpc_uri_; |
| } |
| |
| private: |
| // Perform initialization of the D-Bus object exposed by the tested code. |
| void SetUpDBus() { |
| const dbus::ObjectPath kDBusObjectPath(kWilcoDtcSupportdServicePath); |
| |
| // Expect that the /org/chromium/WilcoDtcSupportd object is exported. |
| wilco_dtc_supportd_dbus_object_ = new StrictMock<dbus::MockExportedObject>( |
| dbus_bus_.get(), kDBusObjectPath); |
| EXPECT_CALL(*dbus_bus_, GetExportedObject(kDBusObjectPath)) |
| .WillOnce(Return(wilco_dtc_supportd_dbus_object_.get())); |
| |
| // Expect that standard methods on the org.freedesktop.DBus.Properties |
| // interface are exported. |
| EXPECT_CALL( |
| *wilco_dtc_supportd_dbus_object_, |
| ExportMethod(dbus::kPropertiesInterface, dbus::kPropertiesGet, _, _)); |
| EXPECT_CALL( |
| *wilco_dtc_supportd_dbus_object_, |
| ExportMethod(dbus::kPropertiesInterface, dbus::kPropertiesSet, _, _)); |
| EXPECT_CALL(*wilco_dtc_supportd_dbus_object_, |
| ExportMethod(dbus::kPropertiesInterface, |
| dbus::kPropertiesGetAll, _, _)); |
| |
| // Expect that methods on the org.chromium.WilcoDtcSupportdInterface |
| // interface are exported. |
| EXPECT_CALL( |
| *wilco_dtc_supportd_dbus_object_, |
| ExportMethod(kWilcoDtcSupportdServiceInterface, |
| kWilcoDtcSupportdBootstrapMojoConnectionMethod, _, _)) |
| .WillOnce(SaveArg<2 /* method_call_callback */>( |
| &bootstrap_mojo_connection_dbus_method_)); |
| |
| // Run the tested code that exports D-Bus objects and methods. |
| scoped_refptr<brillo::dbus_utils::AsyncEventSequencer> dbus_sequencer( |
| new brillo::dbus_utils::AsyncEventSequencer()); |
| core()->RegisterDBusObjectsAsync(dbus_bus_, dbus_sequencer.get()); |
| |
| // Verify that required D-Bus methods are exported. |
| EXPECT_FALSE(bootstrap_mojo_connection_dbus_method_.is_null()); |
| } |
| |
| // Set mock expectations for calls triggered during test destruction. |
| void SetDBusShutdownExpectations() { |
| EXPECT_CALL(*wilco_dtc_supportd_dbus_object_, Unregister()); |
| } |
| |
| // Creates FIFO to emulates the EC event file used by EC event service. |
| void SetUpEcEventService() { |
| core()->set_ec_event_service_fd_events_for_testing(POLLIN); |
| ASSERT_TRUE(base::CreateDirectory(ec_event_file_path().DirName())); |
| ASSERT_EQ(mkfifo(ec_event_file_path().value().c_str(), 0600), 0); |
| } |
| |
| // Setups |ec_event_service_fd_| FIFO file descriptor. Must be called only |
| // after |WilcoDtcSupportdCore::Start()| call. Otherwise, it will block |
| // thread. |
| void SetUpEcEventServiceFifoWriteEnd() { |
| ASSERT_FALSE(ec_event_service_fd_.is_valid()); |
| ec_event_service_fd_.reset( |
| open(ec_event_file_path().value().c_str(), O_WRONLY)); |
| ASSERT_TRUE(ec_event_service_fd_.is_valid()); |
| } |
| |
| base::FilePath ec_event_file_path() const { |
| return temp_dir_.GetPath().Append(kEcEventFilePath); |
| } |
| |
| base::ScopedTempDir temp_dir_; |
| |
| // gRPC URI on which the tested "WilcoDtcSupportd" gRPC service (owned by |
| // WilcoDtcSupportdCore) is listening. |
| std::string wilco_dtc_supportd_grpc_uri_; |
| // gRPC URI on which the fake "WilcoDtc" gRPC service (owned by FakeWilcoDtc) |
| // is listening, eligible to receive UI messages. |
| std::string ui_message_receiver_wilco_dtc_grpc_uri_; |
| // gRPC URI on which the fake "WilcoDtc" gRPC service (owned by FakeWilcoDtc) |
| // is listening. |
| std::string wilco_dtc_grpc_uri_; |
| |
| scoped_refptr<StrictMock<dbus::MockBus>> dbus_bus_ = |
| new StrictMock<dbus::MockBus>(dbus::Bus::Options()); |
| |
| // Mock D-Bus integration helper for the object exposed by the tested code. |
| scoped_refptr<StrictMock<dbus::MockExportedObject>> |
| wilco_dtc_supportd_dbus_object_; |
| |
| // Mojo interface to the service factory exposed by the tested code. |
| mojo::InterfacePtr<MojomWilcoDtcSupportdServiceFactory> |
| mojo_service_factory_interface_ptr_; |
| |
| // Write end of FIFO that emulates EC event file. EC event service |
| // operates with read end of FIFO as with usual file. |
| // Must be initialized only after |WilcoDtcSupportdCore::Start()| call. |
| base::ScopedFD ec_event_service_fd_; |
| |
| // Callback that the tested code exposed as the BootstrapMojoConnection D-Bus |
| // method. |
| dbus::ExportedObject::MethodCallCallback |
| bootstrap_mojo_connection_dbus_method_; |
| |
| std::unique_ptr<FakeBrowser> fake_browser_; |
| }; |
| |
| // Test that the Mojo service gets successfully bootstrapped after the |
| // BootstrapMojoConnection D-Bus method is called. |
| TEST_F(StartedWilcoDtcSupportdCoreTest, MojoBootstrapSuccess) { |
| FakeMojoFdGenerator fake_mojo_fd_generator; |
| SetSuccessMockBindWilcoDtcSupportdMojoService(&fake_mojo_fd_generator); |
| |
| EXPECT_TRUE(fake_browser()->BootstrapMojoConnection(&fake_mojo_fd_generator)); |
| |
| EXPECT_TRUE(*mojo_service_factory_interface_ptr()); |
| } |
| |
| // Test failure to bootstrap the Mojo service due to en error returned by |
| // BindWilcoDtcSupportdMojoService() delegate method. |
| TEST_F(StartedWilcoDtcSupportdCoreTest, MojoBootstrapErrorToBind) { |
| FakeMojoFdGenerator fake_mojo_fd_generator; |
| EXPECT_CALL(*core_delegate(), |
| BindWilcoDtcSupportdMojoServiceFactoryImpl(_, _)) |
| .WillOnce(Return(nullptr)); |
| EXPECT_CALL(*core_delegate(), BeginDaemonShutdown()); |
| |
| EXPECT_FALSE( |
| fake_browser()->BootstrapMojoConnection(&fake_mojo_fd_generator)); |
| |
| Mock::VerifyAndClearExpectations(core_delegate()); |
| } |
| |
| // Test that second attempt to bootstrap the Mojo service results in error and |
| // the daemon shutdown. |
| TEST_F(StartedWilcoDtcSupportdCoreTest, MojoBootstrapErrorRepeated) { |
| FakeMojoFdGenerator first_fake_mojo_fd_generator; |
| SetSuccessMockBindWilcoDtcSupportdMojoService(&first_fake_mojo_fd_generator); |
| |
| EXPECT_TRUE( |
| fake_browser()->BootstrapMojoConnection(&first_fake_mojo_fd_generator)); |
| Mock::VerifyAndClearExpectations(core_delegate()); |
| |
| FakeMojoFdGenerator second_fake_mojo_fd_generator; |
| EXPECT_CALL(*core_delegate(), BeginDaemonShutdown()); |
| |
| EXPECT_FALSE( |
| fake_browser()->BootstrapMojoConnection(&second_fake_mojo_fd_generator)); |
| |
| Mock::VerifyAndClearExpectations(core_delegate()); |
| } |
| |
| // Test that the daemon gets shut down when the previously bootstrapped Mojo |
| // connection aborts. |
| TEST_F(StartedWilcoDtcSupportdCoreTest, MojoBootstrapSuccessThenAbort) { |
| FakeMojoFdGenerator fake_mojo_fd_generator; |
| SetSuccessMockBindWilcoDtcSupportdMojoService(&fake_mojo_fd_generator); |
| |
| EXPECT_TRUE(fake_browser()->BootstrapMojoConnection(&fake_mojo_fd_generator)); |
| |
| Mock::VerifyAndClearExpectations(core_delegate()); |
| |
| EXPECT_CALL(*core_delegate(), BeginDaemonShutdown()); |
| |
| // Abort the Mojo connection by closing the browser-side endpoint. |
| mojo_service_factory_interface_ptr()->reset(); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(core_delegate()); |
| } |
| |
| // Tests for the WilcoDtcSupportdCore class with the already established Mojo |
| // connection to the fake browser and gRPC communication with the fake |
| // wilco_dtc. |
| class BootstrappedWilcoDtcSupportdCoreTest |
| : public StartedWilcoDtcSupportdCoreTest { |
| protected: |
| void SetUp() override { |
| ASSERT_NO_FATAL_FAILURE(StartedWilcoDtcSupportdCoreTest::SetUp()); |
| |
| FakeMojoFdGenerator fake_mojo_fd_generator; |
| SetSuccessMockBindWilcoDtcSupportdMojoService(&fake_mojo_fd_generator); |
| ASSERT_TRUE( |
| fake_browser()->BootstrapMojoConnection(&fake_mojo_fd_generator)); |
| ASSERT_TRUE(*mojo_service_factory_interface_ptr()); |
| |
| fake_wilco_dtc_ = std::make_unique<FakeWilcoDtc>( |
| wilco_dtc_grpc_uri(), wilco_dtc_supportd_grpc_uri()); |
| |
| fake_ui_message_receiver_wilco_dtc_ = |
| std::make_unique<FakeWilcoDtc>(ui_message_receiver_wilco_dtc_grpc_uri(), |
| wilco_dtc_supportd_grpc_uri()); |
| } |
| |
| void TearDown() override { |
| fake_wilco_dtc_.reset(); |
| fake_ui_message_receiver_wilco_dtc_.reset(); |
| StartedWilcoDtcSupportdCoreTest::TearDown(); |
| } |
| |
| FakeWilcoDtc* fake_ui_message_receiver_wilco_dtc() { |
| return fake_ui_message_receiver_wilco_dtc_.get(); |
| } |
| |
| FakeWilcoDtc* fake_wilco_dtc() { return fake_wilco_dtc_.get(); } |
| |
| base::Callback<void(mojo::ScopedHandle)> fake_browser_valid_handle_callback( |
| const base::Closure& callback, |
| const std::string& expected_response_json_message) { |
| return base::Bind( |
| [](const base::Closure& callback, |
| const std::string& expected_response_json_message, |
| mojo::ScopedHandle response_json_message_handle) { |
| std::unique_ptr<base::SharedMemory> shared_memory = |
| GetReadOnlySharedMemoryFromMojoHandle( |
| std::move(response_json_message_handle)); |
| ASSERT_TRUE(shared_memory); |
| ASSERT_EQ( |
| expected_response_json_message, |
| std::string(static_cast<const char*>(shared_memory->memory()), |
| shared_memory->mapped_size())); |
| callback.Run(); |
| }, |
| callback, expected_response_json_message); |
| } |
| |
| base::Callback<void(mojo::ScopedHandle)> fake_browser_invalid_handle_callback( |
| const base::Closure& callback) { |
| return base::Bind( |
| [](const base::Closure& callback, |
| mojo::ScopedHandle response_json_message_handle) { |
| ASSERT_FALSE(response_json_message_handle.is_valid()); |
| callback.Run(); |
| }, |
| callback); |
| } |
| |
| MockMojomWilcoDtcSupportdClient* wilco_dtc_supportd_client() { |
| return fake_browser()->wilco_dtc_supportd_client(); |
| } |
| |
| private: |
| std::unique_ptr<FakeWilcoDtc> fake_ui_message_receiver_wilco_dtc_; |
| std::unique_ptr<FakeWilcoDtc> fake_wilco_dtc_; |
| }; |
| |
| // Test that the UI message receiver wilco_dtc will receive message from |
| // browser. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, SendGrpcUiMessageToWilcoDtc) { |
| const std::string json_message = "{\"some_key\": \"some_value\"}"; |
| const std::string response_json_message = "{\"key\": \"value\"}"; |
| |
| base::RunLoop run_loop_wilco_dtc; |
| base::RunLoop run_loop_fake_browser; |
| |
| fake_ui_message_receiver_wilco_dtc()->set_handle_message_from_ui_callback( |
| run_loop_wilco_dtc.QuitClosure()); |
| fake_ui_message_receiver_wilco_dtc() |
| ->set_handle_message_from_ui_json_message_response(response_json_message); |
| fake_wilco_dtc()->set_handle_message_from_ui_callback(base::Bind([]() { |
| // The wilco_dtc not eligible to receive messages from UI must not |
| // receive them. |
| FAIL(); |
| })); |
| |
| auto callback = fake_browser_valid_handle_callback( |
| run_loop_fake_browser.QuitClosure(), response_json_message); |
| EXPECT_TRUE(fake_browser()->SendUiMessageToWilcoDtc(json_message, callback)); |
| |
| run_loop_wilco_dtc.Run(); |
| run_loop_fake_browser.Run(); |
| EXPECT_EQ(json_message, fake_ui_message_receiver_wilco_dtc() |
| ->handle_message_from_ui_actual_json_message()); |
| } |
| |
| // Test that the UI message receiver wilco_dtc will not receive message from |
| // browser if JSON message is invalid. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcUiMessageToWilcoDtcInvalidJSON) { |
| const std::string json_message = "{'some_key': 'some_value'}"; |
| |
| base::RunLoop run_loop_fake_browser; |
| |
| auto callback = |
| fake_browser_invalid_handle_callback(run_loop_fake_browser.QuitClosure()); |
| EXPECT_TRUE(fake_browser()->SendUiMessageToWilcoDtc(json_message, callback)); |
| |
| run_loop_fake_browser.Run(); |
| // There's no reliable way to wait till the wrong HandleMessageFromUi(), if |
| // the tested code is buggy and calls it, gets executed. The RunUntilIdle() is |
| // used to make the test failing at least with some probability in case of |
| // such a bug. |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(fake_ui_message_receiver_wilco_dtc() |
| ->handle_message_from_ui_actual_json_message() |
| .has_value()); |
| } |
| |
| // Test that the UI message receiver wilco_dtc will receive message from |
| // browser. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcUiMessageToWilcoDtcInvalidResponseJSON) { |
| const std::string json_message = "{\"some_key\": \"some_value\"}"; |
| const std::string response_json_message = "{'key': 'value'}"; |
| |
| base::RunLoop run_loop_wilco_dtc; |
| base::RunLoop run_loop_fake_browser; |
| |
| fake_ui_message_receiver_wilco_dtc()->set_handle_message_from_ui_callback( |
| run_loop_wilco_dtc.QuitClosure()); |
| fake_ui_message_receiver_wilco_dtc() |
| ->set_handle_message_from_ui_json_message_response(response_json_message); |
| |
| auto callback = |
| fake_browser_invalid_handle_callback(run_loop_fake_browser.QuitClosure()); |
| EXPECT_TRUE(fake_browser()->SendUiMessageToWilcoDtc(json_message, callback)); |
| |
| run_loop_wilco_dtc.Run(); |
| run_loop_fake_browser.Run(); |
| EXPECT_EQ(json_message, fake_ui_message_receiver_wilco_dtc() |
| ->handle_message_from_ui_actual_json_message()); |
| } |
| |
| // Test that wilco_dtc will be notified about configuration changes from |
| // browser. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, NotifyConfigurationDataChanged) { |
| base::RunLoop run_loop; |
| const base::Closure barrier_closure = |
| BarrierClosure(2, run_loop.QuitClosure()); |
| |
| fake_ui_message_receiver_wilco_dtc()->set_configuration_data_changed_callback( |
| barrier_closure); |
| fake_wilco_dtc()->set_configuration_data_changed_callback(barrier_closure); |
| |
| fake_browser()->NotifyConfigurationDataChanged(); |
| run_loop.Run(); |
| } |
| |
| // Test that message can be send from wilco_dtc to browser and |
| // returns an expected response |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, SendWilcoDtcMessageToUi) { |
| const std::string kFakeMessageToUi = |
| "{\"fake-message\": \"Fake JSON message\"}"; |
| EXPECT_CALL(*wilco_dtc_supportd_client(), |
| SendWilcoDtcMessageToUiImpl(kFakeMessageToUi, _)); |
| |
| std::unique_ptr<grpc_api::SendMessageToUiResponse> response; |
| { |
| base::RunLoop run_loop; |
| grpc_api::SendMessageToUiRequest request; |
| request.set_json_message(kFakeMessageToUi); |
| fake_wilco_dtc()->SendMessageToUi( |
| request, MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(response); |
| grpc_api::SendMessageToUiResponse expected_response; |
| expected_response.set_response_json_message(kFakeMessageToUi); |
| EXPECT_THAT(*response, ProtobufEquals(expected_response)) |
| << "Actual: {" << response->ShortDebugString() << "}"; |
| } |
| |
| // Test that the GetProcData() method exposed by the daemon's gRPC server |
| // returns a dump of the corresponding file from the disk. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, GetProcDataGrpcCall) { |
| const std::string kFakeFileContents = "foo"; |
| const base::FilePath file_path = temp_dir_path().Append("proc/uptime"); |
| ASSERT_TRUE(WriteFileAndCreateParentDirs(file_path, kFakeFileContents)); |
| |
| grpc_api::GetProcDataRequest request; |
| request.set_type(grpc_api::GetProcDataRequest::FILE_UPTIME); |
| std::unique_ptr<grpc_api::GetProcDataResponse> response; |
| base::RunLoop run_loop; |
| fake_wilco_dtc()->GetProcData(request, |
| MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(response); |
| grpc_api::GetProcDataResponse expected_response; |
| expected_response.add_file_dump(); |
| expected_response.mutable_file_dump(0)->set_path(file_path.value()); |
| expected_response.mutable_file_dump(0)->set_canonical_path(file_path.value()); |
| expected_response.mutable_file_dump(0)->set_contents(kFakeFileContents); |
| EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( |
| *response, expected_response)) |
| << "Obtained: " << response->ShortDebugString() |
| << ",\nExpected: " << expected_response.ShortDebugString(); |
| } |
| |
| // Test that the GetEcTelemetry() method exposed by the daemon's gRPC server |
| // writes payload to devfs file exposed by the EC driver and reads response |
| // using the same file. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, GetEcTelemetryGrpcCall) { |
| const base::FilePath file_path = |
| temp_dir_path().Append(kEcGetTelemetryFilePath); |
| const std::string kRequestPayload = "12345"; |
| const std::string kResponsePayload = "67890"; |
| |
| // Write request and response payload because EC telemetry char device is |
| // non-seekable. |
| ASSERT_TRUE(WriteFileAndCreateParentDirs(file_path, |
| kRequestPayload + kResponsePayload)); |
| |
| grpc_api::GetEcTelemetryRequest request; |
| request.set_payload(kRequestPayload); |
| std::unique_ptr<grpc_api::GetEcTelemetryResponse> response; |
| base::RunLoop run_loop; |
| fake_wilco_dtc()->GetEcTelemetry( |
| request, MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(response); |
| grpc_api::GetEcTelemetryResponse expected_response; |
| expected_response.set_status(grpc_api::GetEcTelemetryResponse::STATUS_OK); |
| expected_response.set_payload(kResponsePayload); |
| EXPECT_THAT(*response, ProtobufEquals(expected_response)) |
| << "Actual: {" << response->ShortDebugString() << "}"; |
| } |
| |
| // Test that PerformWebRequest() method exposed by the daemon's gRPC returns a |
| // Web request response from the browser. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, PerformWebRequestToBrowser) { |
| constexpr char kHttpsUrl[] = "https://www.google.com"; |
| constexpr int kHttpStatusOk = 200; |
| |
| grpc_api::PerformWebRequestParameter request; |
| request.set_http_method( |
| grpc_api::PerformWebRequestParameter::HTTP_METHOD_GET); |
| request.set_url(kHttpsUrl); |
| |
| std::unique_ptr<grpc_api::PerformWebRequestResponse> response; |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(*fake_browser()->wilco_dtc_supportd_client(), |
| PerformWebRequestImpl(_, _, _, _, _)); |
| fake_wilco_dtc()->PerformWebRequest( |
| request, MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(response); |
| grpc_api::PerformWebRequestResponse expected_response; |
| expected_response.set_status(grpc_api::PerformWebRequestResponse::STATUS_OK); |
| expected_response.set_http_status(kHttpStatusOk); |
| EXPECT_THAT(*response, ProtobufEquals(expected_response)) |
| << "Actual: {" << response->ShortDebugString() << "}"; |
| } |
| |
| // Test that GetConfigurationData() method exposed by the daemon's gRPC returns |
| // a response from the browser. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, GetConfigurationDataFromBrowser) { |
| constexpr char kFakeJsonConfigurationData[] = |
| "{\"fake-message\": \"Fake JSON configuration data\"}"; |
| EXPECT_CALL(*wilco_dtc_supportd_client(), GetConfigurationData(_)) |
| .WillOnce( |
| Invoke([kFakeJsonConfigurationData]( |
| const base::Callback<void(const std::string&)>& callback) { |
| callback.Run(kFakeJsonConfigurationData); |
| })); |
| std::unique_ptr<grpc_api::GetConfigurationDataResponse> response; |
| { |
| base::RunLoop run_loop; |
| grpc_api::GetConfigurationDataRequest request; |
| fake_wilco_dtc()->GetConfigurationData( |
| request, MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(response); |
| grpc_api::GetConfigurationDataResponse expected_response; |
| expected_response.set_json_configuration_data(kFakeJsonConfigurationData); |
| EXPECT_THAT(*response, ProtobufEquals(expected_response)) |
| << "Actual: {" << response->ShortDebugString() << "}"; |
| } |
| |
| // Test that GetDriveSystemData() method exposed by the daemon's gRPC returns |
| // a response from the debugd. |
| TEST_F(BootstrappedWilcoDtcSupportdCoreTest, GetDriveSystemData) { |
| constexpr char kFakeSmartctlData[] = "Fake smartctl data"; |
| EXPECT_CALL(*core_delegate()->debugd_adapter(), GetSmartAttributes(_)) |
| .WillOnce(WithArg<0>( |
| [kFakeSmartctlData]( |
| const base::Callback<void(const std::string&, brillo::Error*)>& |
| callback) { callback.Run(kFakeSmartctlData, nullptr); })); |
| std::unique_ptr<grpc_api::GetDriveSystemDataResponse> response; |
| { |
| base::RunLoop run_loop; |
| grpc_api::GetDriveSystemDataRequest request; |
| request.set_type(grpc_api::GetDriveSystemDataRequest::SMART_ATTRIBUTES); |
| fake_wilco_dtc()->GetDriveSystemData( |
| request, MakeAsyncResponseWriter(&response, &run_loop)); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(response); |
| grpc_api::GetDriveSystemDataResponse expected_response; |
| expected_response.set_status(grpc_api::GetDriveSystemDataResponse::STATUS_OK); |
| expected_response.set_payload(kFakeSmartctlData); |
| EXPECT_THAT(*response, ProtobufEquals(expected_response)) |
| << "Actual: {" << response->ShortDebugString() << "}"; |
| } |
| |
| // Fake types to be used to emulate EC events. |
| const uint16_t kFakeEcEventType1 = 0xabcd; |
| const uint16_t kFakeEcEventType2 = 0x1234; |
| |
| // Tests for EC event service. |
| class EcEventServiceBootstrappedWilcoDtcSupportdCoreTest |
| : public BootstrappedWilcoDtcSupportdCoreTest { |
| protected: |
| // Holds EC event type and payload of |grpc_api::HandleEcNotificationResponse| |
| using GrpcEvent = std::pair<uint16_t, std::string>; |
| |
| std::string GetPayload(size_t expected_size_in_bytes) const { |
| return std::string(reinterpret_cast<const char*>(kPayload), |
| expected_size_in_bytes); |
| } |
| |
| void EmulateEcEvent(uint16_t size_in_words, uint16_t type) const { |
| WriteEcEventToEcEventFile(GetEcEvent(size_in_words, type)); |
| } |
| |
| void ExpectAllFakeWilcoDtcReceivedEcEvents( |
| const std::multiset<GrpcEvent>& expected_ec_events) { |
| base::RunLoop run_loop; |
| auto barrier_closure = |
| BarrierClosure(2 * expected_ec_events.size(), run_loop.QuitClosure()); |
| |
| std::multiset<GrpcEvent> fake_wilco_dtc_ec_events; |
| std::multiset<GrpcEvent> fake_ui_message_receiver_wilco_dtc_ec_events; |
| SetupFakeWilcoDtcEcEventCallback(barrier_closure, fake_wilco_dtc(), |
| &fake_wilco_dtc_ec_events); |
| SetupFakeWilcoDtcEcEventCallback( |
| barrier_closure, fake_ui_message_receiver_wilco_dtc(), |
| &fake_ui_message_receiver_wilco_dtc_ec_events); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(fake_wilco_dtc_ec_events, expected_ec_events); |
| EXPECT_EQ(fake_ui_message_receiver_wilco_dtc_ec_events, expected_ec_events); |
| } |
| |
| private: |
| const uint16_t kData[6]{0x0102, 0x1314, 0x2526, 0x3738, 0x494a, 0x5b5c}; |
| // |kData| bytes little endian representation. |
| const uint8_t kPayload[12]{0x02, 0x01, 0x14, 0x13, 0x26, 0x25, |
| 0x38, 0x37, 0x4a, 0x49, 0x5c, 0x5b}; |
| |
| EcEvent GetEcEvent(uint16_t size_in_words, uint16_t type) const { |
| return EcEvent(size_in_words, static_cast<EcEvent::Type>(type), kData); |
| } |
| |
| void SetupFakeWilcoDtcEcEventCallback(const base::Closure& callback, |
| FakeWilcoDtc* fake_wilco_dtc, |
| std::multiset<GrpcEvent>* events_out) { |
| DCHECK(fake_wilco_dtc); |
| DCHECK(events_out); |
| fake_wilco_dtc->set_handle_ec_event_request_callback(base::BindRepeating( |
| [](const base::Closure& callback, std::multiset<GrpcEvent>* events_out, |
| int32_t type, const std::string& payload) { |
| DCHECK(events_out); |
| events_out->insert({type, payload}); |
| callback.Run(); |
| }, |
| callback, events_out)); |
| } |
| }; |
| |
| // Test that the method |HandleEcNotification()| exposed by wilco_dtc gRPC is |
| // called by wilco_dtc support daemon. |
| TEST_F(EcEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcEventToWilcoDtcSize0) { |
| EmulateEcEvent(0, kFakeEcEventType1); |
| ExpectAllFakeWilcoDtcReceivedEcEvents({{kFakeEcEventType1, GetPayload(0)}}); |
| } |
| |
| // Test that the method |HandleEcNotification()| exposed by wilco_dtc gRPC is |
| // called by wilco_dtc support daemon. |
| TEST_F(EcEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcEventToWilcoDtcSize5) { |
| EmulateEcEvent(5, kFakeEcEventType1); |
| ExpectAllFakeWilcoDtcReceivedEcEvents({{kFakeEcEventType1, GetPayload(10)}}); |
| } |
| |
| // Test that the method |HandleEcNotification()| exposed by wilco_dtc gRPC is |
| // called by wilco_dtc support daemon. |
| TEST_F(EcEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcEventToWilcoDtcSize6) { |
| EmulateEcEvent(6, kFakeEcEventType1); |
| ExpectAllFakeWilcoDtcReceivedEcEvents({{kFakeEcEventType1, GetPayload(12)}}); |
| } |
| |
| // Test that the method |HandleEcNotification()| exposed by wilco_dtc gRPC is |
| // called by wilco_dtc support daemon multiple times. |
| TEST_F(EcEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcEventToWilcoDtcMultipleEvents) { |
| EmulateEcEvent(3, kFakeEcEventType1); |
| EmulateEcEvent(4, kFakeEcEventType2); |
| ExpectAllFakeWilcoDtcReceivedEcEvents( |
| {{kFakeEcEventType1, GetPayload(6)}, {kFakeEcEventType2, GetPayload(8)}}); |
| } |
| |
| // Test that the method |HandleEcNotification()| exposed by wilco_dtc gRPC is |
| // not called by wilco_dtc support daemon when |ec_event.size| exceeds |
| // allocated data array. |
| TEST_F(EcEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| SendGrpcEventToWilcoDtcInvalidSize) { |
| EmulateEcEvent(3, kFakeEcEventType1); |
| EmulateEcEvent(7, kFakeEcEventType2); |
| // Expect only EC event with valid size. |
| ExpectAllFakeWilcoDtcReceivedEcEvents({{kFakeEcEventType1, GetPayload(6)}}); |
| } |
| |
| // Tests for powerd event service. |
| // |
| // This is a parametrized test with the following parameters: |
| // * |power_event| - the power event. |
| // * |expected_power_event| - the expected power event passed to fake_wilco_dtc |
| // over gRPC. |
| class PowerdEventServiceBootstrappedWilcoDtcSupportdCoreTest |
| : public BootstrappedWilcoDtcSupportdCoreTest, |
| public testing::WithParamInterface<std::tuple< |
| PowerdEventService::Observer::PowerEventType /* power_event */, |
| grpc_api::HandlePowerNotificationRequest:: |
| PowerEvent /* expected_power_event */>> { |
| protected: |
| PowerdEventService::Observer::PowerEventType power_event() const { |
| return std::get<0>(GetParam()); |
| } |
| grpc_api::HandlePowerNotificationRequest::PowerEvent expected_power_event() |
| const { |
| return std::get<1>(GetParam()); |
| } |
| |
| void SetupFakeWilcoDtcPowerEventCallback( |
| const base::Closure& callback, |
| FakeWilcoDtc* fake_wilco_dtc, |
| grpc_api::HandlePowerNotificationRequest::PowerEvent* event_out) { |
| DCHECK(fake_wilco_dtc); |
| DCHECK(event_out); |
| fake_wilco_dtc->set_handle_power_event_request_callback(base::BindRepeating( |
| [](const base::Closure& callback, |
| grpc_api::HandlePowerNotificationRequest::PowerEvent* event_out, |
| grpc_api::HandlePowerNotificationRequest::PowerEvent event) { |
| DCHECK(event_out); |
| *event_out = event; |
| callback.Run(); |
| }, |
| callback, event_out)); |
| } |
| }; |
| |
| // Test that the method |HandlePowerNotification()| exposed by wilco_dtc gRPC is |
| // called by wilco_dtc support daemon. |
| TEST_P(PowerdEventServiceBootstrappedWilcoDtcSupportdCoreTest, PowerEvent) { |
| core_delegate()->powerd_event_service()->EmitPowerEvent(power_event()); |
| |
| base::RunLoop run_loop; |
| auto barrier_closure = BarrierClosure(2, run_loop.QuitClosure()); |
| |
| grpc_api::HandlePowerNotificationRequest::PowerEvent |
| fake_wilco_dtc_power_event; |
| grpc_api::HandlePowerNotificationRequest::PowerEvent |
| fake_ui_message_receiver_wilco_dtc_power_event; |
| SetupFakeWilcoDtcPowerEventCallback(barrier_closure, fake_wilco_dtc(), |
| &fake_wilco_dtc_power_event); |
| SetupFakeWilcoDtcPowerEventCallback( |
| barrier_closure, fake_ui_message_receiver_wilco_dtc(), |
| &fake_ui_message_receiver_wilco_dtc_power_event); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ(fake_wilco_dtc_power_event, expected_power_event()); |
| EXPECT_EQ(fake_ui_message_receiver_wilco_dtc_power_event, |
| expected_power_event()); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| , |
| PowerdEventServiceBootstrappedWilcoDtcSupportdCoreTest, |
| testing::Values( |
| std::make_tuple(PowerdEventService::Observer::PowerEventType::kAcInsert, |
| grpc_api::HandlePowerNotificationRequest::AC_INSERT), |
| std::make_tuple(PowerdEventService::Observer::PowerEventType::kAcRemove, |
| grpc_api::HandlePowerNotificationRequest::AC_REMOVE), |
| std::make_tuple( |
| PowerdEventService::Observer::PowerEventType::kOsSuspend, |
| grpc_api::HandlePowerNotificationRequest::OS_SUSPEND), |
| std::make_tuple(PowerdEventService::Observer::PowerEventType::kOsResume, |
| grpc_api::HandlePowerNotificationRequest::OS_RESUME))); |
| |
| } // namespace |
| |
| } // namespace diagnostics |