| // Copyright 2018 The Chromium 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 "chrome/browser/chromeos/policy/app_install_event_log_uploader.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/test/test_mock_time_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" |
| #include "components/policy/proto/device_management_backend.pb.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::Invoke; |
| using testing::Mock; |
| using testing::Pointee; |
| using testing::SaveArg; |
| using testing::WithArgs; |
| using testing::_; |
| |
| namespace em = enterprise_management; |
| |
| namespace policy { |
| |
| namespace { |
| |
| constexpr base::TimeDelta kMinRetryBackoff = base::TimeDelta::FromSeconds(10); |
| constexpr base::TimeDelta kMaxRetryBackoff = base::TimeDelta::FromDays(1); |
| |
| static const char kDmToken[] = "token"; |
| static const char kPackageName[] = "package"; |
| |
| MATCHER_P(MatchProto, expected, "matches protobuf") { |
| return arg.SerializePartialAsString() == expected.SerializePartialAsString(); |
| } |
| |
| ACTION_TEMPLATE(MoveArg, |
| HAS_1_TEMPLATE_PARAMS(int, k), |
| AND_1_VALUE_PARAMS(out)) { |
| *out = std::move(*testing::get<k>(args)); |
| }; |
| |
| class MockAppInstallEventLogUploaderDelegate |
| : public AppInstallEventLogUploader::Delegate { |
| public: |
| MockAppInstallEventLogUploaderDelegate() {} |
| |
| void SerializeForUpload(SerializationCallback callback) override { |
| SerializeForUpload_(&callback); |
| } |
| |
| MOCK_METHOD1(SerializeForUpload_, void(SerializationCallback*)); |
| MOCK_METHOD0(OnUploadSuccess, void()); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockAppInstallEventLogUploaderDelegate); |
| }; |
| |
| } // namespace |
| |
| class AppInstallEventLogUploaderTest : public testing::Test { |
| protected: |
| AppInstallEventLogUploaderTest() {} |
| |
| void SetUp() override { |
| task_runner_ = new base::TestMockTimeTaskRunner(); |
| task_runner_handle_ = |
| std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_); |
| } |
| |
| void TearDown() override { |
| Mock::VerifyAndClearExpectations(&client_); |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| uploader_.reset(); |
| } |
| |
| void RegisterClient() { |
| client_.dm_token_ = kDmToken; |
| client_.NotifyRegistrationStateChanged(); |
| } |
| |
| void UnregisterClient() { |
| client_.dm_token_.clear(); |
| client_.NotifyRegistrationStateChanged(); |
| } |
| |
| void CreateUploader() { |
| uploader_ = std::make_unique<AppInstallEventLogUploader>(&client_); |
| uploader_->SetDelegate(&delegate_); |
| } |
| |
| void CompleteSerialize() { |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)) |
| .WillOnce(WithArgs<0>(Invoke( |
| [=](AppInstallEventLogUploader::Delegate::SerializationCallback* |
| callback) { std::move(*callback).Run(&log_); }))); |
| } |
| |
| void CaptureSerialize( |
| AppInstallEventLogUploader::Delegate::SerializationCallback* callback) { |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)) |
| .WillOnce(MoveArg<0>(callback)); |
| } |
| |
| void CompleteUpload(bool success) { |
| EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _)) |
| .WillOnce(WithArgs<1>( |
| Invoke([=](const CloudPolicyClient::StatusCallback& callback) { |
| callback.Run(success); |
| }))); |
| } |
| |
| void CaptureUpload(CloudPolicyClient::StatusCallback* callback) { |
| CloudPolicyClient::StatusCallback status_callback; |
| EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _)) |
| .WillOnce(SaveArg<1>(callback)); |
| } |
| |
| void CompleteSerializeAndUpload(bool success) { |
| CompleteSerialize(); |
| CompleteUpload(success); |
| } |
| |
| void CompleteSerializeAndCaptureUpload( |
| CloudPolicyClient::StatusCallback* callback) { |
| CompleteSerialize(); |
| CaptureUpload(callback); |
| } |
| |
| em::AppInstallReportRequest log_; |
| |
| MockCloudPolicyClient client_; |
| MockAppInstallEventLogUploaderDelegate delegate_; |
| std::unique_ptr<AppInstallEventLogUploader> uploader_; |
| |
| scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(AppInstallEventLogUploaderTest); |
| }; |
| |
| // Make a log upload request. Have serialization and log upload succeed. Verify |
| // that the delegate is notified of the success. |
| TEST_F(AppInstallEventLogUploaderTest, RequestSerializeAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| uploader_->RequestUpload(); |
| } |
| |
| // Make a log upload request. Have serialization succeed and log upload begin. |
| // Make a second upload request. Have the first upload succeed. Verify that the |
| // delegate is notified of the first request's success and no serialization is |
| // started for the second request. |
| TEST_F(AppInstallEventLogUploaderTest, RequestSerializeRequestAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CloudPolicyClient::StatusCallback status_callback; |
| CompleteSerializeAndCaptureUpload(&status_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)).Times(0); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)).Times(0); |
| status_callback.Run(true); |
| } |
| |
| // Make a log upload request. Have serialization begin. Make a second upload |
| // request. Verify that no serialization is started for the second request. |
| // Then, have the first request's serialization and upload succeed. Verify that |
| // the delegate is notified of the first request's success. |
| TEST_F(AppInstallEventLogUploaderTest, RequestRequestSerializeAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| AppInstallEventLogUploader::Delegate::SerializationCallback |
| serialization_callback; |
| CaptureSerialize(&serialization_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)).Times(0); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| CompleteUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| std::move(serialization_callback).Run(&log_); |
| } |
| |
| // Make a log upload request. Have serialization begin. Cancel the request. Have |
| // the serialization succeed. Verify that the serialization result is ignored |
| // and no upload is started. |
| TEST_F(AppInstallEventLogUploaderTest, RequestCancelAndSerialize) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| AppInstallEventLogUploader::Delegate::SerializationCallback |
| serialization_callback; |
| CaptureSerialize(&serialization_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| uploader_->CancelUpload(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| std::move(serialization_callback).Run(&log_); |
| } |
| |
| // Make a log upload request. Have serialization succeed and log upload begin. |
| // Cancel the request. Verify that the upload is canceled in the client. |
| TEST_F(AppInstallEventLogUploaderTest, RequestSerializeAndCancel) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CloudPolicyClient::StatusCallback status_callback; |
| CompleteSerializeAndCaptureUpload(&status_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| uploader_->CancelUpload(); |
| } |
| |
| // Make a log upload request. Have serialization succeed but log upload fail. |
| // Verify that serialization and log upload are retried with exponential |
| // backoff. Have the retries fail until the maximum backoff is seen twice. Then, |
| // have serialization and log upload succeed. Verify that the delegate is |
| // notified of the success. Then, make another log upload request. Have the |
| // serialization succeed but log upload fail again. Verify that the backoff has |
| // returned to the minimum. |
| TEST_F(AppInstallEventLogUploaderTest, Retry) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CompleteSerializeAndUpload(false /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| const base::TimeDelta min_delay = kMinRetryBackoff; |
| const base::TimeDelta max_delay = kMaxRetryBackoff; |
| |
| base::TimeDelta expected_delay = min_delay; |
| int max_delay_count = 0; |
| while (max_delay_count < 2) { |
| EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay()); |
| |
| CompleteSerializeAndUpload(false /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| task_runner_->FastForwardBy(expected_delay); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| if (expected_delay == max_delay) { |
| ++max_delay_count; |
| } |
| expected_delay = std::min(expected_delay * 2, max_delay); |
| } |
| |
| EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay()); |
| |
| log_.add_app_install_report()->set_package(kPackageName); |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| task_runner_->FastForwardBy(expected_delay); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| CompleteSerializeAndUpload(false /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| uploader_->RequestUpload(); |
| |
| EXPECT_EQ(min_delay, task_runner_->NextPendingTaskDelay()); |
| } |
| |
| // Create the uploader using a client that is not registered with the server |
| // yet. Register the client with the server. Make a log upload request. Have |
| // serialization and log upload succeed. Verify that the delegate is notified of |
| // the success. |
| TEST_F(AppInstallEventLogUploaderTest, RegisterRequestSerializeAndUpload) { |
| CreateUploader(); |
| RegisterClient(); |
| |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| uploader_->RequestUpload(); |
| } |
| |
| // Create the uploader using a client that is not registered with the server |
| // yet. Make a log upload request. Verify that serialization is not started. |
| // Then, register the client with the server. Verify that serialization is |
| // started. Have serialization and log upload succeed. Verify that the delegate |
| // is notified of the success. |
| TEST_F(AppInstallEventLogUploaderTest, RequestRegisterSerializeAndUpload) { |
| CreateUploader(); |
| |
| EXPECT_CALL(delegate_, SerializeForUpload_(_)).Times(0); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| RegisterClient(); |
| } |
| |
| // Make a log upload request. Have serialization succeed and log upload begin. |
| // Unregister the client from the server. Register the client with the server. |
| // Verify that a new serialization is started. Then, have serialization and log |
| // upload succeed. Verify that the delegate is notified of the success. |
| TEST_F(AppInstallEventLogUploaderTest, |
| RequestSerializeUnregisterRegisterAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CloudPolicyClient::StatusCallback status_callback; |
| CompleteSerializeAndCaptureUpload(&status_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| UnregisterClient(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| log_.add_app_install_report()->set_package(kPackageName); |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| RegisterClient(); |
| } |
| |
| // Make a log upload request. Have serialization begin. Unregister the client |
| // from the server. Have serialization succeed. Verify that the serialization |
| // result is ignored and no upload is started. Then, register the client with |
| // the server. Verify that a new serialization is started. Then, have |
| // serialization and log upload succeed. Verify that the delegate is notified of |
| // the success. |
| TEST_F(AppInstallEventLogUploaderTest, |
| RequestUnregisterSerializeRegisterAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| AppInstallEventLogUploader::Delegate::SerializationCallback |
| serialization_callback; |
| CaptureSerialize(&serialization_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| UnregisterClient(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| std::move(serialization_callback).Run(&log_); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| log_.add_app_install_report()->set_package(kPackageName); |
| CompleteSerializeAndUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| RegisterClient(); |
| } |
| |
| // Make a log upload request. Have serialization begin. Unregister the client |
| // from the server. Register the client with the server. Verify that a second |
| // serialization is requested. Then, have the first serialization succeed. |
| // Verify that he serialization result is ignored and no upload is started. |
| // Then, have the second serialization succeed. Verify that an upload is |
| // started. Then, have the upload succeed. Verify that the delegate is notified |
| // of the success. |
| TEST_F(AppInstallEventLogUploaderTest, |
| RequestUnregisterRegisterSerializeAndUpload) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| AppInstallEventLogUploader::Delegate::SerializationCallback |
| serialization_callback_1; |
| CaptureSerialize(&serialization_callback_1); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| UnregisterClient(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| AppInstallEventLogUploader::Delegate::SerializationCallback |
| serialization_callback_2; |
| CaptureSerialize(&serialization_callback_2); |
| RegisterClient(); |
| |
| EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); |
| EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); |
| std::move(serialization_callback_1).Run(&log_); |
| Mock::VerifyAndClearExpectations(&delegate_); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| log_.add_app_install_report()->set_package(kPackageName); |
| CompleteUpload(true /* success */); |
| EXPECT_CALL(delegate_, OnUploadSuccess()); |
| std::move(serialization_callback_2).Run(&log_); |
| } |
| |
| // Make a log upload request. Have serialization succeed and log upload begin. |
| // Remove the delegate. Verify that the upload is canceled in the client. |
| TEST_F(AppInstallEventLogUploaderTest, RequestAndRemoveDelegate) { |
| RegisterClient(); |
| CreateUploader(); |
| |
| CloudPolicyClient::StatusCallback status_callback; |
| CompleteSerializeAndCaptureUpload(&status_callback); |
| uploader_->RequestUpload(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| EXPECT_CALL(client_, CancelAppInstallReportUpload()); |
| uploader_->SetDelegate(nullptr); |
| } |
| |
| } // namespace policy |