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