| // 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 <fuchsia/ledger/internal/cpp/fidl.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <lib/callback/capture.h> |
| #include <lib/callback/set_when_called.h> |
| #include <lib/callback/waiter.h> |
| |
| #include "peridot/bin/ledger/testing/ledger_matcher.h" |
| #include "peridot/bin/ledger/tests/integration/integration_test.h" |
| #include "peridot/bin/ledger/tests/integration/test_utils.h" |
| |
| using testing::IsEmpty; |
| |
| namespace ledger { |
| namespace { |
| |
| // Tests in this suite execute a series of operations and check the content of |
| // the Page afterwards. |
| class PageMutationTest : public IntegrationTest { |
| public: |
| void SetUp() override { |
| IntegrationTest::SetUp(); |
| app_instance_ = NewLedgerAppInstance(); |
| page_ = app_instance_->GetTestPage(); |
| } |
| |
| PageSnapshotPtr PageGetSnapshot() { |
| Status status; |
| PageSnapshotPtr snapshot; |
| auto waiter = NewWaiter(); |
| page_->GetSnapshot(snapshot.NewRequest(), fidl::VectorPtr<uint8_t>::New(0), |
| nullptr, |
| callback::Capture(waiter->GetCallback(), &status)); |
| if (!waiter->RunUntilCalled()) { |
| ADD_FAILURE() << "|GetSnapshot| failed to called back."; |
| return nullptr; |
| } |
| EXPECT_EQ(Status::OK, status); |
| return snapshot; |
| } |
| |
| std::vector<Entry> GetEntries() { |
| PageSnapshotPtr snapshot = PageGetSnapshot(); |
| return SnapshotGetEntries(this, &snapshot); |
| } |
| |
| testing::AssertionResult Put(std::string key, std::string value) { |
| return Do("Put", [&](auto callback) { |
| page_->Put(convert::ToArray(key), convert::ToArray(value), |
| std::move(callback)); |
| }); |
| } |
| |
| testing::AssertionResult Delete(std::string key) { |
| return Do("Delete", [&](auto callback) { |
| page_->Delete(convert::ToArray(key), std::move(callback)); |
| }); |
| } |
| |
| testing::AssertionResult Clear() { |
| return Do("Clear", |
| [&](auto callback) { page_->Clear(std::move(callback)); }); |
| } |
| |
| testing::AssertionResult StartTransaction() { |
| return Do("StartTransaction", [&](auto callback) { |
| page_->StartTransaction(std::move(callback)); |
| }); |
| } |
| |
| testing::AssertionResult Commit() { |
| return Do("Commit", |
| [&](auto callback) { page_->Commit(std::move(callback)); }); |
| } |
| |
| testing::AssertionResult Rollback() { |
| return Do("Rollback", |
| [&](auto callback) { page_->Rollback(std::move(callback)); }); |
| } |
| |
| private: |
| // Executes the given action on the current page. |
| // |
| // This helper function handles the heavy lifting of calling an operation of |
| // the page, waiting for the result and returning an assertion error in case |
| // of non ok status. It expects |action| to operate the operation on the page |
| // and returns the status in its callback. |
| testing::AssertionResult Do( |
| std::string operation_name, |
| fit::function<void(fit::function<void(Status)>)> action) { |
| Status status; |
| auto waiter = NewWaiter(); |
| action(callback::Capture(waiter->GetCallback(), &status)); |
| if (!waiter->RunUntilCalled()) { |
| return testing::AssertionFailure() |
| << "Error while executing " << operation_name |
| << ". |action| failed to call back."; |
| } |
| if (status == Status::OK) { |
| return testing::AssertionSuccess(); |
| } |
| return testing::AssertionFailure() |
| << "Error while executing " << operation_name |
| << ". Status: " << static_cast<uint32_t>(status); |
| } |
| |
| protected: |
| std::unique_ptr<LedgerAppInstanceFactory::LedgerAppInstance> app_instance_; |
| PagePtr page_; |
| }; |
| |
| TEST_P(PageMutationTest, InitialSnapshotIsEmpty) { |
| EXPECT_THAT(GetEntries(), IsEmpty()); |
| } |
| |
| TEST_P(PageMutationTest, PutOutsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key", "value"}})); |
| |
| ASSERT_TRUE(Put("key2", "value2")); |
| |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| } |
| |
| TEST_P(PageMutationTest, PutInsideOfTransaction) { |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Put("key", "value")); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| } |
| |
| TEST_P(PageMutationTest, RollbackTransaction) { |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Put("key", "value")); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_TRUE(Rollback()); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| } |
| |
| TEST_P(PageMutationTest, DeleteOutsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| |
| ASSERT_TRUE(Delete("key")); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key2", "value2"}})); |
| } |
| |
| TEST_P(PageMutationTest, DeleteInsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Delete("key")); |
| ASSERT_TRUE(Put("key3", "value3")); |
| ASSERT_TRUE(Delete("key3")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key2", "value2"}})); |
| } |
| |
| TEST_P(PageMutationTest, ClearOutsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| |
| ASSERT_TRUE(Clear()); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| } |
| |
| TEST_P(PageMutationTest, ClearInsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Put("key3", "value3")); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Put("key4", "value4")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key4", "value4"}})); |
| } |
| |
| TEST_P(PageMutationTest, MultipleClearCallsInsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Put("key2", "value2")); |
| ASSERT_THAT(GetEntries(), |
| MatchEntries({{"key", "value"}, {"key2", "value2"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Put("key3", "value3")); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Put("key4", "value4")); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Put("key5", "value5")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key5", "value5"}})); |
| } |
| |
| TEST_P(PageMutationTest, ClearAndDeleteInsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key", "value"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Delete("key")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| } |
| |
| TEST_P(PageMutationTest, DeleteAndClearInsideOfTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key", "value"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Delete("key")); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), IsEmpty()); |
| } |
| |
| TEST_P(PageMutationTest, ClearAndRestoreInsideTransaction) { |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key", "value"}})); |
| |
| ASSERT_TRUE(StartTransaction()); |
| ASSERT_TRUE(Clear()); |
| ASSERT_TRUE(Put("key", "value")); |
| ASSERT_TRUE(Commit()); |
| |
| ASSERT_THAT(GetEntries(), MatchEntries({{"key", "value"}})); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| PageMutationTest, PageMutationTest, |
| ::testing::ValuesIn(GetLedgerAppInstanceFactoryBuilders())); |
| |
| } // namespace |
| } // namespace ledger |