blob: e42b02ca118b5df9333de9894d0f3e093d3fe923 [file] [log] [blame]
// 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