#include "chrome/browser/policy/messaging_layer/upload/record_handler_impl.h"
#include <cstddef>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/types/expected.h"
#include "base/uuid.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/policy/messaging_layer/public/report_client.h"
#include "chrome/browser/policy/messaging_layer/public/report_client_test_util.h"
#include "chrome/browser/policy/messaging_layer/upload/file_upload_job.h"
#include "chrome/browser/policy/messaging_layer/upload/file_upload_job_test_util.h"
#include "chrome/browser/policy/messaging_layer/upload/record_upload_request_builder.h"
#include "chrome/browser/policy/messaging_layer/upload/server_uploader.h"
#include "chrome/browser/policy/messaging_layer/util/reporting_server_connector.h"
#include "chrome/browser/policy/messaging_layer/util/reporting_server_connector_test_util.h"
#include "chrome/browser/policy/messaging_layer/util/test_request_payload.h"
#include "chrome/browser/policy/messaging_layer/util/test_response_payload.h"
#include "components/policy/core/common/management/scoped_management_service_override_for_testing.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/resources/resource_manager.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/statusor.h"
#include "components/reporting/util/test_support_callbacks.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
_;
AllOf;
ContainerEq;
Eq;
Gt;
IsEmpty;
Not;
NotNull;
Property;
SizeIs;
StrEq;
namespace reporting {
namespace {
static constexpr size_t kNumTestRecords = …;
static constexpr int64_t kGenerationId = …;
MATCHER_P(ResponseEquals,
expected,
"Compares StatusOr<response> to expected response") { … }
class MockFileUploadDelegate : public FileUploadJob::Delegate { … };
class RecordHandlerImplTest : public ::testing::TestWithParam<
::testing::tuple< bool,
bool>> { … };
std::pair<ScopedReservation, std::vector<EncryptedRecord>>
BuildTestRecordsVector(size_t number_of_test_records,
int64_t generation_id,
std::string generation_guid,
scoped_refptr<ResourceManager> memory_resource) { … }
std::list<int64_t> GetExpectedCachedSeqIds(
const std::vector<EncryptedRecord>& records) { … }
TEST_P(RecordHandlerImplTest, UploadRecords) { … }
TEST_P(RecordHandlerImplTest, MissingPriorityField) { … }
TEST_P(RecordHandlerImplTest, InvalidPriorityField) { … }
TEST_P(RecordHandlerImplTest, ContainsGenerationGuid) { … }
TEST_P(RecordHandlerImplTest, ValidGenerationGuid) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_P(RecordHandlerImplTest, InvalidGenerationGuid) {
auto test_records = BuildTestRecordsVector(kNumTestRecords, kGenerationId,
kGenerationGuid, memory_resource_);
const auto force_confirm_by_server = force_confirm();
const auto expected_cached_seq_ids =
GetExpectedCachedSeqIds(test_records.second);
test::TestEvent<StatusOr<std::list<int64_t>>> enqueued_event;
test::TestEvent<SignedEncryptionInfo> encryption_key_attached_event;
test::TestEvent<ConfigFile> config_file_attached_event;
test::TestEvent<CompletionResponse> responder_event;
handler_->HandleRecords(need_encryption_key(), -1,
std::move(test_records.second),
std::move(test_records.first), enqueued_event.cb(),
responder_event.cb(),
encryption_key_attached_event.repeating_cb(),
config_file_attached_event.repeating_cb());
const auto& enqueued_result = enqueued_event.result();
ASSERT_OK(enqueued_result) << enqueued_result.error();
EXPECT_THAT(enqueued_result.value(), ContainerEq(expected_cached_seq_ids));
task_environment_.RunUntilIdle();
ASSERT_THAT(*test_env_->url_loader_factory()->pending_requests(), SizeIs(1u));
auto request_body = test_env_->request_body(0);
EXPECT_THAT(request_body, IsDataUploadRequestValid());
auto response = ResponseBuilder(std::move(request_body))
.SetForceConfirm(force_confirm_by_server)
.Build();
ASSERT_TRUE(response.has_value());
response->SetByDottedPath("lastSucceedUploadedRecord.generationGuid",
"invalid-generation-guid");
test_env_->SimulateCustomResponseForRequest(0, std::move(response.value()));
const auto result = responder_event.result();
EXPECT_THAT(result.error(),
Property(&Status::error_code, Eq(error::INTERNAL)));
}
#endif
TEST_P(RecordHandlerImplTest, MissingGenerationGuidFromManagedDeviceIsOk) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_P(RecordHandlerImplTest,
MissingGenerationGuidFromUnmanagedDeviceReturnError) {
policy::ScopedManagementServiceOverrideForTesting scoped_management_service_ =
policy::ScopedManagementServiceOverrideForTesting(
policy::ManagementServiceFactory::GetForPlatform(),
policy::EnterpriseManagementAuthority::NONE);
auto test_records = BuildTestRecordsVector(kNumTestRecords, kGenerationId,
kGenerationGuid, memory_resource_);
const auto force_confirm_by_server = force_confirm();
const auto expected_cached_seq_ids =
GetExpectedCachedSeqIds(test_records.second);
test::TestEvent<StatusOr<std::list<int64_t>>> enqueued_event;
test::TestEvent<SignedEncryptionInfo> encryption_key_attached_event;
test::TestEvent<ConfigFile> config_file_attached_event;
test::TestEvent<CompletionResponse> responder_event;
handler_->HandleRecords(need_encryption_key(), -1,
std::move(test_records.second),
std::move(test_records.first), enqueued_event.cb(),
responder_event.cb(),
encryption_key_attached_event.repeating_cb(),
config_file_attached_event.repeating_cb());
const auto& enqueued_result = enqueued_event.result();
ASSERT_OK(enqueued_result) << enqueued_result.error();
EXPECT_THAT(enqueued_result.value(), ContainerEq(expected_cached_seq_ids));
task_environment_.RunUntilIdle();
ASSERT_THAT(*test_env_->url_loader_factory()->pending_requests(), SizeIs(1u));
auto request_body = test_env_->request_body(0);
EXPECT_THAT(request_body, IsDataUploadRequestValid());
auto response = ResponseBuilder(std::move(request_body))
.SetForceConfirm(force_confirm_by_server)
.Build();
ASSERT_TRUE(response.has_value());
response->RemoveByDottedPath("lastSucceedUploadedRecord.generationGuid");
test_env_->SimulateCustomResponseForRequest(0, std::move(response.value()));
const auto result = responder_event.result();
EXPECT_FALSE(result.has_value());
EXPECT_THAT(result.error(),
Property(&Status::error_code, Eq(error::INTERNAL)));
}
#endif
TEST_P(RecordHandlerImplTest, MissingSequenceInformation) { … }
TEST_P(RecordHandlerImplTest, ReportsUploadFailure) { … }
TEST_P(RecordHandlerImplTest, DISABLED_UploadsGapRecordOnServerFailure) { … }
TEST_P(RecordHandlerImplTest, HandleUnknownResponseFromServer) { … }
TEST_P(RecordHandlerImplTest, AssignsRequestIdForRecordUploads) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_P(RecordHandlerImplTest,
ContainsConfigFileInResponseWithExperimentEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(kShouldRequestConfigurationFile);
auto test_records = BuildTestRecordsVector(kNumTestRecords, kGenerationId,
kGenerationGuid, memory_resource_);
const auto force_confirm_by_server = force_confirm();
const auto expected_cached_seq_ids =
GetExpectedCachedSeqIds(test_records.second);
SuccessfulUploadResponse expected_response{
.sequence_information = test_records.second.back().sequence_information(),
.force_confirm = force_confirm()};
test::TestEvent<StatusOr<std::list<int64_t>>> enqueued_event;
test::TestEvent<SignedEncryptionInfo> encryption_key_attached_event;
test::TestEvent<ConfigFile> config_file_attached_event;
test::TestEvent<CompletionResponse> responder_event;
handler_->HandleRecords(need_encryption_key(), 1,
std::move(test_records.second),
std::move(test_records.first), enqueued_event.cb(),
responder_event.cb(),
encryption_key_attached_event.repeating_cb(),
config_file_attached_event.repeating_cb());
const auto& enqueued_result = enqueued_event.result();
ASSERT_OK(enqueued_result) << enqueued_result.error();
EXPECT_THAT(enqueued_result.value(), ContainerEq(expected_cached_seq_ids));
task_environment_.RunUntilIdle();
ASSERT_THAT(*test_env_->url_loader_factory()->pending_requests(), SizeIs(1));
auto request_body = test_env_->request_body(0);
EXPECT_THAT(request_body, IsDataUploadRequestValid());
auto response = ResponseBuilder(std::move(request_body))
.SetForceConfirm(force_confirm_by_server)
.Build();
ASSERT_TRUE(response.has_value());
test_env_->SimulateCustomResponseForRequest(0, std::move(response.value()));
if (need_encryption_key()) {
EXPECT_THAT(
encryption_key_attached_event.result(),
AllOf(Property(&SignedEncryptionInfo::public_asymmetric_key,
Not(IsEmpty())),
Property(&SignedEncryptionInfo::public_key_id, Gt(0)),
Property(&SignedEncryptionInfo::signature, Not(IsEmpty()))));
}
EXPECT_THAT(
config_file_attached_event.result(),
AllOf(Property(&ConfigFile::config_file_signature, Not(IsEmpty())),
Property(&ConfigFile::version, Gt(0)),
Property(&ConfigFile::blocked_event_configs, Not(IsEmpty()))));
const auto result = responder_event.result();
EXPECT_THAT(result, ResponseEquals(expected_response));
}
#endif
INSTANTIATE_TEST_SUITE_P(…);
}
}