1 // Copyright 2013 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 "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h" 6 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "chrome/browser/sync_file_system/drive_backend/drive_metadata_store.h" 11 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "third_party/leveldatabase/src/include/leveldb/db.h" 14 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 15 #include "url/gurl.h" 16 #include "webkit/browser/fileapi/external_mount_points.h" 17 #include "webkit/common/fileapi/file_system_util.h" 18 19 #define FPL FILE_PATH_LITERAL 20 21 namespace sync_file_system { 22 namespace drive_backend { 23 24 namespace { 25 26 const char kV0ServiceName[] = "drive"; 27 28 bool CreateV0SerializedSyncableFileSystemURL( 29 const GURL& origin, 30 const base::FilePath& path, 31 std::string* serialized_url) { 32 fileapi::ScopedExternalFileSystem scoped_fs( 33 kV0ServiceName, fileapi::kFileSystemTypeSyncable, base::FilePath()); 34 35 fileapi::FileSystemURL url = 36 fileapi::ExternalMountPoints::GetSystemInstance()-> 37 CreateExternalFileSystemURL(origin, kV0ServiceName, path); 38 if (!url.is_valid()) 39 return false; 40 *serialized_url = fileapi::GetExternalFileSystemRootURIString( 41 origin, kV0ServiceName) + url.path().AsUTF8Unsafe(); 42 return true; 43 } 44 45 } // namespace 46 47 TEST(DriveMetadataDBMigrationUtilTest, ParseV0FormatFileSystemURL) { 48 const GURL kOrigin("chrome-extension://example"); 49 const base::FilePath kFile(FPL("foo bar")); 50 51 std::string serialized_url; 52 ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL( 53 kOrigin, kFile, &serialized_url)); 54 55 GURL origin; 56 base::FilePath path; 57 EXPECT_TRUE(ParseV0FormatFileSystemURL(GURL(serialized_url), &origin, &path)); 58 EXPECT_EQ(kOrigin, origin); 59 EXPECT_EQ(kFile, path); 60 } 61 62 TEST(DriveMetadataDBMigrationUtilTest, AddWapiIdPrefix) { 63 DriveMetadata_ResourceType type_file = 64 DriveMetadata_ResourceType_RESOURCE_TYPE_FILE; 65 DriveMetadata_ResourceType type_folder = 66 DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER; 67 68 EXPECT_EQ("file:xxx", AddWapiFilePrefix("xxx")); 69 EXPECT_EQ("folder:yyy", AddWapiFolderPrefix("yyy")); 70 EXPECT_EQ("file:xxx", AddWapiIdPrefix("xxx", type_file)); 71 EXPECT_EQ("folder:yyy", AddWapiIdPrefix("yyy", type_folder)); 72 73 EXPECT_EQ("", AddWapiFilePrefix("")); 74 EXPECT_EQ("", AddWapiFolderPrefix("")); 75 EXPECT_EQ("", AddWapiIdPrefix("", type_file)); 76 EXPECT_EQ("", AddWapiIdPrefix("", type_folder)); 77 } 78 79 TEST(DriveMetadataDBMigrationUtilTest, RemoveWapiIdPrefix) { 80 EXPECT_EQ("xxx", RemoveWapiIdPrefix("xxx")); 81 EXPECT_EQ("yyy", RemoveWapiIdPrefix("file:yyy")); 82 EXPECT_EQ("zzz", RemoveWapiIdPrefix("folder:zzz")); 83 84 EXPECT_EQ("", RemoveWapiIdPrefix("")); 85 EXPECT_EQ("foo:xxx", RemoveWapiIdPrefix("foo:xxx")); 86 } 87 88 TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV0) { 89 const char kDatabaseVersionKey[] = "VERSION"; 90 const char kChangeStampKey[] = "CHANGE_STAMP"; 91 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; 92 const char kDriveMetadataKeyPrefix[] = "METADATA: "; 93 const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: "; 94 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; 95 96 const GURL kOrigin1("chrome-extension://example1"); 97 const GURL kOrigin2("chrome-extension://example2"); 98 const std::string kSyncRootResourceId("folder:sync_root_resource_id"); 99 const std::string kResourceId1("folder:hoge"); 100 const std::string kResourceId2("folder:fuga"); 101 const std::string kFileResourceId("file:piyo"); 102 const base::FilePath kFile(FPL("foo bar")); 103 const std::string kFileMD5("file_md5"); 104 105 base::ScopedTempDir base_dir; 106 ASSERT_TRUE(base_dir.CreateUniqueTempDir()); 107 108 leveldb::Options options; 109 options.create_if_missing = true; 110 options.max_open_files = 64; // Use minimum. 111 leveldb::DB* db_ptr = NULL; 112 std::string db_dir = fileapi::FilePathToString( 113 base_dir.path().Append(DriveMetadataStore::kDatabaseName)); 114 leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr); 115 116 scoped_ptr<leveldb::DB> db(db_ptr); 117 ASSERT_TRUE(status.ok()); 118 119 // Setup the database with the schema version 0. 120 leveldb::WriteBatch batch; 121 batch.Put(kChangeStampKey, "1"); 122 batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId); 123 124 // Setup drive metadata. 125 DriveMetadata drive_metadata; 126 drive_metadata.set_resource_id(kFileResourceId); 127 drive_metadata.set_md5_checksum(kFileMD5); 128 drive_metadata.set_conflicted(false); 129 drive_metadata.set_to_be_fetched(false); 130 131 std::string serialized_url; 132 ASSERT_TRUE(CreateV0SerializedSyncableFileSystemURL( 133 kOrigin1, kFile, &serialized_url)); 134 std::string metadata_string; 135 drive_metadata.SerializeToString(&metadata_string); 136 batch.Put(kDriveMetadataKeyPrefix + serialized_url, metadata_string); 137 138 // Setup batch sync origin and incremental sync origin. 139 batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1); 140 batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(), 141 kResourceId2); 142 143 status = db->Write(leveldb::WriteOptions(), &batch); 144 EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status)); 145 146 // Migrate the database. 147 MigrateDatabaseFromV0ToV1(db.get()); 148 149 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 150 151 // Verify DB schema version. 152 int64 database_version = 0; 153 itr->Seek(kDatabaseVersionKey); 154 EXPECT_TRUE(itr->Valid()); 155 EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version)); 156 EXPECT_EQ(1, database_version); 157 158 // Verify the largest changestamp. 159 int64 changestamp = 0; 160 itr->Seek(kChangeStampKey); 161 EXPECT_TRUE(itr->Valid()); 162 EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp)); 163 EXPECT_EQ(1, changestamp); 164 165 // Verify the sync root directory. 166 itr->Seek(kSyncRootDirectoryKey); 167 EXPECT_TRUE(itr->Valid()); 168 EXPECT_EQ(kSyncRootResourceId, itr->value().ToString()); 169 170 // Verify the metadata. 171 itr->Seek(kDriveMetadataKeyPrefix); 172 EXPECT_TRUE(itr->Valid()); 173 DriveMetadata metadata; 174 EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString())); 175 EXPECT_EQ(kFileResourceId, metadata.resource_id()); 176 EXPECT_EQ(kFileMD5, metadata.md5_checksum()); 177 EXPECT_FALSE(metadata.conflicted()); 178 EXPECT_FALSE(metadata.to_be_fetched()); 179 180 // Verify the batch sync origin. 181 itr->Seek(kDriveBatchSyncOriginKeyPrefix); 182 EXPECT_TRUE(itr->Valid()); 183 EXPECT_EQ(kResourceId1, itr->value().ToString()); 184 185 // Verify the incremental sync origin. 186 itr->Seek(kDriveIncrementalSyncOriginKeyPrefix); 187 EXPECT_TRUE(itr->Valid()); 188 EXPECT_EQ(kResourceId2, itr->value().ToString()); 189 } 190 191 TEST(DriveMetadataDBMigrationUtilTest, MigrationFromV1) { 192 const char kDatabaseVersionKey[] = "VERSION"; 193 const char kChangeStampKey[] = "CHANGE_STAMP"; 194 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; 195 const char kDriveMetadataKeyPrefix[] = "METADATA: "; 196 const char kMetadataKeySeparator = ' '; 197 const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: "; 198 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; 199 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: "; 200 201 const GURL kOrigin1("chrome-extension://example1"); 202 const GURL kOrigin2("chrome-extension://example2"); 203 const GURL kOrigin3("chrome-extension://example3"); 204 205 const std::string kSyncRootResourceId("folder:sync_root_resource_id"); 206 const std::string kResourceId1("folder:hoge"); 207 const std::string kResourceId2("folder:fuga"); 208 const std::string kResourceId3("folder:hogera"); 209 const std::string kFileResourceId("file:piyo"); 210 const base::FilePath kFile(FPL("foo bar")); 211 const std::string kFileMD5("file_md5"); 212 213 RegisterSyncableFileSystem(); 214 215 base::ScopedTempDir base_dir; 216 ASSERT_TRUE(base_dir.CreateUniqueTempDir()); 217 218 leveldb::Options options; 219 options.create_if_missing = true; 220 leveldb::DB* db_ptr = NULL; 221 std::string db_dir = fileapi::FilePathToString( 222 base_dir.path().Append(DriveMetadataStore::kDatabaseName)); 223 leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr); 224 225 scoped_ptr<leveldb::DB> db(db_ptr); 226 ASSERT_TRUE(status.ok()); 227 228 // Setup the database with the schema version 1. 229 leveldb::WriteBatch batch; 230 batch.Put(kDatabaseVersionKey, "1"); 231 batch.Put(kChangeStampKey, "1"); 232 batch.Put(kSyncRootDirectoryKey, kSyncRootResourceId); 233 234 fileapi::FileSystemURL url = CreateSyncableFileSystemURL(kOrigin1, kFile); 235 236 // Setup drive metadata. 237 DriveMetadata drive_metadata; 238 drive_metadata.set_resource_id(kFileResourceId); 239 drive_metadata.set_md5_checksum(kFileMD5); 240 drive_metadata.set_conflicted(false); 241 drive_metadata.set_to_be_fetched(false); 242 std::string metadata_string; 243 drive_metadata.SerializeToString(&metadata_string); 244 std::string metadata_key = kDriveMetadataKeyPrefix + kOrigin1.spec() + 245 kMetadataKeySeparator + url.path().AsUTF8Unsafe(); 246 batch.Put(metadata_key, metadata_string); 247 248 // Setup origins. 249 batch.Put(kDriveBatchSyncOriginKeyPrefix + kOrigin1.spec(), kResourceId1); 250 batch.Put(kDriveIncrementalSyncOriginKeyPrefix + kOrigin2.spec(), 251 kResourceId2); 252 batch.Put(kDriveDisabledOriginKeyPrefix + kOrigin3.spec(), kResourceId3); 253 254 status = db->Write(leveldb::WriteOptions(), &batch); 255 EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status)); 256 257 RevokeSyncableFileSystem(); 258 259 // Migrate the database. 260 MigrateDatabaseFromV1ToV2(db.get()); 261 262 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 263 264 // Verify DB schema version. 265 int64 database_version = 0; 266 itr->Seek(kDatabaseVersionKey); 267 EXPECT_TRUE(itr->Valid()); 268 EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &database_version)); 269 EXPECT_EQ(2, database_version); 270 271 // Verify the largest changestamp. 272 int64 changestamp = 0; 273 itr->Seek(kChangeStampKey); 274 EXPECT_TRUE(itr->Valid()); 275 EXPECT_TRUE(base::StringToInt64(itr->value().ToString(), &changestamp)); 276 EXPECT_EQ(1, changestamp); 277 278 // Verify the sync root directory. 279 itr->Seek(kSyncRootDirectoryKey); 280 EXPECT_TRUE(itr->Valid()); 281 EXPECT_EQ(RemoveWapiIdPrefix(kSyncRootResourceId), itr->value().ToString()); 282 283 // Verify the metadata. 284 itr->Seek(kDriveMetadataKeyPrefix); 285 EXPECT_TRUE(itr->Valid()); 286 DriveMetadata metadata; 287 EXPECT_TRUE(metadata.ParseFromString(itr->value().ToString())); 288 EXPECT_EQ(RemoveWapiIdPrefix(kFileResourceId), metadata.resource_id()); 289 EXPECT_EQ(kFileMD5, metadata.md5_checksum()); 290 EXPECT_FALSE(metadata.conflicted()); 291 EXPECT_FALSE(metadata.to_be_fetched()); 292 293 // Verify the batch sync origin. 294 itr->Seek(kDriveBatchSyncOriginKeyPrefix); 295 EXPECT_FALSE(StartsWithASCII(kDriveBatchSyncOriginKeyPrefix, 296 itr->key().ToString(), true)); 297 298 // Verify the incremental sync origin. 299 itr->Seek(kDriveIncrementalSyncOriginKeyPrefix); 300 EXPECT_TRUE(itr->Valid()); 301 EXPECT_EQ(RemoveWapiIdPrefix(kResourceId2), itr->value().ToString()); 302 303 // Verify the disabled origin. 304 itr->Seek(kDriveDisabledOriginKeyPrefix); 305 EXPECT_TRUE(itr->Valid()); 306 EXPECT_EQ(RemoveWapiIdPrefix(kResourceId3), itr->value().ToString()); 307 } 308 309 } // namespace drive_backend 310 } // namespace sync_file_system 311