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/sync/remove_performer.h"
6
7#include "base/task_runner_util.h"
8#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
9#include "chrome/browser/chromeos/drive/file_system_util.h"
10#include "chrome/browser/chromeos/drive/job_scheduler.h"
11#include "chrome/browser/chromeos/drive/resource_metadata.h"
12#include "chrome/browser/drive/fake_drive_service.h"
13#include "content/public/test/test_utils.h"
14#include "google_apis/drive/drive_api_parser.h"
15#include "google_apis/drive/test_util.h"
16
17namespace drive {
18namespace internal {
19
20typedef file_system::OperationTestBase RemovePerformerTest;
21
22TEST_F(RemovePerformerTest, RemoveFile) {
23  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
24                            metadata());
25
26  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
27  base::FilePath file_in_subdir(
28      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
29
30  // Remove a file in root.
31  ResourceEntry entry;
32  FileError error = FILE_ERROR_FAILED;
33  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &entry));
34  performer.Remove(entry.local_id(),
35                   ClientContext(USER_INITIATED),
36                   google_apis::test_util::CreateCopyResultCallback(&error));
37  content::RunAllBlockingPoolTasksUntilIdle();
38  EXPECT_EQ(FILE_ERROR_OK, error);
39
40  // Remove a file in subdirectory.
41  error = FILE_ERROR_FAILED;
42  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry));
43  const std::string resource_id = entry.resource_id();
44
45  performer.Remove(entry.local_id(),
46                   ClientContext(USER_INITIATED),
47                   google_apis::test_util::CreateCopyResultCallback(&error));
48  content::RunAllBlockingPoolTasksUntilIdle();
49  EXPECT_EQ(FILE_ERROR_OK, error);
50
51  // Verify the file is indeed removed in the server.
52  google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
53  scoped_ptr<google_apis::FileResource> gdata_entry;
54  fake_service()->GetFileResource(
55      resource_id,
56      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
57                                                       &gdata_entry));
58  content::RunAllBlockingPoolTasksUntilIdle();
59  ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
60  EXPECT_TRUE(gdata_entry->labels().is_trashed());
61
62  // Try removing non-existing file.
63  error = FILE_ERROR_FAILED;
64  performer.Remove("non-existing-id",
65                   ClientContext(USER_INITIATED),
66                   google_apis::test_util::CreateCopyResultCallback(&error));
67  content::RunAllBlockingPoolTasksUntilIdle();
68  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
69}
70
71TEST_F(RemovePerformerTest, RemoveShared) {
72  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
73                            metadata());
74
75  const base::FilePath kPathInMyDrive(FILE_PATH_LITERAL(
76      "drive/root/shared.txt"));
77  const base::FilePath kPathInOther(FILE_PATH_LITERAL(
78      "drive/other/shared.txt"));
79
80  // Prepare a shared file to the root folder.
81  google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
82  scoped_ptr<google_apis::FileResource> gdata_entry;
83  fake_service()->AddNewFile(
84      "text/plain",
85      "dummy content",
86      fake_service()->GetRootResourceId(),
87      kPathInMyDrive.BaseName().AsUTF8Unsafe(),
88      true,  // shared_with_me,
89      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
90                                                       &gdata_entry));
91  content::RunAllBlockingPoolTasksUntilIdle();
92  ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error);
93  CheckForUpdates();
94
95  // Remove it. Locally, the file should be moved to drive/other.
96  ResourceEntry entry;
97  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInMyDrive, &entry));
98  FileError error = FILE_ERROR_FAILED;
99  performer.Remove(entry.local_id(),
100                   ClientContext(USER_INITIATED),
101                   google_apis::test_util::CreateCopyResultCallback(&error));
102  content::RunAllBlockingPoolTasksUntilIdle();
103  EXPECT_EQ(FILE_ERROR_OK, error);
104  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
105            GetLocalResourceEntry(kPathInMyDrive, &entry));
106  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInOther, &entry));
107
108  // Remotely, the entry should have lost its parent.
109  gdata_error = google_apis::GDATA_OTHER_ERROR;
110  const std::string resource_id = gdata_entry->file_id();
111  fake_service()->GetFileResource(
112      resource_id,
113      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
114                                                       &gdata_entry));
115  content::RunAllBlockingPoolTasksUntilIdle();
116  ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
117  EXPECT_FALSE(gdata_entry->labels().is_trashed());  // It's not deleted.
118  EXPECT_TRUE(gdata_entry->parents().empty());
119}
120
121TEST_F(RemovePerformerTest, RemoveLocallyCreatedFile) {
122  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
123                            metadata());
124
125  // Add an entry without resource ID.
126  ResourceEntry entry;
127  entry.set_title("New File.txt");
128  entry.set_parent_local_id(util::kDriveTrashDirLocalId);
129
130  FileError error = FILE_ERROR_FAILED;
131  std::string local_id;
132  base::PostTaskAndReplyWithResult(
133      blocking_task_runner(),
134      FROM_HERE,
135      base::Bind(&ResourceMetadata::AddEntry,
136                 base::Unretained(metadata()),
137                 entry,
138                 &local_id),
139      google_apis::test_util::CreateCopyResultCallback(&error));
140  content::RunAllBlockingPoolTasksUntilIdle();
141  EXPECT_EQ(FILE_ERROR_OK, error);
142
143  // Remove the entry.
144  performer.Remove(local_id, ClientContext(USER_INITIATED),
145                   google_apis::test_util::CreateCopyResultCallback(&error));
146  content::RunAllBlockingPoolTasksUntilIdle();
147  EXPECT_EQ(FILE_ERROR_OK, error);
148  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntryById(local_id, &entry));
149}
150
151TEST_F(RemovePerformerTest, Remove_InsufficientPermission) {
152  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
153                            metadata());
154
155  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
156
157  ResourceEntry src_entry;
158  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
159
160  // Remove locally.
161  ResourceEntry updated_entry(src_entry);
162  updated_entry.set_parent_local_id(util::kDriveTrashDirLocalId);
163
164  FileError error = FILE_ERROR_FAILED;
165  base::PostTaskAndReplyWithResult(
166      blocking_task_runner(),
167      FROM_HERE,
168      base::Bind(&ResourceMetadata::RefreshEntry,
169                 base::Unretained(metadata()),
170                 updated_entry),
171      google_apis::test_util::CreateCopyResultCallback(&error));
172  content::RunAllBlockingPoolTasksUntilIdle();
173  EXPECT_EQ(FILE_ERROR_OK, error);
174
175  // Set user permission to forbid server side update.
176  EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission(
177      src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER));
178
179  // Try to perform remove.
180  error = FILE_ERROR_FAILED;
181  performer.Remove(src_entry.local_id(),
182                   ClientContext(USER_INITIATED),
183                   google_apis::test_util::CreateCopyResultCallback(&error));
184  content::RunAllBlockingPoolTasksUntilIdle();
185  EXPECT_EQ(FILE_ERROR_OK, error);
186
187  // This should result in reverting the local change.
188  ResourceEntry result_entry;
189  EXPECT_EQ(FILE_ERROR_OK,
190            GetLocalResourceEntryById(src_entry.local_id(), &result_entry));
191  EXPECT_EQ(src_entry.parent_local_id(), result_entry.parent_local_id());
192
193  ASSERT_EQ(1U, delegate()->drive_sync_errors().size());
194  EXPECT_EQ(file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION,
195            delegate()->drive_sync_errors()[0]);
196}
197
198}  // namespace internal
199}  // namespace drive
200