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/chromeos/drive/change_list_loader.h"
7 #include "base/callback_helpers.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/testing_pref_service.h"
11 #include "base/run_loop.h"
12 #include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
13 #include "chrome/browser/chromeos/drive/file_cache.h"
14 #include "chrome/browser/chromeos/drive/file_change.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/drive/job_scheduler.h"
17 #include "chrome/browser/chromeos/drive/resource_metadata.h"
18 #include "chrome/browser/chromeos/drive/test_util.h"
19 #include "chrome/browser/drive/event_logger.h"
20 #include "chrome/browser/drive/fake_drive_service.h"
21 #include "chrome/browser/drive/test_util.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "google_apis/drive/drive_api_parser.h"
24 #include "google_apis/drive/test_util.h"
25 #include "testing/gtest/include/gtest/gtest.h"
30 class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
32 explicit TestChangeListLoaderObserver(ChangeListLoader* loader)
34 load_from_server_complete_count_(0),
35 initial_load_complete_count_(0) {
36 loader_->AddObserver(this);
39 virtual ~TestChangeListLoaderObserver() {
40 loader_->RemoveObserver(this);
43 const FileChange& changed_files() const { return changed_files_; }
44 void clear_changed_files() { changed_files_.ClearForTest(); }
46 int load_from_server_complete_count() const {
47 return load_from_server_complete_count_;
49 int initial_load_complete_count() const {
50 return initial_load_complete_count_;
53 // ChageListObserver overrides:
54 virtual void OnFileChanged(const FileChange& changed_files) override {
55 changed_files_.Apply(changed_files);
57 virtual void OnLoadFromServerComplete() override {
58 ++load_from_server_complete_count_;
60 virtual void OnInitialLoadComplete() override {
61 ++initial_load_complete_count_;
65 ChangeListLoader* loader_;
66 FileChange changed_files_;
67 int load_from_server_complete_count_;
68 int initial_load_complete_count_;
70 DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
73 class ChangeListLoaderTest : public testing::Test {
75 virtual void SetUp() override {
76 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
77 pref_service_.reset(new TestingPrefServiceSimple);
78 test_util::RegisterDrivePrefs(pref_service_->registry());
80 logger_.reset(new EventLogger);
82 drive_service_.reset(new FakeDriveService);
83 ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
85 scheduler_.reset(new JobScheduler(pref_service_.get(),
88 base::MessageLoopProxy::current().get()));
89 metadata_storage_.reset(new ResourceMetadataStorage(
90 temp_dir_.path(), base::MessageLoopProxy::current().get()));
91 ASSERT_TRUE(metadata_storage_->Initialize());
93 cache_.reset(new FileCache(metadata_storage_.get(),
95 base::MessageLoopProxy::current().get(),
96 NULL /* free_disk_space_getter */));
97 ASSERT_TRUE(cache_->Initialize());
99 metadata_.reset(new ResourceMetadata(
100 metadata_storage_.get(), cache_.get(),
101 base::MessageLoopProxy::current().get()));
102 ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
104 about_resource_loader_.reset(new AboutResourceLoader(scheduler_.get()));
105 loader_controller_.reset(new LoaderController);
106 change_list_loader_.reset(
107 new ChangeListLoader(logger_.get(),
108 base::MessageLoopProxy::current().get(),
111 about_resource_loader_.get(),
112 loader_controller_.get()));
115 // Adds a new file to the root directory of the service.
116 scoped_ptr<google_apis::FileResource> AddNewFile(const std::string& title) {
117 google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR;
118 scoped_ptr<google_apis::FileResource> entry;
119 drive_service_->AddNewFile(
122 drive_service_->GetRootResourceId(),
124 false, // shared_with_me
125 google_apis::test_util::CreateCopyResultCallback(&error, &entry));
126 base::RunLoop().RunUntilIdle();
127 EXPECT_EQ(google_apis::HTTP_CREATED, error);
131 content::TestBrowserThreadBundle thread_bundle_;
132 base::ScopedTempDir temp_dir_;
133 scoped_ptr<TestingPrefServiceSimple> pref_service_;
134 scoped_ptr<EventLogger> logger_;
135 scoped_ptr<FakeDriveService> drive_service_;
136 scoped_ptr<JobScheduler> scheduler_;
137 scoped_ptr<ResourceMetadataStorage,
138 test_util::DestroyHelperForTests> metadata_storage_;
139 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
140 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
141 scoped_ptr<AboutResourceLoader> about_resource_loader_;
142 scoped_ptr<LoaderController> loader_controller_;
143 scoped_ptr<ChangeListLoader> change_list_loader_;
146 TEST_F(ChangeListLoaderTest, AboutResourceLoader) {
147 google_apis::GDataErrorCode error[6] = {};
148 scoped_ptr<google_apis::AboutResource> about[6];
150 // No resource is cached at the beginning.
151 ASSERT_FALSE(about_resource_loader_->cached_about_resource());
153 // Since no resource is cached, this "Get" should trigger the update.
154 about_resource_loader_->GetAboutResource(
155 google_apis::test_util::CreateCopyResultCallback(error + 0, about + 0));
156 // Since there is one in-flight update, the next "Get" just wait for it.
157 about_resource_loader_->GetAboutResource(
158 google_apis::test_util::CreateCopyResultCallback(error + 1, about + 1));
160 base::RunLoop().RunUntilIdle();
161 EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]);
162 EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]);
163 const int64 first_changestamp = about[0]->largest_change_id();
164 EXPECT_EQ(first_changestamp, about[1]->largest_change_id());
165 ASSERT_TRUE(about_resource_loader_->cached_about_resource());
168 about_resource_loader_->cached_about_resource()->largest_change_id());
170 // Increment changestamp by 1.
172 // Explicitly calling UpdateAboutResource will start another API call.
173 about_resource_loader_->UpdateAboutResource(
174 google_apis::test_util::CreateCopyResultCallback(error + 2, about + 2));
175 // It again waits for the in-flight UpdateAboutResoure call, even though this
176 // time there is a cached result.
177 about_resource_loader_->GetAboutResource(
178 google_apis::test_util::CreateCopyResultCallback(error + 3, about + 3));
180 base::RunLoop().RunUntilIdle();
181 EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]);
182 EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]);
183 EXPECT_EQ(first_changestamp + 1, about[2]->largest_change_id());
184 EXPECT_EQ(first_changestamp + 1, about[3]->largest_change_id());
186 first_changestamp + 1,
187 about_resource_loader_->cached_about_resource()->largest_change_id());
189 // Increment changestamp by 1.
191 // Now no UpdateAboutResource task is running. Returns the cached result.
192 about_resource_loader_->GetAboutResource(
193 google_apis::test_util::CreateCopyResultCallback(error + 4, about + 4));
194 // Explicitly calling UpdateAboutResource will start another API call.
195 about_resource_loader_->UpdateAboutResource(
196 google_apis::test_util::CreateCopyResultCallback(error + 5, about + 5));
198 base::RunLoop().RunUntilIdle();
199 EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]);
200 EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]);
201 EXPECT_EQ(first_changestamp + 1, about[4]->largest_change_id());
202 EXPECT_EQ(first_changestamp + 2, about[5]->largest_change_id());
204 first_changestamp + 2,
205 about_resource_loader_->cached_about_resource()->largest_change_id());
207 EXPECT_EQ(3, drive_service_->about_resource_load_count());
210 TEST_F(ChangeListLoaderTest, Load) {
211 EXPECT_FALSE(change_list_loader_->IsRefreshing());
213 // Start initial load.
214 TestChangeListLoaderObserver observer(change_list_loader_.get());
216 EXPECT_EQ(0, drive_service_->about_resource_load_count());
218 FileError error = FILE_ERROR_FAILED;
219 change_list_loader_->LoadIfNeeded(
220 google_apis::test_util::CreateCopyResultCallback(&error));
221 EXPECT_TRUE(change_list_loader_->IsRefreshing());
222 base::RunLoop().RunUntilIdle();
223 EXPECT_EQ(FILE_ERROR_OK, error);
225 EXPECT_FALSE(change_list_loader_->IsRefreshing());
226 int64 changestamp = 0;
227 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
228 EXPECT_LT(0, changestamp);
229 EXPECT_EQ(1, drive_service_->file_list_load_count());
230 EXPECT_EQ(1, drive_service_->about_resource_load_count());
231 EXPECT_EQ(1, observer.initial_load_complete_count());
232 EXPECT_EQ(1, observer.load_from_server_complete_count());
233 EXPECT_TRUE(observer.changed_files().empty());
235 base::FilePath file_path =
236 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
238 EXPECT_EQ(FILE_ERROR_OK,
239 metadata_->GetResourceEntryByPath(file_path, &entry));
242 TEST_F(ChangeListLoaderTest, Load_LocalMetadataAvailable) {
244 FileError error = FILE_ERROR_FAILED;
245 change_list_loader_->LoadIfNeeded(
246 google_apis::test_util::CreateCopyResultCallback(&error));
247 base::RunLoop().RunUntilIdle();
248 EXPECT_EQ(FILE_ERROR_OK, error);
251 about_resource_loader_.reset(new AboutResourceLoader(scheduler_.get()));
252 change_list_loader_.reset(
253 new ChangeListLoader(logger_.get(),
254 base::MessageLoopProxy::current().get(),
257 about_resource_loader_.get(),
258 loader_controller_.get()));
260 // Add a file to the service.
261 scoped_ptr<google_apis::FileResource> gdata_entry = AddNewFile("New File");
262 ASSERT_TRUE(gdata_entry);
264 // Start loading. Because local metadata is available, the load results in
265 // returning FILE_ERROR_OK without fetching full list of resources.
266 const int previous_file_list_load_count =
267 drive_service_->file_list_load_count();
268 TestChangeListLoaderObserver observer(change_list_loader_.get());
270 change_list_loader_->LoadIfNeeded(
271 google_apis::test_util::CreateCopyResultCallback(&error));
272 EXPECT_TRUE(change_list_loader_->IsRefreshing());
273 base::RunLoop().RunUntilIdle();
274 EXPECT_EQ(FILE_ERROR_OK, error);
275 EXPECT_EQ(previous_file_list_load_count,
276 drive_service_->file_list_load_count());
277 EXPECT_EQ(1, observer.initial_load_complete_count());
279 // Update should be checked by Load().
280 int64 changestamp = 0;
281 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
282 EXPECT_EQ(drive_service_->about_resource().largest_change_id(), changestamp);
283 EXPECT_EQ(1, drive_service_->change_list_load_count());
284 EXPECT_EQ(1, observer.load_from_server_complete_count());
286 observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
288 base::FilePath file_path =
289 util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
291 EXPECT_EQ(FILE_ERROR_OK,
292 metadata_->GetResourceEntryByPath(file_path, &entry));
295 TEST_F(ChangeListLoaderTest, CheckForUpdates) {
296 // CheckForUpdates() results in no-op before load.
297 FileError check_for_updates_error = FILE_ERROR_FAILED;
298 change_list_loader_->CheckForUpdates(
299 google_apis::test_util::CreateCopyResultCallback(
300 &check_for_updates_error));
301 EXPECT_FALSE(change_list_loader_->IsRefreshing());
302 base::RunLoop().RunUntilIdle();
303 EXPECT_EQ(FILE_ERROR_FAILED,
304 check_for_updates_error); // Callback was not run.
305 int64 changestamp = 0;
306 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
307 EXPECT_EQ(0, changestamp);
308 EXPECT_EQ(0, drive_service_->file_list_load_count());
309 EXPECT_EQ(0, drive_service_->about_resource_load_count());
311 // Start initial load.
312 FileError load_error = FILE_ERROR_FAILED;
313 change_list_loader_->LoadIfNeeded(
314 google_apis::test_util::CreateCopyResultCallback(&load_error));
315 EXPECT_TRUE(change_list_loader_->IsRefreshing());
317 // CheckForUpdates() while loading.
318 change_list_loader_->CheckForUpdates(
319 google_apis::test_util::CreateCopyResultCallback(
320 &check_for_updates_error));
322 base::RunLoop().RunUntilIdle();
323 EXPECT_FALSE(change_list_loader_->IsRefreshing());
324 EXPECT_EQ(FILE_ERROR_OK, load_error);
325 EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error);
326 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
327 EXPECT_LT(0, changestamp);
328 EXPECT_EQ(1, drive_service_->file_list_load_count());
330 int64 previous_changestamp = 0;
331 EXPECT_EQ(FILE_ERROR_OK,
332 metadata_->GetLargestChangestamp(&previous_changestamp));
333 // CheckForUpdates() results in no update.
334 change_list_loader_->CheckForUpdates(
335 google_apis::test_util::CreateCopyResultCallback(
336 &check_for_updates_error));
337 EXPECT_TRUE(change_list_loader_->IsRefreshing());
338 base::RunLoop().RunUntilIdle();
339 EXPECT_FALSE(change_list_loader_->IsRefreshing());
340 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
341 EXPECT_EQ(previous_changestamp, changestamp);
343 // Add a file to the service.
344 scoped_ptr<google_apis::FileResource> gdata_entry = AddNewFile("New File");
345 ASSERT_TRUE(gdata_entry);
347 // CheckForUpdates() results in update.
348 TestChangeListLoaderObserver observer(change_list_loader_.get());
349 change_list_loader_->CheckForUpdates(
350 google_apis::test_util::CreateCopyResultCallback(
351 &check_for_updates_error));
352 EXPECT_TRUE(change_list_loader_->IsRefreshing());
353 base::RunLoop().RunUntilIdle();
354 EXPECT_FALSE(change_list_loader_->IsRefreshing());
355 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp));
356 EXPECT_LT(previous_changestamp, changestamp);
357 EXPECT_EQ(1, observer.load_from_server_complete_count());
359 observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
361 // The new file is found in the local metadata.
362 base::FilePath new_file_path =
363 util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
365 EXPECT_EQ(FILE_ERROR_OK,
366 metadata_->GetResourceEntryByPath(new_file_path, &entry));
369 TEST_F(ChangeListLoaderTest, Lock) {
370 FileError error = FILE_ERROR_FAILED;
371 change_list_loader_->LoadIfNeeded(
372 google_apis::test_util::CreateCopyResultCallback(&error));
373 base::RunLoop().RunUntilIdle();
374 EXPECT_EQ(FILE_ERROR_OK, error);
377 scoped_ptr<google_apis::FileResource> file = AddNewFile("New File");
381 scoped_ptr<base::ScopedClosureRunner> lock = loader_controller_->GetLock();
384 TestChangeListLoaderObserver observer(change_list_loader_.get());
385 FileError check_for_updates_error = FILE_ERROR_FAILED;
386 change_list_loader_->CheckForUpdates(
387 google_apis::test_util::CreateCopyResultCallback(
388 &check_for_updates_error));
389 base::RunLoop().RunUntilIdle();
391 // Update is pending due to the lock.
392 EXPECT_TRUE(observer.changed_files().empty());
394 // Unlock the loader, this should resume the pending update.
396 base::RunLoop().RunUntilIdle();
398 observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
401 } // namespace internal