| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/btm/btm_database_migrator.h" |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| #include "content/browser/btm/btm_test_utils.h" |
| #include "sql/database.h" |
| #include "sql/test/test_helpers.h" |
| #include "sql/transaction.h" |
| #include "testing/gmock/include/gmock/gmock-matchers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::AssertionFailure; |
| using testing::AssertionResult; |
| using testing::AssertionSuccess; |
| |
| namespace content { |
| |
| using internal::BtmDatabaseMigrator; |
| |
| class BtmDatabaseMigrationTest : public testing::Test { |
| protected: |
| base::FilePath db_path() { return db_path_; } |
| |
| [[nodiscard]] AssertionResult LoadDatabase(const char* file_name) { |
| base::FilePath root; |
| if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &root)) { |
| return AssertionFailure() << "Could not get test data directory root"; |
| } |
| base::FilePath file_path = root.AppendASCII("content") |
| .AppendASCII("test") |
| .AppendASCII("data") |
| .AppendASCII("btm") |
| .AppendASCII(file_name); |
| if (!base::PathExists(file_path)) { |
| return AssertionFailure() << file_path << " does not exist"; |
| } |
| if (!sql::test::CreateDatabaseFromSQL(db_path(), file_path)) { |
| return AssertionFailure() << "Could not create database at " << db_path(); |
| } |
| return AssertionSuccess(); |
| } |
| |
| int GetDatabaseVersion(sql::Database* db) { |
| sql::Statement kGetVersionSql( |
| db->GetUniqueStatement("SELECT value FROM meta WHERE key='version'")); |
| if (!kGetVersionSql.Step()) { |
| return 0; |
| } |
| return kGetVersionSql.ColumnInt(0); |
| } |
| |
| int GetDatabaseLastCompatibleVersion(sql::Database* db) { |
| sql::Statement kGetLastCompatibleVersionSql(db->GetUniqueStatement( |
| "SELECT value FROM meta WHERE key='last_compatible_version'")); |
| if (!kGetLastCompatibleVersionSql.Step()) { |
| return 0; |
| } |
| return kGetLastCompatibleVersionSql.ColumnInt(0); |
| } |
| |
| std::optional<int> GetPrepopulatedFromMetaTable(sql::Database* db) { |
| sql::Statement kGetPrepopulatedSql(db->GetUniqueStatement( |
| "SELECT value FROM meta WHERE key='prepopulated'")); |
| if (!kGetPrepopulatedSql.Step()) { |
| return std::nullopt; |
| } |
| return kGetPrepopulatedSql.ColumnInt(0); |
| } |
| |
| std::optional<int64_t> GetPrepopulatedFromConfigTable(sql::Database* db) { |
| sql::Statement kGetPrepopulatedSql(db->GetUniqueStatement( |
| "SELECT int_value FROM config WHERE key='prepopulated'")); |
| if (!kGetPrepopulatedSql.Step()) { |
| return std::nullopt; |
| } |
| return kGetPrepopulatedSql.ColumnInt64(0); |
| } |
| |
| std::string DbBouncesToString(sql::Database* db) { |
| return sql::test::ExecuteWithResults( |
| db, "SELECT * FROM bounces ORDER BY site", "|", "\n"); |
| } |
| |
| std::string DbPopupsToString(sql::Database* db) { |
| return sql::test::ExecuteWithResults( |
| db, "SELECT * FROM popups ORDER BY opener_site", "|", "\n"); |
| } |
| |
| std::string DbConfigToString(sql::Database* db) { |
| return sql::test::ExecuteWithResults( |
| db, "SELECT * FROM config ORDER BY key", "|", "\n"); |
| } |
| |
| std::vector<std::string> GetFirstAndLastColumnForSite(sql::Database* db, |
| const char* column, |
| const char* site) { |
| std::string both_times = sql::test::ExecuteWithResults( |
| db, |
| base::StringPrintf("SELECT first_%s_time,last_%s_time FROM bounces " |
| "WHERE site='%s'", |
| column, column, site), |
| "|", ","); |
| |
| return base::SplitString(both_times, "|", base::KEEP_WHITESPACE, |
| base::SPLIT_WANT_ALL); |
| } |
| |
| void ExpectAllEntriesInColumnToBeNull(sql::Database* db, |
| const char* table, |
| const char* column) { |
| const std::string num_rows_with_non_null_column_value = |
| sql::test::ExecuteWithResult( |
| db, |
| base::StringPrintf("SELECT COUNT(*) FROM %s WHERE %s IS NOT NULL", |
| table, column)); |
| EXPECT_EQ(num_rows_with_non_null_column_value, "0"); |
| } |
| |
| private: |
| base::ScopedTempDir temp_dir_; |
| base::FilePath db_path_; |
| // Test setup. |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| db_path_ = temp_dir_.GetPath().AppendASCII("BTM.db"); |
| } |
| |
| void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); } |
| }; |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV1ToLatestVersion) { |
| ASSERT_TRUE(LoadDatabase("v1.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 1); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 1); |
| |
| EXPECT_TRUE(db.DoesTableExist("bounces")); |
| EXPECT_FALSE(db.DoesTableExist("popups")); |
| EXPECT_FALSE(db.DoesTableExist("config")); |
| |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|0|0|4|4|1|4|2|6\n" |
| "site-storage-stateful-bounce-drop.test|1|1|0|0|0|0|0|0\n" |
| "stateful-bounce.test|0|0|4|4|1|1|0|0\n" |
| "stateless-bounce.test|0|0|4|4|0|0|1|1\n" |
| "storage.test|1|1|4|4|0|0|0|0"); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 1, 1)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| MigrateBtmSchemaToLatestVersion(db, meta_table); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), BtmDatabase::kLatestSchemaVersion); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), |
| BtmDatabase::kMinCompatibleSchemaVersion); |
| |
| ASSERT_TRUE(db.DoesTableExist("bounces")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "site")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "first_bounce_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "last_bounce_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "first_user_activation_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "last_user_activation_time")); |
| EXPECT_TRUE( |
| db.DoesColumnExist("bounces", "first_web_authn_assertion_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "last_web_authn_assertion_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_stateless_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_stateless_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_stateful_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_stateful_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_site_storage_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_site_storage_time")); |
| |
| ASSERT_TRUE(db.DoesTableExist("popups")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "opener_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "popup_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "access_id")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "last_popup_time")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "is_current_interaction")); |
| |
| ASSERT_TRUE(db.DoesTableExist("config")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "key")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "int_value")); |
| |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|4|4|1|6||\n" |
| "stateful-bounce.test|4|4|1|1||\n" |
| "stateless-bounce.test|4|4|1|1||\n" |
| "storage.test|4|4||||"); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV1ToV2) { |
| ASSERT_TRUE(LoadDatabase("v1.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 1); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 1); |
| |
| EXPECT_FALSE(db.DoesTableExist("popups")); |
| EXPECT_FALSE(db.DoesTableExist("config")); |
| |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "first_stateless_bounce_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "last_stateless_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_bounce_time")); |
| EXPECT_FALSE( |
| db.DoesColumnExist("bounces", "first_web_authn_assertion_time")); |
| EXPECT_FALSE( |
| db.DoesColumnExist("bounces", "last_web_authn_assertion_time")); |
| |
| // These values are all set in v1.sql. |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|0|0|4|4|1|4|2|6\n" |
| "site-storage-stateful-bounce-drop.test|1|1|0|0|0|0|0|0\n" |
| "stateful-bounce.test|0|0|4|4|1|1|0|0\n" |
| "stateless-bounce.test|0|0|4|4|0|0|1|1\n" |
| "storage.test|1|1|4|4|0|0|0|0"); |
| |
| // Note: that the stateful bounce happens earlier than the stateless bounce |
| // this should be reflected in the first/last bounce times for this in v2. |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateful_bounce", |
| "both-bounce-kinds.test"), |
| testing::ElementsAre("1", "4")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateless_bounce", |
| "both-bounce-kinds.test"), |
| testing::ElementsAre("2", "6")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "both-bounce-kinds.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateful_bounce", |
| "stateful-bounce.test"), |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "stateful-bounce.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateless_bounce", |
| "stateless-bounce.test"), |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "stateless-bounce.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "site_storage", "storage.test"), |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "user_interaction", "storage.test"), |
| testing::ElementsAre("4", "4")); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 1, 1)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| migrator.MigrateSchemaVersionFrom1To2(); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 2); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 2); |
| |
| // Verify that all 0s were transformed to NULLs. |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|||4|4|1|4|1|6\n" |
| "site-storage-stateful-bounce-drop.test|1|1||||||\n" |
| "stateful-bounce.test|||4|4|1|1|1|1\n" |
| "stateless-bounce.test|||4|4|||1|1\n" |
| "storage.test|1|1|4|4||||"); |
| |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateful_bounce", |
| "both-bounce-kinds.test"), |
| testing::ElementsAre("1", "4")); |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "bounce", "both-bounce-kinds.test"), |
| testing::ElementsAre( |
| // first_bounce_time should be the minimum of |
| // first_stateful_bounce_time and first_stateless_bounce_time. |
| "1", |
| // last_bounce_time should be the maximum of |
| // last_stateful_bounce_time and last_stateless_bounce_time. |
| "6")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "both-bounce-kinds.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "stateful_bounce", |
| "stateful-bounce.test"), |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "bounce", "stateful-bounce.test"), |
| // first_ and last_bounce_time should populate even if the old |
| // *_stateless_bounce_time columns were null. |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "stateful-bounce.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "bounce", "stateless-bounce.test"), |
| // first_ and last_bounce_time should populate even if the |
| // *_stateful_bounce_times columns were null. |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT(GetFirstAndLastColumnForSite(&db, "user_interaction", |
| "stateful-bounce.test"), |
| testing::ElementsAre("4", "4")); |
| |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "site_storage", "storage.test"), |
| testing::ElementsAre("1", "1")); |
| EXPECT_THAT( |
| GetFirstAndLastColumnForSite(&db, "user_interaction", "storage.test"), |
| testing::ElementsAre("4", "4")); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV2ToV3) { |
| ASSERT_TRUE(LoadDatabase("v2.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 2); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 2); |
| EXPECT_EQ(GetPrepopulatedFromMetaTable(&db), 1); |
| |
| EXPECT_FALSE(db.DoesTableExist("popups")); |
| EXPECT_FALSE(db.DoesTableExist("config")); |
| |
| EXPECT_FALSE( |
| db.DoesColumnExist("bounces", "first_web_authn_assertion_time")); |
| EXPECT_FALSE( |
| db.DoesColumnExist("bounces", "last_web_authn_assertion_time")); |
| |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|||4|4|1|4|2|6\n" |
| "stateful-bounce.test|||4|4|1|1||\n" |
| "stateless-bounce.test|||4|4|||1|1\n" |
| "storage.test|1|1|4|4||||"); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 2, 2)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| migrator.MigrateSchemaVersionFrom2To3(); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 3); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 3); |
| |
| ASSERT_TRUE( |
| db.DoesColumnExist("bounces", "first_web_authn_assertion_time")); |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "last_web_authn_assertion_time")); |
| |
| ExpectAllEntriesInColumnToBeNull(&db, "bounces", |
| "first_web_authn_assertion_time"); |
| ExpectAllEntriesInColumnToBeNull(&db, "bounces", |
| "last_web_authn_assertion_time"); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV3ToV4) { |
| ASSERT_TRUE(LoadDatabase("v3.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 3); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 3); |
| EXPECT_EQ(GetPrepopulatedFromMetaTable(&db), 1); |
| |
| EXPECT_FALSE(db.DoesTableExist("popups")); |
| EXPECT_FALSE(db.DoesTableExist("config")); |
| |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|||4|4|1|4|2|6||\n" |
| "stateful-bounce.test|||4|4|1|1||||\n" |
| "stateless-bounce.test|||4|4|||1|1||\n" |
| "storage.test|1|1|4|4||||||"); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 3, 3)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| migrator.MigrateSchemaVersionFrom3To4(); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 4); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 4); |
| |
| EXPECT_TRUE(db.DoesTableExist("popups")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "opener_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "popup_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "access_id")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "last_popup_time")); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV4ToV5) { |
| ASSERT_TRUE(LoadDatabase("v4.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 4); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 4); |
| EXPECT_EQ(GetPrepopulatedFromMetaTable(&db), 1); |
| |
| EXPECT_FALSE(db.DoesTableExist("config")); |
| |
| EXPECT_TRUE(db.DoesColumnExist("popups", "opener_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "popup_site")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "access_id")); |
| EXPECT_TRUE(db.DoesColumnExist("popups", "last_popup_time")); |
| |
| EXPECT_EQ(DbPopupsToString(&db), |
| "site1.com|3p-site.com|123|2023-10-01 12:00:00\n" |
| "site2.com|3p-site.com|456|2023-10-02 12:00:00"); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 4, 4)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| migrator.MigrateSchemaVersionFrom4To5(); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 5); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 5); |
| |
| ASSERT_TRUE(db.DoesColumnExist("popups", "is_current_interaction")); |
| ExpectAllEntriesInColumnToBeNull(&db, "popups", "is_current_interaction"); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV5ToV6) { |
| ASSERT_TRUE(LoadDatabase("v5.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 5); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 5); |
| ASSERT_EQ(GetPrepopulatedFromMetaTable(&db), 1); |
| |
| ASSERT_TRUE(db.DoesTableExist("bounces")); |
| ASSERT_TRUE(db.DoesTableExist("popups")); |
| ASSERT_FALSE(db.DoesTableExist("config")); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 5, 5)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| migrator.MigrateSchemaVersionFrom5To6(); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 6); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 6); |
| |
| EXPECT_TRUE(db.DoesTableExist("config")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "key")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "int_value")); |
| |
| EXPECT_EQ(GetPrepopulatedFromMetaTable(&db), std::nullopt); |
| EXPECT_EQ(GetPrepopulatedFromConfigTable(&db), 1); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV6ToV7) { |
| ASSERT_TRUE(LoadDatabase("v6.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 6); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 6); |
| |
| ASSERT_TRUE(db.DoesTableExist("config")); |
| ASSERT_TRUE(db.DoesColumnExist("config", "key")); |
| ASSERT_TRUE(db.DoesColumnExist("config", "int_value")); |
| |
| ASSERT_EQ(GetPrepopulatedFromConfigTable(&db), 1); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 6, 6)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| ASSERT_TRUE(migrator.MigrateSchemaVersionFrom6To7()); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 7); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 6); |
| |
| EXPECT_TRUE(db.DoesTableExist("config")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "key")); |
| EXPECT_TRUE(db.DoesColumnExist("config", "int_value")); |
| |
| EXPECT_EQ(GetPrepopulatedFromConfigTable(&db), std::nullopt); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV7ToV8) { |
| ASSERT_TRUE(LoadDatabase("v7.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 7); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 6); |
| |
| ASSERT_TRUE(db.DoesTableExist("config")); |
| ASSERT_TRUE(db.DoesColumnExist("config", "key")); |
| ASSERT_TRUE(db.DoesColumnExist("config", "int_value")); |
| |
| ASSERT_EQ(GetPrepopulatedFromConfigTable(&db), std::nullopt); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 7, 6)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| ASSERT_TRUE(migrator.MigrateSchemaVersionFrom7To8()); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 8); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 8); |
| |
| ASSERT_TRUE(db.DoesColumnExist("popups", "is_authentication_interaction")); |
| ExpectAllEntriesInColumnToBeNull(&db, "popups", |
| "is_authentication_interaction"); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV8ToV9) { |
| ASSERT_TRUE(LoadDatabase("v8.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 8); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 8); |
| |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "first_user_interaction_time")); |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "last_user_interaction_time")); |
| ASSERT_FALSE(db.DoesColumnExist("bounces", "first_user_activation_time")); |
| ASSERT_FALSE(db.DoesColumnExist("bounces", "last_user_activation_time")); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 8, 8)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| ASSERT_TRUE(migrator.MigrateSchemaVersionFrom8To9()); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "first_user_activation_time")); |
| EXPECT_TRUE(db.DoesColumnExist("bounces", "last_user_activation_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_user_interaction_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_user_interaction_time")); |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 9); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 9); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV9ToV10) { |
| ASSERT_TRUE(LoadDatabase("v9.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 9); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 9); |
| |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "first_site_storage_time")); |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "last_site_storage_time")); |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "first_stateful_bounce_time")); |
| ASSERT_TRUE(db.DoesColumnExist("bounces", "last_stateful_bounce_time")); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 9, 9)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| ASSERT_TRUE(migrator.MigrateSchemaVersionFrom9To10()); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify post-migration conditions. |
| |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_site_storage_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_site_storage_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "first_stateful_bounce_time")); |
| EXPECT_FALSE(db.DoesColumnExist("bounces", "last_stateful_bounce_time")); |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 10); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 10); |
| } |
| } |
| |
| TEST_F(BtmDatabaseMigrationTest, MigrateV10ToV11) { |
| ASSERT_TRUE(LoadDatabase("v10.sql")); |
| |
| { |
| sql::Database db(sql::test::kTestTag); |
| ASSERT_TRUE(db.Open(db_path())); |
| |
| // Verify pre-migration conditions. |
| |
| ASSERT_EQ(GetDatabaseVersion(&db), 10); |
| ASSERT_EQ(GetDatabaseLastCompatibleVersion(&db), 10); |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|4|4|2|6||\n" |
| "site-storage-stateful-bounce-drop.test||||||\n" |
| "stateful-bounce.test|4|4||||\n" |
| "stateless-bounce.test|4|4|1|1||\n" |
| "storage.test|4|4||||"); |
| |
| // Migrate. |
| |
| sql::MetaTable meta_table; |
| ASSERT_TRUE(meta_table.Init(&db, 10, 10)); |
| |
| sql::Transaction transaction(&db); |
| ASSERT_TRUE(transaction.Begin()); |
| BtmDatabaseMigrator migrator(&db, &meta_table); |
| ASSERT_TRUE(migrator.MigrateSchemaVersionFrom10To11()); |
| ASSERT_TRUE(transaction.Commit()); |
| |
| // Verify empty row is removed. |
| |
| EXPECT_EQ(DbBouncesToString(&db), |
| "both-bounce-kinds.test|4|4|2|6||\n" |
| "stateful-bounce.test|4|4||||\n" |
| "stateless-bounce.test|4|4|1|1||\n" |
| "storage.test|4|4||||"); |
| |
| EXPECT_EQ(GetDatabaseVersion(&db), 11); |
| EXPECT_EQ(GetDatabaseLastCompatibleVersion(&db), 11); |
| } |
| } |
| |
| } // namespace content |