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.
5 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/format_macros.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/drive/drive_uploader.h"
13 #include "chrome/browser/drive/fake_drive_service.h"
14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
15 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
16 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
18 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
19 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
20 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "google_apis/drive/gdata_wapi_parser.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/leveldatabase/src/include/leveldb/db.h"
25 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
27 namespace sync_file_system
{
28 namespace drive_backend
{
31 const int64 kSyncRootTrackerID
= 100;
34 class RegisterAppTaskTest
: public testing::Test
,
35 public SyncEngineContext
{
38 : next_file_id_(1000),
39 next_tracker_id_(10000) {}
40 virtual ~RegisterAppTaskTest() {}
42 virtual void SetUp() OVERRIDE
{
43 ASSERT_TRUE(database_dir_
.CreateUniqueTempDir());
45 fake_drive_service_
.reset(new drive::FakeDriveService
);
46 ASSERT_TRUE(fake_drive_service_
->LoadAccountMetadataForWapi(
47 "sync_file_system/account_metadata.json"));
48 ASSERT_TRUE(fake_drive_service_
->LoadResourceListForWapi(
49 "gdata/empty_feed.json"));
51 drive_uploader_
.reset(new drive::DriveUploader(
52 fake_drive_service_
.get(), base::MessageLoopProxy::current()));
54 fake_drive_service_helper_
.reset(new FakeDriveServiceHelper(
55 fake_drive_service_
.get(), drive_uploader_
.get(),
56 kSyncRootFolderTitle
));
58 ASSERT_EQ(google_apis::HTTP_CREATED
,
59 fake_drive_service_helper_
->AddOrphanedFolder(
60 kSyncRootFolderTitle
, &sync_root_folder_id_
));
63 virtual void TearDown() OVERRIDE
{
64 metadata_database_
.reset();
65 base::RunLoop().RunUntilIdle();
68 virtual drive::DriveServiceInterface
* GetDriveService() OVERRIDE
{
69 return fake_drive_service_
.get();
72 virtual drive::DriveUploaderInterface
* GetDriveUploader() OVERRIDE
{
76 virtual MetadataDatabase
* GetMetadataDatabase() OVERRIDE
{
77 return metadata_database_
.get();
80 virtual RemoteChangeProcessor
* GetRemoteChangeProcessor() OVERRIDE
{
84 virtual base::SequencedTaskRunner
* GetBlockingTaskRunner() OVERRIDE
{
85 return base::MessageLoopProxy::current();
89 scoped_ptr
<leveldb::DB
> OpenLevelDB() {
90 leveldb::DB
* db
= NULL
;
91 leveldb::Options options
;
92 options
.create_if_missing
= true;
93 leveldb::Status status
=
94 leveldb::DB::Open(options
, database_dir_
.path().AsUTF8Unsafe(), &db
);
95 EXPECT_TRUE(status
.ok());
96 return make_scoped_ptr
<leveldb::DB
>(db
);
99 void SetUpInitialData(leveldb::DB
* db
) {
100 ServiceMetadata service_metadata
;
101 service_metadata
.set_largest_change_id(100);
102 service_metadata
.set_sync_root_tracker_id(kSyncRootTrackerID
);
103 service_metadata
.set_next_tracker_id(next_tracker_id_
);
105 FileDetails sync_root_details
;
106 sync_root_details
.set_title(kSyncRootFolderTitle
);
107 sync_root_details
.set_file_kind(FILE_KIND_FOLDER
);
108 sync_root_details
.set_change_id(1);
110 FileMetadata sync_root_metadata
;
111 sync_root_metadata
.set_file_id(sync_root_folder_id_
);
112 *sync_root_metadata
.mutable_details() = sync_root_details
;
114 FileTracker sync_root_tracker
;
115 sync_root_tracker
.set_tracker_id(service_metadata
.sync_root_tracker_id());
116 sync_root_tracker
.set_parent_tracker_id(0);
117 sync_root_tracker
.set_file_id(sync_root_metadata
.file_id());
118 sync_root_tracker
.set_tracker_kind(TRACKER_KIND_REGULAR
);
119 *sync_root_tracker
.mutable_synced_details() = sync_root_details
;
120 sync_root_tracker
.set_active(true);
122 leveldb::WriteBatch batch
;
123 batch
.Put(kDatabaseVersionKey
,
124 base::Int64ToString(kCurrentDatabaseVersion
));
125 PutServiceMetadataToBatch(service_metadata
, &batch
);
126 PutFileToBatch(sync_root_metadata
, &batch
);
127 PutTrackerToBatch(sync_root_tracker
, &batch
);
128 EXPECT_TRUE(db
->Write(leveldb::WriteOptions(), &batch
).ok());
131 void CreateMetadataDatabase(scoped_ptr
<leveldb::DB
> db
) {
133 ASSERT_FALSE(metadata_database_
);
134 ASSERT_EQ(SYNC_STATUS_OK
,
135 MetadataDatabase::CreateForTesting(
136 db
.Pass(), &metadata_database_
));
139 SyncStatusCode
RunRegisterAppTask(const std::string
& app_id
) {
140 RegisterAppTask
task(this, app_id
);
141 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
142 task
.Run(CreateResultReceiver(&status
));
143 base::RunLoop().RunUntilIdle();
147 void SetUpRegisteredAppRoot(
148 const std::string
& app_id
,
151 details
.set_title(app_id
);
152 details
.set_file_kind(FILE_KIND_FOLDER
);
153 details
.add_parent_folder_ids(sync_root_folder_id_
);
155 FileMetadata metadata
;
156 metadata
.set_file_id(GenerateFileID());
157 *metadata
.mutable_details() = details
;
160 tracker
.set_parent_tracker_id(kSyncRootTrackerID
);
161 tracker
.set_tracker_id(next_tracker_id_
++);
162 tracker
.set_file_id(metadata
.file_id());
163 tracker
.set_tracker_kind(TRACKER_KIND_APP_ROOT
);
164 tracker
.set_app_id(app_id
);
165 *tracker
.mutable_synced_details() = details
;
166 tracker
.set_active(true);
168 leveldb::WriteBatch batch
;
169 PutFileToBatch(metadata
, &batch
);
170 PutTrackerToBatch(tracker
, &batch
);
171 EXPECT_TRUE(db
->Write(leveldb::WriteOptions(), &batch
).ok());
174 void SetUpUnregisteredAppRoot(const std::string
& app_id
,
177 details
.set_title(app_id
);
178 details
.set_file_kind(FILE_KIND_FOLDER
);
179 details
.add_parent_folder_ids(sync_root_folder_id_
);
181 FileMetadata metadata
;
182 metadata
.set_file_id(GenerateFileID());
183 *metadata
.mutable_details() = details
;
186 tracker
.set_parent_tracker_id(kSyncRootTrackerID
);
187 tracker
.set_tracker_id(next_tracker_id_
++);
188 tracker
.set_file_id(metadata
.file_id());
189 tracker
.set_tracker_kind(TRACKER_KIND_REGULAR
);
190 *tracker
.mutable_synced_details() = details
;
191 tracker
.set_active(false);
193 leveldb::WriteBatch batch
;
194 PutFileToBatch(metadata
, &batch
);
195 PutTrackerToBatch(tracker
, &batch
);
196 EXPECT_TRUE(db
->Write(leveldb::WriteOptions(), &batch
).ok());
199 size_t CountRegisteredAppRoot() {
200 // TODO(tzik): Add function to MetadataDatabase to list trackers by parent.
201 typedef MetadataDatabase::TrackersByTitle TrackersByTitle
;
202 const TrackersByTitle
& trackers_by_title
=
203 metadata_database_
->trackers_by_parent_and_title_
[kSyncRootTrackerID
];
206 for (TrackersByTitle::const_iterator itr
= trackers_by_title
.begin();
207 itr
!= trackers_by_title
.end(); ++itr
) {
208 if (itr
->second
.has_active())
215 bool IsAppRegistered(const std::string
& app_id
) {
217 if (!metadata_database_
->FindTrackersByParentAndTitle(
218 kSyncRootTrackerID
, app_id
, &trackers
))
220 return trackers
.has_active();
223 size_t CountRemoteFileInSyncRoot() {
224 ScopedVector
<google_apis::ResourceEntry
> files
;
225 EXPECT_EQ(google_apis::HTTP_SUCCESS
,
226 fake_drive_service_helper_
->ListFilesInFolder(
227 sync_root_folder_id_
, &files
));
231 bool HasRemoteAppRoot(const std::string
& app_id
) {
233 if (!metadata_database_
->FindTrackersByParentAndTitle(
234 kSyncRootTrackerID
, app_id
, &files
) ||
238 std::string app_root_folder_id
= files
.active_tracker()->file_id();
239 scoped_ptr
<google_apis::ResourceEntry
> entry
;
240 if (google_apis::HTTP_SUCCESS
!=
241 fake_drive_service_helper_
->GetResourceEntry(
242 app_root_folder_id
, &entry
))
245 return !entry
->deleted();
249 std::string
GenerateFileID() {
250 return base::StringPrintf("file_id_%" PRId64
, next_file_id_
++);
253 std::string sync_root_folder_id_
;
256 int64 next_tracker_id_
;
258 content::TestBrowserThreadBundle browser_threads_
;
259 base::ScopedTempDir database_dir_
;
261 scoped_ptr
<drive::FakeDriveService
> fake_drive_service_
;
262 scoped_ptr
<drive::DriveUploader
> drive_uploader_
;
263 scoped_ptr
<FakeDriveServiceHelper
> fake_drive_service_helper_
;
265 scoped_ptr
<MetadataDatabase
> metadata_database_
;
267 DISALLOW_COPY_AND_ASSIGN(RegisterAppTaskTest
);
270 TEST_F(RegisterAppTaskTest
, AlreadyRegistered
) {
271 scoped_ptr
<leveldb::DB
> db(OpenLevelDB());
273 SetUpInitialData(db
.get());
275 const std::string kAppID
= "app_id";
276 SetUpRegisteredAppRoot(kAppID
, db
.get());
278 CreateMetadataDatabase(db
.Pass());
279 EXPECT_EQ(SYNC_STATUS_OK
, RunRegisterAppTask(kAppID
));
281 EXPECT_EQ(1u, CountRegisteredAppRoot());
282 EXPECT_TRUE(IsAppRegistered(kAppID
));
285 TEST_F(RegisterAppTaskTest
, CreateAppFolder
) {
286 scoped_ptr
<leveldb::DB
> db(OpenLevelDB());
288 SetUpInitialData(db
.get());
290 const std::string kAppID
= "app_id";
291 CreateMetadataDatabase(db
.Pass());
292 RunRegisterAppTask(kAppID
);
294 EXPECT_EQ(1u, CountRegisteredAppRoot());
295 EXPECT_TRUE(IsAppRegistered(kAppID
));
297 EXPECT_EQ(1u, CountRemoteFileInSyncRoot());
298 EXPECT_TRUE(HasRemoteAppRoot(kAppID
));
301 TEST_F(RegisterAppTaskTest
, RegisterExistingFolder
) {
302 scoped_ptr
<leveldb::DB
> db(OpenLevelDB());
304 SetUpInitialData(db
.get());
306 const std::string kAppID
= "app_id";
307 SetUpUnregisteredAppRoot(kAppID
, db
.get());
309 CreateMetadataDatabase(db
.Pass());
310 RunRegisterAppTask(kAppID
);
312 EXPECT_EQ(1u, CountRegisteredAppRoot());
313 EXPECT_TRUE(IsAppRegistered(kAppID
));
316 TEST_F(RegisterAppTaskTest
, RegisterExistingFolder_MultipleCandidate
) {
317 scoped_ptr
<leveldb::DB
> db(OpenLevelDB());
319 SetUpInitialData(db
.get());
321 const std::string kAppID
= "app_id";
322 SetUpUnregisteredAppRoot(kAppID
, db
.get());
323 SetUpUnregisteredAppRoot(kAppID
, db
.get());
325 CreateMetadataDatabase(db
.Pass());
326 RunRegisterAppTask(kAppID
);
328 EXPECT_EQ(1u, CountRegisteredAppRoot());
329 EXPECT_TRUE(IsAppRegistered(kAppID
));
332 } // namespace drive_backend
333 } // namespace sync_file_system