Commit 4646621f authored by Leonid Baraz's avatar Leonid Baraz Committed by Commit Bot

Fix for test flakiness.

ReportClient creation made fully asynchronous,
and problematic test can now wait for initialization to complete.

Bug: b:169427520
Change-Id: Ic6566e9973dc48de86b36c8b1180d688de84ce76
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2444409Reviewed-by: default avatarZach Trudo <zatrudo@google.com>
Commit-Queue: Leonid Baraz <lbaraz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813206}
parent 5766fef9
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#if defined(OS_CHROMEOS) #ifdef OS_CHROMEOS
#include "chrome/browser/chromeos/login/users/chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
...@@ -57,7 +57,7 @@ namespace { ...@@ -57,7 +57,7 @@ namespace {
// NOT THREAD SAFE - these functions must be called on the main thread. // NOT THREAD SAFE - these functions must be called on the main thread.
// TODO(chromium:1078512) Wrap CloudPolicyClient in a new object so that its // TODO(chromium:1078512) Wrap CloudPolicyClient in a new object so that its
// methods, constructor, and destructor are accessed on the correct thread. // methods, constructor, and destructor are accessed on the correct thread.
#if defined(OS_CHROMEOS) #ifdef OS_CHROMEOS
void BuildCloudPolicyClient( void BuildCloudPolicyClient(
base::OnceCallback< base::OnceCallback<
void(StatusOr<std::unique_ptr<policy::CloudPolicyClient>>)> build_cb) { void(StatusOr<std::unique_ptr<policy::CloudPolicyClient>>)> build_cb) {
...@@ -376,7 +376,7 @@ void ReportingClient::InitializingContext::OnLeaderPromotionResult( ...@@ -376,7 +376,7 @@ void ReportingClient::InitializingContext::OnLeaderPromotionResult(
StatusOr<ReportingClient::InitializationStateTracker::ReleaseLeaderCallback> StatusOr<ReportingClient::InitializationStateTracker::ReleaseLeaderCallback>
promo_result) { promo_result) {
if (promo_result.status().error_code() == error::FAILED_PRECONDITION) { if (promo_result.status().error_code() == error::FAILED_PRECONDITION) {
// Between building this InitializationContext and attempting to promote to // Between building this InitializingContext and attempting to promote to
// leader, the ReportingClient was configured. Ok response. // leader, the ReportingClient was configured. Ok response.
Complete(Status::StatusOK()); Complete(Status::StatusOK());
return; return;
...@@ -449,11 +449,41 @@ void ReportingClient::InitializingContext::OnStorageModuleConfigured( ...@@ -449,11 +449,41 @@ void ReportingClient::InitializingContext::OnStorageModuleConfigured(
} }
client_config_->storage = storage_result.ValueOrDie(); client_config_->storage = storage_result.ValueOrDie();
Schedule(
base::BindOnce(&ReportingClient::InitializingContext::CreateUploadClient,
base::Unretained(this)));
}
void ReportingClient::InitializingContext::CreateUploadClient() {
ReportingClient* const instance = GetInstance();
DCHECK(!instance->upload_client_);
UploadClient::Create(
std::move(client_config_->cloud_policy_client),
base::BindRepeating(&StorageModule::ReportSuccess,
client_config_->storage),
base::BindOnce(&InitializingContext::OnUploadClientCreated,
base::Unretained(this)));
}
void ReportingClient::InitializingContext::OnUploadClientCreated(
StatusOr<std::unique_ptr<UploadClient>> upload_client_result) {
if (!upload_client_result.ok()) {
Complete(Status(error::FAILED_PRECONDITION,
base::StrCat({"Unable to create UploadClient: ",
upload_client_result.status().message()})));
return;
}
Schedule(&ReportingClient::InitializingContext::UpdateConfiguration, Schedule(&ReportingClient::InitializingContext::UpdateConfiguration,
base::Unretained(this)); base::Unretained(this),
std::move(upload_client_result.ValueOrDie()));
} }
void ReportingClient::InitializingContext::UpdateConfiguration() { void ReportingClient::InitializingContext::UpdateConfiguration(
std::unique_ptr<UploadClient> upload_client) {
ReportingClient* const instance = GetInstance();
DCHECK(!instance->upload_client_);
instance->upload_client_ = std::move(upload_client);
std::move(update_config_cb_) std::move(update_config_cb_)
.Run(std::move(client_config_), .Run(std::move(client_config_),
base::BindOnce(&ReportingClient::InitializingContext::Complete, base::BindOnce(&ReportingClient::InitializingContext::Complete,
...@@ -603,13 +633,7 @@ void ReportingClient::BuildRequestQueue( ...@@ -603,13 +633,7 @@ void ReportingClient::BuildRequestQueue(
StatusOr<std::unique_ptr<Storage::UploaderInterface>> StatusOr<std::unique_ptr<Storage::UploaderInterface>>
ReportingClient::BuildUploader(Priority priority) { ReportingClient::BuildUploader(Priority priority) {
ReportingClient* const instance = GetInstance(); ReportingClient* const instance = GetInstance();
if (instance->upload_client_ == nullptr) { DCHECK(instance->upload_client_);
ASSIGN_OR_RETURN(
instance->upload_client_,
UploadClient::Create(std::move(instance->config_->cloud_policy_client),
base::BindRepeating(&StorageModule::ReportSuccess,
instance->config_->storage)));
}
return Uploader::Create( return Uploader::Create(
base::BindOnce(&UploadClient::EnqueueUpload, base::BindOnce(&UploadClient::EnqueueUpload,
base::Unretained(instance->upload_client_.get()))); base::Unretained(instance->upload_client_.get())));
......
...@@ -133,7 +133,11 @@ class ReportingClient { ...@@ -133,7 +133,11 @@ class ReportingClient {
void OnStorageModuleConfigured( void OnStorageModuleConfigured(
StatusOr<scoped_refptr<StorageModule>> storage_result); StatusOr<scoped_refptr<StorageModule>> storage_result);
void UpdateConfiguration(); void CreateUploadClient();
void OnUploadClientCreated(
StatusOr<std::unique_ptr<UploadClient>> upload_client_result);
void UpdateConfiguration(std::unique_ptr<UploadClient> upload_client);
// Complete calls response with |client_config_| // Complete calls response with |client_config_|
void Complete(Status status); void Complete(Status status);
......
...@@ -21,12 +21,11 @@ ...@@ -21,12 +21,11 @@
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
// #if defined(OS_CHROMEOS) #ifdef OS_CHROMEOS
// #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
// #include "components/policy/proto/chrome_device_policy.pb.h" #include "chrome/test/base/testing_profile.h"
// #else #include "components/user_manager/scoped_user_manager.h"
// #include "chrome/browser/policy/chrome_browser_policy_connector.h" #endif // OS_CHROMEOS
// #endif
namespace reporting { namespace reporting {
namespace { namespace {
...@@ -54,16 +53,44 @@ class TestCallbackWaiter { ...@@ -54,16 +53,44 @@ class TestCallbackWaiter {
class ReportingClientTest : public testing::Test { class ReportingClientTest : public testing::Test {
public: public:
void SetUp() override { void SetUp() override {
#ifdef OS_CHROMEOS
// Set up fake primary profile.
auto mock_user_manager =
std::make_unique<testing::NiceMock<chromeos::FakeChromeUserManager>>();
profile_ = std::make_unique<TestingProfile>(
base::FilePath(FILE_PATH_LITERAL("/home/chronos/u-0123456789abcdef")));
const AccountId account_id(AccountId::FromUserEmailGaiaId(
profile_->GetProfileUserName(), "12345"));
const user_manager::User* user =
mock_user_manager->AddPublicAccountUser(account_id);
mock_user_manager->UserLoggedIn(account_id, user->username_hash(),
/*browser_restart=*/false,
/*is_child=*/false);
user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(mock_user_manager));
#endif // OS_CHROMEOS
// Provide a mock cloud policy client.
auto client = std::make_unique<policy::MockCloudPolicyClient>(); auto client = std::make_unique<policy::MockCloudPolicyClient>();
client->SetDMToken( client->SetDMToken(
policy::DMToken::CreateValidTokenForTesting("FAKE_DM_TOKEN").value()); policy::DMToken::CreateValidTokenForTesting("FAKE_DM_TOKEN").value());
ReportingClient::Setup_test(std::move(client)); ReportingClient::Setup_test(std::move(client));
} }
void TearDown() override { ReportingClient::Reset_test(); } void TearDown() override {
ReportingClient::Reset_test();
#ifdef OS_CHROMEOS
user_manager_.reset();
profile_.reset();
#endif // OS_CHROMEOS
}
protected: protected:
content::BrowserTaskEnvironment task_envrionment_; content::BrowserTaskEnvironment task_envrionment_;
#ifdef OS_CHROMEOS
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<user_manager::ScopedUserManager> user_manager_;
#endif // OS_CHROMEOS
const DMToken dm_token_ = DMToken::CreateValidTokenForTesting("TOKEN"); const DMToken dm_token_ = DMToken::CreateValidTokenForTesting("TOKEN");
const Destination destination_ = Destination::UPLOAD_EVENTS; const Destination destination_ = Destination::UPLOAD_EVENTS;
const Priority priority_ = Priority::IMMEDIATE; const Priority priority_ = Priority::IMMEDIATE;
......
...@@ -26,13 +26,14 @@ ...@@ -26,13 +26,14 @@
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#if defined(OS_CHROMEOS) #ifdef OS_CHROMEOS
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
namespace reporting { namespace reporting {
namespace { namespace {
// This function must run on UI thread.
StatusOr<Profile*> GetPrimaryProfile() { StatusOr<Profile*> GetPrimaryProfile() {
if (!user_manager::UserManager::IsInitialized()) { if (!user_manager::UserManager::IsInitialized()) {
return Status(error::FAILED_PRECONDITION, "User manager not initialized"); return Status(error::FAILED_PRECONDITION, "User manager not initialized");
...@@ -250,18 +251,39 @@ void DmServerUploader::ProcessSuccessfulUploadAddition( ...@@ -250,18 +251,39 @@ void DmServerUploader::ProcessSuccessfulUploadAddition(
highest_successful_sequence_ = sequencing_information; highest_successful_sequence_ = sequencing_information;
} }
StatusOr<std::unique_ptr<DmServerUploadService>> DmServerUploadService::Create( void DmServerUploadService::Create(
std::unique_ptr<policy::CloudPolicyClient> client, std::unique_ptr<policy::CloudPolicyClient> client,
ReportSuccessfulUploadCallback upload_cb) { ReportSuccessfulUploadCallback report_upload_success_cb,
base::OnceCallback<void(StatusOr<std::unique_ptr<DmServerUploadService>>)>
created_cb) {
if (client == nullptr) { if (client == nullptr) {
return Status(error::INVALID_ARGUMENT, "client may not be nullptr."); std::move(created_cb)
.Run(Status(error::INVALID_ARGUMENT, "client may not be nullptr."));
return;
} }
auto uploader =
base::WrapUnique(new DmServerUploadService(std::move(client), upload_cb));
RETURN_IF_ERROR(uploader->InitRecordHandlers());
return uploader; auto uploader = base::WrapUnique(
new DmServerUploadService(std::move(client), report_upload_success_cb));
#ifdef OS_CHROMEOS
content::GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&GetPrimaryProfile),
base::BindOnce(
[](std::unique_ptr<DmServerUploadService> uploader,
base::OnceCallback<void(
StatusOr<std::unique_ptr<DmServerUploadService>>)> created_cb,
StatusOr<Profile*> primary_profile_result) {
if (!primary_profile_result.ok()) {
std::move(created_cb).Run(primary_profile_result.status());
return;
}
InitRecordHandlers(std::move(uploader),
primary_profile_result.ValueOrDie(),
std::move(created_cb));
},
std::move(uploader), std::move(created_cb)));
#else
InitRecordHandlers(std::move(uploader), std::move(created_cb));
#endif // OS_CHROMEOS
} }
DmServerUploadService::DmServerUploadService( DmServerUploadService::DmServerUploadService(
...@@ -295,24 +317,74 @@ Status DmServerUploadService::EnqueueUpload( ...@@ -295,24 +317,74 @@ Status DmServerUploadService::EnqueueUpload(
return Status::StatusOK(); return Status::StatusOK();
} }
Status DmServerUploadService::InitRecordHandlers() { namespace {
auto* client = GetClient();
if (client == nullptr) { class CollectorCallback {
return Status(error::FAILED_PRECONDITION, "Client was null"); public:
CollectorCallback(size_t count, base::OnceClosure done_cb)
: count_(count), done_cb_(std::move(done_cb)) {
DCHECK_GT(count, 0u);
}
CollectorCallback(CollectorCallback& other) = delete;
CollectorCallback& operator=(CollectorCallback& other) = delete;
~CollectorCallback() { std::move(done_cb_).Run(); }
void Decrement() {
size_t old_count = count_.fetch_sub(1);
DCHECK_GT(old_count, 0u);
if (old_count > 1) {
return;
}
delete this;
} }
record_handlers_->PushBack(std::make_unique<AppInstallReportHandler>(client), private:
base::DoNothing()); std::atomic<size_t> count_;
base::OnceClosure done_cb_;
};
} // namespace
// Temporary wrapper for MeetDeviceTelementry void DmServerUploadService::InitRecordHandlers(
std::unique_ptr<DmServerUploadService> uploader,
#ifdef OS_CHROMEOS #ifdef OS_CHROMEOS
ASSIGN_OR_RETURN(Profile* const primary_profile, GetPrimaryProfile()); Profile* primary_profile,
record_handlers_->PushBack(std::make_unique<MeetDeviceTelemetryReportHandler>(
primary_profile, client),
base::DoNothing());
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
base::OnceCallback<void(StatusOr<std::unique_ptr<DmServerUploadService>>)>
created_cb) {
auto* client = uploader->GetClient();
if (client == nullptr) {
std::move(created_cb)
.Run(Status(error::FAILED_PRECONDITION, "Client was null"));
return;
}
return Status::StatusOK(); std::vector<std::unique_ptr<RecordHandler>> handlers;
handlers.emplace_back(std::make_unique<AppInstallReportHandler>(client));
#ifdef OS_CHROMEOS
// Temporary wrapper for MeetDeviceTelemetry
handlers.emplace_back(std::make_unique<MeetDeviceTelemetryReportHandler>(
primary_profile, client));
#endif // OS_CHROMEOS
// Copy record_handlers_ aside, because uploader is going to be moved.
auto record_handlers = uploader->record_handlers_;
// collector_cb self-destructs upon completion.
CollectorCallback* const collector_cb = new CollectorCallback(
handlers.size(),
base::BindOnce(
[](std::unique_ptr<DmServerUploadService> uploader,
base::OnceCallback<void(
StatusOr<std::unique_ptr<DmServerUploadService>>)>
created_cb) {
std::move(created_cb).Run(std::move(uploader));
},
std::move(uploader), std::move(created_cb)));
for (auto& handler : handlers) {
record_handlers->PushBack(std::move(handler),
base::BindOnce(&CollectorCallback::Decrement,
base::Unretained(collector_cb)));
}
} }
void DmServerUploadService::UploadCompletion( void DmServerUploadService::UploadCompletion(
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
#include "components/policy/proto/record_constants.pb.h" #include "components/policy/proto/record_constants.pb.h"
#include "net/base/backoff_entry.h" #include "net/base/backoff_entry.h"
#ifdef OS_CHROMEOS
#include "chrome/browser/profiles/profile.h"
#endif // OS_CHROMEOS
namespace reporting { namespace reporting {
// DmServerUploadService uploads events to the DMServer. It does not manage // DmServerUploadService uploads events to the DMServer. It does not manage
...@@ -131,18 +135,20 @@ class DmServerUploadService { ...@@ -131,18 +135,20 @@ class DmServerUploadService {
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
}; };
// Will create a DMServerUploadService with handlers. // Will asynchronously create a DMServerUploadService with handlers.
// On successful completion returns a DMServerUploadService. // On successful completion will call |created_cb| with DMServerUploadService.
// If |client| is null, will return error::INVALID_ARGUMENT. // If |client| is null, will call |created_cb| with error::INVALID_ARGUMENT.
// If any handlers fail to create, or the policy::CloudPolicyClient is null, // If any handlers fail to create, or the policy::CloudPolicyClient is null,
// will return error::UNAVAILABLE. // will call |created_cb| with error::UNAVAILABLE.
// //
// |client| must not be null. // |client| must not be null.
// |completion_cb| should report back to the holder of the created object // |report_upload_success_cb| should report back to the holder of the created
// whenever a record set is successfully uploaded. // object whenever a record set is successfully uploaded.
static StatusOr<std::unique_ptr<DmServerUploadService>> Create( static void Create(
std::unique_ptr<policy::CloudPolicyClient> client, std::unique_ptr<policy::CloudPolicyClient> client,
ReportSuccessfulUploadCallback completion_cb); ReportSuccessfulUploadCallback report_upload_success_cb,
base::OnceCallback<void(StatusOr<std::unique_ptr<DmServerUploadService>>)>
created_cb);
~DmServerUploadService(); ~DmServerUploadService();
Status EnqueueUpload(std::unique_ptr<std::vector<EncryptedRecord>> record); Status EnqueueUpload(std::unique_ptr<std::vector<EncryptedRecord>> record);
...@@ -151,7 +157,13 @@ class DmServerUploadService { ...@@ -151,7 +157,13 @@ class DmServerUploadService {
DmServerUploadService(std::unique_ptr<policy::CloudPolicyClient> client, DmServerUploadService(std::unique_ptr<policy::CloudPolicyClient> client,
ReportSuccessfulUploadCallback completion_cb); ReportSuccessfulUploadCallback completion_cb);
Status InitRecordHandlers(); static void InitRecordHandlers(
std::unique_ptr<DmServerUploadService> uploader,
#ifdef OS_CHROMEOS
Profile* primary_profile,
#endif // OS_CHROMEOS
base::OnceCallback<void(StatusOr<std::unique_ptr<DmServerUploadService>>)>
created_cb);
void UploadCompletion(StatusOr<SequencingInformation>) const; void UploadCompletion(StatusOr<SequencingInformation>) const;
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/synchronization/waitable_event.h"
#include "base/task_runner.h" #include "base/task_runner.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "chrome/browser/policy/messaging_layer/util/shared_vector.h" #include "chrome/browser/policy/messaging_layer/util/shared_vector.h"
...@@ -16,6 +15,7 @@ ...@@ -16,6 +15,7 @@
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace reporting { namespace reporting {
...@@ -24,10 +24,48 @@ namespace { ...@@ -24,10 +24,48 @@ namespace {
using testing::_; using testing::_;
using testing::Return; using testing::Return;
// Usage (in tests only):
//
// TestEvent<ResType> e;
// ... Do some async work passing e.cb() as a completion callback of
// base::OnceCallback<void(ResType* res)> type which also may perform some
// other action specified by |done| callback provided by the caller.
// ... = e.result(); // Will wait for e.cb() to be called and return the
// collected result.
//
template <typename ResType>
class TestEvent {
public:
TestEvent() : run_loop_(std::make_unique<base::RunLoop>()) {}
~TestEvent() = default;
TestEvent(const TestEvent& other) = delete;
TestEvent& operator=(const TestEvent& other) = delete;
ResType result() {
run_loop_->Run();
return std::forward<ResType>(result_);
}
// Completion callback to hand over to the processing method.
base::OnceCallback<void(ResType res)> cb() {
return base::BindOnce(
[](base::RunLoop* run_loop, ResType* result, ResType res) {
*result = std::forward<ResType>(res);
run_loop->Quit();
},
base::Unretained(run_loop_.get()), base::Unretained(&result_));
}
private:
std::unique_ptr<base::RunLoop> run_loop_;
ResType result_;
};
// Ensures that profile cannot be null. // Ensures that profile cannot be null.
TEST(DmServerUploadServiceTest, DeniesNullptrProfile) { TEST(DmServerUploadServiceTest, DeniesNullptrProfile) {
auto result = content::BrowserTaskEnvironment task_envrionment;
DmServerUploadService::Create(/*profile=*/nullptr, base::DoNothing()); TestEvent<StatusOr<std::unique_ptr<DmServerUploadService>>> e;
DmServerUploadService::Create(/*profile=*/nullptr, base::DoNothing(), e.cb());
StatusOr<std::unique_ptr<DmServerUploadService>> result = e.result();
EXPECT_FALSE(result.ok()); EXPECT_FALSE(result.ok());
EXPECT_EQ(result.status().error_code(), error::INVALID_ARGUMENT); EXPECT_EQ(result.status().error_code(), error::INVALID_ARGUMENT);
} }
...@@ -109,7 +147,7 @@ class DmServerUploaderTest : public testing::Test { ...@@ -109,7 +147,7 @@ class DmServerUploaderTest : public testing::Test {
} }
protected: protected:
base::test::TaskEnvironment task_envrionment_{ content::BrowserTaskEnvironment task_envrionment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::test::TaskEnvironment::TimeSource::MOCK_TIME};
TestRecordHandler* handler_; TestRecordHandler* handler_;
......
...@@ -17,15 +17,28 @@ ...@@ -17,15 +17,28 @@
namespace reporting { namespace reporting {
// static // static
StatusOr<std::unique_ptr<UploadClient>> UploadClient::Create( void UploadClient::Create(
std::unique_ptr<policy::CloudPolicyClient> cloud_policy_client, std::unique_ptr<policy::CloudPolicyClient> cloud_policy_client,
ReportSuccessfulUploadCallback report_success_cb) { ReportSuccessfulUploadCallback report_upload_success_cb,
base::OnceCallback<void(StatusOr<std::unique_ptr<UploadClient>>)>
created_cb) {
auto upload_client = base::WrapUnique(new UploadClient()); auto upload_client = base::WrapUnique(new UploadClient());
ASSIGN_OR_RETURN(upload_client->dm_server_upload_service_, DmServerUploadService::Create(
DmServerUploadService::Create(std::move(cloud_policy_client), std::move(cloud_policy_client), report_upload_success_cb,
report_success_cb)); base::BindOnce(
[](std::unique_ptr<UploadClient> upload_client,
return upload_client; base::OnceCallback<void(StatusOr<std::unique_ptr<UploadClient>>)>
created_cb,
StatusOr<std::unique_ptr<DmServerUploadService>> uploader) {
if (!uploader.ok()) {
std::move(created_cb).Run(uploader.status());
return;
}
upload_client->dm_server_upload_service_ =
std::move(uploader.ValueOrDie());
std::move(created_cb).Run(std::move(upload_client));
},
std::move(upload_client), std::move(created_cb)));
} }
Status UploadClient::EnqueueUpload( Status UploadClient::EnqueueUpload(
......
...@@ -26,9 +26,11 @@ class UploadClient { ...@@ -26,9 +26,11 @@ class UploadClient {
using ReportSuccessfulUploadCallback = using ReportSuccessfulUploadCallback =
base::RepeatingCallback<void(SequencingInformation)>; base::RepeatingCallback<void(SequencingInformation)>;
static StatusOr<std::unique_ptr<UploadClient>> Create( static void Create(
std::unique_ptr<policy::CloudPolicyClient> cloud_policy_client, std::unique_ptr<policy::CloudPolicyClient> cloud_policy_client,
ReportSuccessfulUploadCallback report_success_cb); ReportSuccessfulUploadCallback report_upload_success_cb,
base::OnceCallback<void(StatusOr<std::unique_ptr<UploadClient>>)>
created_cb);
~UploadClient(); ~UploadClient();
UploadClient(const UploadClient& other) = delete; UploadClient(const UploadClient& other) = delete;
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#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/proto/record.pb.h" #include "components/policy/proto/record.pb.h"
#include "components/policy/proto/record_constants.pb.h" #include "components/policy/proto/record_constants.pb.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "services/network/test/test_network_connection_tracker.h" #include "services/network/test/test_network_connection_tracker.h"
...@@ -34,6 +36,42 @@ using testing::Invoke; ...@@ -34,6 +36,42 @@ using testing::Invoke;
using testing::InvokeArgument; using testing::InvokeArgument;
using testing::WithArgs; using testing::WithArgs;
// Usage (in tests only):
//
// TestEvent<ResType> e;
// ... Do some async work passing e.cb() as a completion callback of
// base::OnceCallback<void(ResType* res)> type which also may perform some
// other action specified by |done| callback provided by the caller.
// ... = e.result(); // Will wait for e.cb() to be called and return the
// collected result.
//
template <typename ResType>
class TestEvent {
public:
TestEvent() : run_loop_(std::make_unique<base::RunLoop>()) {}
~TestEvent() = default;
TestEvent(const TestEvent& other) = delete;
TestEvent& operator=(const TestEvent& other) = delete;
ResType result() {
run_loop_->Run();
return std::forward<ResType>(result_);
}
// Completion callback to hand over to the processing method.
base::OnceCallback<void(ResType res)> cb() {
return base::BindOnce(
[](base::RunLoop* run_loop, ResType* result, ResType res) {
*result = std::forward<ResType>(res);
run_loop->Quit();
},
base::Unretained(run_loop_.get()), base::Unretained(&result_));
}
private:
std::unique_ptr<base::RunLoop> run_loop_;
ResType result_;
};
class TestCallbackWaiter { class TestCallbackWaiter {
public: public:
TestCallbackWaiter() : run_loop_(std::make_unique<base::RunLoop>()) {} TestCallbackWaiter() : run_loop_(std::make_unique<base::RunLoop>()) {}
...@@ -62,26 +100,45 @@ class TestCallbackWaiterWithCounter : public TestCallbackWaiter { ...@@ -62,26 +100,45 @@ class TestCallbackWaiterWithCounter : public TestCallbackWaiter {
std::atomic<int> counter_limit_; std::atomic<int> counter_limit_;
}; };
TEST(UploadClientTest, CreateUploadClient) { class UploadClientTest : public ::testing::Test {
content::BrowserTaskEnvironment task_envrionment_; public:
UploadClientTest() = default;
protected:
void SetUp() override {
#ifdef OS_CHROMEOS #ifdef OS_CHROMEOS
// Set up fake primary profile. // Set up fake primary profile.
auto mock_user_manager = auto mock_user_manager =
std::make_unique<testing::NiceMock<chromeos::FakeChromeUserManager>>(); std::make_unique<testing::NiceMock<chromeos::FakeChromeUserManager>>();
auto profile = std::make_unique<TestingProfile>( profile_ = std::make_unique<TestingProfile>(
base::FilePath(FILE_PATH_LITERAL("/home/chronos/u-0123456789abcdef"))); base::FilePath(FILE_PATH_LITERAL("/home/chronos/u-0123456789abcdef")));
const AccountId account_id( const AccountId account_id(AccountId::FromUserEmailGaiaId(
AccountId::FromUserEmailGaiaId(profile->GetProfileUserName(), "12345")); profile_->GetProfileUserName(), "12345"));
const user_manager::User* user = const user_manager::User* user =
mock_user_manager->AddPublicAccountUser(account_id); mock_user_manager->AddPublicAccountUser(account_id);
mock_user_manager->UserLoggedIn(account_id, user->username_hash(), mock_user_manager->UserLoggedIn(account_id, user->username_hash(),
/*browser_restart=*/false, /*browser_restart=*/false,
/*is_child=*/false); /*is_child=*/false);
auto user_manager = std::make_unique<user_manager::ScopedUserManager>( user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(mock_user_manager)); std::move(mock_user_manager));
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
}
void TearDown() override {
#ifdef OS_CHROMEOS
user_manager_.reset();
profile_.reset();
#endif // OS_CHROMEOS
}
content::BrowserTaskEnvironment task_envrionment_;
#ifdef OS_CHROMEOS
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<user_manager::ScopedUserManager> user_manager_;
#endif // OS_CHROMEOS
};
TEST_F(UploadClientTest, CreateUploadClient) {
const int kExpectedCallTimes = 10; const int kExpectedCallTimes = 10;
const uint64_t kGenerationId = 1234; const uint64_t kGenerationId = 1234;
...@@ -98,9 +155,9 @@ TEST(UploadClientTest, CreateUploadClient) { ...@@ -98,9 +155,9 @@ TEST(UploadClientTest, CreateUploadClient) {
waiter.Signal(); waiter.Signal();
}))); })));
auto upload_client_result = TestEvent<StatusOr<std::unique_ptr<UploadClient>>> e;
UploadClient::Create(std::move(client), base::DoNothing()); UploadClient::Create(std::move(client), base::DoNothing(), e.cb());
StatusOr<std::unique_ptr<UploadClient>> upload_client_result = e.result();
ASSERT_OK(upload_client_result) << upload_client_result.status(); ASSERT_OK(upload_client_result) << upload_client_result.status();
base::Value data{base::Value::Type::DICTIONARY}; base::Value data{base::Value::Type::DICTIONARY};
......
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