Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits>
      6 #include <string>
      7 
      8 #include "app/sql/statement.h"
      9 #include "base/file_util.h"
     10 #include "base/memory/scoped_temp_dir.h"
     11 #include "base/utf_string_conversions.h"
     12 #include "build/build_config.h"
     13 #include "chrome/browser/password_manager/encryptor.h"
     14 #include "chrome/browser/sync/syncable/directory_manager.h"
     15 #include "chrome/browser/sync/util/user_settings.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 using std::numeric_limits;
     19 
     20 namespace {
     21 
     22 const FilePath::CharType kV10UserSettingsDB[] =
     23     FILE_PATH_LITERAL("Version10Settings.sqlite3");
     24 const FilePath::CharType kV11UserSettingsDB[] =
     25     FILE_PATH_LITERAL("Version11Settings.sqlite3");
     26 const FilePath::CharType kOldStyleSyncDataDB[] =
     27     FILE_PATH_LITERAL("OldStyleSyncData.sqlite3");
     28 
     29 }  // namespace
     30 
     31 class UserSettingsTest : public testing::Test {
     32  public:
     33   UserSettingsTest() : sync_data_("Some sync data") {}
     34 
     35   virtual void SetUp() {
     36 #if defined(OS_MACOSX)
     37     // Need to mock the Keychain for unit tests on Mac to avoid possible
     38     // blocking UI.  |SetAuthTokenForService| uses Encryptor.
     39     Encryptor::UseMockKeychain(true);
     40 #endif
     41   }
     42 
     43   // Creates and populates the V10 database files within
     44   // |destination_directory|.
     45   void SetUpVersion10Databases(const FilePath& destination_directory) {
     46     v10_user_setting_db_path_ =
     47         destination_directory.Append(FilePath(kV10UserSettingsDB));
     48 
     49     sql::Connection db;
     50     ASSERT_TRUE(db.Open(v10_user_setting_db_path_));
     51 
     52     old_style_sync_data_path_ =
     53         destination_directory.Append(FilePath(kOldStyleSyncDataDB));
     54 
     55     ASSERT_EQ(sync_data_.length(),
     56               static_cast<size_t>(file_util::WriteFile(
     57                   old_style_sync_data_path_, sync_data_.data(),
     58                   sync_data_.length())));
     59 
     60     // Create settings table.
     61     ASSERT_TRUE(db.Execute(
     62         "CREATE TABLE settings (email, key, value,  PRIMARY KEY(email, key)"
     63         " ON CONFLICT REPLACE)"));
     64 
     65     // Add a blank signin table.
     66     ASSERT_TRUE(db.Execute(
     67         "CREATE TABLE signin_types (signin, signin_type)"));
     68 
     69     // Create and populate version table.
     70     ASSERT_TRUE(db.Execute("CREATE TABLE db_version (version)"));
     71     {
     72       const char* query = "INSERT INTO db_version VALUES(?)";
     73       sql::Statement s(db.GetUniqueStatement(query));
     74       if (!s)
     75         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
     76 
     77       s.BindInt(0, 10);
     78       if (!s.Run())
     79         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
     80     }
     81 
     82     // Create shares table.
     83     ASSERT_TRUE(db.Execute(
     84         "CREATE TABLE shares (email, share_name, file_name,"
     85         " PRIMARY KEY(email, share_name) ON CONFLICT REPLACE)"));
     86     // Populate a share.
     87     {
     88       const char* query = "INSERT INTO shares VALUES(?, ?, ?)";
     89       sql::Statement s(db.GetUniqueStatement(query));
     90       if (!s)
     91         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
     92 
     93       s.BindString(0, "foo (at) foo.com");
     94       s.BindString(1, "foo (at) foo.com");
     95 #if defined(OS_WIN)
     96       s.BindString(2, WideToUTF8(old_style_sync_data_path_.value()));
     97 #elif defined(OS_POSIX)
     98       s.BindString(2, old_style_sync_data_path_.value());
     99 #endif
    100       if (!s.Run())
    101         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    102     }
    103   }
    104 
    105    // Creates and populates the V11 database file within
    106   // |destination_directory|.
    107   void SetUpVersion11Database(const FilePath& destination_directory) {
    108     v11_user_setting_db_path_ =
    109         destination_directory.Append(FilePath(kV11UserSettingsDB));
    110 
    111     sql::Connection db;
    112     ASSERT_TRUE(db.Open(v11_user_setting_db_path_));
    113 
    114     // Create settings table.
    115     ASSERT_TRUE(db.Execute(
    116         "CREATE TABLE settings (email, key, value, PRIMARY KEY(email, key)"
    117         " ON CONFLICT REPLACE)"));
    118 
    119     // Create and populate version table.
    120     ASSERT_TRUE(db.Execute("CREATE TABLE db_version (version)"));
    121     {
    122       const char* query = "INSERT INTO db_version VALUES(?)";
    123       sql::Statement s(db.GetUniqueStatement(query));
    124       if (!s)
    125         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    126 
    127       s.BindInt(0, 11);
    128       if (!s.Run())
    129         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    130     }
    131 
    132     ASSERT_TRUE(db.Execute(
    133         "CREATE TABLE signin_types (signin, signin_type)"));
    134     {
    135       const char* query = "INSERT INTO signin_types VALUES(?, ?)";
    136       sql::Statement s(db.GetUniqueStatement(query));
    137       if (!s)
    138         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    139 
    140       s.BindString(0, "test");
    141       s.BindString(1, "test");
    142       if (!s.Run())
    143         LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    144     }
    145   }
    146 
    147   const std::string& sync_data() const { return sync_data_; }
    148   const FilePath& v10_user_setting_db_path() const {
    149     return v10_user_setting_db_path_;
    150   }
    151   const FilePath& v11_user_setting_db_path() const {
    152     return v11_user_setting_db_path_;
    153   }
    154   const FilePath& old_style_sync_data_path() const {
    155     return old_style_sync_data_path_;
    156   }
    157 
    158  private:
    159   FilePath v10_user_setting_db_path_;
    160   FilePath old_style_sync_data_path_;
    161 
    162   FilePath v11_user_setting_db_path_;
    163 
    164   std::string sync_data_;
    165 };
    166 
    167 TEST_F(UserSettingsTest, MigrateFromV10ToV11) {
    168   ScopedTempDir temp_dir;
    169   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    170   SetUpVersion10Databases(temp_dir.path());
    171   {
    172     // Create a UserSettings, which should trigger migration code. We do this
    173     // inside a scoped block so it closes itself and we can poke around to see
    174     // what happened later.
    175     browser_sync::UserSettings settings;
    176     settings.Init(v10_user_setting_db_path());
    177   }
    178 
    179   // Now poke around using sqlite to see if UserSettings migrated properly.
    180   sql::Connection db;
    181   ASSERT_TRUE(db.Open(v10_user_setting_db_path()));
    182 
    183   // Note that we don't use ScopedStatement to avoid closing the sqlite handle
    184   // before finalizing the statement.
    185   {
    186     const char* query = "SELECT version FROM db_version";
    187     sql::Statement version_query(db.GetUniqueStatement(query));
    188     if (!version_query)
    189       LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    190 
    191     ASSERT_TRUE(version_query.Step());
    192     const int version = version_query.ColumnInt(0);
    193     EXPECT_GE(version, 11);
    194   }
    195 
    196   EXPECT_FALSE(file_util::PathExists(old_style_sync_data_path()));
    197 
    198   FilePath new_style_path = temp_dir.path().Append(
    199       syncable::DirectoryManager::GetSyncDataDatabaseFilename());
    200 
    201   std::string contents;
    202   ASSERT_TRUE(file_util::ReadFileToString(new_style_path, &contents));
    203   EXPECT_TRUE(sync_data() == contents);
    204 }
    205 
    206 TEST_F(UserSettingsTest, MigrateFromV11ToV12) {
    207   ScopedTempDir temp_dir;
    208   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    209   SetUpVersion11Database(temp_dir.path());
    210   {
    211     browser_sync::UserSettings settings;
    212     settings.Init(v11_user_setting_db_path());
    213   }
    214   sql::Connection db;
    215   ASSERT_TRUE(db.Open(v11_user_setting_db_path()));
    216 
    217   {
    218     const char* query = "SELECT version FROM db_version";
    219     sql::Statement version_query(db.GetUniqueStatement(query));
    220     if (!version_query)
    221       LOG(FATAL) << query << "\n" << db.GetErrorMessage();
    222 
    223     ASSERT_TRUE(version_query.Step());
    224     const int version = version_query.ColumnInt(0);
    225     EXPECT_GE(version, 12);
    226 
    227     const char* query2 = "SELECT name FROM sqlite_master "
    228                          "WHERE type='table' AND name='signin_types'";
    229     sql::Statement table_query(db.GetUniqueStatement(query2));
    230     if (!table_query)
    231       LOG(FATAL) << query2 << "\n" << db.GetErrorMessage();
    232 
    233     ASSERT_FALSE(table_query.Step());
    234   }
    235 }
    236 
    237 TEST_F(UserSettingsTest, APEncode) {
    238   std::string test;
    239   char i;
    240   for (i = numeric_limits<char>::min(); i < numeric_limits<char>::max(); ++i)
    241     test.push_back(i);
    242   test.push_back(i);
    243   const std::string encoded = browser_sync::APEncode(test);
    244   const std::string decoded = browser_sync::APDecode(encoded);
    245   ASSERT_EQ(test, decoded);
    246 }
    247 
    248 TEST_F(UserSettingsTest, PersistEmptyToken) {
    249   ScopedTempDir temp_dir;
    250   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    251   browser_sync::UserSettings settings;
    252   settings.Init(temp_dir.path().AppendASCII("UserSettings.sqlite3"));
    253   settings.SetAuthTokenForService("username", "service", "");
    254   std::string username;
    255   std::string token;
    256   ASSERT_TRUE(settings.GetLastUserAndServiceToken("service", &username,
    257       &token));
    258   EXPECT_EQ("", token);
    259   EXPECT_EQ("username", username);
    260 }
    261 
    262 TEST_F(UserSettingsTest, PersistNonEmptyToken) {
    263   ScopedTempDir temp_dir;
    264   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    265   browser_sync::UserSettings settings;
    266   settings.Init(temp_dir.path().AppendASCII("UserSettings.sqlite3"));
    267   settings.SetAuthTokenForService("username", "service",
    268       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah"
    269       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah"
    270       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah");
    271   std::string username;
    272   std::string token;
    273   ASSERT_TRUE(settings.GetLastUserAndServiceToken("service", &username,
    274       &token));
    275   EXPECT_EQ(
    276       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah"
    277       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah"
    278       "oonetuhasonteuhasonetuhasonetuhasonetuhasouhasonetuhasonetuhasonetuhah",
    279       token);
    280   EXPECT_EQ("username", username);
    281 }
    282