1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/scoped_temp_dir.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/external_mount_points.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/fileapi/file_system_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#define FPL FILE_PATH_LITERAL
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace sync_file_system {
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive_backend {
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VerifyKeyAndValue(const std::string& key,
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       const std::string& expect_val,
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       leveldb::DB* db) {
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  itr->Seek(key);
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(itr->Valid());
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(expect_val, itr->value().ToString());
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VerifyNotExist(const std::string& key, leveldb::DB* db) {
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  itr->Seek(key);
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(!itr->Valid() ||
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              !StartsWithASCII(itr->key().ToString(), key, true));
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST(DriveMetadataDBMigrationUtilTest, RollbackFromV4ToV3) {
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Rollback from version 4 to version 3.
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Please see metadata_database_index.cc for version 3 format, and
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // metadata_database_index_on_disk.cc for version 4 format.
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kDatabaseVersionKey[] = "VERSION";
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kServiceMetadataKey[] = "SERVICE";
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kFileMetadataKeyPrefix[] = "FILE: ";
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kFileTrackerKeyPrefix[] = "TRACKER: ";
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Key prefixes used in version 4.
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kAppRootIDByAppIDKeyPrefix[] = "APP_ROOT: ";
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kActiveTrackerIDByFileIDKeyPrefix[] = "ACTIVE_FILE: ";
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kTrackerIDByFileIDKeyPrefix[] = "TRACKER_FILE: ";
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kMultiTrackerByFileIDKeyPrefix[] = "MULTI_FILE: ";
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kActiveTrackerIDByParentAndTitleKeyPrefix[] = "ACTIVE_PATH: ";
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kTrackerIDByParentAndTitleKeyPrefix[] = "TRACKER_PATH: ";
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kMultiBackingParentAndTitleKeyPrefix[] = "MULTI_PATH: ";
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kDirtyIDKeyPrefix[] = "DIRTY: ";
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char kDemotedDirtyIDKeyPrefix[] = "DEMOTED_DIRTY: ";
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Set up environment.
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::DB* db_ptr = NULL;
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::ScopedTempDir base_dir;
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ASSERT_TRUE(base_dir.CreateUniqueTempDir());
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    leveldb::Options options;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    options.create_if_missing = true;
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::string db_dir =
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        storage::FilePathToString(base_dir.path().Append(kDatabaseName));
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ASSERT_TRUE(status.ok());
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<leveldb::DB> db(db_ptr);
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Setup the database with the schema version 4, without IDs.
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::WriteBatch batch;
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kDatabaseVersionKey, "4");
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kServiceMetadataKey, "service_metadata");
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kFileMetadataKeyPrefix, "file_metadata");
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kFileTrackerKeyPrefix, "file_tracker");
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kAppRootIDByAppIDKeyPrefix, "app_root_id");
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kActiveTrackerIDByFileIDKeyPrefix, "active_id_by_file");
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kTrackerIDByFileIDKeyPrefix, "tracker_id_by_file");
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kMultiTrackerByFileIDKeyPrefix, "multi_tracker_by_file");
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kActiveTrackerIDByParentAndTitleKeyPrefix, "active_id_by_path");
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kTrackerIDByParentAndTitleKeyPrefix, "tracker_id_by_path");
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kMultiBackingParentAndTitleKeyPrefix, "multi_tracker_by_path");
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kDirtyIDKeyPrefix, "dirty");
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  batch.Put(kDemotedDirtyIDKeyPrefix, "demoted_dirty");
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  leveldb::Status status = db->Write(leveldb::WriteOptions(), &batch);
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(SYNC_STATUS_OK, LevelDBStatusToSyncStatusCode(status));
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Migrate the database.
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MigrateDatabaseFromV4ToV3(db.get());
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Verify DB schema verison
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyKeyAndValue(kDatabaseVersionKey, "3", db.get());
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Verify remained entries.
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyKeyAndValue(kServiceMetadataKey, "service_metadata", db.get());
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyKeyAndValue(kFileMetadataKeyPrefix, "file_metadata", db.get());
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyKeyAndValue(kFileTrackerKeyPrefix, "file_tracker", db.get());
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Verify
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kAppRootIDByAppIDKeyPrefix, db.get());
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kActiveTrackerIDByFileIDKeyPrefix, db.get());
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kTrackerIDByFileIDKeyPrefix, db.get());
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kMultiTrackerByFileIDKeyPrefix, db.get());
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kActiveTrackerIDByParentAndTitleKeyPrefix, db.get());
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kTrackerIDByParentAndTitleKeyPrefix, db.get());
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kMultiBackingParentAndTitleKeyPrefix, db.get());
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kDirtyIDKeyPrefix, db.get());
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyNotExist(kDemotedDirtyIDKeyPrefix, db.get());
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive_backend
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace sync_file_system
125