change_list_processor_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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/chromeos/drive/change_list_processor.h"
6
7#include "base/files/scoped_temp_dir.h"
8#include "base/message_loop/message_loop_proxy.h"
9#include "base/values.h"
10#include "chrome/browser/chromeos/drive/drive.pb.h"
11#include "chrome/browser/chromeos/drive/file_system_util.h"
12#include "chrome/browser/chromeos/drive/resource_metadata.h"
13#include "chrome/browser/chromeos/drive/test_util.h"
14#include "chrome/browser/google_apis/drive_api_parser.h"
15#include "chrome/browser/google_apis/gdata_wapi_parser.h"
16#include "chrome/browser/google_apis/test_util.h"
17#include "content/public/test/test_browser_thread_bundle.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace drive {
21namespace internal {
22
23namespace {
24
25const int64 kBaseResourceListChangestamp = 123;
26const char kBaseResourceListFile[] = "gdata/root_feed.json";
27const char kRootId[] = "fake_root";
28
29enum FileOrDirectory {
30  FILE,
31  DIRECTORY,
32};
33
34struct EntryExpectation {
35  std::string path;
36  std::string id;
37  std::string parent_id;
38  FileOrDirectory type;
39};
40
41class ChangeListProcessorTest : public testing::Test {
42 protected:
43  virtual void SetUp() OVERRIDE {
44    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
45
46    metadata_storage_.reset(new ResourceMetadataStorage(
47        temp_dir_.path(), base::MessageLoopProxy::current().get()));
48    ASSERT_TRUE(metadata_storage_->Initialize());
49
50    metadata_.reset(new internal::ResourceMetadata(
51        metadata_storage_.get(), base::MessageLoopProxy::current()));
52    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
53  }
54
55  // Parses a json file at |test_data_path| relative to Chrome test directory
56  // into a ScopedVector<drive::internal::ChangeList>.
57  ScopedVector<ChangeList> ParseChangeList(const std::string& test_data_path) {
58    ScopedVector<ChangeList> changes;
59    changes.push_back(new ChangeList(
60        *google_apis::ResourceList::ExtractAndParse(
61            *google_apis::test_util::LoadJSONFile(
62                test_data_path))));
63    return changes.Pass();
64  }
65
66  // Applies the |changes| to |metadata_| as a full resource list of changestamp
67  // |kBaseResourceListChangestamp|.
68  void ApplyFullResourceList(ScopedVector<ChangeList> changes) {
69    scoped_ptr<google_apis::AboutResource> about_resource(
70        new google_apis::AboutResource);
71    about_resource->set_largest_change_id(kBaseResourceListChangestamp);
72    about_resource->set_root_folder_id(kRootId);
73
74    ChangeListProcessor processor(metadata_.get());
75    processor.Apply(about_resource.Pass(),
76                    changes.Pass(),
77                    false /* is_delta_update */);
78  }
79
80  // Applies the |changes| to |metadata_| as a delta update. Delta changelists
81  // should contain their changestamp in themselves.
82  std::set<base::FilePath> ApplyChangeList(ScopedVector<ChangeList> changes) {
83    ChangeListProcessor processor(metadata_.get());
84    processor.Apply(scoped_ptr<google_apis::AboutResource>(),
85                    changes.Pass(),
86                    true /* is_delta_update */);
87    return processor.changed_dirs();
88  }
89
90  // Gets the resource entry for the path from |metadata_| synchronously.
91  // Returns null if the entry does not exist.
92  scoped_ptr<ResourceEntry> GetResourceEntry(const std::string& path) {
93    scoped_ptr<ResourceEntry> entry(new ResourceEntry);
94    FileError error = metadata_->GetResourceEntryByPath(
95        base::FilePath::FromUTF8Unsafe(path), entry.get());
96    if (error != FILE_ERROR_OK)
97      entry.reset();
98    return entry.Pass();
99  }
100
101  content::TestBrowserThreadBundle thread_bundle_;
102  base::ScopedTempDir temp_dir_;
103  scoped_ptr<ResourceMetadataStorage,
104             test_util::DestroyHelperForTests> metadata_storage_;
105  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
106};
107
108}  // namespace
109
110TEST_F(ChangeListProcessorTest, ApplyFullResourceList) {
111  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
112
113  const EntryExpectation kExpected[] = {
114      // Root files
115      {"drive/root",
116          kRootId, util::kDriveGrandRootSpecialResourceId, DIRECTORY},
117      {"drive/root/File 1.txt",
118          "file:2_file_resource_id", kRootId, FILE},
119      {"drive/root/Slash \xE2\x88\x95 in file 1.txt",
120          "file:slash_file_resource_id", kRootId, FILE},
121      {"drive/root/Document 1 excludeDir-test.gdoc",
122          "document:5_document_resource_id", kRootId, FILE},
123      // Subdirectory files
124      {"drive/root/Directory 1",
125          "folder:1_folder_resource_id", kRootId, DIRECTORY},
126      {"drive/root/Directory 1/SubDirectory File 1.txt",
127          "file:subdirectory_file_1_id", "folder:1_folder_resource_id", FILE},
128      {"drive/root/Directory 1/Shared To The Account Owner.txt",
129          "file:subdirectory_unowned_file_1_id",
130          "folder:1_folder_resource_id", FILE},
131      {"drive/root/Directory 2 excludeDir-test",
132          "folder:sub_dir_folder_2_self_link", kRootId, DIRECTORY},
133      {"drive/root/Slash \xE2\x88\x95 in directory",
134          "folder:slash_dir_folder_resource_id", kRootId, DIRECTORY},
135      {"drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt",
136          "file:slash_subdir_file",
137          "folder:slash_dir_folder_resource_id", FILE},
138      // Deeper
139      {"drive/root/Directory 1/Sub Directory Folder",
140          "folder:sub_dir_folder_resource_id",
141          "folder:1_folder_resource_id", DIRECTORY},
142      {"drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder",
143          "folder:sub_sub_directory_folder_id",
144          "folder:sub_dir_folder_resource_id", DIRECTORY},
145      // Orphan
146      {"drive/other/Orphan File 1.txt",
147          "file:1_orphanfile_resource_id",
148          util::kDriveOtherDirSpecialResourceId, FILE},
149  };
150
151  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpected); ++i) {
152    scoped_ptr<ResourceEntry> entry = GetResourceEntry(kExpected[i].path);
153    ASSERT_TRUE(entry) << "for path: " << kExpected[i].path;
154    EXPECT_EQ(kExpected[i].id, entry->resource_id());
155    EXPECT_EQ(kExpected[i].parent_id, entry->parent_local_id());
156    EXPECT_EQ(kExpected[i].type,
157              entry->file_info().is_directory() ? DIRECTORY : FILE);
158  }
159
160  EXPECT_EQ(kBaseResourceListChangestamp, metadata_->GetLargestChangestamp());
161}
162
163TEST_F(ChangeListProcessorTest, DeltaFileAddedInNewDirectory) {
164  const char kTestJson[] =
165      "gdata/delta_file_added_in_new_directory.json";
166
167  ChangeListProcessor::ResourceEntryMap entry_map;
168  ChangeListProcessor::ConvertToMap(
169      ParseChangeList(kTestJson), &entry_map, NULL);
170
171  const std::string kNewFolderId("folder:new_folder_resource_id");
172  const std::string kNewFileId("document:file_added_in_new_dir_id");
173
174  // Check the content of parsed ResourceEntryMap.
175  EXPECT_EQ(2U, entry_map.size());
176  EXPECT_TRUE(entry_map.count(kNewFolderId));
177  EXPECT_TRUE(entry_map.count(kNewFileId));
178  EXPECT_EQ(kRootId, entry_map[kNewFolderId].parent_local_id());
179  EXPECT_EQ(kNewFolderId, entry_map[kNewFileId].parent_local_id());
180  EXPECT_TRUE(entry_map[kNewFolderId].file_info().is_directory());
181  EXPECT_FALSE(entry_map[kNewFileId].file_info().is_directory());
182  EXPECT_EQ("New Directory", entry_map[kNewFolderId].title());
183  EXPECT_EQ("File in new dir", entry_map[kNewFileId].title());
184
185  // Apply the changelist and check the effect.
186  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
187  std::set<base::FilePath> changed_dirs =
188      ApplyChangeList(ParseChangeList(kTestJson));
189
190  // The value is written in kTestJson.
191  EXPECT_EQ(16730, metadata_->GetLargestChangestamp());
192  EXPECT_TRUE(GetResourceEntry("drive/root/New Directory"));
193  EXPECT_TRUE(GetResourceEntry(
194      "drive/root/New Directory/File in new dir.gdoc"));
195
196  EXPECT_EQ(2U, changed_dirs.size());
197  EXPECT_TRUE(changed_dirs.count(
198      base::FilePath::FromUTF8Unsafe("drive/root")));
199  EXPECT_TRUE(changed_dirs.count(
200      base::FilePath::FromUTF8Unsafe("drive/root/New Directory")));
201}
202
203TEST_F(ChangeListProcessorTest, DeltaDirMovedFromRootToDirectory) {
204  const char kTestJson[] =
205      "gdata/delta_dir_moved_from_root_to_directory.json";
206
207  ChangeListProcessor::ResourceEntryMap entry_map;
208  ChangeListProcessor::ConvertToMap(
209      ParseChangeList(kTestJson), &entry_map, NULL);
210
211  const std::string kMovedId("folder:1_folder_resource_id");
212  const std::string kDestId("folder:sub_dir_folder_2_self_link");
213
214  // Check the content of parsed ResourceEntryMap.
215  EXPECT_EQ(2U, entry_map.size());
216  EXPECT_TRUE(entry_map.count(kMovedId));
217  EXPECT_TRUE(entry_map.count(kDestId));
218  EXPECT_EQ(kDestId, entry_map[kMovedId].parent_local_id());
219
220  // Apply the changelist and check the effect.
221  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
222  std::set<base::FilePath> changed_dirs =
223      ApplyChangeList(ParseChangeList(kTestJson));
224
225  // The value is written in kTestJson.
226  EXPECT_EQ(16809, metadata_->GetLargestChangestamp());
227  EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1"));
228  EXPECT_TRUE(GetResourceEntry(
229      "drive/root/Directory 2 excludeDir-test/Directory 1"));
230
231  EXPECT_EQ(4U, changed_dirs.size());
232  EXPECT_TRUE(changed_dirs.count(
233      base::FilePath::FromUTF8Unsafe("drive/root")));
234  EXPECT_TRUE(changed_dirs.count(
235      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
236  EXPECT_TRUE(changed_dirs.count(
237      base::FilePath::FromUTF8Unsafe(
238          "drive/root/Directory 2 excludeDir-test")));
239  EXPECT_TRUE(changed_dirs.count(
240      base::FilePath::FromUTF8Unsafe(
241          "drive/root/Directory 2 excludeDir-test/Directory 1")));
242}
243
244TEST_F(ChangeListProcessorTest, DeltaFileMovedFromDirectoryToRoot) {
245  const char kTestJson[] =
246      "gdata/delta_file_moved_from_directory_to_root.json";
247
248  ChangeListProcessor::ResourceEntryMap entry_map;
249  ChangeListProcessor::ConvertToMap(
250      ParseChangeList(kTestJson), &entry_map, NULL);
251
252  const std::string kMovedId("file:subdirectory_file_1_id");
253  const std::string kSrcId("folder:1_folder_resource_id");
254
255  // Check the content of parsed ResourceEntryMap.
256  EXPECT_EQ(2U, entry_map.size());
257  EXPECT_TRUE(entry_map.count(kMovedId));
258  EXPECT_TRUE(entry_map.count(kSrcId));
259  EXPECT_EQ(kRootId, entry_map[kMovedId].parent_local_id());
260
261  // Apply the changelist and check the effect.
262  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
263  std::set<base::FilePath> changed_dirs =
264      ApplyChangeList(ParseChangeList(kTestJson));
265
266  // The value is written in kTestJson.
267  EXPECT_EQ(16815, metadata_->GetLargestChangestamp());
268  EXPECT_FALSE(GetResourceEntry(
269      "drive/root/Directory 1/SubDirectory File 1.txt"));
270  EXPECT_TRUE(GetResourceEntry("drive/root/SubDirectory File 1.txt"));
271
272  EXPECT_EQ(2U, changed_dirs.size());
273  EXPECT_TRUE(changed_dirs.count(
274      base::FilePath::FromUTF8Unsafe("drive/root")));
275  EXPECT_TRUE(changed_dirs.count(
276      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
277}
278
279TEST_F(ChangeListProcessorTest, DeltaFileRenamedInDirectory) {
280  const char kTestJson[] =
281      "gdata/delta_file_renamed_in_directory.json";
282
283  ChangeListProcessor::ResourceEntryMap entry_map;
284  ChangeListProcessor::ConvertToMap(
285      ParseChangeList(kTestJson), &entry_map, NULL);
286
287  const std::string kRenamedId("file:subdirectory_file_1_id");
288  const std::string kParentId("folder:1_folder_resource_id");
289
290  // Check the content of parsed ResourceEntryMap.
291  EXPECT_EQ(2U, entry_map.size());
292  EXPECT_TRUE(entry_map.count(kRenamedId));
293  EXPECT_TRUE(entry_map.count(kParentId));
294  EXPECT_EQ(kParentId, entry_map[kRenamedId].parent_local_id());
295  EXPECT_EQ("New SubDirectory File 1.txt", entry_map[kRenamedId].title());
296
297  // Apply the changelist and check the effect.
298  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
299  std::set<base::FilePath> changed_dirs =
300      ApplyChangeList(ParseChangeList(kTestJson));
301
302  // The value is written in kTestJson.
303  EXPECT_EQ(16767, metadata_->GetLargestChangestamp());
304  EXPECT_FALSE(GetResourceEntry(
305      "drive/root/Directory 1/SubDirectory File 1.txt"));
306  EXPECT_TRUE(GetResourceEntry(
307      "drive/root/Directory 1/New SubDirectory File 1.txt"));
308
309  EXPECT_EQ(2U, changed_dirs.size());
310  EXPECT_TRUE(changed_dirs.count(
311      base::FilePath::FromUTF8Unsafe("drive/root")));
312  EXPECT_TRUE(changed_dirs.count(
313      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
314}
315
316TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileInRoot) {
317  const char kTestJsonAdd[] =
318      "gdata/delta_file_added_in_root.json";
319  const char kTestJsonDelete[] =
320      "gdata/delta_file_deleted_in_root.json";
321
322  const std::string kParentId(kRootId);
323  const std::string kFileId("document:added_in_root_id");
324
325  ChangeListProcessor::ResourceEntryMap entry_map;
326
327  // Check the content of kTestJsonAdd.
328  ChangeListProcessor::ConvertToMap(
329      ParseChangeList(kTestJsonAdd), &entry_map, NULL);
330  EXPECT_EQ(1U, entry_map.size());
331  EXPECT_TRUE(entry_map.count(kFileId));
332  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
333  EXPECT_EQ("Added file", entry_map[kFileId].title());
334  EXPECT_FALSE(entry_map[kFileId].deleted());
335
336  // Apply.
337  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
338  std::set<base::FilePath> changed_dirs =
339      ApplyChangeList(ParseChangeList(kTestJsonAdd));
340  EXPECT_EQ(16683, metadata_->GetLargestChangestamp());
341  EXPECT_TRUE(GetResourceEntry("drive/root/Added file.gdoc"));
342  EXPECT_EQ(1U, changed_dirs.size());
343  EXPECT_TRUE(changed_dirs.count(
344      base::FilePath::FromUTF8Unsafe("drive/root")));
345
346  // Check the content of kTestJsonDelete.
347  entry_map.clear();
348  ChangeListProcessor::ConvertToMap(
349      ParseChangeList(kTestJsonDelete), &entry_map, NULL);
350  EXPECT_EQ(1U, entry_map.size());
351  EXPECT_TRUE(entry_map.count(kFileId));
352  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
353  EXPECT_EQ("Added file", entry_map[kFileId].title());
354  EXPECT_TRUE(entry_map[kFileId].deleted());
355
356  // Apply.
357  changed_dirs = ApplyChangeList(ParseChangeList(kTestJsonDelete));
358  EXPECT_EQ(16687, metadata_->GetLargestChangestamp());
359  EXPECT_FALSE(GetResourceEntry("drive/root/Added file.gdoc"));
360  EXPECT_EQ(1U, changed_dirs.size());
361  EXPECT_TRUE(changed_dirs.count(
362      base::FilePath::FromUTF8Unsafe("drive/root")));
363}
364
365
366TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileFromExistingDirectory) {
367  const char kTestJsonAdd[] =
368      "gdata/delta_file_added_in_directory.json";
369  const char kTestJsonDelete[] =
370      "gdata/delta_file_deleted_in_directory.json";
371
372  const std::string kParentId("folder:1_folder_resource_id");
373  const std::string kFileId("document:added_in_root_id");
374
375  ChangeListProcessor::ResourceEntryMap entry_map;
376
377  // Check the content of kTestJsonAdd.
378  ChangeListProcessor::ConvertToMap(
379      ParseChangeList(kTestJsonAdd), &entry_map, NULL);
380  EXPECT_EQ(2U, entry_map.size());
381  EXPECT_TRUE(entry_map.count(kFileId));
382  EXPECT_TRUE(entry_map.count(kParentId));
383  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
384  EXPECT_EQ("Added file", entry_map[kFileId].title());
385  EXPECT_FALSE(entry_map[kFileId].deleted());
386
387  // Apply.
388  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
389  std::set<base::FilePath> changed_dirs =
390      ApplyChangeList(ParseChangeList(kTestJsonAdd));
391  EXPECT_EQ(16730, metadata_->GetLargestChangestamp());
392  EXPECT_TRUE(GetResourceEntry("drive/root/Directory 1/Added file.gdoc"));
393
394  EXPECT_EQ(2U, changed_dirs.size());
395  EXPECT_TRUE(changed_dirs.count(
396      base::FilePath::FromUTF8Unsafe("drive/root")));
397  EXPECT_TRUE(changed_dirs.count(
398      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
399
400  // Check the content of kTestJsonDelete.
401  entry_map.clear();
402  ChangeListProcessor::ConvertToMap(
403      ParseChangeList(kTestJsonDelete), &entry_map, NULL);
404  EXPECT_EQ(1U, entry_map.size());
405  EXPECT_TRUE(entry_map.count(kFileId));
406  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
407  EXPECT_EQ("Added file", entry_map[kFileId].title());
408  EXPECT_TRUE(entry_map[kFileId].deleted());
409
410  // Apply.
411  changed_dirs = ApplyChangeList(ParseChangeList(kTestJsonDelete));
412  EXPECT_EQ(16770, metadata_->GetLargestChangestamp());
413  EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1/Added file.gdoc"));
414
415  EXPECT_EQ(1U, changed_dirs.size());
416  EXPECT_TRUE(changed_dirs.count(
417      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
418}
419
420TEST_F(ChangeListProcessorTest, DeltaAddFileToNewButDeletedDirectory) {
421  // This file contains the following updates:
422  // 1) A new PDF file is added to a new directory
423  // 2) but the new directory is marked "deleted" (i.e. moved to Trash)
424  // Hence, the PDF file should be just ignored.
425  const char kTestJson[] =
426      "gdata/delta_file_added_in_new_but_deleted_directory.json";
427
428  ChangeListProcessor::ResourceEntryMap entry_map;
429  ChangeListProcessor::ConvertToMap(
430      ParseChangeList(kTestJson), &entry_map, NULL);
431
432  const std::string kDirId("folder:new_folder_resource_id");
433  const std::string kFileId("pdf:file_added_in_deleted_dir_id");
434
435  // Check the content of parsed ResourceEntryMap.
436  EXPECT_EQ(2U, entry_map.size());
437  EXPECT_TRUE(entry_map.count(kDirId));
438  EXPECT_TRUE(entry_map.count(kFileId));
439  EXPECT_EQ(kDirId, entry_map[kFileId].parent_local_id());
440  EXPECT_TRUE(entry_map[kDirId].deleted());
441
442  // Apply the changelist and check the effect.
443  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
444  std::set<base::FilePath> changed_dirs =
445      ApplyChangeList(ParseChangeList(kTestJson));
446
447  // The value is written in kTestJson.
448  EXPECT_EQ(16730, metadata_->GetLargestChangestamp());
449  EXPECT_FALSE(GetResourceEntry("drive/root/New Directory/new_pdf_file.pdf"));
450
451  EXPECT_TRUE(changed_dirs.empty());
452}
453
454TEST_F(ChangeListProcessorTest, RefreshDirectory) {
455  // Prepare metadata.
456  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
457
458  // Create a map.
459  ChangeListProcessor::ResourceEntryMap entry_map;
460
461  // Add a new file to the map.
462  ResourceEntry new_file;
463  new_file.set_title("new_file");
464  new_file.set_resource_id("new_file_id");
465  new_file.set_parent_local_id(kRootId);
466  entry_map["new_file_id"] = new_file;
467
468  // Add "Directory 1" to the map with a new name.
469  ResourceEntry dir1;
470  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
471      util::GetDriveMyDriveRootPath().AppendASCII("Directory 1"), &dir1));
472  dir1.set_title(dir1.title() + " (renamed)");
473  entry_map[dir1.resource_id()] = dir1;
474
475  // Update the directory with the map.
476  const int64 kNewChangestamp = 12345;
477  base::FilePath file_path;
478  EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
479      metadata_.get(),
480      DirectoryFetchInfo(kRootId, kNewChangestamp),
481      entry_map,
482      &file_path));
483  EXPECT_EQ(util::GetDriveMyDriveRootPath().value(), file_path.value());
484
485  // The new changestamp should be set.
486  ResourceEntry entry;
487  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
488      util::GetDriveMyDriveRootPath(), &entry));
489  EXPECT_EQ(kNewChangestamp, entry.directory_specific_info().changestamp());
490
491  // "new_file" should be added.
492  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
493      util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
494
495  // "Directory 1" should be renamed.
496  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
497      util::GetDriveMyDriveRootPath().AppendASCII(dir1.title()), &entry));
498}
499
500TEST_F(ChangeListProcessorTest, RefreshDirectory_WrongParentId) {
501  // Prepare metadata.
502  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
503
504  // Create a map and add a new file to it.
505  ChangeListProcessor::ResourceEntryMap entry_map;
506  ResourceEntry new_file;
507  new_file.set_title("new_file");
508  new_file.set_resource_id("new_file_id");
509  // This entry should not be added because the parent ID does not match.
510  new_file.set_parent_local_id("some-random-resource-id");
511  entry_map["new_file_id"] = new_file;
512
513  // Update the directory with the map.
514  const int64 kNewChangestamp = 12345;
515  base::FilePath file_path;
516  EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
517      metadata_.get(),
518      DirectoryFetchInfo(kRootId, kNewChangestamp),
519      entry_map,
520      &file_path));
521  EXPECT_EQ(util::GetDriveMyDriveRootPath().value(), file_path.value());
522
523  // "new_file" should not be added.
524  ResourceEntry entry;
525  EXPECT_EQ(FILE_ERROR_NOT_FOUND, metadata_->GetResourceEntryByPath(
526      util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
527}
528
529}  // namespace internal
530}  // namespace drive
531