blob: 024164b7795110569e47401bdb2cfc8a57f67db2 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "src/ledger/bin/cloud_sync/impl/user_sync_impl.h"
#include <unistd.h>
#include <utility>
#include "src/ledger/bin/clocks/public/device_fingerprint_manager.h"
#include "src/ledger/bin/clocks/public/types.h"
#include "src/ledger/bin/cloud_sync/impl/testing/test_cloud_provider.h"
#include "src/ledger/bin/encryption/fake/fake_encryption_service.h"
#include "src/ledger/bin/platform/scoped_tmp_location.h"
#include "src/ledger/bin/public/status.h"
#include "src/ledger/bin/testing/test_with_environment.h"
#include "src/ledger/lib/backoff/testing/test_backoff.h"
namespace cloud_sync {
namespace {
class TestSyncStateWatcher : public SyncStateWatcher {
public:
TestSyncStateWatcher() = default;
~TestSyncStateWatcher() override = default;
void Notify(SyncStateContainer /*sync_state*/) override {}
};
class TestDeviceFingerprintManager : public clocks::DeviceFingerprintManager {
public:
TestDeviceFingerprintManager() = default;
~TestDeviceFingerprintManager() override = default;
ledger::Status GetDeviceFingerprint(coroutine::CoroutineHandler* /*handler*/,
clocks::DeviceFingerprint* device_fingerprint,
CloudUploadStatus* status) override {
*device_fingerprint = fingerprint_;
*status = sync_status_ ? CloudUploadStatus::UPLOADED : CloudUploadStatus::NOT_UPLOADED;
return ledger::Status::OK;
}
// Records that a device fingerprint has been synced with the cloud.
ledger::Status SetDeviceFingerprintSynced(coroutine::CoroutineHandler* /*handler*/) override {
sync_status_ = true;
return ledger::Status::OK;
}
clocks::DeviceFingerprint fingerprint_ = "unsynced_fingerprint";
bool sync_status_ = false;
};
class UserSyncImplTest : public ledger::TestWithEnvironment {
public:
UserSyncImplTest()
: tmp_location_(environment_.file_system()->CreateScopedTmpLocation()),
cloud_provider_(cloud_provider_ptr_.NewRequest()),
encryption_service_(dispatcher()) {
UserConfig user_config;
user_config.user_directory = tmp_location_->path();
user_config.cloud_provider = std::move(cloud_provider_ptr_);
auto backoff = std::make_unique<ledger::TestBackoff>();
backoff->SetOnGetNext([this] {
// Make RunLoopUntilIdle() return once a backoff is requested, to avoid an
// infinite loop.
QuitLoop();
});
user_sync_ = std::make_unique<UserSyncImpl>(
&environment_, std::move(user_config), std::move(backoff),
[this] { on_version_mismatch_calls_++; }, &fingerprint_manager_);
user_sync_->SetSyncWatcher(&sync_state_watcher_);
}
UserSyncImplTest(const UserSyncImplTest&) = delete;
UserSyncImplTest& operator=(const UserSyncImplTest&) = delete;
~UserSyncImplTest() override = default;
protected:
void SetFingerprintFile(std::string content) {
fingerprint_manager_.fingerprint_ = std::move(content);
fingerprint_manager_.sync_status_ = true;
}
std::unique_ptr<ledger::ScopedTmpLocation> tmp_location_;
cloud_provider::CloudProviderPtr cloud_provider_ptr_;
TestCloudProvider cloud_provider_;
std::unique_ptr<UserSyncImpl> user_sync_;
encryption::FakeEncryptionService encryption_service_;
TestSyncStateWatcher sync_state_watcher_;
TestDeviceFingerprintManager fingerprint_manager_;
int on_version_mismatch_calls_ = 0;
};
// Verifies that the mismatch callback is called if the fingerprint appears to
// be erased from the cloud.
TEST_F(UserSyncImplTest, CloudCheckErased) {
SetFingerprintFile("some-value");
cloud_provider_.device_set.status_to_return = cloud_provider::Status::NOT_FOUND;
EXPECT_EQ(on_version_mismatch_calls_, 0);
user_sync_->Start();
RunLoopUntilIdle();
EXPECT_EQ(on_version_mismatch_calls_, 1);
}
// Verifies that if the version checker reports that cloud is compatible, upload
// is enabled in LedgerSync.
TEST_F(UserSyncImplTest, CloudCheckOk) {
SetFingerprintFile("some-value");
cloud_provider_.device_set.status_to_return = cloud_provider::Status::OK;
EXPECT_EQ(on_version_mismatch_calls_, 0);
user_sync_->Start();
auto ledger_a = user_sync_->CreateLedgerSync("app-id", &encryption_service_);
auto ledger_a_ptr = static_cast<LedgerSyncImpl*>(ledger_a.get());
EXPECT_FALSE(ledger_a_ptr->IsUploadEnabled());
RunLoopUntilIdle();
EXPECT_TRUE(ledger_a_ptr->IsUploadEnabled());
EXPECT_EQ(on_version_mismatch_calls_, 0);
EXPECT_EQ(cloud_provider_.device_set.checked_fingerprint, "some-value");
// Verify that newly created LedgerSyncs also have the upload enabled.
auto ledger_b = user_sync_->CreateLedgerSync("app-id", &encryption_service_);
auto ledger_b_ptr = static_cast<LedgerSyncImpl*>(ledger_b.get());
EXPECT_TRUE(ledger_b_ptr->IsUploadEnabled());
}
// Verifies that if there is no fingerprint file, it is created and set in the
// cloud.
TEST_F(UserSyncImplTest, CloudCheckSet) {
auto fingerprint_path = user_sync_->GetFingerprintPath();
EXPECT_FALSE(fingerprint_manager_.sync_status_);
cloud_provider_.device_set.status_to_return = cloud_provider::Status::OK;
EXPECT_EQ(on_version_mismatch_calls_, 0);
user_sync_->Start();
auto ledger = user_sync_->CreateLedgerSync("app-id", &encryption_service_);
auto ledger_ptr = static_cast<LedgerSyncImpl*>(ledger.get());
EXPECT_FALSE(ledger_ptr->IsUploadEnabled());
RunLoopUntilIdle();
EXPECT_TRUE(ledger_ptr->IsUploadEnabled());
EXPECT_EQ(on_version_mismatch_calls_, 0);
EXPECT_FALSE(cloud_provider_.device_set.set_fingerprint.empty());
// Verify that the fingerprint file was created.
EXPECT_TRUE(fingerprint_manager_.sync_status_);
}
// Verifies that the cloud watcher for the fingerprint is set and triggers the
// mismatch callback when cloud erase is detected.
TEST_F(UserSyncImplTest, WatchErase) {
SetFingerprintFile("some-value");
cloud_provider_.device_set.status_to_return = cloud_provider::Status::OK;
user_sync_->Start();
RunLoopUntilIdle();
EXPECT_TRUE(cloud_provider_.device_set.set_watcher.is_bound());
EXPECT_EQ(cloud_provider_.device_set.watched_fingerprint, "some-value");
EXPECT_EQ(on_version_mismatch_calls_, 0);
cloud_provider_.device_set.set_watcher->OnCloudErased();
RunLoopUntilIdle();
EXPECT_EQ(on_version_mismatch_calls_, 1);
}
// Verifies that setting the cloud watcher for is retried on network errors.
TEST_F(UserSyncImplTest, WatchRetry) {
SetFingerprintFile("some-value");
cloud_provider_.device_set.set_watcher_status_to_return = cloud_provider::Status::NETWORK_ERROR;
user_sync_->Start();
RunLoopUntilIdle();
EXPECT_EQ(cloud_provider_.device_set.set_watcher_calls, 1);
}
} // namespace
} // namespace cloud_sync