| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "missive/daemon/missive_daemon.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <base/test/task_environment.h> |
| #include <brillo/dbus/dbus_method_response.h> |
| #include <brillo/dbus/mock_dbus_method_response.h> |
| #include <brillo/message_loops/base_message_loop.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dbus/bus.h> |
| #include <dbus/mock_bus.h> |
| #include <dbus/mock_exported_object.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "missive/dbus/dbus_adaptor.h" |
| #include "missive/missive/missive_service.h" |
| #include "missive/proto/interface.pb.h" |
| #include "missive/proto/record.pb.h" |
| #include "missive/proto/record_constants.pb.h" |
| #include "missive/storage/storage_uploader_interface.h" |
| #include "missive/util/status.h" |
| #include "missive/util/test_support_callbacks.h" |
| #include "missive/util/test_util.h" |
| |
| using ::brillo::dbus_utils::AsyncEventSequencer; |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::Eq; |
| using ::testing::Invoke; |
| using ::testing::NiceMock; |
| using ::testing::NotNull; |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| using ::testing::WithArg; |
| |
| namespace reporting { |
| namespace { |
| |
| class MockMissive : public MissiveService { |
| public: |
| MockMissive() = default; |
| |
| MOCK_METHOD(void, |
| StartUp, |
| (scoped_refptr<dbus::Bus> bus, |
| base::OnceCallback<void(Status)> cb), |
| (override)); |
| MOCK_METHOD(Status, ShutDown, (), (override)); |
| MOCK_METHOD(void, OnReady, (), (const override)); |
| |
| MOCK_METHOD(void, |
| AsyncStartUpload, |
| (UploaderInterface::UploadReason reason, |
| UploaderInterface::UploaderInterfaceResultCb uploader_result_cb), |
| (override)); |
| MOCK_METHOD(void, |
| EnqueueRecord, |
| (const EnqueueRecordRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| EnqueueRecordResponse>> out_response), |
| (override)); |
| MOCK_METHOD(void, |
| FlushPriority, |
| (const FlushPriorityRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| FlushPriorityResponse>> out_response), |
| (override)); |
| MOCK_METHOD(void, |
| ConfirmRecordUpload, |
| (const ConfirmRecordUploadRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| ConfirmRecordUploadResponse>> out_response), |
| (override)); |
| MOCK_METHOD(void, |
| UpdateEncryptionKey, |
| (const UpdateEncryptionKeyRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| UpdateEncryptionKeyResponse>> out_response), |
| (override)); |
| }; |
| |
| class MissiveDaemonTest : public ::testing::Test { |
| public: |
| MissiveDaemonTest() = default; |
| |
| void TearDown() override { |
| if (missive_daemon_) { |
| if (mock_missive_) { |
| EXPECT_CALL(*mock_missive_, ShutDown()).Times(1); |
| } |
| missive_daemon_->Shutdown(); |
| missive_daemon_.reset(); |
| } |
| } |
| |
| void StartUp( |
| Status status = Status::StatusOK(), |
| base::OnceCallback<void(Status)> failure_cb = base::DoNothing()) { |
| ASSERT_FALSE(mock_missive_) << "Can call StartUp only once"; |
| auto mock_missive = std::make_unique<StrictMock<MockMissive>>(); |
| mock_missive_ = mock_missive.get(); |
| |
| dbus::Bus::Options options; |
| mock_bus_ = base::MakeRefCounted<NiceMock<dbus::MockBus>>(options); |
| dbus::ObjectPath path(missive::kMissiveServicePath); |
| |
| mock_exported_object_ = |
| base::MakeRefCounted<StrictMock<dbus::MockExportedObject>>( |
| mock_bus_.get(), path); |
| |
| ON_CALL(*mock_bus_, GetExportedObject(path)) |
| .WillByDefault(Return(mock_exported_object_.get())); |
| |
| ON_CALL(*mock_bus_, GetDBusTaskRunner()) |
| .WillByDefault( |
| Return(task_environment_.GetMainThreadTaskRunner().get())); |
| |
| EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _)) |
| .Times(AnyNumber()); |
| |
| auto missive = std::make_unique<StrictMock<MockMissive>>(); |
| mock_missive_ = missive.get(); |
| EXPECT_CALL(*mock_missive_, StartUp(NotNull(), _)) |
| .WillOnce(WithArg<1>([&status](base::OnceCallback<void(Status)> cb) { |
| std::move(cb).Run(status); |
| })); |
| |
| missive_daemon_.reset( |
| new DBusAdaptor(mock_bus_, std::move(missive), std::move(failure_cb))); |
| } |
| |
| void WaitForReady() { |
| test::TestCallbackAutoWaiter waiter; |
| EXPECT_CALL(*mock_missive_, OnReady()) |
| .WillOnce(Invoke(&waiter, &test::TestCallbackWaiter::Signal)); |
| } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_; |
| |
| scoped_refptr<dbus::MockBus> mock_bus_; |
| scoped_refptr<dbus::MockExportedObject> mock_exported_object_; |
| StrictMock<MockMissive>* mock_missive_ = nullptr; |
| std::unique_ptr<DBusAdaptor> missive_daemon_; |
| }; |
| |
| TEST_F(MissiveDaemonTest, EnqueueRecordTest) { |
| StartUp(); |
| WaitForReady(); |
| |
| EnqueueRecordRequest request; |
| request.mutable_record()->set_data("DATA"); |
| request.mutable_record()->set_destination(HEARTBEAT_EVENTS); |
| request.set_priority(FAST_BATCH); |
| |
| EXPECT_CALL(*mock_missive_, EnqueueRecord(EqualsProto(request), _)) |
| .WillOnce([](const EnqueueRecordRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| EnqueueRecordResponse>> out_response) { |
| EnqueueRecordResponse response; // Success |
| out_response->Return(response); |
| }); |
| |
| auto response = std::make_unique< |
| brillo::dbus_utils::MockDBusMethodResponse<EnqueueRecordResponse>>(); |
| test::TestEvent<const EnqueueRecordResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->EnqueueRecord(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error::OK)); |
| } |
| |
| TEST_F(MissiveDaemonTest, FlushPriorityTest) { |
| StartUp(); |
| WaitForReady(); |
| |
| FlushPriorityRequest request; |
| request.set_priority(MANUAL_BATCH); |
| |
| EXPECT_CALL(*mock_missive_, FlushPriority(EqualsProto(request), _)) |
| .WillOnce([](const FlushPriorityRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| FlushPriorityResponse>> out_response) { |
| FlushPriorityResponse response; // Success |
| out_response->Return(response); |
| }); |
| |
| auto response = std::make_unique< |
| brillo::dbus_utils::MockDBusMethodResponse<FlushPriorityResponse>>(); |
| test::TestEvent<const FlushPriorityResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->FlushPriority(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error::OK)); |
| } |
| |
| TEST_F(MissiveDaemonTest, ConfirmRecordUploadTest) { |
| StartUp(); |
| WaitForReady(); |
| |
| ConfirmRecordUploadRequest request; |
| request.mutable_sequence_information()->set_sequencing_id(1234L); |
| request.mutable_sequence_information()->set_generation_id(9876L); |
| request.mutable_sequence_information()->set_priority(IMMEDIATE); |
| request.set_force_confirm(true); |
| |
| EXPECT_CALL(*mock_missive_, ConfirmRecordUpload(EqualsProto(request), _)) |
| .WillOnce([](const ConfirmRecordUploadRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| ConfirmRecordUploadResponse>> out_response) { |
| ConfirmRecordUploadResponse response; // Success |
| out_response->Return(response); |
| }); |
| |
| auto response = std::make_unique<brillo::dbus_utils::MockDBusMethodResponse< |
| ConfirmRecordUploadResponse>>(); |
| test::TestEvent<const ConfirmRecordUploadResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->ConfirmRecordUpload(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error::OK)); |
| } |
| |
| TEST_F(MissiveDaemonTest, UpdateEncryptionKeyTest) { |
| StartUp(); |
| WaitForReady(); |
| |
| UpdateEncryptionKeyRequest request; |
| request.mutable_signed_encryption_info()->set_public_asymmetric_key( |
| "PUBLIC_KEY"); |
| request.mutable_signed_encryption_info()->set_public_key_id(555666); |
| request.mutable_signed_encryption_info()->set_signature("SIGNATURE"); |
| |
| EXPECT_CALL(*mock_missive_, UpdateEncryptionKey(EqualsProto(request), _)) |
| .WillOnce([](const UpdateEncryptionKeyRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| UpdateEncryptionKeyResponse>> out_response) { |
| UpdateEncryptionKeyResponse response; // Success |
| out_response->Return(response); |
| }); |
| |
| auto response = std::make_unique<brillo::dbus_utils::MockDBusMethodResponse< |
| UpdateEncryptionKeyResponse>>(); |
| test::TestEvent<const UpdateEncryptionKeyResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->UpdateEncryptionKey(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error::OK)); |
| } |
| |
| TEST_F(MissiveDaemonTest, ResponseWithErrorTest) { |
| StartUp(); |
| WaitForReady(); |
| |
| const Status error{error::INTERNAL, "Test generated error"}; |
| |
| FlushPriorityRequest request; |
| request.set_priority(SLOW_BATCH); |
| |
| EXPECT_CALL(*mock_missive_, FlushPriority(EqualsProto(request), _)) |
| .WillOnce([&error](const FlushPriorityRequest& in_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< |
| FlushPriorityResponse>> out_response) { |
| FlushPriorityResponse response; |
| error.SaveTo(response.mutable_status()); |
| out_response->Return(response); |
| }); |
| |
| auto response = std::make_unique< |
| brillo::dbus_utils::MockDBusMethodResponse<FlushPriorityResponse>>(); |
| test::TestEvent<const FlushPriorityResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->FlushPriority(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error.error_code())); |
| EXPECT_THAT(response_result.status().error_message(), |
| StrEq(std::string(error.error_message()))); |
| } |
| |
| TEST_F(MissiveDaemonTest, UnavailableTest) { |
| const Status failure_status = |
| Status(error::UNAVAILABLE, "Test did not start daemon"); |
| test::TestEvent<Status> failure_event; |
| StartUp(failure_status, failure_event.cb()); |
| const auto result = failure_event.result(); |
| ASSERT_THAT(result.error_code(), Eq(failure_status.error_code())) << result; |
| ASSERT_THAT(result.error_message(), |
| StrEq(std::string(failure_status.error_message()))) |
| << result; |
| |
| FlushPriorityRequest request; |
| request.set_priority(IMMEDIATE); |
| |
| EXPECT_CALL(*mock_missive_, FlushPriority(EqualsProto(request), _)).Times(0); |
| |
| auto response = std::make_unique< |
| brillo::dbus_utils::MockDBusMethodResponse<FlushPriorityResponse>>(); |
| test::TestEvent<const FlushPriorityResponse&> response_event; |
| response->set_return_callback(response_event.cb()); |
| missive_daemon_->FlushPriority(std::move(response), request); |
| const auto& response_result = response_event.ref_result(); |
| EXPECT_THAT(response_result.status().code(), Eq(error::UNAVAILABLE)); |
| } |
| } // namespace |
| } // namespace reporting |