Commit 8e8b36aa authored by Swapnil's avatar Swapnil Committed by Commit Bot

Add unit tests for ExtensionInstallEventLogUploader

ExtensionInstallEventLogUploader class acts as an adapter between the
system that captures and stores extension install event logs and the
policy system which uploads them to the management server. Add unit
tests for the class.

Bug: 1100862
Change-Id: Id0e753ebe846ce25417e8ce6be8159007b9335f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2275894Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Commit-Queue: Swapnil Gupta <swapnilgupta@google.com>
Cr-Commit-Position: refs/heads/master@{#784478}
parent 128988e8
......@@ -3261,6 +3261,7 @@ source_set("unit_tests") {
"policy/extension_cache_unittest.cc",
"policy/extension_install_event_log_collector_unittest.cc",
"policy/extension_install_event_log_unittest.cc",
"policy/extension_install_event_log_uploader_unittest.cc",
"policy/extension_install_event_logger_unittest.cc",
"policy/external_data_handlers/device_native_printers_external_data_handler_unittest.cc",
"policy/fake_affiliated_invalidation_service_provider.cc",
......
// Copyright 2020 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/extension_install_event_log_uploader.h"
#include <algorithm>
#include <memory>
#include <string>
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ref_counted.h"
#include "base/test/gmock_move_support.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/install_event_log_util.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.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::_;
using testing::Invoke;
using testing::Mock;
using testing::WithArgs;
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 kExtensionId[] = "abcdefghabcdefghabcdefghabcdefgh";
MATCHER_P(MatchValue, expected, "matches base::Value") {
std::string arg_serialized_string;
JSONStringValueSerializer arg_serializer(&arg_serialized_string);
if (!arg_serializer.Serialize(arg))
return false;
DCHECK(expected);
std::string expected_serialized_string;
JSONStringValueSerializer expected_serializer(&expected_serialized_string);
if (!expected_serializer.Serialize(*expected))
return false;
return arg_serialized_string == expected_serialized_string;
}
class MockExtensionInstallEventLogUploaderDelegate
: public ExtensionInstallEventLogUploader::Delegate {
public:
MockExtensionInstallEventLogUploaderDelegate() {}
void SerializeExtensionLogForUpload(
ExtensionLogSerializationCallback callback) override {
SerializeExtensionLogForUpload_(callback);
}
MOCK_METHOD1(SerializeExtensionLogForUpload_,
void(ExtensionLogSerializationCallback&));
MOCK_METHOD0(OnExtensionLogUploadSuccess, void());
};
} // namespace
class ExtensionInstallEventLogUploaderTest : public testing::Test {
protected:
ExtensionInstallEventLogUploaderTest() = default;
void TearDown() override {
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
uploader_.reset();
}
void RegisterClient() {
client_.dm_token_ = kDmToken;
client_.NotifyRegistrationStateChanged();
}
void UnregisterClient() {
client_.dm_token_.clear();
client_.NotifyRegistrationStateChanged();
}
void CreateUploader() {
uploader_ = std::make_unique<ExtensionInstallEventLogUploader>(
&client_, /*profile=*/nullptr);
uploader_->SetDelegate(&delegate_);
}
void CompleteSerialize() {
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_))
.WillOnce(WithArgs<0>(
Invoke([=](ExtensionInstallEventLogUploader::Delegate::
ExtensionLogSerializationCallback& callback) {
std::move(callback).Run(&log_);
})));
}
void CaptureSerialize(ExtensionInstallEventLogUploader::Delegate::
ExtensionLogSerializationCallback* callback) {
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_))
.WillOnce(MoveArg<0>(callback));
}
void ClearReportDict() {
base::DictionaryValue* mutable_dict;
if (value_report_.GetAsDictionary(&mutable_dict))
mutable_dict->Clear();
else
NOTREACHED();
}
void CompleteUpload(bool success) {
ClearReportDict();
base::Value context = reporting::GetContext(/*profile=*/nullptr);
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertExtensionProtoToValue(&log_, context), std::move(context));
EXPECT_CALL(client_,
UploadExtensionInstallReport_(MatchValue(&value_report_), _))
.WillOnce(WithArgs<1>(
Invoke([=](CloudPolicyClient::StatusCallback& callback) {
std::move(callback).Run(success);
})));
}
void CaptureUpload(CloudPolicyClient::StatusCallback* callback) {
ClearReportDict();
base::Value context = reporting::GetContext(/*profile=*/nullptr);
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertExtensionProtoToValue(&log_, context), std::move(context));
CloudPolicyClient::StatusCallback status_callback;
EXPECT_CALL(client_,
UploadExtensionInstallReport_(MatchValue(&value_report_), _))
.WillOnce(MoveArg<1>(callback));
}
void CompleteSerializeAndUpload(bool success) {
CompleteSerialize();
CompleteUpload(success);
}
void CompleteSerializeAndCaptureUpload(
CloudPolicyClient::StatusCallback* callback) {
CompleteSerialize();
CaptureUpload(callback);
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
em::ExtensionInstallReportRequest log_;
base::Value value_report_{base::Value::Type::DICTIONARY};
MockCloudPolicyClient client_;
MockExtensionInstallEventLogUploaderDelegate delegate_;
std::unique_ptr<ExtensionInstallEventLogUploader> uploader_;
chromeos::system::ScopedFakeStatisticsProvider
scoped_fake_statistics_provider_;
};
// Make a log upload request. Have serialization and log upload succeed. Verify
// that the delegate is notified of the success.
TEST_F(ExtensionInstallEventLogUploaderTest, RequestSerializeAndUpload) {
RegisterClient();
CreateUploader();
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest, RequestSerializeRequestAndUpload) {
RegisterClient();
CreateUploader();
CloudPolicyClient::StatusCallback status_callback;
CompleteSerializeAndCaptureUpload(&status_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_)).Times(0);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_)).Times(0);
std::move(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(ExtensionInstallEventLogUploaderTest, RequestRequestSerializeAndUpload) {
RegisterClient();
CreateUploader();
ExtensionInstallEventLogUploader::Delegate::ExtensionLogSerializationCallback
serialization_callback;
CaptureSerialize(&serialization_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_)).Times(0);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
CompleteUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest, RequestCancelAndSerialize) {
RegisterClient();
CreateUploader();
ExtensionInstallEventLogUploader::Delegate::ExtensionLogSerializationCallback
serialization_callback;
CaptureSerialize(&serialization_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
uploader_->CancelUpload();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadExtensionInstallReport_(_, _)).Times(0);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).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(ExtensionInstallEventLogUploaderTest, RequestSerializeAndCancel) {
RegisterClient();
CreateUploader();
CloudPolicyClient::StatusCallback status_callback;
CompleteSerializeAndCaptureUpload(&status_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
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(ExtensionInstallEventLogUploaderTest, Retry) {
RegisterClient();
CreateUploader();
CompleteSerializeAndUpload(false /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).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_environment_.NextMainThreadPendingTaskDelay());
CompleteSerializeAndUpload(false /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).Times(0);
task_environment_.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_environment_.NextMainThreadPendingTaskDelay());
log_.add_extension_install_reports()->set_extension_id(kExtensionId);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
task_environment_.FastForwardBy(expected_delay);
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
CompleteSerializeAndUpload(false /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).Times(0);
uploader_->RequestUpload();
EXPECT_EQ(min_delay, task_environment_.NextMainThreadPendingTaskDelay());
}
// 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(ExtensionInstallEventLogUploaderTest,
RegisterRequestSerializeAndUpload) {
CreateUploader();
RegisterClient();
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest,
RequestRegisterSerializeAndUpload) {
CreateUploader();
EXPECT_CALL(delegate_, SerializeExtensionLogForUpload_(_)).Times(0);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest,
RequestSerializeUnregisterRegisterAndUpload) {
RegisterClient();
CreateUploader();
CloudPolicyClient::StatusCallback status_callback;
CompleteSerializeAndCaptureUpload(&status_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
UnregisterClient();
Mock::VerifyAndClearExpectations(&client_);
log_.add_extension_install_reports()->set_extension_id(kExtensionId);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest,
RequestUnregisterSerializeRegisterAndUpload) {
RegisterClient();
CreateUploader();
ExtensionInstallEventLogUploader::Delegate::ExtensionLogSerializationCallback
serialization_callback;
CaptureSerialize(&serialization_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
UnregisterClient();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadExtensionInstallReport_(_, _)).Times(0);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).Times(0);
std::move(serialization_callback).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
log_.add_extension_install_reports()->set_extension_id(kExtensionId);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest,
RequestUnregisterRegisterSerializeAndUpload) {
RegisterClient();
CreateUploader();
ExtensionInstallEventLogUploader::Delegate::ExtensionLogSerializationCallback
serialization_callback_1;
CaptureSerialize(&serialization_callback_1);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&delegate_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
UnregisterClient();
Mock::VerifyAndClearExpectations(&client_);
ExtensionInstallEventLogUploader::Delegate::ExtensionLogSerializationCallback
serialization_callback_2;
CaptureSerialize(&serialization_callback_2);
RegisterClient();
EXPECT_CALL(client_, UploadExtensionInstallReport_(_, _)).Times(0);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess()).Times(0);
std::move(serialization_callback_1).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
log_.add_extension_install_reports()->set_extension_id(kExtensionId);
CompleteUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
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(ExtensionInstallEventLogUploaderTest, RequestAndRemoveDelegate) {
RegisterClient();
CreateUploader();
CloudPolicyClient::StatusCallback status_callback;
CompleteSerializeAndCaptureUpload(&status_callback);
uploader_->RequestUpload();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, CancelExtensionInstallReportUpload());
uploader_->SetDelegate(nullptr);
}
// When there is more than one identical event in the log, ensure that only one
// of those duplicate events is in the created report.
TEST_F(ExtensionInstallEventLogUploaderTest, DuplicateEvents) {
RegisterClient();
CreateUploader();
em::ExtensionInstallReport* report = log_.add_extension_install_reports();
report->set_extension_id(kExtensionId);
// Adding 3 events, but the first two are identical, so the final report
// should only contain 2 events.
em::ExtensionInstallReportLogEvent* ev1 = report->add_logs();
ev1->set_event_type(em::ExtensionInstallReportLogEvent::SUCCESS);
ev1->set_timestamp(0);
em::ExtensionInstallReportLogEvent* ev2 = report->add_logs();
ev2->set_event_type(em::ExtensionInstallReportLogEvent::SUCCESS);
ev2->set_timestamp(0);
em::ExtensionInstallReportLogEvent* ev3 = report->add_logs();
ev3->set_event_type(em::ExtensionInstallReportLogEvent::SUCCESS);
ev3->set_timestamp(1000);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnExtensionLogUploadSuccess());
uploader_->RequestUpload();
EXPECT_EQ(2u,
value_report_
.FindListKey(RealtimeReportingJobConfiguration::kEventListKey)
->GetList()
.size());
}
} // namespace policy
......@@ -67,6 +67,7 @@ class MockCloudPolicyClient : public CloudPolicyClient {
const enterprise_management::ChildStatusReportRequest*,
StatusCallback&));
MOCK_METHOD0(CancelAppInstallReportUpload, void(void));
MOCK_METHOD0(CancelExtensionInstallReportUpload, void(void));
void UpdateGcmId(const std::string& id, StatusCallback callback) override {
UpdateGcmId_(id, callback);
}
......@@ -109,6 +110,12 @@ class MockCloudPolicyClient : public CloudPolicyClient {
UploadAppInstallReport_(value, callback);
}
MOCK_METHOD2(UploadAppInstallReport_, void(base::Value&, StatusCallback&));
void UploadExtensionInstallReport(base::Value value,
StatusCallback callback) override {
UploadExtensionInstallReport_(value, callback);
}
MOCK_METHOD2(UploadExtensionInstallReport_,
void(base::Value&, StatusCallback&));
MOCK_METHOD5(ClientCertProvisioningStartCsr,
void(const std::string& cert_scope,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment