| // Copyright 2018 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 <lib/callback/capture.h> |
| #include <lib/callback/waiter.h> |
| #include <lib/fidl/cpp/optional.h> |
| |
| #include "peridot/bin/ledger/tests/integration/integration_test.h" |
| #include "peridot/bin/ledger/tests/integration/sync/test_sync_state_watcher.h" |
| #include "peridot/lib/convert/convert.h" |
| |
| namespace ledger { |
| namespace { |
| |
| class LongHistorySyncTest : public IntegrationTest { |
| protected: |
| std::unique_ptr<TestSyncStateWatcher> WatchPageSyncState(PagePtr* page) { |
| auto watcher = std::make_unique<TestSyncStateWatcher>(); |
| |
| Status status = Status::INTERNAL_ERROR; |
| auto waiter = NewWaiter(); |
| (*page)->SetSyncStateWatcher( |
| watcher->NewBinding(), |
| callback::Capture(waiter->GetCallback(), &status)); |
| if (!waiter->RunUntilCalled()) { |
| return nullptr; |
| } |
| if (status != Status::OK) { |
| return nullptr; |
| } |
| return watcher; |
| } |
| |
| bool WaitUntilSyncIsIdle(TestSyncStateWatcher* watcher) { |
| return RunLoopUntil([watcher] { |
| return watcher->Equals(SyncState::IDLE, SyncState::IDLE); |
| }); |
| } |
| }; |
| |
| TEST_P(LongHistorySyncTest, SyncLongHistory) { |
| PageId page_id; |
| Status status = Status::INTERNAL_ERROR; |
| |
| // Create the first instance and write the page entries. |
| auto instance1 = NewLedgerAppInstance(); |
| auto page1 = instance1->GetTestPage(); |
| auto page1_state_watcher = WatchPageSyncState(&page1); |
| ASSERT_TRUE(page1_state_watcher); |
| const int commit_history_length = 500; |
| // Overwrite one key N times, creating N implicit commits. |
| for (int i = 0; i < commit_history_length; i++) { |
| // TODO(ppi): switch to using a StatusWaiter to wait in parallel on all |
| // puts, once this does not crash w/ ZX_ERR_SHOULD_WAIT in the test loop |
| // dispatcher. |
| auto put_waiter = NewWaiter(); |
| page1->Put(convert::ToArray("iteration"), |
| convert::ToArray(std::to_string(i)), |
| callback::Capture(put_waiter->GetCallback(), &status)); |
| ASSERT_TRUE(put_waiter->RunUntilCalled()); |
| ASSERT_EQ(Status::OK, status); |
| } |
| // Wait until the commits are uploaded. |
| EXPECT_TRUE(WaitUntilSyncIsIdle(page1_state_watcher.get())); |
| |
| // Retrieve the page ID so that we can later connect to the same page from |
| // another app instance. |
| auto waiter = NewWaiter(); |
| page1->GetId(callback::Capture(waiter->GetCallback(), &page_id)); |
| ASSERT_TRUE(waiter->RunUntilCalled()); |
| |
| // Create the second instance, connect to the same page and download the |
| // data. |
| auto instance2 = NewLedgerAppInstance(); |
| auto page2 = instance2->GetPage(fidl::MakeOptional(page_id), Status::OK); |
| auto page2_state_watcher = WatchPageSyncState(&page2); |
| ASSERT_TRUE(page2_state_watcher); |
| EXPECT_TRUE(WaitUntilSyncIsIdle(page2_state_watcher.get())); |
| |
| PageSnapshotPtr snapshot; |
| waiter = NewWaiter(); |
| page2->GetSnapshot(snapshot.NewRequest(), fidl::VectorPtr<uint8_t>::New(0), |
| nullptr, |
| callback::Capture(waiter->GetCallback(), &status)); |
| ASSERT_TRUE(waiter->RunUntilCalled()); |
| ASSERT_EQ(Status::OK, status); |
| std::unique_ptr<InlinedValue> inlined_value; |
| |
| waiter = NewWaiter(); |
| snapshot->GetInline( |
| convert::ToArray("iteration"), |
| callback::Capture(waiter->GetCallback(), &status, &inlined_value)); |
| ASSERT_TRUE(waiter->RunUntilCalled()); |
| ASSERT_EQ(Status::OK, status); |
| ASSERT_TRUE(inlined_value); |
| const int last_iteration = commit_history_length - 1; |
| ASSERT_EQ(std::to_string(last_iteration), |
| convert::ToString(inlined_value->value)); |
| |
| // Verify that the sync state of the second page connection eventually becomes |
| // idle. |
| EXPECT_TRUE(WaitUntilSyncIsIdle(page2_state_watcher.get())); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| LongHistorySyncTest, LongHistorySyncTest, |
| ::testing::ValuesIn(GetLedgerAppInstanceFactoryBuilders())); |
| |
| } // namespace |
| } // namespace ledger |