Commit 6ca3ae96 authored by Askar Aitzhan's avatar Askar Aitzhan Committed by Commit Bot

Refactor AppInstall Reporting to report directly to Chrome Reporting API

Currently ARC++ apps stored as protos defined in
components/policy/proto/device_management_backend.proto, and are being
uploaded to DMServer. In turn DMServer converts those reports to a proto
format defined in
google3/chrome/cros/reporting/proto/chrome_app_install_events.proto,
appends serial_number and gaia_id and redirects those reports to Chrome
Reporting API.

Refactor AppInstall Reporting system to report directly to Chrome
Reporting API.

Bug: 996213
Change-Id: I32239e4713f3d2b804d9710fee60141ce39c0c61
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1763421Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Reviewed-by: default avatarRoger Tawa <rogerta@chromium.org>
Reviewed-by: default avatarStefan Kuhne <skuhne@chromium.org>
Reviewed-by: default avatarNathan Parker <nparker@chromium.org>
Commit-Queue: Askar Aitzhan <askaraitzhan@google.com>
Cr-Commit-Position: refs/heads/master@{#694293}
parent d91292f2
...@@ -1483,6 +1483,8 @@ jumbo_split_static_library("browser") { ...@@ -1483,6 +1483,8 @@ jumbo_split_static_library("browser") {
"profiles/renderer_updater.h", "profiles/renderer_updater.h",
"profiles/renderer_updater_factory.cc", "profiles/renderer_updater_factory.cc",
"profiles/renderer_updater_factory.h", "profiles/renderer_updater_factory.h",
"profiles/reporting_util.cc",
"profiles/reporting_util.h",
"profiles/sql_init_error_message_ids.cc", "profiles/sql_init_error_message_ids.cc",
"profiles/sql_init_error_message_ids.h", "profiles/sql_init_error_message_ids.h",
"profiles/storage_partition_descriptor.h", "profiles/storage_partition_descriptor.h",
......
...@@ -1607,6 +1607,8 @@ source_set("chromeos") { ...@@ -1607,6 +1607,8 @@ source_set("chromeos") {
"policy/app_install_event_log_manager_wrapper.h", "policy/app_install_event_log_manager_wrapper.h",
"policy/app_install_event_log_uploader.cc", "policy/app_install_event_log_uploader.cc",
"policy/app_install_event_log_uploader.h", "policy/app_install_event_log_uploader.h",
"policy/app_install_event_log_util.cc",
"policy/app_install_event_log_util.h",
"policy/app_install_event_logger.cc", "policy/app_install_event_logger.cc",
"policy/app_install_event_logger.h", "policy/app_install_event_logger.h",
"policy/auto_enrollment_client.h", "policy/auto_enrollment_client.h",
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/json/json_string_value_serializer.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/test/scoped_mock_time_message_loop_task_runner.h"
...@@ -20,10 +21,14 @@ ...@@ -20,10 +21,14 @@
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log.h" #include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_uploader.h" #include "chrome/browser/chromeos/policy/app_install_event_log_uploader.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "components/arc/arc_prefs.h" #include "components/arc/arc_prefs.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.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 "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
...@@ -94,8 +99,37 @@ bool ContainsSameEvents(const Events& expected, ...@@ -94,8 +99,37 @@ bool ContainsSameEvents(const Events& expected,
return true; return true;
} }
base::Value ConvertEventsToValue(const Events& events, Profile* profile) {
base::Value event_list(base::Value::Type::LIST);
base::Value::ListStorage& mutable_list = event_list.GetList();
for (auto it = events.begin(); it != events.end(); ++it) {
const std::string& package = (*it).first;
for (const em::AppInstallReportLogEvent& app_install_report_log_event :
(*it).second) {
base::Value wrapper;
wrapper =
ConvertEventToValue(package, app_install_report_log_event, profile);
mutable_list.push_back(std::move(wrapper));
}
}
return event_list;
}
MATCHER_P(MatchEvents, expected, "contains events") { MATCHER_P(MatchEvents, expected, "contains events") {
return ContainsSameEvents(expected, arg); 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 TestLogTaskRunnerWrapper class TestLogTaskRunnerWrapper
...@@ -124,10 +158,14 @@ class TestLogTaskRunnerWrapper ...@@ -124,10 +158,14 @@ class TestLogTaskRunnerWrapper
class AppInstallEventLogManagerTest : public testing::Test { class AppInstallEventLogManagerTest : public testing::Test {
protected: protected:
AppInstallEventLogManagerTest() AppInstallEventLogManagerTest()
: uploader_(&cloud_policy_client_), : uploader_(&cloud_policy_client_, nullptr),
log_task_runner_(log_task_runner_wrapper_.test_task_runner()), log_task_runner_(log_task_runner_wrapper_.test_task_runner()),
log_file_path_(profile_.GetPath().Append(kLogFileName)), log_file_path_(profile_.GetPath().Append(kLogFileName)),
packages_{std::begin(kPackageNames), std::end(kPackageNames)} {} packages_{std::begin(kPackageNames), std::end(kPackageNames)},
events_value_(base::Value::Type::DICTIONARY),
scoped_fake_statistics_provider_(
std::make_unique<
chromeos::system::ScopedFakeStatisticsProvider>()) {}
// testing::Test: // testing::Test:
void SetUp() override { void SetUp() override {
...@@ -180,10 +218,22 @@ class AppInstallEventLogManagerTest : public testing::Test { ...@@ -180,10 +218,22 @@ class AppInstallEventLogManagerTest : public testing::Test {
void AddLogEntryForAllApps() { AddLogEntryForsetOfApps(packages_); } void AddLogEntryForAllApps() { AddLogEntryForsetOfApps(packages_); }
void ClearEventsDict() {
base::DictionaryValue* mutable_dict;
if (events_value_.GetAsDictionary(&mutable_dict))
mutable_dict->Clear();
else
NOTREACHED();
}
void ExpectUploadAndCaptureCallback( void ExpectUploadAndCaptureCallback(
CloudPolicyClient::StatusCallback* callback) { CloudPolicyClient::StatusCallback* callback) {
ClearEventsDict();
events_value_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertEventsToValue(events_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(cloud_policy_client_, EXPECT_CALL(cloud_policy_client_,
UploadAppInstallReport(Pointee(MatchEvents(events_)), _)) UploadRealtimeReport(MatchEvents(&events_value_), _))
.WillOnce(SaveArg<1>(callback)); .WillOnce(SaveArg<1>(callback));
} }
...@@ -193,12 +243,16 @@ class AppInstallEventLogManagerTest : public testing::Test { ...@@ -193,12 +243,16 @@ class AppInstallEventLogManagerTest : public testing::Test {
} }
void ExpectAndCompleteUpload() { void ExpectAndCompleteUpload() {
ClearEventsDict();
events_value_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertEventsToValue(events_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(cloud_policy_client_, EXPECT_CALL(cloud_policy_client_,
UploadAppInstallReport(Pointee(MatchEvents(events_)), _)) UploadRealtimeReport(MatchEvents(&events_value_), _))
.WillOnce(Invoke([](const em::AppInstallReportRequest*, .WillOnce(Invoke(
const CloudPolicyClient::StatusCallback& callback) { [](base::Value, const CloudPolicyClient::StatusCallback& callback) {
callback.Run(true /* success */); callback.Run(true /* success */);
})); }));
} }
void FlushNonDelayedTasks() { void FlushNonDelayedTasks() {
...@@ -251,6 +305,9 @@ class AppInstallEventLogManagerTest : public testing::Test { ...@@ -251,6 +305,9 @@ class AppInstallEventLogManagerTest : public testing::Test {
const base::FilePath log_file_path_; const base::FilePath log_file_path_;
const std::set<std::string> packages_; const std::set<std::string> packages_;
base::Value events_value_;
std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider>
scoped_fake_statistics_provider_;
em::AppInstallReportLogEvent event_; em::AppInstallReportLogEvent event_;
Events events_; Events events_;
......
...@@ -13,8 +13,15 @@ ...@@ -13,8 +13,15 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/policy/proto/device_management_backend.pb.h" #include "components/policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy { namespace policy {
namespace { namespace {
...@@ -31,8 +38,12 @@ const int kMaxRetryBackoffMs = 24 * 60 * 60 * 1000; // 24 hours ...@@ -31,8 +38,12 @@ const int kMaxRetryBackoffMs = 24 * 60 * 60 * 1000; // 24 hours
AppInstallEventLogUploader::Delegate::~Delegate() {} AppInstallEventLogUploader::Delegate::~Delegate() {}
AppInstallEventLogUploader::AppInstallEventLogUploader( AppInstallEventLogUploader::AppInstallEventLogUploader(
CloudPolicyClient* client) CloudPolicyClient* client,
: client_(client), retry_backoff_ms_(kMinRetryBackoffMs) { Profile* profile)
: client_(client),
profile_(profile),
retry_backoff_ms_(kMinRetryBackoffMs) {
DCHECK(client_);
client_->AddObserver(this); client_->AddObserver(this);
} }
...@@ -87,11 +98,14 @@ void AppInstallEventLogUploader::StartSerialization() { ...@@ -87,11 +98,14 @@ void AppInstallEventLogUploader::StartSerialization() {
} }
void AppInstallEventLogUploader::OnSerialized( void AppInstallEventLogUploader::OnSerialized(
const enterprise_management::AppInstallReportRequest* report) { const em::AppInstallReportRequest* report) {
base::Value value_report = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(report, profile_), reporting::GetContext(profile_));
// base::Unretained() is safe here as the destructor cancels any pending // base::Unretained() is safe here as the destructor cancels any pending
// upload, after which the |client_| is guaranteed to not call the callback. // upload, after which the |client_| is guaranteed to not call the callback.
client_->UploadAppInstallReport( client_->UploadRealtimeReport(
report, std::move(value_report),
base::AdaptCallbackForRepeating(base::BindOnce( base::AdaptCallbackForRepeating(base::BindOnce(
&AppInstallEventLogUploader::OnUploadDone, base::Unretained(this)))); &AppInstallEventLogUploader::OnUploadDone, base::Unretained(this))));
} }
......
...@@ -14,6 +14,8 @@ namespace enterprise_management { ...@@ -14,6 +14,8 @@ namespace enterprise_management {
class AppInstallReportRequest; class AppInstallReportRequest;
} }
class Profile;
namespace policy { namespace policy {
// Adapter between the system that captures and stores app push-install event // Adapter between the system that captures and stores app push-install event
...@@ -45,7 +47,7 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer { ...@@ -45,7 +47,7 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer {
}; };
// |client| must outlive |this|. // |client| must outlive |this|.
explicit AppInstallEventLogUploader(CloudPolicyClient* client); AppInstallEventLogUploader(CloudPolicyClient* client, Profile* profile);
~AppInstallEventLogUploader() override; ~AppInstallEventLogUploader() override;
// Sets the delegate. The delegate must either outlive |this| or be explicitly // Sets the delegate. The delegate must either outlive |this| or be explicitly
...@@ -101,6 +103,9 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer { ...@@ -101,6 +103,9 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer {
// The client used to upload logs to the server. // The client used to upload logs to the server.
CloudPolicyClient* client_ = nullptr; CloudPolicyClient* client_ = nullptr;
// Profile used to fetch the context attributes for report request.
Profile* profile_ = nullptr;
// The delegate that provides serialized logs to be uploaded. // The delegate that provides serialized logs to be uploaded.
Delegate* delegate_ = nullptr; Delegate* delegate_ = nullptr;
......
...@@ -8,18 +8,23 @@ ...@@ -8,18 +8,23 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h" #include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.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 "components/policy/proto/device_management_backend.pb.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using testing::Invoke; using testing::Invoke;
using testing::Mock; using testing::Mock;
using testing::Pointee;
using testing::SaveArg; using testing::SaveArg;
using testing::WithArgs; using testing::WithArgs;
using testing::_; using testing::_;
...@@ -36,8 +41,19 @@ constexpr base::TimeDelta kMaxRetryBackoff = base::TimeDelta::FromDays(1); ...@@ -36,8 +41,19 @@ constexpr base::TimeDelta kMaxRetryBackoff = base::TimeDelta::FromDays(1);
static const char kDmToken[] = "token"; static const char kDmToken[] = "token";
static const char kPackageName[] = "package"; static const char kPackageName[] = "package";
MATCHER_P(MatchProto, expected, "matches protobuf") { MATCHER_P(MatchValue, expected, "matches base::Value") {
return arg.SerializePartialAsString() == expected.SerializePartialAsString(); 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;
} }
ACTION_TEMPLATE(MoveArg, ACTION_TEMPLATE(MoveArg,
...@@ -66,13 +82,11 @@ class MockAppInstallEventLogUploaderDelegate ...@@ -66,13 +82,11 @@ class MockAppInstallEventLogUploaderDelegate
class AppInstallEventLogUploaderTest : public testing::Test { class AppInstallEventLogUploaderTest : public testing::Test {
protected: protected:
AppInstallEventLogUploaderTest() {} AppInstallEventLogUploaderTest()
: scoped_task_environment_(
void SetUp() override { base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME,
task_runner_ = new base::TestMockTimeTaskRunner(); base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY),
task_runner_handle_ = value_report_(base::Value::Type::DICTIONARY) {}
std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
}
void TearDown() override { void TearDown() override {
Mock::VerifyAndClearExpectations(&client_); Mock::VerifyAndClearExpectations(&client_);
...@@ -91,7 +105,7 @@ class AppInstallEventLogUploaderTest : public testing::Test { ...@@ -91,7 +105,7 @@ class AppInstallEventLogUploaderTest : public testing::Test {
} }
void CreateUploader() { void CreateUploader() {
uploader_ = std::make_unique<AppInstallEventLogUploader>(&client_); uploader_ = std::make_unique<AppInstallEventLogUploader>(&client_, nullptr);
uploader_->SetDelegate(&delegate_); uploader_->SetDelegate(&delegate_);
} }
...@@ -108,8 +122,20 @@ class AppInstallEventLogUploaderTest : public testing::Test { ...@@ -108,8 +122,20 @@ class AppInstallEventLogUploaderTest : public testing::Test {
.WillOnce(MoveArg<0>(callback)); .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) { void CompleteUpload(bool success) {
EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _)) ClearReportDict();
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(&log_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(client_, UploadRealtimeReport(MatchValue(&value_report_), _))
.WillOnce(WithArgs<1>( .WillOnce(WithArgs<1>(
Invoke([=](const CloudPolicyClient::StatusCallback& callback) { Invoke([=](const CloudPolicyClient::StatusCallback& callback) {
callback.Run(success); callback.Run(success);
...@@ -117,8 +143,12 @@ class AppInstallEventLogUploaderTest : public testing::Test { ...@@ -117,8 +143,12 @@ class AppInstallEventLogUploaderTest : public testing::Test {
} }
void CaptureUpload(CloudPolicyClient::StatusCallback* callback) { void CaptureUpload(CloudPolicyClient::StatusCallback* callback) {
ClearReportDict();
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(&log_, nullptr), reporting::GetContext(nullptr));
CloudPolicyClient::StatusCallback status_callback; CloudPolicyClient::StatusCallback status_callback;
EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _)) EXPECT_CALL(client_, UploadRealtimeReport(MatchValue(&value_report_), _))
.WillOnce(SaveArg<1>(callback)); .WillOnce(SaveArg<1>(callback));
} }
...@@ -133,15 +163,14 @@ class AppInstallEventLogUploaderTest : public testing::Test { ...@@ -133,15 +163,14 @@ class AppInstallEventLogUploaderTest : public testing::Test {
CaptureUpload(callback); CaptureUpload(callback);
} }
base::test::ScopedTaskEnvironment scoped_task_environment_;
em::AppInstallReportRequest log_; em::AppInstallReportRequest log_;
base::Value value_report_;
MockCloudPolicyClient client_; MockCloudPolicyClient client_;
MockAppInstallEventLogUploaderDelegate delegate_; MockAppInstallEventLogUploaderDelegate delegate_;
std::unique_ptr<AppInstallEventLogUploader> uploader_; std::unique_ptr<AppInstallEventLogUploader> uploader_;
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_;
private: private:
DISALLOW_COPY_AND_ASSIGN(AppInstallEventLogUploaderTest); DISALLOW_COPY_AND_ASSIGN(AppInstallEventLogUploaderTest);
}; };
...@@ -219,7 +248,7 @@ TEST_F(AppInstallEventLogUploaderTest, RequestCancelAndSerialize) { ...@@ -219,7 +248,7 @@ TEST_F(AppInstallEventLogUploaderTest, RequestCancelAndSerialize) {
uploader_->CancelUpload(); uploader_->CancelUpload();
Mock::VerifyAndClearExpectations(&client_); Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback).Run(&log_); std::move(serialization_callback).Run(&log_);
} }
...@@ -262,11 +291,12 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) { ...@@ -262,11 +291,12 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
base::TimeDelta expected_delay = min_delay; base::TimeDelta expected_delay = min_delay;
int max_delay_count = 0; int max_delay_count = 0;
while (max_delay_count < 2) { while (max_delay_count < 2) {
EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay()); EXPECT_EQ(expected_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
CompleteSerializeAndUpload(false /* success */); CompleteSerializeAndUpload(false /* success */);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
task_runner_->FastForwardBy(expected_delay); scoped_task_environment_.FastForwardBy(expected_delay);
Mock::VerifyAndClearExpectations(&delegate_); Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_); Mock::VerifyAndClearExpectations(&client_);
...@@ -276,12 +306,13 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) { ...@@ -276,12 +306,13 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
expected_delay = std::min(expected_delay * 2, max_delay); expected_delay = std::min(expected_delay * 2, max_delay);
} }
EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay()); EXPECT_EQ(expected_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
log_.add_app_install_reports()->set_package(kPackageName); log_.add_app_install_reports()->set_package(kPackageName);
CompleteSerializeAndUpload(true /* success */); CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnUploadSuccess()); EXPECT_CALL(delegate_, OnUploadSuccess());
task_runner_->FastForwardBy(expected_delay); scoped_task_environment_.FastForwardBy(expected_delay);
Mock::VerifyAndClearExpectations(&delegate_); Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_); Mock::VerifyAndClearExpectations(&client_);
...@@ -289,7 +320,8 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) { ...@@ -289,7 +320,8 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
uploader_->RequestUpload(); uploader_->RequestUpload();
EXPECT_EQ(min_delay, task_runner_->NextPendingTaskDelay()); EXPECT_EQ(min_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
} }
// Create the uploader using a client that is not registered with the server // Create the uploader using a client that is not registered with the server
...@@ -368,7 +400,7 @@ TEST_F(AppInstallEventLogUploaderTest, ...@@ -368,7 +400,7 @@ TEST_F(AppInstallEventLogUploaderTest,
UnregisterClient(); UnregisterClient();
Mock::VerifyAndClearExpectations(&client_); Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback).Run(&log_); std::move(serialization_callback).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_); Mock::VerifyAndClearExpectations(&delegate_);
...@@ -407,7 +439,7 @@ TEST_F(AppInstallEventLogUploaderTest, ...@@ -407,7 +439,7 @@ TEST_F(AppInstallEventLogUploaderTest,
CaptureSerialize(&serialization_callback_2); CaptureSerialize(&serialization_callback_2);
RegisterClient(); RegisterClient();
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0); EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0); EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback_1).Run(&log_); std::move(serialization_callback_1).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_); Mock::VerifyAndClearExpectations(&delegate_);
......
// 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/chromeos/policy/app_install_event_log_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/system/statistics_provider.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
namespace em = enterprise_management;
namespace policy {
namespace {
// Key names used when building the dictionary to pass to the Chrome Reporting
// API.
constexpr char kAppPackage[] = "appPackage";
constexpr char kEventType[] = "eventType";
constexpr char kStatefulTotal[] = "statefulTotal";
constexpr char kStatefulFree[] = "statefulFree";
constexpr char kCloudDpsResponse[] = "clouddpsResponse";
constexpr char kOnline[] = "online";
constexpr char kSessionStateChangeType[] = "sessionStateChangeType";
constexpr char kSerialNumber[] = "serialNumber";
constexpr char kGaiaId[] = "gaiaId";
constexpr char kAndroidAppInstallEvent[] = "androidAppInstallEvent";
constexpr char kTime[] = "time";
} // namespace
bool GetGaiaId(Profile* profile, int* gaia_id) {
if (!profile)
return false;
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
if (!user)
return false;
if (!base::StringToInt(user->GetAccountId().GetGaiaId(), gaia_id))
return false;
return true;
}
std::string GetSerialNumber() {
return chromeos::system::StatisticsProvider::GetInstance()
->GetEnterpriseMachineID();
}
base::Value ConvertProtoToValue(
const em::AppInstallReportRequest* app_install_report_request,
Profile* profile) {
DCHECK(app_install_report_request);
base::Value event_list(base::Value::Type::LIST);
base::Value::ListStorage& mutable_list = event_list.GetList();
for (const em::AppInstallReport& app_install_report :
app_install_report_request->app_install_reports()) {
for (const em::AppInstallReportLogEvent& app_install_report_log_event :
app_install_report.logs()) {
base::Value wrapper;
wrapper = ConvertEventToValue(
app_install_report.has_package() ? app_install_report.package() : "",
app_install_report_log_event, profile);
mutable_list.push_back(std::move(wrapper));
}
}
return event_list;
}
base::Value ConvertEventToValue(
const std::string& package,
const em::AppInstallReportLogEvent& app_install_report_log_event,
Profile* profile) {
base::Value event(base::Value::Type::DICTIONARY);
if (!package.empty())
event.SetStringKey(kAppPackage, package);
if (app_install_report_log_event.has_event_type()) {
event.SetIntKey(kEventType, app_install_report_log_event.event_type());
}
if (app_install_report_log_event.has_stateful_total()) {
event.SetIntKey(kStatefulTotal,
app_install_report_log_event.stateful_total());
}
if (app_install_report_log_event.has_stateful_free()) {
event.SetIntKey(kStatefulFree,
app_install_report_log_event.stateful_free());
}
if (app_install_report_log_event.has_clouddps_response()) {
event.SetIntKey(kCloudDpsResponse,
app_install_report_log_event.clouddps_response());
}
if (app_install_report_log_event.has_online())
event.SetBoolKey(kOnline, app_install_report_log_event.online());
if (app_install_report_log_event.has_session_state_change_type()) {
event.SetIntKey(kSessionStateChangeType,
app_install_report_log_event.session_state_change_type());
}
event.SetStringKey(kSerialNumber, GetSerialNumber());
int gaia_id;
if (GetGaiaId(profile, &gaia_id))
event.SetIntKey(kGaiaId, gaia_id);
base::Value wrapper(base::Value::Type::DICTIONARY);
wrapper.SetKey(kAndroidAppInstallEvent, std::move(event));
if (app_install_report_log_event.has_timestamp()) {
// Format the current time (UTC) in RFC3339 format
base::Time timestamp =
base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(
app_install_report_log_event.timestamp());
base::Time::Exploded time_exploded;
timestamp.UTCExplode(&time_exploded);
std::string time_str = base::StringPrintf(
"%d-%02d-%02dT%02d:%02d:%02d.%03dZ", time_exploded.year,
time_exploded.month, time_exploded.day_of_month, time_exploded.hour,
time_exploded.minute, time_exploded.second, time_exploded.millisecond);
wrapper.SetStringKey(kTime, time_str);
}
return wrapper;
}
} // namespace policy
// 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.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
#include "components/policy/proto/device_management_backend.pb.h"
namespace base {
class Value;
} // namespace base
class Profile;
namespace em = enterprise_management;
namespace policy {
// Returns true if GAIA ID can be fetched for a given |profile|, and it can be
// converted to a number. If GAIA ID can be fetched, it gets written to
// |gaia_id|, otherwise returns false.
bool GetGaiaId(Profile* profile, int* gaia_id);
// Return serial number of the device.
std::string GetSerialNumber();
// Converts AppInstallReportRequest proto defined in
// components/policy/proto/device_management_backend.proto to a dictionary value
// that corresponds to the definition of Event defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto. This is
// done because events to Chrome Reporting API are sent as json over HTTP, and
// has different proto definition compare to the proto used to store events
// locally.
base::Value ConvertProtoToValue(
const em::AppInstallReportRequest* app_install_report_request,
Profile* profile);
// Converts AppInstallReportLogEvent proto defined in
// components/policy/proto/device_management_backend.proto to a dictionary value
// that corresponds to the definition of AndroidAppInstallEvent defined in
// google3/chrome/cros/reporting/proto/chrome_app_install_events.proto.
base::Value ConvertEventToValue(
const std::string& package,
const em::AppInstallReportLogEvent& app_install_report_log_event,
Profile* profile);
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
...@@ -279,7 +279,7 @@ void UserCloudPolicyManagerChromeOS::Connect( ...@@ -279,7 +279,7 @@ void UserCloudPolicyManagerChromeOS::Connect(
} }
app_install_event_log_uploader_ = app_install_event_log_uploader_ =
std::make_unique<AppInstallEventLogUploader>(client()); std::make_unique<AppInstallEventLogUploader>(client(), profile_);
} }
void UserCloudPolicyManagerChromeOS::OnAccessTokenAvailable( void UserCloudPolicyManagerChromeOS::OnAccessTokenAvailable(
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/common/extensions/api/safe_browsing_private.h" #include "chrome/common/extensions/api/safe_browsing_private.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/cloud_policy_client.h"
...@@ -70,30 +71,6 @@ SafeBrowsingPrivateEventRouter::SafeBrowsingPrivateEventRouter( ...@@ -70,30 +71,6 @@ SafeBrowsingPrivateEventRouter::SafeBrowsingPrivateEventRouter(
InitRealtimeReportingClient(); InitRealtimeReportingClient();
} }
// TODO(rogerta): once new event types are implemented, will likely want to
// move this to a more common place.
base::Value BuildRealtimeReport(Profile* profile, base::Value event) {
base::Value context(base::Value::Type::DICTIONARY);
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry = nullptr;
if (storage.GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
context.SetStringPath("profile.profileName", entry->GetName());
context.SetStringPath("profile.gaiaEmail", entry->GetUserName());
}
context.SetStringPath("profile.profilePath", profile->GetPath().value());
context.SetStringPath("browser.userAgent", GetUserAgent());
base::Value report(base::Value::Type::DICTIONARY);
report.SetKey(policy::RealtimeReportingJobConfiguration::kContextKey,
std::move(context));
report.SetKey(policy::RealtimeReportingJobConfiguration::kEventKey,
std::move(event));
return report;
}
SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {} SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {}
void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected( void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
...@@ -388,9 +365,13 @@ void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(const char* name, ...@@ -388,9 +365,13 @@ void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(const char* name,
wrapper.SetStringKey("time", now_str); wrapper.SetStringKey("time", now_str);
wrapper.SetKey(name, std::move(event)); wrapper.SetKey(name, std::move(event));
base::Value event_list(base::Value::Type::LIST);
event_list.GetList().push_back(std::move(wrapper));
client_->UploadRealtimeReport( client_->UploadRealtimeReport(
BuildRealtimeReport(Profile::FromBrowserContext(context_), policy::RealtimeReportingJobConfiguration::BuildReport(
std::move(wrapper)), std::move(event_list),
reporting::GetContext(Profile::FromBrowserContext(context_))),
base::DoNothing()); base::DoNothing());
} }
......
...@@ -159,12 +159,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnReuseDetected) { ...@@ -159,12 +159,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnReuseDetected) {
Mock::VerifyAndClearExpectations(client_); Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type()); EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper = base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey); report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, wrapper); ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type()); EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event = base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent); wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent);
EXPECT_NE(nullptr, event); EXPECT_NE(nullptr, event);
EXPECT_EQ("https://phishing.com/", EXPECT_EQ("https://phishing.com/",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyUrl)); *event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyUrl));
...@@ -190,12 +194,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnPasswordChanged) { ...@@ -190,12 +194,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnPasswordChanged) {
Mock::VerifyAndClearExpectations(client_); Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type()); EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper = base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey); report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, wrapper); ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type()); EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value* event = wrapper->FindKey( base::Value::ListStorage& mutable_list = event_list->GetList();
SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent); ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event =
wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent);
EXPECT_NE(nullptr, event); EXPECT_NE(nullptr, event);
EXPECT_EQ("user_name_2", *event->FindStringKey( EXPECT_EQ("user_name_2", *event->FindStringKey(
SafeBrowsingPrivateEventRouter::kKeyUserName)); SafeBrowsingPrivateEventRouter::kKeyUserName));
...@@ -225,11 +233,15 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnDangerousDownloadOpened) { ...@@ -225,11 +233,15 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnDangerousDownloadOpened) {
Mock::VerifyAndClearExpectations(client_); Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type()); EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper = base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey); report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, wrapper); ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type()); EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value* event = wrapper->FindKey( base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event = wrapper.FindKey(
SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent); SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent);
EXPECT_NE(nullptr, event); EXPECT_NE(nullptr, event);
EXPECT_EQ( EXPECT_EQ(
...@@ -259,12 +271,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, ...@@ -259,12 +271,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest,
Mock::VerifyAndClearExpectations(client_); Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type()); EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper = base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey); report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, wrapper); ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type()); EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event = base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent); wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
EXPECT_NE(nullptr, event); EXPECT_NE(nullptr, event);
EXPECT_EQ("PHISHING", EXPECT_EQ("PHISHING",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason)); *event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason));
...@@ -295,12 +311,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnSecurityInterstitialShown) { ...@@ -295,12 +311,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnSecurityInterstitialShown) {
Mock::VerifyAndClearExpectations(client_); Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type()); EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper = base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey); report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, wrapper); ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type()); EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event = base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent); wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
EXPECT_NE(nullptr, event); EXPECT_NE(nullptr, event);
EXPECT_EQ("PHISHING", EXPECT_EQ("PHISHING",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason)); *event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason));
......
// 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/profiles/reporting_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
namespace reporting {
base::Value GetContext(Profile* profile) {
base::Value context(base::Value::Type::DICTIONARY);
context.SetStringPath("browser.userAgent", GetUserAgent());
if (!profile)
return context;
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry = nullptr;
if (storage.GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
context.SetStringPath("profile.profileName", entry->GetName());
context.SetStringPath("profile.gaiaEmail", entry->GetUserName());
}
context.SetStringPath("profile.profilePath", profile->GetPath().value());
return context;
}
} // namespace reporting
// 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.
#ifndef CHROME_BROWSER_PROFILES_REPORTING_UTIL_H_
#define CHROME_BROWSER_PROFILES_REPORTING_UTIL_H_
class Profile;
namespace base {
class Value;
} // namespace base
namespace reporting {
// Fetches additional information that is common to every event. Fetches and
// returns corresponding info to a Device, Browser and Profile protos defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto.
base::Value GetContext(Profile* profile);
} // namespace reporting
#endif // CHROME_BROWSER_PROFILES_REPORTING_UTIL_H_
...@@ -1437,17 +1437,26 @@ TEST_F(CloudPolicyClientTest, UploadRealtimeReport) { ...@@ -1437,17 +1437,26 @@ TEST_F(CloudPolicyClientTest, UploadRealtimeReport) {
CloudPolicyClient::StatusCallback callback = CloudPolicyClient::StatusCallback callback =
base::Bind(&MockStatusCallbackObserver::OnCallbackComplete, base::Bind(&MockStatusCallbackObserver::OnCallbackComplete,
base::Unretained(&callback_observer_)); base::Unretained(&callback_observer_));
base::Value report(base::Value::Type::DICTIONARY);
report.SetStringPath("context.gaiaEmail", "name@gmail.com"); base::Value context(base::Value::Type::DICTIONARY);
report.SetStringPath("context.userAgent", "User-Agent"); context.SetStringPath("gaiaEmail", "name@gmail.com");
report.SetStringPath("context.profileName", "Profile 1"); context.SetStringPath("userAgent", "User-Agent");
report.SetStringPath("context.profilePath", "C:\\User Data\\Profile 1"); context.SetStringPath("profileName", "Profile 1");
report.SetStringPath("event.time", "2019-05-22T13:01:45Z"); context.SetStringPath("profilePath", "C:\\User Data\\Profile 1");
report.SetStringPath("event.foo.prop1", "value1");
report.SetStringPath("event.foo.prop2", "value2"); base::Value event;
report.SetStringPath("event.foo.prop3", "value3"); event.SetStringPath("time", "2019-05-22T13:01:45Z");
event.SetStringPath("foo.prop1", "value1");
client_->UploadRealtimeReport(std::move(report), callback); event.SetStringPath("foo.prop2", "value2");
event.SetStringPath("foo.prop3", "value3");
base::Value event_list(base::Value::Type::LIST);
event_list.GetList().push_back(std::move(event));
client_->UploadRealtimeReport(
std::move(policy::RealtimeReportingJobConfiguration::BuildReport(
std::move(event_list), std::move(context))),
callback);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_EQ( EXPECT_EQ(
DeviceManagementService::JobConfiguration::TYPE_UPLOAD_REAL_TIME_REPORT, DeviceManagementService::JobConfiguration::TYPE_UPLOAD_REAL_TIME_REPORT,
......
...@@ -20,7 +20,7 @@ namespace em = enterprise_management; ...@@ -20,7 +20,7 @@ namespace em = enterprise_management;
namespace policy { namespace policy {
const char RealtimeReportingJobConfiguration::kContextKey[] = "context"; const char RealtimeReportingJobConfiguration::kContextKey[] = "context";
const char RealtimeReportingJobConfiguration::kEventKey[] = "event"; const char RealtimeReportingJobConfiguration::kEventListKey[] = "eventList";
const char RealtimeReportingJobConfiguration::kBrowserIdKey[] = const char RealtimeReportingJobConfiguration::kBrowserIdKey[] =
"browser.browserId"; "browser.browserId";
...@@ -35,6 +35,15 @@ const char RealtimeReportingJobConfiguration::kMachineUserKey[] = ...@@ -35,6 +35,15 @@ const char RealtimeReportingJobConfiguration::kMachineUserKey[] =
const char RealtimeReportingJobConfiguration::kOsVersionKey[] = const char RealtimeReportingJobConfiguration::kOsVersionKey[] =
"device.osVersion"; "device.osVersion";
base::Value RealtimeReportingJobConfiguration::BuildReport(
base::Value events,
base::Value context) {
base::Value value_report(base::Value::Type::DICTIONARY);
value_report.SetKey(kEventListKey, std::move(events));
value_report.SetKey(kContextKey, std::move(context));
return value_report;
}
RealtimeReportingJobConfiguration::RealtimeReportingJobConfiguration( RealtimeReportingJobConfiguration::RealtimeReportingJobConfiguration(
CloudPolicyClient* client, CloudPolicyClient* client,
std::unique_ptr<DMAuth> auth_data, std::unique_ptr<DMAuth> auth_data,
...@@ -59,8 +68,8 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) { ...@@ -59,8 +68,8 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) {
return false; return false;
base::Optional<base::Value> context = report.ExtractKey(kContextKey); base::Optional<base::Value> context = report.ExtractKey(kContextKey);
base::Optional<base::Value> event = report.ExtractKey(kEventKey); base::Optional<base::Value> event_list = report.ExtractKey(kEventListKey);
if (!context || !event) if (!context || !event_list || !event_list->is_list())
return false; return false;
// Move context keys to the payload. It is possible to add multiple reports // Move context keys to the payload. It is possible to add multiple reports
...@@ -71,9 +80,11 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) { ...@@ -71,9 +80,11 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) {
payload_.SetKey(item.first, item.second.Clone()); payload_.SetKey(item.first, item.second.Clone());
} }
// Append event to the list. // Append event_list to the payload.
base::Value::ListStorage& list = payload_.FindListKey(kEventsKey)->GetList(); base::Value::ListStorage& to = payload_.FindListKey(kEventsKey)->GetList();
list.push_back(std::move(*event)); base::Value::ListStorage& from = event_list->GetList();
to.insert(to.end(), std::make_move_iterator(from.begin()),
std::make_move_iterator(from.end()));
return true; return true;
} }
......
...@@ -24,7 +24,7 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration ...@@ -24,7 +24,7 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration
public: public:
// Keys used in report dictionary. // Keys used in report dictionary.
static const char kContextKey[]; static const char kContextKey[];
static const char kEventKey[]; static const char kEventListKey[];
// Keys used in request payload dictionary. Public for testing. // Keys used in request payload dictionary. Public for testing.
static const char kBrowserIdKey[]; static const char kBrowserIdKey[];
...@@ -41,15 +41,21 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration ...@@ -41,15 +41,21 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration
const base::Value&)> const base::Value&)>
Callback; Callback;
// Combines the info given in |events| that corresponds to Event proto, and
// info given in |context| that corresponds to the Device, Browser and Profile
// proto, to a UploadEventsRequest proto defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto.
static base::Value BuildReport(base::Value events, base::Value context);
RealtimeReportingJobConfiguration(CloudPolicyClient* client, RealtimeReportingJobConfiguration(CloudPolicyClient* client,
std::unique_ptr<DMAuth> auth_data, std::unique_ptr<DMAuth> auth_data,
Callback callback); Callback callback);
~RealtimeReportingJobConfiguration() override; ~RealtimeReportingJobConfiguration() override;
// Add a new report to the payload. A report is a dictionary that contains // Add a new report to the payload. A report is a dictionary that
// two keys: "event" and "context". The first key is a dictionary defined by // contains two keys: "events" and "context". The first key is a list of
// the Event message described at // dictionaries, where dictionary is defined by the Event message described at
// google/internal/chrome/reporting/v1/chromereporting.proto. // google/internal/chrome/reporting/v1/chromereporting.proto.
// //
// The second is context information about this instance of chrome that // The second is context information about this instance of chrome that
......
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