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/list_changes_task.h"
6 
7 #include <stddef.h>
8 #include <string>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/format_macros.h"
14 #include "base/macros.h"
15 #include "base/run_loop.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
18 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
19 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
20 #include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
21 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
22 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
23 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
24 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
25 #include "content/public/test/browser_task_environment.h"
26 #include "google_apis/drive/drive_api_parser.h"
27 #include "mojo/public/cpp/bindings/pending_remote.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "third_party/leveldatabase/leveldb_chrome.h"
30 
31 namespace sync_file_system {
32 namespace drive_backend {
33 
34 namespace {
35 
36 const char kAppID[] = "app_id";
37 const char kUnregisteredAppID[] = "app_id unregistered";
38 
39 }  // namespace
40 
41 class ListChangesTaskTest : public testing::Test {
42  public:
ListChangesTaskTest()43   ListChangesTaskTest()
44       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
~ListChangesTaskTest()45   ~ListChangesTaskTest() override {}
46 
SetUp()47   void SetUp() override {
48     ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
49     in_memory_env_ = leveldb_chrome::NewMemEnv("ListChangesTaskTest");
50 
51     std::unique_ptr<drive::FakeDriveService> fake_drive_service(
52         new drive::FakeDriveService);
53 
54     std::unique_ptr<drive::DriveUploaderInterface> drive_uploader(
55         new drive::DriveUploader(fake_drive_service.get(),
56                                  base::ThreadTaskRunnerHandle::Get(),
57                                  mojo::NullRemote()));
58 
59     fake_drive_service_helper_.reset(
60         new FakeDriveServiceHelper(fake_drive_service.get(),
61                                    drive_uploader.get(),
62                                    kSyncRootFolderTitle));
63 
64     sync_task_manager_.reset(new SyncTaskManager(
65         base::WeakPtr<SyncTaskManager::Client>(),
66         10 /* maximum_background_task */, base::ThreadTaskRunnerHandle::Get()));
67     sync_task_manager_->Initialize(SYNC_STATUS_OK);
68 
69     context_.reset(new SyncEngineContext(
70         std::move(fake_drive_service), std::move(drive_uploader),
71         nullptr /* task_logger */, base::ThreadTaskRunnerHandle::Get(),
72         base::ThreadTaskRunnerHandle::Get()));
73 
74     SetUpRemoteFolders();
75 
76     InitializeMetadataDatabase();
77     RegisterApp(kAppID);
78   }
79 
TearDown()80   void TearDown() override {
81     sync_task_manager_.reset();
82     context_.reset();
83     base::RunLoop().RunUntilIdle();
84   }
85 
86  protected:
RunTask(std::unique_ptr<SyncTask> sync_task)87   SyncStatusCode RunTask(std::unique_ptr<SyncTask> sync_task) {
88     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
89     sync_task_manager_->ScheduleSyncTask(FROM_HERE, std::move(sync_task),
90                                          SyncTaskManager::PRIORITY_MED,
91                                          CreateResultReceiver(&status));
92     base::RunLoop().RunUntilIdle();
93     return status;
94   }
95 
CountDirtyTracker()96   size_t CountDirtyTracker() {
97     return context_->GetMetadataDatabase()->CountDirtyTracker();
98   }
99 
fake_drive_service_helper()100   FakeDriveServiceHelper* fake_drive_service_helper() {
101     return fake_drive_service_helper_.get();
102   }
103 
SetUpChangesInFolder(const std::string & folder_id)104   void SetUpChangesInFolder(const std::string& folder_id) {
105     std::string new_file_id;
106     ASSERT_EQ(google_apis::HTTP_SUCCESS,
107               fake_drive_service_helper()->AddFile(
108                   folder_id, "new file", "file contents", &new_file_id));
109     std::string same_name_file_id;
110     ASSERT_EQ(google_apis::HTTP_SUCCESS,
111               fake_drive_service_helper()->AddFile(
112                   folder_id, "new file", "file contents",
113                   &same_name_file_id));
114 
115     std::string new_folder_id;
116     ASSERT_EQ(google_apis::HTTP_CREATED,
117               fake_drive_service_helper()->AddFolder(
118                   folder_id, "new folder", &new_folder_id));
119 
120     std::string modified_file_id;
121     ASSERT_EQ(google_apis::HTTP_SUCCESS,
122               fake_drive_service_helper()->AddFile(
123                   folder_id, "modified file", "file content",
124                   &modified_file_id));
125     ASSERT_EQ(google_apis::HTTP_SUCCESS,
126               fake_drive_service_helper()->UpdateFile(
127                   modified_file_id, "modified file content"));
128 
129 
130     std::string deleted_file_id;
131     ASSERT_EQ(google_apis::HTTP_SUCCESS,
132               fake_drive_service_helper()->AddFile(
133                   folder_id, "trashed file", "file content",
134                   &deleted_file_id));
135     ASSERT_EQ(google_apis::HTTP_NO_CONTENT,
136               fake_drive_service_helper()->DeleteResource(deleted_file_id));
137   }
138 
root_resource_id()139   std::string root_resource_id() {
140     return context_->GetDriveService()->GetRootResourceId();
141   }
142 
app_root_folder_id()143   std::string app_root_folder_id() {
144     return app_root_folder_id_;
145   }
146 
unregistered_app_root_folder_id()147   std::string unregistered_app_root_folder_id() {
148     return unregistered_app_root_folder_id_;
149   }
150 
GetSyncEngineContext()151   SyncEngineContext* GetSyncEngineContext() {
152     return context_.get();
153   }
154 
155  private:
SetUpRemoteFolders()156   void SetUpRemoteFolders() {
157     ASSERT_EQ(google_apis::HTTP_CREATED,
158               fake_drive_service_helper_->AddOrphanedFolder(
159                   kSyncRootFolderTitle, &sync_root_folder_id_));
160     ASSERT_EQ(google_apis::HTTP_CREATED,
161               fake_drive_service_helper_->AddFolder(
162                   sync_root_folder_id_, kAppID, &app_root_folder_id_));
163     ASSERT_EQ(google_apis::HTTP_CREATED,
164               fake_drive_service_helper_->AddFolder(
165                   sync_root_folder_id_, kUnregisteredAppID,
166                   &unregistered_app_root_folder_id_));
167   }
168 
InitializeMetadataDatabase()169   void InitializeMetadataDatabase() {
170     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
171     SyncEngineInitializer* initializer = new SyncEngineInitializer(
172         context_.get(), database_dir_.GetPath(), in_memory_env_.get());
173 
174     sync_task_manager_->ScheduleSyncTask(
175         FROM_HERE, std::unique_ptr<SyncTask>(initializer),
176         SyncTaskManager::PRIORITY_MED,
177         base::Bind(&ListChangesTaskTest::DidInitializeMetadataDatabase,
178                    base::Unretained(this), initializer, &status));
179 
180     base::RunLoop().RunUntilIdle();
181 
182     EXPECT_EQ(SYNC_STATUS_OK, status);
183   }
184 
DidInitializeMetadataDatabase(SyncEngineInitializer * initializer,SyncStatusCode * status_out,SyncStatusCode status)185   void DidInitializeMetadataDatabase(SyncEngineInitializer* initializer,
186                                      SyncStatusCode* status_out,
187                                      SyncStatusCode status) {
188     context_->SetMetadataDatabase(initializer->PassMetadataDatabase());
189     *status_out = status;
190   }
191 
RegisterApp(const std::string & app_id)192   void RegisterApp(const std::string& app_id) {
193     EXPECT_EQ(SYNC_STATUS_OK,
194               RunTask(std::unique_ptr<SyncTask>(
195                   new RegisterAppTask(context_.get(), app_id))));
196   }
197 
198   std::unique_ptr<leveldb::Env> in_memory_env_;
199 
200   std::string sync_root_folder_id_;
201   std::string app_root_folder_id_;
202   std::string unregistered_app_root_folder_id_;
203 
204   content::BrowserTaskEnvironment task_environment_;
205   base::ScopedTempDir database_dir_;
206 
207   std::unique_ptr<SyncEngineContext> context_;
208   std::unique_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
209 
210   std::unique_ptr<SyncTaskManager> sync_task_manager_;
211 
212   DISALLOW_COPY_AND_ASSIGN(ListChangesTaskTest);
213 };
214 
TEST_F(ListChangesTaskTest,NoChange)215 TEST_F(ListChangesTaskTest, NoChange) {
216   size_t num_dirty_trackers = CountDirtyTracker();
217 
218   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC,
219             RunTask(std::unique_ptr<SyncTask>(
220                 new ListChangesTask(GetSyncEngineContext()))));
221 
222   EXPECT_EQ(num_dirty_trackers, CountDirtyTracker());
223 }
224 
TEST_F(ListChangesTaskTest,UnrelatedChange)225 TEST_F(ListChangesTaskTest, UnrelatedChange) {
226   size_t num_dirty_trackers = CountDirtyTracker();
227 
228   SetUpChangesInFolder(root_resource_id());
229   SetUpChangesInFolder(unregistered_app_root_folder_id());
230 
231   EXPECT_EQ(SYNC_STATUS_OK, RunTask(std::unique_ptr<SyncTask>(
232                                 new ListChangesTask(GetSyncEngineContext()))));
233 
234   EXPECT_EQ(num_dirty_trackers, CountDirtyTracker());
235 }
236 
TEST_F(ListChangesTaskTest,UnderTrackedFolder)237 TEST_F(ListChangesTaskTest, UnderTrackedFolder) {
238   size_t num_dirty_trackers = CountDirtyTracker();
239 
240   SetUpChangesInFolder(app_root_folder_id());
241 
242   EXPECT_EQ(SYNC_STATUS_OK, RunTask(std::unique_ptr<SyncTask>(
243                                 new ListChangesTask(GetSyncEngineContext()))));
244 
245   EXPECT_EQ(num_dirty_trackers + 4, CountDirtyTracker());
246 }
247 
TEST_F(ListChangesTaskTest,TeamDriveChangeInChangeList)248 TEST_F(ListChangesTaskTest, TeamDriveChangeInChangeList) {
249   size_t num_dirty_trackers = CountDirtyTracker();
250 
251   SetUpChangesInFolder(app_root_folder_id());
252 
253   // Adding a team drive will return a TeamDriveResource entry when the
254   // change list is retrieved.
255   fake_drive_service_helper()->AddTeamDrive("team_drive_id", "team_drive_name");
256 
257   EXPECT_EQ(SYNC_STATUS_OK, RunTask(std::unique_ptr<SyncTask>(
258                                 new ListChangesTask(GetSyncEngineContext()))));
259 
260   EXPECT_EQ(num_dirty_trackers + 4, CountDirtyTracker());
261 }
262 
263 }  // namespace drive_backend
264 }  // namespace sync_file_system
265