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/register_app_task.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <utility>
11 #include <vector>
12
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/format_macros.h"
15 #include "base/macros.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
21 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
22 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
23 #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
24 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
25 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
26 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
27 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
28 #include "components/drive/drive_uploader.h"
29 #include "components/drive/service/fake_drive_service.h"
30 #include "content/public/test/browser_task_environment.h"
31 #include "google_apis/drive/drive_api_parser.h"
32 #include "mojo/public/cpp/bindings/pending_remote.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "third_party/leveldatabase/env_chromium.h"
35 #include "third_party/leveldatabase/leveldb_chrome.h"
36 #include "third_party/leveldatabase/src/include/leveldb/db.h"
37
38 namespace sync_file_system {
39 namespace drive_backend {
40
41 namespace {
42 const int64_t kSyncRootTrackerID = 100;
43 } // namespace
44
45 class RegisterAppTaskTest : public testing::Test {
46 public:
RegisterAppTaskTest()47 RegisterAppTaskTest()
48 : next_file_id_(1000),
49 next_tracker_id_(10000) {}
~RegisterAppTaskTest()50 ~RegisterAppTaskTest() override {}
51
SetUp()52 void SetUp() override {
53 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
54 in_memory_env_ = leveldb_chrome::NewMemEnv("RegisterAppTaskTest");
55
56 std::unique_ptr<drive::FakeDriveService> fake_drive_service(
57 new drive::FakeDriveService);
58 std::unique_ptr<drive::DriveUploaderInterface> drive_uploader(
59 new drive::DriveUploader(fake_drive_service.get(),
60 base::ThreadTaskRunnerHandle::Get(),
61 mojo::NullRemote()));
62
63 fake_drive_service_helper_.reset(new FakeDriveServiceHelper(
64 fake_drive_service.get(), drive_uploader.get(),
65 kSyncRootFolderTitle));
66
67 context_.reset(new SyncEngineContext(
68 std::move(fake_drive_service), std::move(drive_uploader),
69 nullptr /* task_logger */, base::ThreadTaskRunnerHandle::Get(),
70 base::ThreadTaskRunnerHandle::Get()));
71
72 ASSERT_EQ(google_apis::HTTP_CREATED,
73 fake_drive_service_helper_->AddOrphanedFolder(
74 kSyncRootFolderTitle, &sync_root_folder_id_));
75 }
76
TearDown()77 void TearDown() override {
78 context_.reset();
79 base::RunLoop().RunUntilIdle();
80 }
81
82 protected:
OpenLevelDB()83 std::unique_ptr<LevelDBWrapper> OpenLevelDB() {
84 std::unique_ptr<leveldb::DB> db;
85 leveldb_env::Options options;
86 options.create_if_missing = true;
87 options.env = in_memory_env_.get();
88 leveldb::Status status = leveldb_env::OpenDB(
89 options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
90 EXPECT_TRUE(status.ok());
91 return std::make_unique<LevelDBWrapper>(std::move(db));
92 }
93
SetUpInitialData(LevelDBWrapper * db)94 void SetUpInitialData(LevelDBWrapper* db) {
95 ServiceMetadata service_metadata;
96 service_metadata.set_largest_change_id(100);
97 service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
98 service_metadata.set_next_tracker_id(next_tracker_id_);
99
100 FileDetails sync_root_details;
101 sync_root_details.set_title(kSyncRootFolderTitle);
102 sync_root_details.set_file_kind(FILE_KIND_FOLDER);
103 sync_root_details.set_change_id(1);
104
105 FileMetadata sync_root_metadata;
106 sync_root_metadata.set_file_id(sync_root_folder_id_);
107 *sync_root_metadata.mutable_details() = sync_root_details;
108
109 FileTracker sync_root_tracker;
110 sync_root_tracker.set_tracker_id(service_metadata.sync_root_tracker_id());
111 sync_root_tracker.set_parent_tracker_id(0);
112 sync_root_tracker.set_file_id(sync_root_metadata.file_id());
113 sync_root_tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
114 *sync_root_tracker.mutable_synced_details() = sync_root_details;
115 sync_root_tracker.set_active(true);
116
117 db->Put(kDatabaseVersionKey, base::NumberToString(kCurrentDatabaseVersion));
118 PutServiceMetadataToDB(service_metadata, db);
119 PutFileMetadataToDB(sync_root_metadata, db);
120 PutFileTrackerToDB(sync_root_tracker, db);
121 EXPECT_TRUE(db->Commit().ok());
122 }
123
CreateMetadataDatabase(std::unique_ptr<LevelDBWrapper> db)124 void CreateMetadataDatabase(std::unique_ptr<LevelDBWrapper> db) {
125 ASSERT_TRUE(db);
126 ASSERT_FALSE(context_->GetMetadataDatabase());
127 std::unique_ptr<MetadataDatabase> metadata_db;
128 ASSERT_EQ(
129 SYNC_STATUS_OK,
130 MetadataDatabase::CreateForTesting(
131 std::move(db), true /* enable_on_disk_index */, &metadata_db));
132 context_->SetMetadataDatabase(std::move(metadata_db));
133 }
134
RunRegisterAppTask(const std::string & app_id)135 SyncStatusCode RunRegisterAppTask(const std::string& app_id) {
136 RegisterAppTask task(context_.get(), app_id);
137 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
138 task.RunExclusive(CreateResultReceiver(&status));
139 base::RunLoop().RunUntilIdle();
140 return status;
141 }
142
SetUpRegisteredAppRoot(const std::string & app_id,LevelDBWrapper * db)143 void SetUpRegisteredAppRoot(
144 const std::string& app_id,
145 LevelDBWrapper* db) {
146 FileDetails details;
147 details.set_title(app_id);
148 details.set_file_kind(FILE_KIND_FOLDER);
149 details.add_parent_folder_ids(sync_root_folder_id_);
150
151 FileMetadata metadata;
152 metadata.set_file_id(GenerateFileID());
153 *metadata.mutable_details() = details;
154
155 FileTracker tracker;
156 tracker.set_parent_tracker_id(kSyncRootTrackerID);
157 tracker.set_tracker_id(next_tracker_id_++);
158 tracker.set_file_id(metadata.file_id());
159 tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
160 tracker.set_app_id(app_id);
161 *tracker.mutable_synced_details() = details;
162 tracker.set_active(true);
163
164 PutFileMetadataToDB(metadata, db);
165 PutFileTrackerToDB(tracker, db);
166 EXPECT_TRUE(db->Commit().ok());
167 }
168
SetUpUnregisteredAppRoot(const std::string & app_id,LevelDBWrapper * db)169 void SetUpUnregisteredAppRoot(const std::string& app_id,
170 LevelDBWrapper* db) {
171 FileDetails details;
172 details.set_title(app_id);
173 details.set_file_kind(FILE_KIND_FOLDER);
174 details.add_parent_folder_ids(sync_root_folder_id_);
175
176 FileMetadata metadata;
177 metadata.set_file_id(GenerateFileID());
178 *metadata.mutable_details() = details;
179
180 FileTracker tracker;
181 tracker.set_parent_tracker_id(kSyncRootTrackerID);
182 tracker.set_tracker_id(next_tracker_id_++);
183 tracker.set_file_id(metadata.file_id());
184 tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
185 *tracker.mutable_synced_details() = details;
186 tracker.set_active(false);
187
188 PutFileMetadataToDB(metadata, db);
189 PutFileTrackerToDB(tracker, db);
190 EXPECT_TRUE(db->Commit().ok());
191 }
192
CountRegisteredAppRoot()193 size_t CountRegisteredAppRoot() {
194 std::vector<std::string> app_ids;
195 context_->GetMetadataDatabase()->GetRegisteredAppIDs(&app_ids);
196 return app_ids.size();
197 }
198
IsAppRegistered(const std::string & app_id)199 bool IsAppRegistered(const std::string& app_id) {
200 TrackerIDSet trackers;
201 if (!context_->GetMetadataDatabase()->FindTrackersByParentAndTitle(
202 kSyncRootTrackerID, app_id, &trackers))
203 return false;
204 return trackers.has_active();
205 }
206
CountRemoteFileInSyncRoot()207 size_t CountRemoteFileInSyncRoot() {
208 std::vector<std::unique_ptr<google_apis::FileResource>> files;
209 EXPECT_EQ(google_apis::HTTP_SUCCESS,
210 fake_drive_service_helper_->ListFilesInFolder(
211 sync_root_folder_id_, &files));
212 return files.size();
213 }
214
GetAppRootFolderID(const std::string & app_id,std::string * app_root_folder_id)215 bool GetAppRootFolderID(const std::string& app_id,
216 std::string* app_root_folder_id) {
217 TrackerIDSet files;
218 if (!context_->GetMetadataDatabase()->FindTrackersByParentAndTitle(
219 kSyncRootTrackerID, app_id, &files) ||
220 !files.has_active())
221 return false;
222
223 FileTracker app_root_tracker;
224 EXPECT_TRUE(context_->GetMetadataDatabase()->FindTrackerByTrackerID(
225 files.active_tracker(), &app_root_tracker));
226 *app_root_folder_id = app_root_tracker.file_id();
227 return true;
228 }
229
HasRemoteAppRoot(const std::string & app_id)230 bool HasRemoteAppRoot(const std::string& app_id) {
231 std::string app_root_folder_id;
232 if (!GetAppRootFolderID(app_id, &app_root_folder_id))
233 return false;
234
235 std::unique_ptr<google_apis::FileResource> entry;
236 if (google_apis::HTTP_SUCCESS !=
237 fake_drive_service_helper_->GetFileResource(app_root_folder_id, &entry))
238 return false;
239
240 return !entry->labels().is_trashed();
241 }
242
VerifyRemoteAppRootVisibility(const std::string & app_id)243 bool VerifyRemoteAppRootVisibility(const std::string& app_id) {
244 std::string app_root_folder_id;
245 if (!GetAppRootFolderID(app_id, &app_root_folder_id))
246 return false;
247
248 google_apis::drive::FileVisibility visibility;
249 if (google_apis::HTTP_SUCCESS !=
250 fake_drive_service_helper_->GetFileVisibility(
251 app_root_folder_id, &visibility))
252 return false;
253 if (visibility != google_apis::drive::FILE_VISIBILITY_PRIVATE)
254 return false;
255
256 return true;
257 }
258
259 private:
GenerateFileID()260 std::string GenerateFileID() {
261 return base::StringPrintf("file_id_%" PRId64, next_file_id_++);
262 }
263
264 std::unique_ptr<leveldb::Env> in_memory_env_;
265
266 std::string sync_root_folder_id_;
267
268 int64_t next_file_id_;
269 int64_t next_tracker_id_;
270
271 content::BrowserTaskEnvironment task_environment_;
272 base::ScopedTempDir database_dir_;
273
274 std::unique_ptr<SyncEngineContext> context_;
275 std::unique_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
276
277 DISALLOW_COPY_AND_ASSIGN(RegisterAppTaskTest);
278 };
279
TEST_F(RegisterAppTaskTest,AlreadyRegistered)280 TEST_F(RegisterAppTaskTest, AlreadyRegistered) {
281 std::unique_ptr<LevelDBWrapper> db = OpenLevelDB();
282 ASSERT_TRUE(db);
283 SetUpInitialData(db.get());
284
285 const std::string kAppID = "app_id";
286 SetUpRegisteredAppRoot(kAppID, db.get());
287
288 CreateMetadataDatabase(std::move(db));
289 EXPECT_EQ(SYNC_STATUS_OK, RunRegisterAppTask(kAppID));
290
291 EXPECT_EQ(1u, CountRegisteredAppRoot());
292 EXPECT_TRUE(IsAppRegistered(kAppID));
293 }
294
TEST_F(RegisterAppTaskTest,CreateAppFolder)295 TEST_F(RegisterAppTaskTest, CreateAppFolder) {
296 std::unique_ptr<LevelDBWrapper> db = OpenLevelDB();
297 ASSERT_TRUE(db);
298 SetUpInitialData(db.get());
299
300 const std::string kAppID = "app_id";
301 CreateMetadataDatabase(std::move(db));
302 RunRegisterAppTask(kAppID);
303
304 EXPECT_EQ(1u, CountRegisteredAppRoot());
305 EXPECT_TRUE(IsAppRegistered(kAppID));
306
307 EXPECT_EQ(1u, CountRemoteFileInSyncRoot());
308 EXPECT_TRUE(HasRemoteAppRoot(kAppID));
309 EXPECT_TRUE(VerifyRemoteAppRootVisibility(kAppID));
310 }
311
TEST_F(RegisterAppTaskTest,RegisterExistingFolder)312 TEST_F(RegisterAppTaskTest, RegisterExistingFolder) {
313 std::unique_ptr<LevelDBWrapper> db = OpenLevelDB();
314 ASSERT_TRUE(db);
315 SetUpInitialData(db.get());
316
317 const std::string kAppID = "app_id";
318 SetUpUnregisteredAppRoot(kAppID, db.get());
319
320 CreateMetadataDatabase(std::move(db));
321 RunRegisterAppTask(kAppID);
322
323 EXPECT_EQ(1u, CountRegisteredAppRoot());
324 EXPECT_TRUE(IsAppRegistered(kAppID));
325 }
326
TEST_F(RegisterAppTaskTest,RegisterExistingFolder_MultipleCandidate)327 TEST_F(RegisterAppTaskTest, RegisterExistingFolder_MultipleCandidate) {
328 std::unique_ptr<LevelDBWrapper> db = OpenLevelDB();
329 ASSERT_TRUE(db);
330 SetUpInitialData(db.get());
331
332 const std::string kAppID = "app_id";
333 SetUpUnregisteredAppRoot(kAppID, db.get());
334 SetUpUnregisteredAppRoot(kAppID, db.get());
335
336 CreateMetadataDatabase(std::move(db));
337 RunRegisterAppTask(kAppID);
338
339 EXPECT_EQ(1u, CountRegisteredAppRoot());
340 EXPECT_TRUE(IsAppRegistered(kAppID));
341 }
342
343 } // namespace drive_backend
344 } // namespace sync_file_system
345