Index: components/feature_engagement_tracker/internal/persistent_store_unittest.cc |
diff --git a/components/feature_engagement_tracker/internal/persistent_store_unittest.cc b/components/feature_engagement_tracker/internal/persistent_store_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4068662d2fe9ef8f8460ddb3f1db620e0d52eff6 |
--- /dev/null |
+++ b/components/feature_engagement_tracker/internal/persistent_store_unittest.cc |
@@ -0,0 +1,193 @@ |
+// Copyright 2017 The Chromium 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 "components/feature_engagement_tracker/internal/persistent_store.h" |
+ |
+#include <map> |
+ |
+#include "base/files/file_path.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/optional.h" |
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h" |
+#include "components/feature_engagement_tracker/internal/test/event_util.h" |
+#include "components/leveldb_proto/proto_database.h" |
+#include "components/leveldb_proto/testing/fake_db.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace feature_engagement_tracker { |
+ |
+namespace { |
+ |
+void VerifyEventsInListAndMap(const std::map<std::string, Event>& map, |
+ const std::vector<Event>& list) { |
+ ASSERT_EQ(map.size(), list.size()); |
+ |
+ for (const auto& event : list) { |
+ const auto& it = map.find(event.name()); |
+ ASSERT_NE(map.end(), it); |
+ test::VerifyEventsEqual(&event, &it->second); |
+ } |
+} |
+ |
+class PersistentStoreTest : public ::testing::Test { |
+ public: |
+ PersistentStoreTest() |
+ : db_(nullptr), |
+ storage_dir_(FILE_PATH_LITERAL("/persistent/store/lalala")) { |
+ load_callback_ = |
+ base::Bind(&PersistentStoreTest::LoadCallback, base::Unretained(this)); |
+ } |
+ |
+ void TearDown() override { |
+ db_events_.clear(); |
+ db_ = nullptr; |
+ store_.reset(); |
+ } |
+ |
+ protected: |
+ void SetUpDB() { |
+ DCHECK(!db_); |
+ DCHECK(!store_); |
+ |
+ auto db = base::MakeUnique<leveldb_proto::test::FakeDB<Event>>(&db_events_); |
+ db_ = db.get(); |
+ store_.reset(new PersistentStore(storage_dir_, std::move(db))); |
+ } |
+ |
+ void LoadCallback(bool success, std::unique_ptr<std::vector<Event>> events) { |
+ load_successful_ = success; |
+ load_results_ = std::move(events); |
+ } |
+ |
+ // Callback results. |
+ base::Optional<bool> load_successful_; |
+ std::unique_ptr<std::vector<Event>> load_results_; |
+ |
+ Store::OnLoadedCallback load_callback_; |
+ std::map<std::string, Event> db_events_; |
+ leveldb_proto::test::FakeDB<Event>* db_; |
+ std::unique_ptr<Store> store_; |
+ |
+ // Constant test data. |
+ base::FilePath storage_dir_; |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(PersistentStoreTest, StorageDirectory) { |
+ SetUpDB(); |
+ store_->Load(load_callback_); |
+ EXPECT_EQ(storage_dir_, db_->GetDirectory()); |
+} |
+ |
+TEST_F(PersistentStoreTest, SuccessfulInitAndLoadEmptyStore) { |
+ SetUpDB(); |
+ |
+ store_->Load(load_callback_); |
+ |
+ // The initialize should not trigger a response to the callback. |
+ db_->InitCallback(true); |
+ EXPECT_FALSE(load_successful_.has_value()); |
+ |
+ // The load should trigger a response to the callback. |
+ db_->LoadCallback(true); |
+ EXPECT_TRUE(load_successful_.value()); |
+ |
+ // Validate that we have no entries. |
+ EXPECT_NE(nullptr, load_results_); |
+ EXPECT_TRUE(load_results_->empty()); |
+} |
+ |
+TEST_F(PersistentStoreTest, SuccessfulInitAndLoadWithEvents) { |
+ // Populate fake Event entries. |
+ Event event1; |
+ event1.set_name("event1"); |
+ test::SetEventCountForDay(&event1, 1, 1); |
+ |
+ Event event2; |
+ event2.set_name("event2"); |
+ test::SetEventCountForDay(&event2, 1, 3); |
+ test::SetEventCountForDay(&event2, 2, 5); |
+ |
+ db_events_.insert(std::pair<std::string, Event>(event1.name(), event1)); |
+ db_events_.insert(std::pair<std::string, Event>(event2.name(), event2)); |
+ |
+ SetUpDB(); |
+ |
+ // The initialize should not trigger a response to the callback. |
+ store_->Load(load_callback_); |
+ db_->InitCallback(true); |
+ EXPECT_FALSE(load_successful_.has_value()); |
+ |
+ // The load should trigger a response to the callback. |
+ db_->LoadCallback(true); |
+ EXPECT_TRUE(load_successful_.value()); |
+ EXPECT_NE(nullptr, load_results_); |
+ |
+ // Validate that we have the two events that we expect. |
+ VerifyEventsInListAndMap(db_events_, *load_results_); |
+} |
+ |
+TEST_F(PersistentStoreTest, SuccessfulInitBadLoad) { |
+ SetUpDB(); |
+ |
+ store_->Load(load_callback_); |
+ |
+ // The initialize should not trigger a response to the callback. |
+ db_->InitCallback(true); |
+ EXPECT_FALSE(load_successful_.has_value()); |
+ |
+ // The load will fail and should trigger the callback. |
+ db_->LoadCallback(false); |
+ EXPECT_FALSE(load_successful_.value()); |
+ EXPECT_FALSE(store_->IsReady()); |
+} |
+ |
+TEST_F(PersistentStoreTest, BadInit) { |
+ SetUpDB(); |
+ |
+ store_->Load(load_callback_); |
+ |
+ // The initialize will fail and should trigger the callback. |
+ db_->InitCallback(false); |
+ EXPECT_FALSE(load_successful_.value()); |
+ EXPECT_FALSE(store_->IsReady()); |
+} |
+ |
+TEST_F(PersistentStoreTest, IsReady) { |
+ SetUpDB(); |
+ EXPECT_FALSE(store_->IsReady()); |
+ |
+ store_->Load(load_callback_); |
+ EXPECT_FALSE(store_->IsReady()); |
+ |
+ db_->InitCallback(true); |
+ EXPECT_FALSE(store_->IsReady()); |
+ |
+ db_->LoadCallback(true); |
+ EXPECT_TRUE(store_->IsReady()); |
+} |
+ |
+TEST_F(PersistentStoreTest, WriteEvent) { |
+ SetUpDB(); |
+ |
+ store_->Load(load_callback_); |
+ db_->InitCallback(true); |
+ db_->LoadCallback(true); |
+ |
+ Event event; |
+ event.set_name("event"); |
+ test::SetEventCountForDay(&event, 1, 2); |
+ |
+ store_->WriteEvent(event); |
+ db_->UpdateCallback(true); |
+ |
+ EXPECT_EQ(1U, db_events_.size()); |
+ |
+ const auto& it = db_events_.find("event"); |
+ EXPECT_NE(db_events_.end(), it); |
+ test::VerifyEventsEqual(&event, &it->second); |
+} |
+ |
+} // namespace feature_engagement_tracker |