| // 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 "peridot/bin/ledger/cloud_sync/impl/user_sync_impl.h" |
| |
| #include <utility> |
| |
| #include <lib/backoff/backoff.h> |
| #include <lib/backoff/testing/test_backoff.h> |
| #include <lib/fxl/files/file.h> |
| #include <lib/fxl/macros.h> |
| #include <lib/gtest/test_loop_fixture.h> |
| |
| #include "peridot/bin/ledger/cloud_sync/impl/testing/test_cloud_provider.h" |
| #include "peridot/bin/ledger/encryption/fake/fake_encryption_service.h" |
| #include "peridot/bin/ledger/testing/test_with_environment.h" |
| #include "peridot/lib/scoped_tmpfs/scoped_tmpfs.h" |
| |
| namespace cloud_sync { |
| |
| namespace { |
| |
| class TestSyncStateWatcher : public SyncStateWatcher { |
| public: |
| TestSyncStateWatcher() {} |
| ~TestSyncStateWatcher() override{}; |
| |
| void Notify(SyncStateContainer /*sync_state*/) override {} |
| }; |
| |
| class UserSyncImplTest : public ledger::TestWithEnvironment { |
| public: |
| UserSyncImplTest() |
| : cloud_provider_(cloud_provider_ptr_.NewRequest()), |
| encryption_service_(dispatcher()) { |
| UserConfig user_config; |
| user_config.user_directory = ledger::DetachedPath(tmpfs_.root_fd()); |
| user_config.cloud_provider = std::move(cloud_provider_ptr_); |
| |
| auto backoff = std::make_unique<backoff::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_++; }); |
| user_sync_->SetSyncWatcher(&sync_state_watcher_); |
| } |
| ~UserSyncImplTest() override {} |
| |
| protected: |
| bool SetFingerprintFile(std::string content) { |
| ledger::DetachedPath fingerprint_path = user_sync_->GetFingerprintPath(); |
| return files::WriteFileAt(fingerprint_path.root_fd(), |
| fingerprint_path.path(), content.data(), |
| content.size()); |
| } |
| |
| scoped_tmpfs::ScopedTmpFS tmpfs_; |
| cloud_provider::CloudProviderPtr cloud_provider_ptr_; |
| TestCloudProvider cloud_provider_; |
| std::unique_ptr<UserSyncImpl> user_sync_; |
| encryption::FakeEncryptionService encryption_service_; |
| TestSyncStateWatcher sync_state_watcher_; |
| |
| int on_version_mismatch_calls_ = 0; |
| |
| private: |
| FXL_DISALLOW_COPY_AND_ASSIGN(UserSyncImplTest); |
| }; |
| |
| // Verifies that the mismatch callback is called if the fingerprint appears to |
| // be erased from the cloud. |
| TEST_F(UserSyncImplTest, CloudCheckErased) { |
| ASSERT_TRUE(SetFingerprintFile("some-value")); |
| cloud_provider_.device_set.status_to_return = |
| cloud_provider::Status::NOT_FOUND; |
| EXPECT_EQ(0, on_version_mismatch_calls_); |
| user_sync_->Start(); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, on_version_mismatch_calls_); |
| } |
| |
| // Verifies that if the version checker reports that cloud is compatible, upload |
| // is enabled in LedgerSync. |
| TEST_F(UserSyncImplTest, CloudCheckOk) { |
| ASSERT_TRUE(SetFingerprintFile("some-value")); |
| cloud_provider_.device_set.status_to_return = cloud_provider::Status::OK; |
| EXPECT_EQ(0, on_version_mismatch_calls_); |
| 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(0, on_version_mismatch_calls_); |
| EXPECT_EQ("some-value", cloud_provider_.device_set.checked_fingerprint); |
| |
| // 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( |
| files::IsFileAt(fingerprint_path.root_fd(), fingerprint_path.path())); |
| cloud_provider_.device_set.status_to_return = cloud_provider::Status::OK; |
| EXPECT_EQ(0, on_version_mismatch_calls_); |
| 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(0, on_version_mismatch_calls_); |
| EXPECT_FALSE(cloud_provider_.device_set.set_fingerprint.empty()); |
| |
| // Verify that the fingerprint file was created. |
| EXPECT_TRUE( |
| files::IsFileAt(fingerprint_path.root_fd(), fingerprint_path.path())); |
| } |
| |
| // Verifies that the cloud watcher for the fingerprint is set and triggers the |
| // mismatch callback when cloud erase is detected. |
| TEST_F(UserSyncImplTest, WatchErase) { |
| ASSERT_TRUE(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("some-value", cloud_provider_.device_set.watched_fingerprint); |
| EXPECT_EQ(0, on_version_mismatch_calls_); |
| |
| cloud_provider_.device_set.set_watcher->OnCloudErased(); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, on_version_mismatch_calls_); |
| } |
| |
| // Verifies that setting the cloud watcher for is retried on network errors. |
| TEST_F(UserSyncImplTest, WatchRetry) { |
| ASSERT_TRUE(SetFingerprintFile("some-value")); |
| cloud_provider_.device_set.set_watcher_status_to_return = |
| cloud_provider::Status::NETWORK_ERROR; |
| user_sync_->Start(); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, cloud_provider_.device_set.set_watcher_calls); |
| } |
| |
| } // namespace |
| |
| } // namespace cloud_sync |