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