diff options
Diffstat (limited to 'chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc')
-rw-r--r-- | chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc b/chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc new file mode 100644 index 00000000000..a65f574458d --- /dev/null +++ b/chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc @@ -0,0 +1,288 @@ +// 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/availability_store.h" + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/optional.h" +#include "base/test/scoped_feature_list.h" +#include "components/feature_engagement_tracker/internal/proto/availability.pb.h" +#include "components/feature_engagement_tracker/public/feature_list.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 { +const base::Feature kTestFeatureFoo{"test_foo", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kTestFeatureBar{"test_bar", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kTestFeatureQux{"test_qux", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kTestFeatureNop{"test_nop", + base::FEATURE_DISABLED_BY_DEFAULT}; + +Availability CreateAvailability(const base::Feature& feature, uint32_t day) { + Availability availability; + availability.set_feature_name(feature.name); + availability.set_day(day); + return availability; +} + +class AvailabilityStoreTest : public testing::Test { + public: + AvailabilityStoreTest() + : db_(nullptr), + storage_dir_(FILE_PATH_LITERAL("/persistent/store/lalala")) { + load_callback_ = base::Bind(&AvailabilityStoreTest::LoadCallback, + base::Unretained(this)); + } + + ~AvailabilityStoreTest() override = default; + + // Creates a DB and stores off a pointer to it as a member. + std::unique_ptr<leveldb_proto::test::FakeDB<Availability>> CreateDB() { + auto db = base::MakeUnique<leveldb_proto::test::FakeDB<Availability>>( + &db_availabilities_); + db_ = db.get(); + return db; + } + + void LoadCallback(bool success, + std::unique_ptr<std::map<const base::Feature*, uint32_t>> + availabilities) { + load_successful_ = success; + load_results_ = std::move(availabilities); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + // The end result of the store pipeline. + AvailabilityStore::OnLoadedCallback load_callback_; + + // Callback results. + base::Optional<bool> load_successful_; + std::unique_ptr<std::map<const base::Feature*, uint32_t>> load_results_; + + // |db_availabilities_| is used during creation of the FakeDB in CreateDB(), + // to simplify what the DB has stored. + std::map<std::string, Availability> db_availabilities_; + + // The database that is in use. + leveldb_proto::test::FakeDB<Availability>* db_; + + // Constant test data. + base::FilePath storage_dir_; + + private: + DISALLOW_COPY_AND_ASSIGN(AvailabilityStoreTest); +}; + +} // namespace + +TEST_F(AvailabilityStoreTest, StorageDirectory) { + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + db_->InitCallback(true); + EXPECT_EQ(storage_dir_, db_->GetDirectory()); +} + +TEST_F(AvailabilityStoreTest, InitFail) { + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + + db_->InitCallback(false); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_FALSE(load_successful_.value()); + EXPECT_EQ(0u, load_results_->size()); + EXPECT_EQ(0u, db_availabilities_.size()); +} + +TEST_F(AvailabilityStoreTest, LoadFail) { + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(false); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_FALSE(load_successful_.value()); + EXPECT_EQ(0u, load_results_->size()); + EXPECT_EQ(0u, db_availabilities_.size()); +} + +TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateFailed) { + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->UpdateCallback(false); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_FALSE(load_successful_.value()); + EXPECT_EQ(0u, load_results_->size()); + EXPECT_EQ(0u, db_availabilities_.size()); +} + +TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateOK) { + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->UpdateCallback(true); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_TRUE(load_successful_.value()); + EXPECT_EQ(0u, load_results_->size()); + EXPECT_EQ(0u, db_availabilities_.size()); +} + +TEST_F(AvailabilityStoreTest, AllNewFeatures) { + scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, + {kTestFeatureQux}); + + FeatureVector feature_filter; + feature_filter.push_back(&kTestFeatureFoo); // Enabled. Not in DB. + feature_filter.push_back(&kTestFeatureBar); // Enabled. Not in DB. + feature_filter.push_back(&kTestFeatureQux); // Disabled. Not in DB. + + AvailabilityStore::LoadAndUpdateStore( + storage_dir_, CreateDB(), feature_filter, std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->UpdateCallback(true); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_TRUE(load_successful_.value()); + ASSERT_EQ(2u, load_results_->size()); + ASSERT_EQ(2u, db_availabilities_.size()); + + ASSERT_TRUE(load_results_->find(&kTestFeatureFoo) != load_results_->end()); + EXPECT_EQ(14u, (*load_results_)[&kTestFeatureFoo]); + ASSERT_TRUE(db_availabilities_.find(kTestFeatureFoo.name) != + db_availabilities_.end()); + EXPECT_EQ(14u, db_availabilities_[kTestFeatureFoo.name].day()); + + ASSERT_TRUE(load_results_->find(&kTestFeatureBar) != load_results_->end()); + EXPECT_EQ(14u, (*load_results_)[&kTestFeatureBar]); + ASSERT_TRUE(db_availabilities_.find(kTestFeatureBar.name) != + db_availabilities_.end()); + EXPECT_EQ(14u, db_availabilities_[kTestFeatureBar.name].day()); +} + +TEST_F(AvailabilityStoreTest, TestAllFilterCombinations) { + scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, + {kTestFeatureQux, kTestFeatureNop}); + + FeatureVector feature_filter; + feature_filter.push_back(&kTestFeatureFoo); // Enabled. Not in DB. + feature_filter.push_back(&kTestFeatureBar); // Enabled. In DB. + feature_filter.push_back(&kTestFeatureQux); // Disabled. Not in DB. + feature_filter.push_back(&kTestFeatureNop); // Disabled. In DB. + + db_availabilities_[kTestFeatureBar.name] = + CreateAvailability(kTestFeatureBar, 10u); + db_availabilities_[kTestFeatureNop.name] = + CreateAvailability(kTestFeatureNop, 8u); + + AvailabilityStore::LoadAndUpdateStore( + storage_dir_, CreateDB(), feature_filter, std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->UpdateCallback(true); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_TRUE(load_successful_.value()); + ASSERT_EQ(2u, load_results_->size()); + ASSERT_EQ(2u, db_availabilities_.size()); + + ASSERT_TRUE(load_results_->find(&kTestFeatureFoo) != load_results_->end()); + EXPECT_EQ(14u, (*load_results_)[&kTestFeatureFoo]); + ASSERT_TRUE(db_availabilities_.find(kTestFeatureFoo.name) != + db_availabilities_.end()); + EXPECT_EQ(14u, db_availabilities_[kTestFeatureFoo.name].day()); + + ASSERT_TRUE(load_results_->find(&kTestFeatureBar) != load_results_->end()); + EXPECT_EQ(10u, (*load_results_)[&kTestFeatureBar]); + ASSERT_TRUE(db_availabilities_.find(kTestFeatureBar.name) != + db_availabilities_.end()); + EXPECT_EQ(10u, db_availabilities_[kTestFeatureBar.name].day()); +} + +TEST_F(AvailabilityStoreTest, TestAllCombinationsEmptyFilter) { + scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, + {kTestFeatureQux, kTestFeatureNop}); + + // Empty filter, but the following setup: + // kTestFeatureFoo: Enabled. Not in DB. + // kTestFeatureBar: Enabled. In DB. + // kTestFeatureQux: Disabled. Not in DB. + // kTestFeatureNop: Disabled. In DB. + + db_availabilities_[kTestFeatureBar.name] = + CreateAvailability(kTestFeatureBar, 10u); + db_availabilities_[kTestFeatureNop.name] = + CreateAvailability(kTestFeatureNop, 8u); + + AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(), + FeatureVector(), + std::move(load_callback_), 14u); + + db_->InitCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->LoadCallback(true); + EXPECT_FALSE(load_successful_.has_value()); + + db_->UpdateCallback(true); + + EXPECT_TRUE(load_successful_.has_value()); + EXPECT_TRUE(load_successful_.value()); + EXPECT_EQ(0u, load_results_->size()); + EXPECT_EQ(0u, db_availabilities_.size()); +} + +} // namespace feature_engagement_tracker |