blob: 815aa1f12f15dae84309a7987ed25fa99c66d503 [file] [log] [blame]
// Copyright 2019 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/enterprise_reporting/report_uploader.h"
#include <utility>
#include "base/test/scoped_task_environment.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::Property;
using ::testing::WithArgs;
namespace enterprise_reporting {
namespace {
constexpr const char* kOsUserNames[] = {"name1", "name2"};
} // namespace
class ReportUploaderTest : public ::testing::Test {
public:
ReportUploaderTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
CreateUploader(0);
}
~ReportUploaderTest() override {}
void UploadReportAndSetExpectation(
int number_of_request,
ReportUploader::ReportStatus expected_status) {
DCHECK_LE(number_of_request, 2) << "Please update kOsUserNames above.";
ReportUploader::Requests requests;
for (int i = 0; i < number_of_request; i++) {
auto request = std::make_unique<em::ChromeDesktopReportRequest>();
request->set_os_user_name(kOsUserNames[i]);
requests.push(std::move(request));
}
has_responded_ = false;
uploader_->SetRequestAndUpload(
std::move(requests),
base::BindOnce(&ReportUploaderTest::OnReportUploaded,
base::Unretained(this), expected_status));
}
void OnReportUploaded(ReportUploader::ReportStatus expected_status,
ReportUploader::ReportStatus actuall_status) {
EXPECT_EQ(expected_status, actuall_status);
has_responded_ = true;
}
void CreateUploader(int retry_count) {
uploader_ = std::make_unique<ReportUploader>(&client_, retry_count);
}
// Forwards to send next request and get response.
void RunNextTask() {
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
}
// Verifies the retried is delayed properly.
void VerifyRequestDelay(int delay_seconds) {
if (delay_seconds == 0) {
EXPECT_EQ(base::TimeDelta(),
task_environment_.NextMainThreadPendingTaskDelay());
return;
}
EXPECT_GE(base::TimeDelta::FromSeconds(delay_seconds),
task_environment_.NextMainThreadPendingTaskDelay());
EXPECT_LE(
base::TimeDelta::FromSeconds(static_cast<int>(delay_seconds * 0.9)),
task_environment_.NextMainThreadPendingTaskDelay());
}
base::test::TaskEnvironment task_environment_;
std::unique_ptr<ReportUploader> uploader_;
policy::MockCloudPolicyClient client_;
bool has_responded_ = false;
private:
DISALLOW_COPY_AND_ASSIGN(ReportUploaderTest);
};
class ReportUploaderTestWithTransientError
: public ReportUploaderTest,
public ::testing::WithParamInterface<policy::DeviceManagementStatus> {};
TEST_F(ReportUploaderTest, Success) {
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
UploadReportAndSetExpectation(/*number_of_request=*/1,
ReportUploader::kSuccess);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, PersistentError) {
CreateUploader(/* retry_count = */ 1);
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)));
client_.SetStatus(policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND);
UploadReportAndSetExpectation(/*number_of_request=*/2,
ReportUploader::kPersistentError);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, RequestTooBigError) {
CreateUploader(/* *retyr_count = */ 2);
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.Times(2)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)));
client_.SetStatus(policy::DM_STATUS_REQUEST_TOO_LARGE);
UploadReportAndSetExpectation(/*number_of_request=*/2,
ReportUploader::kSuccess);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, RetryAndSuccess) {
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.Times(2)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
CreateUploader(/* retry_count = */ 1);
client_.SetStatus(policy::DM_STATUS_TEMPORARY_UNAVAILABLE);
UploadReportAndSetExpectation(/*number_of_request=*/1,
ReportUploader::kSuccess);
RunNextTask();
// No response, request is retried.
EXPECT_FALSE(has_responded_);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, RetryAndFailedWithPersistentError) {
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.Times(2)
.WillRepeatedly(WithArgs<1>(policy::ScheduleStatusCallback(false)));
CreateUploader(/* retry_count = */ 1);
client_.SetStatus(policy::DM_STATUS_TEMPORARY_UNAVAILABLE);
UploadReportAndSetExpectation(/*number_of_request=*/1,
ReportUploader::kPersistentError);
RunNextTask();
// No response, request is retried.
EXPECT_FALSE(has_responded_);
// Error is changed.
client_.SetStatus(policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, RetryAndFailedWithTransientError) {
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.Times(2)
.WillRepeatedly(WithArgs<1>(policy::ScheduleStatusCallback(false)));
CreateUploader(/* retry_count = */ 1);
client_.SetStatus(policy::DM_STATUS_TEMPORARY_UNAVAILABLE);
UploadReportAndSetExpectation(/*number_of_request=*/1,
ReportUploader::kTransientError);
RunNextTask();
// No response, request is retried.
EXPECT_FALSE(has_responded_);
RunNextTask();
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
TEST_F(ReportUploaderTest, MultipleReports) {
{
InSequence s;
// First report
EXPECT_CALL(client_,
UploadChromeDesktopReportProxy(
Property(&em::ChromeDesktopReportRequest::os_user_name,
Eq(kOsUserNames[0])),
_))
.Times(3)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
// Second report
EXPECT_CALL(client_,
UploadChromeDesktopReportProxy(
Property(&em::ChromeDesktopReportRequest::os_user_name,
Eq(kOsUserNames[1])),
_))
.Times(2)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)));
}
CreateUploader(/* retry_count = */ 2);
client_.SetStatus(policy::DM_STATUS_TEMPORARY_UNAVAILABLE);
UploadReportAndSetExpectation(/*number_of_request=*/2,
ReportUploader::kTransientError);
// The first request has no delay.
VerifyRequestDelay(0);
RunNextTask();
// The first retry is delayed between 54 to 60 seconds.
VerifyRequestDelay(60);
RunNextTask();
// The second retry is delayed between 108 to 120 seconds.
VerifyRequestDelay(120);
RunNextTask();
// Request is succeeded, send the next request And its first retry is delayed
// between 108 to 120 seconds because there were 2 failures.
VerifyRequestDelay(120);
RunNextTask();
// And we failed again, reach maximum retries count.
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
// Verified three DM server error that is transient.
TEST_P(ReportUploaderTestWithTransientError, WithoutRetry) {
EXPECT_CALL(client_, UploadChromeDesktopReportProxy(_, _))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)));
client_.SetStatus(GetParam());
UploadReportAndSetExpectation(/*number_of_request=*/2,
ReportUploader::kTransientError);
task_environment_.FastForwardBy(base::TimeDelta());
EXPECT_TRUE(has_responded_);
::testing::Mock::VerifyAndClearExpectations(&client_);
}
INSTANTIATE_TEST_SUITE_P(
,
ReportUploaderTestWithTransientError,
::testing::Values(policy::DM_STATUS_REQUEST_FAILED,
policy::DM_STATUS_TEMPORARY_UNAVAILABLE,
policy::DM_STATUS_SERVICE_DEVICE_ID_CONFLICT));
} // namespace enterprise_reporting