fake_drive_service.cc 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930
  1. // Copyright (c) 2012 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. #include "components/drive/service/fake_drive_service.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/bind.h"
  11. #include "base/check_op.h"
  12. #include "base/files/file_util.h"
  13. #include "base/hash/md5.h"
  14. #include "base/json/json_string_value_serializer.h"
  15. #include "base/memory/ptr_util.h"
  16. #include "base/notreached.h"
  17. #include "base/strings/escape.h"
  18. #include "base/strings/string_number_conversions.h"
  19. #include "base/strings/string_split.h"
  20. #include "base/strings/string_tokenizer.h"
  21. #include "base/strings/string_util.h"
  22. #include "base/strings/stringprintf.h"
  23. #include "base/strings/utf_string_conversions.h"
  24. #include "base/threading/thread_restrictions.h"
  25. #include "base/threading/thread_task_runner_handle.h"
  26. #include "base/values.h"
  27. #include "components/drive/drive_api_util.h"
  28. #include "components/drive/file_system_core_util.h"
  29. #include "google_apis/common/test_util.h"
  30. #include "google_apis/drive/drive_api_parser.h"
  31. #include "google_apis/drive/drive_common_callbacks.h"
  32. #include "net/base/url_util.h"
  33. using google_apis::AboutResource;
  34. using google_apis::AboutResourceCallback;
  35. using google_apis::ApiErrorCode;
  36. using google_apis::AuthStatusCallback;
  37. using google_apis::CancelCallbackOnce;
  38. using google_apis::ChangeList;
  39. using google_apis::ChangeListCallback;
  40. using google_apis::ChangeListOnceCallback;
  41. using google_apis::ChangeResource;
  42. using google_apis::DownloadActionCallback;
  43. using google_apis::DRIVE_FILE_ERROR;
  44. using google_apis::EntryActionCallback;
  45. using google_apis::FileList;
  46. using google_apis::FileListCallback;
  47. using google_apis::FileResource;
  48. using google_apis::FileResourceCallback;
  49. using google_apis::GetContentCallback;
  50. using google_apis::HTTP_BAD_REQUEST;
  51. using google_apis::HTTP_CREATED;
  52. using google_apis::HTTP_FORBIDDEN;
  53. using google_apis::HTTP_NO_CONTENT;
  54. using google_apis::HTTP_NOT_FOUND;
  55. using google_apis::HTTP_PRECONDITION;
  56. using google_apis::HTTP_RESUME_INCOMPLETE;
  57. using google_apis::HTTP_SUCCESS;
  58. using google_apis::InitiateUploadCallback;
  59. using google_apis::NO_CONNECTION;
  60. using google_apis::OTHER_ERROR;
  61. using google_apis::ParentReference;
  62. using google_apis::ProgressCallback;
  63. using google_apis::StartPageToken;
  64. using google_apis::TeamDriveList;
  65. using google_apis::TeamDriveListCallback;
  66. using google_apis::TeamDriveResource;
  67. using google_apis::UploadRangeResponse;
  68. using google_apis::drive::UploadRangeCallback;
  69. namespace test_util = google_apis::test_util;
  70. namespace drive {
  71. namespace {
  72. // Returns true if the entry matches with the search query.
  73. // Supports queries consist of following format.
  74. // - Phrases quoted by double/single quotes
  75. // - AND search for multiple words/phrases segmented by space
  76. // - Limited attribute search. Only "title:" is supported.
  77. bool EntryMatchWithQuery(const ChangeResource& entry,
  78. const std::string& query) {
  79. base::StringTokenizer tokenizer(query, " ");
  80. tokenizer.set_quote_chars("\"'");
  81. while (tokenizer.GetNext()) {
  82. std::string key, value;
  83. const std::string& token = tokenizer.token();
  84. if (token.find(':') == std::string::npos) {
  85. base::TrimString(token, "\"'", &value);
  86. } else {
  87. base::StringTokenizer key_value(token, ":");
  88. key_value.set_quote_chars("\"'");
  89. if (!key_value.GetNext())
  90. return false;
  91. key = key_value.token();
  92. if (!key_value.GetNext())
  93. return false;
  94. base::TrimString(key_value.token(), "\"'", &value);
  95. }
  96. // TODO(peria): Deal with other attributes than title.
  97. if (!key.empty() && key != "title")
  98. return false;
  99. // Search query in the title.
  100. if (!entry.file() || entry.file()->title().find(value) == std::string::npos)
  101. return false;
  102. }
  103. return true;
  104. }
  105. void ScheduleUploadRangeCallback(UploadRangeCallback callback,
  106. int64_t start_position,
  107. int64_t end_position,
  108. ApiErrorCode error,
  109. std::unique_ptr<FileResource> entry) {
  110. base::ThreadTaskRunnerHandle::Get()->PostTask(
  111. FROM_HERE,
  112. base::BindOnce(std::move(callback),
  113. UploadRangeResponse(error, start_position, end_position),
  114. std::move(entry)));
  115. }
  116. void FileListCallbackAdapter(FileListCallback callback,
  117. ApiErrorCode error,
  118. std::unique_ptr<ChangeList> change_list) {
  119. std::unique_ptr<FileList> file_list;
  120. if (!change_list) {
  121. std::move(callback).Run(error, std::move(file_list));
  122. return;
  123. }
  124. file_list = std::make_unique<FileList>();
  125. file_list->set_next_link(change_list->next_link());
  126. for (size_t i = 0; i < change_list->items().size(); ++i) {
  127. const ChangeResource& entry = *change_list->items()[i];
  128. if (entry.type() == ChangeResource::FILE && entry.file())
  129. file_list->mutable_items()->push_back(
  130. std::make_unique<FileResource>(*entry.file()));
  131. }
  132. std::move(callback).Run(error, std::move(file_list));
  133. }
  134. bool UserHasWriteAccess(google_apis::drive::PermissionRole user_permission) {
  135. switch (user_permission) {
  136. case google_apis::drive::PERMISSION_ROLE_OWNER:
  137. case google_apis::drive::PERMISSION_ROLE_WRITER:
  138. return true;
  139. case google_apis::drive::PERMISSION_ROLE_READER:
  140. case google_apis::drive::PERMISSION_ROLE_COMMENTER:
  141. break;
  142. }
  143. return false;
  144. }
  145. void CallFileResourceCallback(FileResourceCallback callback,
  146. const UploadRangeResponse& response,
  147. std::unique_ptr<FileResource> entry) {
  148. std::move(callback).Run(response.code, std::move(entry));
  149. }
  150. struct CallResumeUpload {
  151. CallResumeUpload() = default;
  152. ~CallResumeUpload() = default;
  153. void Run(ApiErrorCode code, const GURL& upload_url) {
  154. if (service) {
  155. service->ResumeUpload(
  156. upload_url,
  157. /* start position */ 0,
  158. /* end position */ content_length, content_length, content_type,
  159. local_file_path,
  160. base::BindOnce(&CallFileResourceCallback, std::move(callback)),
  161. progress_callback);
  162. }
  163. }
  164. base::WeakPtr<FakeDriveService> service;
  165. int64_t content_length;
  166. std::string content_type;
  167. base::FilePath local_file_path;
  168. FileResourceCallback callback;
  169. ProgressCallback progress_callback;
  170. };
  171. std::string GetTeamDriveId(const google_apis::ChangeResource& change_resource) {
  172. std::string team_drive_id;
  173. switch (change_resource.type()) {
  174. case ChangeResource::FILE:
  175. team_drive_id = change_resource.file()->team_drive_id();
  176. break;
  177. case ChangeResource::TEAM_DRIVE:
  178. team_drive_id = change_resource.team_drive_id();
  179. break;
  180. case ChangeResource::UNKNOWN:
  181. NOTREACHED();
  182. break;
  183. }
  184. return team_drive_id;
  185. }
  186. } // namespace
  187. struct FakeDriveService::EntryInfo {
  188. EntryInfo()
  189. : user_permission(google_apis::drive::PERMISSION_ROLE_OWNER),
  190. visibility(google_apis::drive::FILE_VISIBILITY_DEFAULT) {}
  191. google_apis::ChangeResource change_resource;
  192. GURL share_url;
  193. std::string content_data;
  194. // Behaves in the same way as "userPermission" described in
  195. // https://developers.google.com/drive/v2/reference/files
  196. google_apis::drive::PermissionRole user_permission;
  197. google_apis::drive::FileVisibility visibility;
  198. };
  199. struct FakeDriveService::UploadSession {
  200. std::string content_type;
  201. int64_t content_length;
  202. std::string parent_resource_id;
  203. std::string resource_id;
  204. std::string etag;
  205. std::string title;
  206. int64_t uploaded_size;
  207. UploadSession() : content_length(0), uploaded_size(0) {}
  208. UploadSession(std::string content_type,
  209. int64_t content_length,
  210. std::string parent_resource_id,
  211. std::string resource_id,
  212. std::string etag,
  213. std::string title)
  214. : content_type(content_type),
  215. content_length(content_length),
  216. parent_resource_id(parent_resource_id),
  217. resource_id(resource_id),
  218. etag(etag),
  219. title(title),
  220. uploaded_size(0) {}
  221. };
  222. FakeDriveService::FakeDriveService()
  223. : about_resource_(new AboutResource),
  224. start_page_token_(new StartPageToken),
  225. date_seq_(0),
  226. next_upload_sequence_number_(0),
  227. largest_changestamp_(654321),
  228. default_max_results_(0),
  229. resource_id_count_(0),
  230. team_drive_list_load_count_(0),
  231. file_list_load_count_(0),
  232. change_list_load_count_(0),
  233. directory_load_count_(0),
  234. about_resource_load_count_(0),
  235. blocked_file_list_load_count_(0),
  236. start_page_token_load_count_(0),
  237. offline_(false),
  238. never_return_all_file_list_(false) {
  239. UpdateLatestChangelistId(largest_changestamp_, std::string());
  240. about_resource_->set_quota_bytes_total(9876543210);
  241. about_resource_->set_quota_bytes_used_aggregate(6789012345);
  242. about_resource_->set_root_folder_id(GetRootResourceId());
  243. }
  244. FakeDriveService::~FakeDriveService() {
  245. DCHECK(thread_checker_.CalledOnValidThread());
  246. }
  247. void FakeDriveService::AddTeamDrive(const std::string& id,
  248. const std::string& name) {
  249. AddTeamDrive(id, name, "");
  250. }
  251. void FakeDriveService::AddTeamDrive(const std::string& id,
  252. const std::string& name,
  253. const std::string& start_page_token) {
  254. DCHECK(entries_.find(id) == entries_.end());
  255. auto team_drive = std::make_unique<TeamDriveResource>();
  256. team_drive->set_id(id);
  257. team_drive->set_name(name);
  258. team_drive_value_.push_back(std::move(team_drive));
  259. team_drive_start_page_tokens_[id] = std::make_unique<StartPageToken>();
  260. team_drive_start_page_tokens_[id]->set_start_page_token(start_page_token);
  261. const EntryInfo* new_entry = AddNewTeamDriveEntry(id, name);
  262. DCHECK(new_entry);
  263. }
  264. void FakeDriveService::SetQuotaValue(int64_t used, int64_t total) {
  265. DCHECK(thread_checker_.CalledOnValidThread());
  266. about_resource_->set_quota_bytes_used_aggregate(used);
  267. about_resource_->set_quota_bytes_total(total);
  268. }
  269. void FakeDriveService::Initialize(const CoreAccountId& account_id) {
  270. DCHECK(thread_checker_.CalledOnValidThread());
  271. }
  272. void FakeDriveService::AddObserver(DriveServiceObserver* observer) {
  273. DCHECK(thread_checker_.CalledOnValidThread());
  274. }
  275. void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) {
  276. DCHECK(thread_checker_.CalledOnValidThread());
  277. }
  278. bool FakeDriveService::CanSendRequest() const {
  279. DCHECK(thread_checker_.CalledOnValidThread());
  280. return true;
  281. }
  282. bool FakeDriveService::HasAccessToken() const {
  283. DCHECK(thread_checker_.CalledOnValidThread());
  284. return true;
  285. }
  286. void FakeDriveService::RequestAccessToken(AuthStatusCallback callback) {
  287. DCHECK(thread_checker_.CalledOnValidThread());
  288. DCHECK(callback);
  289. std::move(callback).Run(google_apis::HTTP_NOT_MODIFIED, "fake_access_token");
  290. }
  291. bool FakeDriveService::HasRefreshToken() const {
  292. DCHECK(thread_checker_.CalledOnValidThread());
  293. return true;
  294. }
  295. void FakeDriveService::ClearAccessToken() {
  296. DCHECK(thread_checker_.CalledOnValidThread());
  297. }
  298. void FakeDriveService::ClearRefreshToken() {
  299. DCHECK(thread_checker_.CalledOnValidThread());
  300. }
  301. std::string FakeDriveService::GetRootResourceId() const {
  302. return "fake_root";
  303. }
  304. void FakeDriveService::GetTeamDriveListInternal(
  305. int start_offset,
  306. int max_results,
  307. int* load_counter,
  308. google_apis::TeamDriveListCallback callback) {
  309. if (offline_) {
  310. base::ThreadTaskRunnerHandle::Get()->PostTask(
  311. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  312. std::unique_ptr<TeamDriveList>()));
  313. return;
  314. }
  315. if (load_counter)
  316. ++*load_counter;
  317. // If max_results is zero then we want to return the entire list.
  318. if (max_results <= 0) {
  319. max_results = team_drive_value_.size();
  320. }
  321. auto result = std::make_unique<TeamDriveList>();
  322. size_t next_start_offset = start_offset + max_results;
  323. if (next_start_offset < team_drive_value_.size()) {
  324. // Embed next start offset to next page token to be read in
  325. // GetRemainingTeamDriveList next time.
  326. result->set_next_page_token(base::NumberToString(next_start_offset));
  327. }
  328. for (size_t i = start_offset;
  329. i < std::min(next_start_offset, team_drive_value_.size()); ++i) {
  330. std::unique_ptr<TeamDriveResource> team_drive(new TeamDriveResource);
  331. team_drive->set_id(team_drive_value_[i]->id());
  332. team_drive->set_name(team_drive_value_[i]->name());
  333. team_drive->set_capabilities(team_drive_value_[i]->capabilities());
  334. result->mutable_items()->push_back(std::move(team_drive));
  335. }
  336. base::ThreadTaskRunnerHandle::Get()->PostTask(
  337. FROM_HERE,
  338. base::BindOnce(std::move(callback), HTTP_SUCCESS, std::move(result)));
  339. }
  340. CancelCallbackOnce FakeDriveService::GetAllTeamDriveList(
  341. TeamDriveListCallback callback) {
  342. DCHECK(thread_checker_.CalledOnValidThread());
  343. DCHECK(callback);
  344. GetTeamDriveListInternal(0, default_max_results_,
  345. &team_drive_list_load_count_, std::move(callback));
  346. return CancelCallbackOnce();
  347. }
  348. CancelCallbackOnce FakeDriveService::GetAllFileList(
  349. const std::string& team_drive_id,
  350. FileListCallback callback) {
  351. DCHECK(thread_checker_.CalledOnValidThread());
  352. if (never_return_all_file_list_) {
  353. ++blocked_file_list_load_count_;
  354. return CancelCallbackOnce();
  355. }
  356. GetChangeListInternal(
  357. 0, // start changestamp
  358. std::string(), // empty search query
  359. std::string(), // no directory resource id,
  360. team_drive_id,
  361. 0, // start offset
  362. default_max_results_, &file_list_load_count_,
  363. base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
  364. return CancelCallbackOnce();
  365. }
  366. CancelCallbackOnce FakeDriveService::GetFileListInDirectory(
  367. const std::string& directory_resource_id,
  368. FileListCallback callback) {
  369. DCHECK(thread_checker_.CalledOnValidThread());
  370. DCHECK(!directory_resource_id.empty());
  371. GetChangeListInternal(
  372. 0, // start changestamp
  373. std::string(), // empty search query
  374. directory_resource_id,
  375. std::string(), // empty team drive id.
  376. 0, // start offset
  377. default_max_results_, &directory_load_count_,
  378. base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
  379. return CancelCallbackOnce();
  380. }
  381. CancelCallbackOnce FakeDriveService::Search(const std::string& search_query,
  382. FileListCallback callback) {
  383. DCHECK(thread_checker_.CalledOnValidThread());
  384. DCHECK(!search_query.empty());
  385. GetChangeListInternal(
  386. 0, // start changestamp
  387. search_query,
  388. std::string(), // no directory resource id,
  389. std::string(), // empty team drive id.
  390. 0, // start offset
  391. default_max_results_, nullptr,
  392. base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
  393. return CancelCallbackOnce();
  394. }
  395. CancelCallbackOnce FakeDriveService::SearchByTitle(
  396. const std::string& title,
  397. const std::string& directory_resource_id,
  398. FileListCallback callback) {
  399. DCHECK(thread_checker_.CalledOnValidThread());
  400. DCHECK(!title.empty());
  401. // Note: the search implementation here doesn't support quotation unescape,
  402. // so don't escape here.
  403. GetChangeListInternal(
  404. 0, // start changestamp
  405. base::StringPrintf("title:'%s'", title.c_str()), directory_resource_id,
  406. std::string(), // empty team drive id.
  407. 0, // start offset
  408. default_max_results_, nullptr,
  409. base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
  410. return CancelCallbackOnce();
  411. }
  412. CancelCallbackOnce FakeDriveService::GetChangeList(
  413. int64_t start_changestamp,
  414. ChangeListCallback callback) {
  415. DCHECK(thread_checker_.CalledOnValidThread());
  416. DCHECK(callback);
  417. GetChangeListInternal(start_changestamp,
  418. std::string(), // empty search query
  419. std::string(), // no directory resource id,
  420. std::string(), // empty team drive id.
  421. 0, // start offset
  422. default_max_results_, &change_list_load_count_,
  423. std::move(callback));
  424. return CancelCallbackOnce();
  425. }
  426. CancelCallbackOnce FakeDriveService::GetChangeListByToken(
  427. const std::string& team_drive_id,
  428. const std::string& start_page_token,
  429. ChangeListCallback callback) {
  430. DCHECK(thread_checker_.CalledOnValidThread());
  431. DCHECK(callback);
  432. int64_t changestamp = 0;
  433. CHECK(base::StringToInt64(start_page_token, &changestamp));
  434. GetChangeListInternal(changestamp,
  435. std::string(), // empty search query
  436. std::string(), // no directory resource id,
  437. team_drive_id,
  438. 0, // start offset
  439. default_max_results_, &change_list_load_count_,
  440. std::move(callback));
  441. return CancelCallbackOnce();
  442. }
  443. CancelCallbackOnce FakeDriveService::GetRemainingChangeList(
  444. const GURL& next_link,
  445. ChangeListCallback callback) {
  446. DCHECK(thread_checker_.CalledOnValidThread());
  447. DCHECK(!next_link.is_empty());
  448. DCHECK(callback);
  449. // "changestamp", "q", "parent" and "start-offset" are parameters to
  450. // implement "paging" of the result on FakeDriveService.
  451. // The URL should be the one filled in GetChangeListInternal of the
  452. // previous method invocation, so it should start with "http://localhost/?".
  453. // See also GetChangeListInternal.
  454. DCHECK_EQ(next_link.host(), "localhost");
  455. DCHECK_EQ(next_link.path(), "/");
  456. int64_t start_changestamp = 0;
  457. std::string search_query;
  458. std::string directory_resource_id;
  459. std::string team_drive_id;
  460. int start_offset = 0;
  461. int max_results = default_max_results_;
  462. base::StringPairs parameters;
  463. if (base::SplitStringIntoKeyValuePairs(next_link.query(), '=', '&',
  464. &parameters)) {
  465. for (const auto& param : parameters) {
  466. if (param.first == "changestamp") {
  467. base::StringToInt64(param.second, &start_changestamp);
  468. } else if (param.first == "q") {
  469. search_query = base::UnescapeBinaryURLComponent(param.second);
  470. } else if (param.first == "parent") {
  471. directory_resource_id = base::UnescapeBinaryURLComponent(param.second);
  472. } else if (param.first == "team-drive-id") {
  473. team_drive_id = base::UnescapeBinaryURLComponent(param.second);
  474. } else if (param.first == "start-offset") {
  475. base::StringToInt(param.second, &start_offset);
  476. } else if (param.first == "max-results") {
  477. base::StringToInt(param.second, &max_results);
  478. }
  479. }
  480. }
  481. GetChangeListInternal(start_changestamp, search_query, directory_resource_id,
  482. team_drive_id, start_offset, max_results, nullptr,
  483. std::move(callback));
  484. return CancelCallbackOnce();
  485. }
  486. CancelCallbackOnce FakeDriveService::GetRemainingTeamDriveList(
  487. const std::string& page_token,
  488. TeamDriveListCallback callback) {
  489. DCHECK(thread_checker_.CalledOnValidThread());
  490. DCHECK(!page_token.empty());
  491. DCHECK(callback);
  492. // Next offset index to page token is embedded in the token.
  493. size_t start_offset;
  494. bool parse_success = base::StringToSizeT(page_token, &start_offset);
  495. DCHECK(parse_success);
  496. GetTeamDriveListInternal(start_offset, default_max_results_, nullptr,
  497. std::move(callback));
  498. return CancelCallbackOnce();
  499. }
  500. CancelCallbackOnce FakeDriveService::GetRemainingFileList(
  501. const GURL& next_link,
  502. FileListCallback callback) {
  503. DCHECK(thread_checker_.CalledOnValidThread());
  504. DCHECK(!next_link.is_empty());
  505. return GetRemainingChangeList(
  506. next_link, base::BindOnce(&FileListCallbackAdapter, std::move(callback)));
  507. }
  508. CancelCallbackOnce FakeDriveService::GetFileResource(
  509. const std::string& resource_id,
  510. FileResourceCallback callback) {
  511. DCHECK(thread_checker_.CalledOnValidThread());
  512. DCHECK(callback);
  513. if (offline_) {
  514. base::ThreadTaskRunnerHandle::Get()->PostTask(
  515. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  516. std::unique_ptr<FileResource>()));
  517. return CancelCallbackOnce();
  518. }
  519. EntryInfo* entry = FindEntryByResourceId(resource_id);
  520. if (entry && entry->change_resource.file()) {
  521. base::ThreadTaskRunnerHandle::Get()->PostTask(
  522. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  523. std::make_unique<FileResource>(
  524. *entry->change_resource.file())));
  525. return CancelCallbackOnce();
  526. }
  527. base::ThreadTaskRunnerHandle::Get()->PostTask(
  528. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  529. std::unique_ptr<FileResource>()));
  530. return CancelCallbackOnce();
  531. }
  532. CancelCallbackOnce FakeDriveService::GetAboutResource(
  533. AboutResourceCallback callback) {
  534. DCHECK(thread_checker_.CalledOnValidThread());
  535. DCHECK(callback);
  536. if (offline_) {
  537. std::unique_ptr<AboutResource> null;
  538. base::ThreadTaskRunnerHandle::Get()->PostTask(
  539. FROM_HERE,
  540. base::BindOnce(std::move(callback), NO_CONNECTION, std::move(null)));
  541. return CancelCallbackOnce();
  542. }
  543. ++about_resource_load_count_;
  544. std::unique_ptr<AboutResource> about_resource(
  545. new AboutResource(*about_resource_));
  546. base::ThreadTaskRunnerHandle::Get()->PostTask(
  547. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  548. std::move(about_resource)));
  549. return CancelCallbackOnce();
  550. }
  551. CancelCallbackOnce FakeDriveService::GetStartPageToken(
  552. const std::string& team_drive_id,
  553. google_apis::StartPageTokenCallback callback) {
  554. DCHECK(thread_checker_.CalledOnValidThread());
  555. DCHECK(callback);
  556. if (offline_) {
  557. std::unique_ptr<StartPageToken> null;
  558. base::ThreadTaskRunnerHandle::Get()->PostTask(
  559. FROM_HERE,
  560. base::BindOnce(std::move(callback), NO_CONNECTION, std::move(null)));
  561. return CancelCallbackOnce();
  562. }
  563. std::unique_ptr<StartPageToken> start_page_token;
  564. if (team_drive_id.empty()) {
  565. start_page_token = std::make_unique<StartPageToken>(*start_page_token_);
  566. } else {
  567. auto it = team_drive_start_page_tokens_.find(team_drive_id);
  568. DCHECK(it != team_drive_start_page_tokens_.end());
  569. start_page_token = std::make_unique<StartPageToken>(*(it->second));
  570. }
  571. ++start_page_token_load_count_;
  572. base::ThreadTaskRunnerHandle::Get()->PostTask(
  573. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  574. std::move(start_page_token)));
  575. return CancelCallbackOnce();
  576. }
  577. CancelCallbackOnce FakeDriveService::DeleteResource(
  578. const std::string& resource_id,
  579. const std::string& etag,
  580. EntryActionCallback callback) {
  581. DCHECK(thread_checker_.CalledOnValidThread());
  582. DCHECK(callback);
  583. if (offline_) {
  584. base::ThreadTaskRunnerHandle::Get()->PostTask(
  585. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION));
  586. return CancelCallbackOnce();
  587. }
  588. EntryInfo* entry = FindEntryByResourceId(resource_id);
  589. if (!entry) {
  590. base::ThreadTaskRunnerHandle::Get()->PostTask(
  591. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  592. return CancelCallbackOnce();
  593. }
  594. ChangeResource* change = &entry->change_resource;
  595. if (change->is_deleted()) {
  596. base::ThreadTaskRunnerHandle::Get()->PostTask(
  597. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  598. return CancelCallbackOnce();
  599. }
  600. const FileResource* file = change->file();
  601. if (!etag.empty() && etag != file->etag()) {
  602. base::ThreadTaskRunnerHandle::Get()->PostTask(
  603. FROM_HERE, base::BindOnce(std::move(callback), HTTP_PRECONDITION));
  604. return CancelCallbackOnce();
  605. }
  606. if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) {
  607. base::ThreadTaskRunnerHandle::Get()->PostTask(
  608. FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN));
  609. return CancelCallbackOnce();
  610. }
  611. change->set_deleted(true);
  612. AddNewChangestamp(change, file->team_drive_id());
  613. change->set_file(std::unique_ptr<FileResource>());
  614. base::ThreadTaskRunnerHandle::Get()->PostTask(
  615. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NO_CONTENT));
  616. base::ThreadTaskRunnerHandle::Get()->PostTask(
  617. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  618. weak_ptr_factory_.GetWeakPtr()));
  619. return CancelCallbackOnce();
  620. }
  621. CancelCallbackOnce FakeDriveService::TrashResource(
  622. const std::string& resource_id,
  623. EntryActionCallback callback) {
  624. DCHECK(thread_checker_.CalledOnValidThread());
  625. DCHECK(callback);
  626. if (offline_) {
  627. base::ThreadTaskRunnerHandle::Get()->PostTask(
  628. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION));
  629. return CancelCallbackOnce();
  630. }
  631. EntryInfo* entry = FindEntryByResourceId(resource_id);
  632. if (!entry) {
  633. base::ThreadTaskRunnerHandle::Get()->PostTask(
  634. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  635. return CancelCallbackOnce();
  636. }
  637. ChangeResource* change = &entry->change_resource;
  638. FileResource* file = change->mutable_file();
  639. if (change->is_deleted() || file->labels().is_trashed()) {
  640. base::ThreadTaskRunnerHandle::Get()->PostTask(
  641. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  642. return CancelCallbackOnce();
  643. }
  644. if (entry->user_permission != google_apis::drive::PERMISSION_ROLE_OWNER) {
  645. base::ThreadTaskRunnerHandle::Get()->PostTask(
  646. FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN));
  647. return CancelCallbackOnce();
  648. }
  649. file->mutable_labels()->set_trashed(true);
  650. AddNewChangestamp(change, file->team_drive_id());
  651. base::ThreadTaskRunnerHandle::Get()->PostTask(
  652. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS));
  653. base::ThreadTaskRunnerHandle::Get()->PostTask(
  654. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  655. weak_ptr_factory_.GetWeakPtr()));
  656. return CancelCallbackOnce();
  657. }
  658. CancelCallbackOnce FakeDriveService::DownloadFile(
  659. const base::FilePath& local_cache_path,
  660. const std::string& resource_id,
  661. DownloadActionCallback download_action_callback,
  662. const GetContentCallback& get_content_callback,
  663. ProgressCallback progress_callback) {
  664. base::ThreadRestrictions::ScopedAllowIO allow_io;
  665. DCHECK(thread_checker_.CalledOnValidThread());
  666. DCHECK(!download_action_callback.is_null());
  667. if (offline_) {
  668. base::ThreadTaskRunnerHandle::Get()->PostTask(
  669. FROM_HERE, base::BindOnce(std::move(download_action_callback),
  670. NO_CONNECTION, base::FilePath()));
  671. return CancelCallbackOnce();
  672. }
  673. EntryInfo* entry = FindEntryByResourceId(resource_id);
  674. if (!entry || entry->change_resource.file()->IsHostedDocument()) {
  675. base::ThreadTaskRunnerHandle::Get()->PostTask(
  676. FROM_HERE, base::BindOnce(std::move(download_action_callback),
  677. HTTP_NOT_FOUND, base::FilePath()));
  678. return CancelCallbackOnce();
  679. }
  680. const FileResource* file = entry->change_resource.file();
  681. const std::string& content_data = entry->content_data;
  682. int64_t file_size = file->file_size();
  683. DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
  684. if (!get_content_callback.is_null()) {
  685. const int64_t kBlockSize = 5;
  686. for (int64_t i = 0; i < file_size; i += kBlockSize) {
  687. const int64_t size = std::min(kBlockSize, file_size - i);
  688. std::unique_ptr<std::string> content_for_callback(
  689. new std::string(content_data.substr(i, size)));
  690. base::ThreadTaskRunnerHandle::Get()->PostTask(
  691. FROM_HERE, base::BindOnce(get_content_callback, HTTP_SUCCESS,
  692. std::move(content_for_callback), i == 0));
  693. }
  694. }
  695. if (!test_util::WriteStringToFile(local_cache_path, content_data)) {
  696. // Failed to write the content.
  697. base::ThreadTaskRunnerHandle::Get()->PostTask(
  698. FROM_HERE, base::BindOnce(std::move(download_action_callback),
  699. DRIVE_FILE_ERROR, base::FilePath()));
  700. return CancelCallbackOnce();
  701. }
  702. if (!progress_callback.is_null()) {
  703. // See also the comment in ResumeUpload(). For testing that clients
  704. // can handle the case progress_callback is called multiple times,
  705. // here we invoke the callback twice.
  706. base::ThreadTaskRunnerHandle::Get()->PostTask(
  707. FROM_HERE, base::BindOnce(progress_callback, file_size / 2, file_size));
  708. base::ThreadTaskRunnerHandle::Get()->PostTask(
  709. FROM_HERE, base::BindOnce(progress_callback, file_size, file_size));
  710. }
  711. base::ThreadTaskRunnerHandle::Get()->PostTask(
  712. FROM_HERE, base::BindOnce(std::move(download_action_callback),
  713. HTTP_SUCCESS, local_cache_path));
  714. return google_apis::CancelCallbackOnce();
  715. }
  716. CancelCallbackOnce FakeDriveService::CopyResource(
  717. const std::string& resource_id,
  718. const std::string& in_parent_resource_id,
  719. const std::string& new_title,
  720. const base::Time& last_modified,
  721. FileResourceCallback callback) {
  722. DCHECK(thread_checker_.CalledOnValidThread());
  723. DCHECK(callback);
  724. if (offline_) {
  725. base::ThreadTaskRunnerHandle::Get()->PostTask(
  726. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  727. std::unique_ptr<FileResource>()));
  728. return CancelCallbackOnce();
  729. }
  730. const std::string& parent_resource_id = in_parent_resource_id.empty()
  731. ? GetRootResourceId()
  732. : in_parent_resource_id;
  733. EntryInfo* entry = FindEntryByResourceId(resource_id);
  734. if (!entry) {
  735. base::ThreadTaskRunnerHandle::Get()->PostTask(
  736. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  737. std::unique_ptr<FileResource>()));
  738. return CancelCallbackOnce();
  739. }
  740. // Make a copy and set the new resource ID and the new title.
  741. std::unique_ptr<EntryInfo> copied_entry(new EntryInfo);
  742. copied_entry->content_data = entry->content_data;
  743. copied_entry->share_url = entry->share_url;
  744. copied_entry->change_resource.set_type(ChangeResource::FILE);
  745. copied_entry->change_resource.set_file(
  746. std::make_unique<FileResource>(*entry->change_resource.file()));
  747. ChangeResource* new_change = &copied_entry->change_resource;
  748. FileResource* new_file = new_change->mutable_file();
  749. const std::string new_resource_id = GetNewResourceId();
  750. new_change->set_file_id(new_resource_id);
  751. new_file->set_file_id(new_resource_id);
  752. new_file->set_title(new_title);
  753. ParentReference parent;
  754. parent.set_file_id(parent_resource_id);
  755. std::vector<ParentReference> parents;
  756. parents.push_back(parent);
  757. *new_file->mutable_parents() = parents;
  758. // Set the team drive for the new entry to the parent.
  759. if (entries_.count(parent_resource_id) > 0) {
  760. const ChangeResource& change =
  761. entries_[parent_resource_id]->change_resource;
  762. new_file->set_team_drive_id(GetTeamDriveId(change));
  763. }
  764. if (!last_modified.is_null()) {
  765. new_file->set_modified_date(last_modified);
  766. new_file->set_modified_by_me_date(last_modified);
  767. } else {
  768. auto now = base::Time::Now();
  769. new_file->set_modified_date(now);
  770. new_file->set_modified_by_me_date(now);
  771. }
  772. AddNewChangestamp(new_change, new_file->team_drive_id());
  773. UpdateETag(new_file);
  774. // Add the new entry to the map.
  775. entries_[new_resource_id] = std::move(copied_entry);
  776. base::ThreadTaskRunnerHandle::Get()->PostTask(
  777. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  778. std::make_unique<FileResource>(*new_file)));
  779. base::ThreadTaskRunnerHandle::Get()->PostTask(
  780. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  781. weak_ptr_factory_.GetWeakPtr()));
  782. return CancelCallbackOnce();
  783. }
  784. CancelCallbackOnce FakeDriveService::UpdateResource(
  785. const std::string& resource_id,
  786. const std::string& parent_resource_id,
  787. const std::string& new_title,
  788. const base::Time& last_modified,
  789. const base::Time& last_viewed_by_me,
  790. const google_apis::drive::Properties& properties,
  791. FileResourceCallback callback) {
  792. DCHECK(thread_checker_.CalledOnValidThread());
  793. DCHECK(callback);
  794. if (offline_) {
  795. base::ThreadTaskRunnerHandle::Get()->PostTask(
  796. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  797. std::unique_ptr<FileResource>()));
  798. return CancelCallbackOnce();
  799. }
  800. EntryInfo* entry = FindEntryByResourceId(resource_id);
  801. if (!entry) {
  802. base::ThreadTaskRunnerHandle::Get()->PostTask(
  803. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  804. std::unique_ptr<FileResource>()));
  805. return CancelCallbackOnce();
  806. }
  807. if (!UserHasWriteAccess(entry->user_permission)) {
  808. base::ThreadTaskRunnerHandle::Get()->PostTask(
  809. FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN,
  810. std::unique_ptr<FileResource>()));
  811. return CancelCallbackOnce();
  812. }
  813. ChangeResource* change = &entry->change_resource;
  814. FileResource* file = change->mutable_file();
  815. if (!new_title.empty())
  816. file->set_title(new_title);
  817. // Set parent if necessary.
  818. if (!parent_resource_id.empty()) {
  819. ParentReference parent;
  820. parent.set_file_id(parent_resource_id);
  821. std::vector<ParentReference> parents;
  822. parents.push_back(parent);
  823. *file->mutable_parents() = parents;
  824. }
  825. if (!last_modified.is_null()) {
  826. file->set_modified_date(last_modified);
  827. file->set_modified_by_me_date(last_modified);
  828. }
  829. if (!last_viewed_by_me.is_null())
  830. file->set_last_viewed_by_me_date(last_viewed_by_me);
  831. AddNewChangestamp(change, file->team_drive_id());
  832. UpdateETag(file);
  833. base::ThreadTaskRunnerHandle::Get()->PostTask(
  834. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  835. std::make_unique<FileResource>(*file)));
  836. base::ThreadTaskRunnerHandle::Get()->PostTask(
  837. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  838. weak_ptr_factory_.GetWeakPtr()));
  839. return CancelCallbackOnce();
  840. }
  841. CancelCallbackOnce FakeDriveService::AddResourceToDirectory(
  842. const std::string& parent_resource_id,
  843. const std::string& resource_id,
  844. EntryActionCallback callback) {
  845. DCHECK(thread_checker_.CalledOnValidThread());
  846. DCHECK(callback);
  847. if (offline_) {
  848. base::ThreadTaskRunnerHandle::Get()->PostTask(
  849. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION));
  850. return CancelCallbackOnce();
  851. }
  852. EntryInfo* entry = FindEntryByResourceId(resource_id);
  853. if (!entry) {
  854. base::ThreadTaskRunnerHandle::Get()->PostTask(
  855. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  856. return CancelCallbackOnce();
  857. }
  858. ChangeResource* change = &entry->change_resource;
  859. // On the real Drive server, resources do not necessary shape a tree
  860. // structure. That is, each resource can have multiple parent.
  861. // We mimic the behavior here; AddResourceToDirectoy just adds
  862. // one more parent, not overwriting old ones.
  863. ParentReference parent;
  864. parent.set_file_id(parent_resource_id);
  865. change->mutable_file()->mutable_parents()->push_back(parent);
  866. AddNewChangestamp(change, change->file()->team_drive_id());
  867. base::ThreadTaskRunnerHandle::Get()->PostTask(
  868. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS));
  869. base::ThreadTaskRunnerHandle::Get()->PostTask(
  870. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  871. weak_ptr_factory_.GetWeakPtr()));
  872. return CancelCallbackOnce();
  873. }
  874. CancelCallbackOnce FakeDriveService::RemoveResourceFromDirectory(
  875. const std::string& parent_resource_id,
  876. const std::string& resource_id,
  877. EntryActionCallback callback) {
  878. DCHECK(thread_checker_.CalledOnValidThread());
  879. DCHECK(callback);
  880. if (offline_) {
  881. base::ThreadTaskRunnerHandle::Get()->PostTask(
  882. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION));
  883. return CancelCallbackOnce();
  884. }
  885. EntryInfo* entry = FindEntryByResourceId(resource_id);
  886. if (!entry) {
  887. base::ThreadTaskRunnerHandle::Get()->PostTask(
  888. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  889. return CancelCallbackOnce();
  890. }
  891. ChangeResource* change = &entry->change_resource;
  892. FileResource* file = change->mutable_file();
  893. std::vector<ParentReference>* parents = file->mutable_parents();
  894. for (size_t i = 0; i < parents->size(); ++i) {
  895. if ((*parents)[i].file_id() == parent_resource_id) {
  896. parents->erase(parents->begin() + i);
  897. AddNewChangestamp(change, file->team_drive_id());
  898. base::ThreadTaskRunnerHandle::Get()->PostTask(
  899. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NO_CONTENT));
  900. base::ThreadTaskRunnerHandle::Get()->PostTask(
  901. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  902. weak_ptr_factory_.GetWeakPtr()));
  903. return CancelCallbackOnce();
  904. }
  905. }
  906. base::ThreadTaskRunnerHandle::Get()->PostTask(
  907. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND));
  908. return CancelCallbackOnce();
  909. }
  910. CancelCallbackOnce FakeDriveService::AddNewDirectory(
  911. const std::string& parent_resource_id,
  912. const std::string& directory_title,
  913. const AddNewDirectoryOptions& options,
  914. FileResourceCallback callback) {
  915. return AddNewDirectoryWithResourceId(
  916. "", parent_resource_id.empty() ? GetRootResourceId() : parent_resource_id,
  917. directory_title, options, std::move(callback));
  918. }
  919. CancelCallbackOnce FakeDriveService::InitiateUploadNewFile(
  920. const std::string& content_type,
  921. int64_t content_length,
  922. const std::string& parent_resource_id,
  923. const std::string& title,
  924. const UploadNewFileOptions& options,
  925. InitiateUploadCallback callback) {
  926. DCHECK(thread_checker_.CalledOnValidThread());
  927. DCHECK(!callback.is_null());
  928. if (offline_) {
  929. base::ThreadTaskRunnerHandle::Get()->PostTask(
  930. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, GURL()));
  931. return CancelCallbackOnce();
  932. }
  933. if (parent_resource_id != GetRootResourceId() &&
  934. !entries_.count(parent_resource_id)) {
  935. base::ThreadTaskRunnerHandle::Get()->PostTask(
  936. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND, GURL()));
  937. return CancelCallbackOnce();
  938. }
  939. GURL session_url = GetNewUploadSessionUrl();
  940. upload_sessions_[session_url] =
  941. UploadSession(content_type, content_length, parent_resource_id,
  942. "", // resource_id
  943. "", // etag
  944. title);
  945. if (title == "never-sync.txt") {
  946. return CancelCallbackOnce();
  947. }
  948. base::ThreadTaskRunnerHandle::Get()->PostTask(
  949. FROM_HERE,
  950. base::BindOnce(std::move(callback), HTTP_SUCCESS, session_url));
  951. return CancelCallbackOnce();
  952. }
  953. CancelCallbackOnce FakeDriveService::InitiateUploadExistingFile(
  954. const std::string& content_type,
  955. int64_t content_length,
  956. const std::string& resource_id,
  957. const UploadExistingFileOptions& options,
  958. InitiateUploadCallback callback) {
  959. DCHECK(thread_checker_.CalledOnValidThread());
  960. DCHECK(!callback.is_null());
  961. if (offline_) {
  962. base::ThreadTaskRunnerHandle::Get()->PostTask(
  963. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, GURL()));
  964. return CancelCallbackOnce();
  965. }
  966. EntryInfo* entry = FindEntryByResourceId(resource_id);
  967. if (!entry) {
  968. base::ThreadTaskRunnerHandle::Get()->PostTask(
  969. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND, GURL()));
  970. return CancelCallbackOnce();
  971. }
  972. if (!UserHasWriteAccess(entry->user_permission)) {
  973. base::ThreadTaskRunnerHandle::Get()->PostTask(
  974. FROM_HERE, base::BindOnce(std::move(callback), HTTP_FORBIDDEN, GURL()));
  975. return CancelCallbackOnce();
  976. }
  977. FileResource* file = entry->change_resource.mutable_file();
  978. if (!options.etag.empty() && options.etag != file->etag()) {
  979. base::ThreadTaskRunnerHandle::Get()->PostTask(
  980. FROM_HERE,
  981. base::BindOnce(std::move(callback), HTTP_PRECONDITION, GURL()));
  982. return CancelCallbackOnce();
  983. }
  984. // TODO(hashimoto): Update |file|'s metadata with |options|.
  985. GURL session_url = GetNewUploadSessionUrl();
  986. upload_sessions_[session_url] =
  987. UploadSession(content_type, content_length,
  988. "", // parent_resource_id
  989. resource_id, file->etag(), "" /* title */);
  990. base::ThreadTaskRunnerHandle::Get()->PostTask(
  991. FROM_HERE,
  992. base::BindOnce(std::move(callback), HTTP_SUCCESS, session_url));
  993. return CancelCallbackOnce();
  994. }
  995. CancelCallbackOnce FakeDriveService::GetUploadStatus(
  996. const GURL& upload_url,
  997. int64_t content_length,
  998. UploadRangeCallback callback) {
  999. DCHECK(thread_checker_.CalledOnValidThread());
  1000. DCHECK(callback);
  1001. return CancelCallbackOnce();
  1002. }
  1003. CancelCallbackOnce FakeDriveService::ResumeUpload(
  1004. const GURL& upload_url,
  1005. int64_t start_position,
  1006. int64_t end_position,
  1007. int64_t content_length,
  1008. const std::string& content_type,
  1009. const base::FilePath& local_file_path,
  1010. UploadRangeCallback callback,
  1011. ProgressCallback progress_callback) {
  1012. DCHECK(thread_checker_.CalledOnValidThread());
  1013. DCHECK(callback);
  1014. FileResourceCallback completion_callback =
  1015. base::BindOnce(&ScheduleUploadRangeCallback, std::move(callback),
  1016. start_position, end_position);
  1017. if (offline_) {
  1018. std::move(completion_callback)
  1019. .Run(NO_CONNECTION, std::unique_ptr<FileResource>());
  1020. return CancelCallbackOnce();
  1021. }
  1022. if (!upload_sessions_.count(upload_url)) {
  1023. std::move(completion_callback)
  1024. .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
  1025. return CancelCallbackOnce();
  1026. }
  1027. UploadSession* session = &upload_sessions_[upload_url];
  1028. // Chunks are required to be sent in such a ways that they fill from the start
  1029. // of the not-yet-uploaded part with no gaps nor overlaps.
  1030. if (session->uploaded_size != start_position) {
  1031. std::move(completion_callback)
  1032. .Run(HTTP_BAD_REQUEST, std::unique_ptr<FileResource>());
  1033. return CancelCallbackOnce();
  1034. }
  1035. if (!progress_callback.is_null()) {
  1036. // In the real GDataWapi/Drive DriveService, progress is reported in
  1037. // nondeterministic timing. In this fake implementation, we choose to call
  1038. // it twice per one ResumeUpload. This is for making sure that client code
  1039. // works fine even if the callback is invoked more than once; it is the
  1040. // crucial difference of the progress callback from others.
  1041. // Note that progress is notified in the relative offset in each chunk.
  1042. const int64_t chunk_size = end_position - start_position;
  1043. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1044. FROM_HERE,
  1045. base::BindOnce(progress_callback, chunk_size / 2, chunk_size));
  1046. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1047. FROM_HERE, base::BindOnce(progress_callback, chunk_size, chunk_size));
  1048. }
  1049. if (content_length != end_position) {
  1050. session->uploaded_size = end_position;
  1051. std::move(completion_callback)
  1052. .Run(HTTP_RESUME_INCOMPLETE, std::unique_ptr<FileResource>());
  1053. return CancelCallbackOnce();
  1054. }
  1055. std::string content_data;
  1056. {
  1057. base::ScopedAllowBlockingForTesting allow_io;
  1058. if (!base::ReadFileToString(local_file_path, &content_data)) {
  1059. session->uploaded_size = end_position;
  1060. std::move(completion_callback)
  1061. .Run(DRIVE_FILE_ERROR, std::unique_ptr<FileResource>());
  1062. return CancelCallbackOnce();
  1063. }
  1064. }
  1065. session->uploaded_size = end_position;
  1066. // |resource_id| is empty if the upload is for new file.
  1067. if (session->resource_id.empty()) {
  1068. DCHECK(!session->parent_resource_id.empty());
  1069. DCHECK(!session->title.empty());
  1070. const EntryInfo* new_entry =
  1071. AddNewEntry("", // auto generate resource id.
  1072. session->content_type, content_data,
  1073. session->parent_resource_id, session->title,
  1074. false); // shared_with_me
  1075. if (!new_entry) {
  1076. std::move(completion_callback)
  1077. .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
  1078. return CancelCallbackOnce();
  1079. }
  1080. std::move(completion_callback)
  1081. .Run(HTTP_CREATED, std::make_unique<FileResource>(
  1082. *new_entry->change_resource.file()));
  1083. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1084. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  1085. weak_ptr_factory_.GetWeakPtr()));
  1086. return CancelCallbackOnce();
  1087. }
  1088. EntryInfo* entry = FindEntryByResourceId(session->resource_id);
  1089. if (!entry) {
  1090. std::move(completion_callback)
  1091. .Run(HTTP_NOT_FOUND, std::unique_ptr<FileResource>());
  1092. return CancelCallbackOnce();
  1093. }
  1094. ChangeResource* change = &entry->change_resource;
  1095. FileResource* file = change->mutable_file();
  1096. if (file->etag().empty() || session->etag != file->etag()) {
  1097. std::move(completion_callback)
  1098. .Run(HTTP_PRECONDITION, std::unique_ptr<FileResource>());
  1099. return CancelCallbackOnce();
  1100. }
  1101. file->set_md5_checksum(base::MD5String(content_data));
  1102. entry->content_data = content_data;
  1103. file->set_file_size(end_position);
  1104. AddNewChangestamp(change, file->team_drive_id());
  1105. UpdateETag(file);
  1106. std::move(completion_callback)
  1107. .Run(HTTP_SUCCESS, std::make_unique<FileResource>(*file));
  1108. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1109. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  1110. weak_ptr_factory_.GetWeakPtr()));
  1111. return CancelCallbackOnce();
  1112. }
  1113. CancelCallbackOnce FakeDriveService::MultipartUploadNewFile(
  1114. const std::string& content_type,
  1115. int64_t content_length,
  1116. const std::string& parent_resource_id,
  1117. const std::string& title,
  1118. const base::FilePath& local_file_path,
  1119. const UploadNewFileOptions& options,
  1120. FileResourceCallback callback,
  1121. ProgressCallback progress_callback) {
  1122. CallResumeUpload* const call_resume_upload = new CallResumeUpload();
  1123. call_resume_upload->service = weak_ptr_factory_.GetWeakPtr();
  1124. call_resume_upload->content_type = content_type;
  1125. call_resume_upload->content_length = content_length;
  1126. call_resume_upload->local_file_path = local_file_path;
  1127. call_resume_upload->callback = std::move(callback);
  1128. call_resume_upload->progress_callback = progress_callback;
  1129. InitiateUploadNewFile(
  1130. content_type, content_length, parent_resource_id, title, options,
  1131. base::BindOnce(&CallResumeUpload::Run, base::Owned(call_resume_upload)));
  1132. return CancelCallbackOnce();
  1133. }
  1134. CancelCallbackOnce FakeDriveService::MultipartUploadExistingFile(
  1135. const std::string& content_type,
  1136. int64_t content_length,
  1137. const std::string& resource_id,
  1138. const base::FilePath& local_file_path,
  1139. const UploadExistingFileOptions& options,
  1140. FileResourceCallback callback,
  1141. ProgressCallback progress_callback) {
  1142. CallResumeUpload* const call_resume_upload = new CallResumeUpload();
  1143. call_resume_upload->service = weak_ptr_factory_.GetWeakPtr();
  1144. call_resume_upload->content_type = content_type;
  1145. call_resume_upload->content_length = content_length;
  1146. call_resume_upload->local_file_path = local_file_path;
  1147. call_resume_upload->callback = std::move(callback);
  1148. call_resume_upload->progress_callback = progress_callback;
  1149. InitiateUploadExistingFile(
  1150. content_type, content_length, resource_id, options,
  1151. base::BindOnce(&CallResumeUpload::Run, base::Owned(call_resume_upload)));
  1152. return CancelCallbackOnce();
  1153. }
  1154. void FakeDriveService::AddNewFile(const std::string& content_type,
  1155. const std::string& content_data,
  1156. const std::string& parent_resource_id,
  1157. const std::string& title,
  1158. bool shared_with_me,
  1159. FileResourceCallback callback) {
  1160. AddNewFileWithResourceId("", content_type, content_data, parent_resource_id,
  1161. title, shared_with_me, std::move(callback));
  1162. }
  1163. void FakeDriveService::AddNewFileWithResourceId(
  1164. const std::string& resource_id,
  1165. const std::string& content_type,
  1166. const std::string& content_data,
  1167. const std::string& parent_resource_id,
  1168. const std::string& title,
  1169. bool shared_with_me,
  1170. FileResourceCallback callback) {
  1171. DCHECK(thread_checker_.CalledOnValidThread());
  1172. DCHECK(callback);
  1173. if (offline_) {
  1174. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1175. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  1176. std::unique_ptr<FileResource>()));
  1177. return;
  1178. }
  1179. const EntryInfo* new_entry =
  1180. AddNewEntry(resource_id, content_type, content_data, parent_resource_id,
  1181. title, shared_with_me);
  1182. if (!new_entry) {
  1183. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1184. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  1185. std::unique_ptr<FileResource>()));
  1186. return;
  1187. }
  1188. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1189. FROM_HERE, base::BindOnce(std::move(callback), HTTP_CREATED,
  1190. std::make_unique<FileResource>(
  1191. *new_entry->change_resource.file())));
  1192. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1193. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  1194. weak_ptr_factory_.GetWeakPtr()));
  1195. }
  1196. CancelCallbackOnce FakeDriveService::AddNewDirectoryWithResourceId(
  1197. const std::string& resource_id,
  1198. const std::string& parent_resource_id,
  1199. const std::string& directory_title,
  1200. const AddNewDirectoryOptions& options,
  1201. FileResourceCallback callback) {
  1202. DCHECK(thread_checker_.CalledOnValidThread());
  1203. DCHECK(callback);
  1204. if (offline_) {
  1205. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1206. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  1207. std::unique_ptr<FileResource>()));
  1208. return CancelCallbackOnce();
  1209. }
  1210. const EntryInfo* new_entry =
  1211. AddNewEntry(resource_id, util::kDriveFolderMimeType,
  1212. "", // content_data
  1213. parent_resource_id, directory_title,
  1214. false); // shared_with_me
  1215. if (!new_entry) {
  1216. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1217. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  1218. std::unique_ptr<FileResource>()));
  1219. return CancelCallbackOnce();
  1220. }
  1221. const google_apis::ApiErrorCode result = SetFileVisibility(
  1222. new_entry->change_resource.file_id(), options.visibility);
  1223. DCHECK_EQ(HTTP_SUCCESS, result);
  1224. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1225. FROM_HERE, base::BindOnce(std::move(callback), HTTP_CREATED,
  1226. std::make_unique<FileResource>(
  1227. *new_entry->change_resource.file())));
  1228. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1229. FROM_HERE, base::BindOnce(&FakeDriveService::NotifyObservers,
  1230. weak_ptr_factory_.GetWeakPtr()));
  1231. return CancelCallbackOnce();
  1232. }
  1233. void FakeDriveService::SetLastModifiedTime(const std::string& resource_id,
  1234. const base::Time& last_modified_time,
  1235. FileResourceCallback callback) {
  1236. DCHECK(thread_checker_.CalledOnValidThread());
  1237. DCHECK(callback);
  1238. if (offline_) {
  1239. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1240. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  1241. std::unique_ptr<FileResource>()));
  1242. return;
  1243. }
  1244. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1245. if (!entry) {
  1246. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1247. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  1248. std::unique_ptr<FileResource>()));
  1249. return;
  1250. }
  1251. ChangeResource* change = &entry->change_resource;
  1252. FileResource* file = change->mutable_file();
  1253. file->set_modified_date(last_modified_time);
  1254. file->set_modified_by_me_date(last_modified_time);
  1255. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1256. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  1257. std::make_unique<FileResource>(*file)));
  1258. }
  1259. void FakeDriveService::SetFileCapabilities(
  1260. const std::string& resource_id,
  1261. const google_apis::FileResourceCapabilities& capabilities,
  1262. FileResourceCallback callback) {
  1263. DCHECK(thread_checker_.CalledOnValidThread());
  1264. DCHECK(callback);
  1265. if (offline_) {
  1266. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1267. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  1268. std::unique_ptr<FileResource>()));
  1269. return;
  1270. }
  1271. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1272. if (!entry) {
  1273. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1274. FROM_HERE, base::BindOnce(std::move(callback), HTTP_NOT_FOUND,
  1275. std::unique_ptr<FileResource>()));
  1276. return;
  1277. }
  1278. ChangeResource& change = entry->change_resource;
  1279. FileResource* file = change.mutable_file();
  1280. file->set_capabilities(capabilities);
  1281. AddNewChangestamp(&change, file->team_drive_id());
  1282. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1283. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  1284. std::make_unique<FileResource>(*file)));
  1285. }
  1286. bool FakeDriveService::SetTeamDriveCapabilities(
  1287. const std::string& team_drive_id,
  1288. const google_apis::TeamDriveCapabilities& capabilities) {
  1289. DCHECK(thread_checker_.CalledOnValidThread());
  1290. if (offline_) {
  1291. return false;
  1292. }
  1293. EntryInfo* entry = FindEntryByResourceId(team_drive_id);
  1294. if (!entry) {
  1295. return false;
  1296. }
  1297. for (size_t i = 0; i < team_drive_value_.size(); ++i) {
  1298. std::unique_ptr<TeamDriveResource> team_drive(new TeamDriveResource);
  1299. if (team_drive_value_[i]->id() == team_drive_id) {
  1300. team_drive_value_[i]->set_capabilities(capabilities);
  1301. }
  1302. }
  1303. ChangeResource& change = entry->change_resource;
  1304. DCHECK_EQ(ChangeResource::TEAM_DRIVE, change.type());
  1305. TeamDriveResource* team_drive = change.mutable_team_drive();
  1306. team_drive->set_capabilities(capabilities);
  1307. // Changes to Team Drives are added to the default changelist.
  1308. AddNewChangestamp(&change, std::string());
  1309. return true;
  1310. }
  1311. google_apis::ApiErrorCode FakeDriveService::SetUserPermission(
  1312. const std::string& resource_id,
  1313. google_apis::drive::PermissionRole user_permission) {
  1314. DCHECK(thread_checker_.CalledOnValidThread());
  1315. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1316. if (!entry)
  1317. return HTTP_NOT_FOUND;
  1318. entry->user_permission = user_permission;
  1319. return HTTP_SUCCESS;
  1320. }
  1321. google_apis::ApiErrorCode FakeDriveService::SetFileVisibility(
  1322. const std::string& resource_id,
  1323. google_apis::drive::FileVisibility visibility) {
  1324. DCHECK(thread_checker_.CalledOnValidThread());
  1325. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1326. if (!entry)
  1327. return HTTP_NOT_FOUND;
  1328. entry->visibility = visibility;
  1329. return HTTP_SUCCESS;
  1330. }
  1331. google_apis::ApiErrorCode FakeDriveService::GetFileVisibility(
  1332. const std::string& resource_id,
  1333. google_apis::drive::FileVisibility* visibility) {
  1334. DCHECK(thread_checker_.CalledOnValidThread());
  1335. DCHECK(visibility);
  1336. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1337. if (!entry)
  1338. return HTTP_NOT_FOUND;
  1339. *visibility = entry->visibility;
  1340. return HTTP_SUCCESS;
  1341. }
  1342. google_apis::ApiErrorCode FakeDriveService::SetFileAsSharedWithMe(
  1343. const std::string& resource_id) {
  1344. DCHECK(thread_checker_.CalledOnValidThread());
  1345. EntryInfo* entry = FindEntryByResourceId(resource_id);
  1346. if (!entry)
  1347. return HTTP_NOT_FOUND;
  1348. entry->change_resource.mutable_file()->set_shared_with_me_date(
  1349. base::Time::Now());
  1350. return HTTP_SUCCESS;
  1351. }
  1352. void FakeDriveService::AddChangeObserver(ChangeObserver* change_observer) {
  1353. change_observers_.AddObserver(change_observer);
  1354. }
  1355. void FakeDriveService::RemoveChangeObserver(ChangeObserver* change_observer) {
  1356. change_observers_.RemoveObserver(change_observer);
  1357. }
  1358. FakeDriveService::EntryInfo* FakeDriveService::FindEntryByResourceId(
  1359. const std::string& resource_id) {
  1360. DCHECK(thread_checker_.CalledOnValidThread());
  1361. auto it = entries_.find(resource_id);
  1362. if (it == entries_.end()) {
  1363. return nullptr;
  1364. }
  1365. // Deleted entries don't have FileResource.
  1366. if (it->second->change_resource.type() != ChangeResource::TEAM_DRIVE &&
  1367. !it->second->change_resource.file()) {
  1368. return nullptr;
  1369. }
  1370. return it->second.get();
  1371. }
  1372. std::string FakeDriveService::GetNewResourceId() {
  1373. DCHECK(thread_checker_.CalledOnValidThread());
  1374. ++resource_id_count_;
  1375. return base::StringPrintf("resource_id_%d", resource_id_count_);
  1376. }
  1377. void FakeDriveService::UpdateETag(google_apis::FileResource* file) {
  1378. file->set_etag("etag_" + start_page_token_->start_page_token());
  1379. }
  1380. void FakeDriveService::AddNewChangestamp(google_apis::ChangeResource* change,
  1381. const std::string& team_drive_id) {
  1382. ++largest_changestamp_;
  1383. UpdateLatestChangelistId(largest_changestamp_, team_drive_id);
  1384. change->set_change_id(largest_changestamp_);
  1385. }
  1386. const FakeDriveService::EntryInfo* FakeDriveService::AddNewEntry(
  1387. const std::string& given_resource_id,
  1388. const std::string& content_type,
  1389. const std::string& content_data,
  1390. const std::string& parent_resource_id,
  1391. const std::string& title,
  1392. bool shared_with_me) {
  1393. DCHECK(thread_checker_.CalledOnValidThread());
  1394. if (!parent_resource_id.empty() &&
  1395. parent_resource_id != GetRootResourceId() &&
  1396. !entries_.count(parent_resource_id)) {
  1397. return nullptr;
  1398. }
  1399. // Extract the team drive id from the parent, if there is one.
  1400. std::string team_drive_id;
  1401. if (!parent_resource_id.empty() && entries_.count(parent_resource_id) > 0) {
  1402. const ChangeResource& resource =
  1403. entries_[parent_resource_id]->change_resource;
  1404. team_drive_id = GetTeamDriveId(resource);
  1405. }
  1406. const std::string resource_id =
  1407. given_resource_id.empty() ? GetNewResourceId() : given_resource_id;
  1408. if (entries_.count(resource_id))
  1409. return nullptr;
  1410. GURL upload_url = GURL("https://xxx/upload/" + resource_id);
  1411. std::unique_ptr<EntryInfo> new_entry = std::make_unique<EntryInfo>();
  1412. ChangeResource* new_change = &new_entry->change_resource;
  1413. new_change->set_type(ChangeResource::FILE);
  1414. new_change->set_team_drive_id(team_drive_id);
  1415. FileResource* new_file = new FileResource;
  1416. new_change->set_file(base::WrapUnique(new_file));
  1417. // Set the resource ID and the title
  1418. new_change->set_file_id(resource_id);
  1419. new_file->set_file_id(resource_id);
  1420. new_file->set_title(title);
  1421. // Set the contents, size and MD5 for a file.
  1422. if (content_type != util::kDriveFolderMimeType &&
  1423. !util::IsKnownHostedDocumentMimeType(content_type)) {
  1424. new_entry->content_data = content_data;
  1425. new_file->set_file_size(content_data.size());
  1426. new_file->set_md5_checksum(base::MD5String(content_data));
  1427. }
  1428. if (shared_with_me) {
  1429. // Set current time to mark the file as shared_with_me.
  1430. new_file->set_shared_with_me_date(base::Time::Now());
  1431. }
  1432. std::string escaped_resource_id = base::EscapePath(resource_id);
  1433. // Set mime type.
  1434. new_file->set_mime_type(content_type);
  1435. // Set the team drive id.
  1436. new_file->set_team_drive_id(team_drive_id);
  1437. // Set alternate link.
  1438. if (content_type == util::kGoogleDocumentMimeType) {
  1439. new_file->set_alternate_link(
  1440. GURL("https://document_alternate_link/" + title));
  1441. } else if (content_type == util::kDriveFolderMimeType) {
  1442. new_file->set_alternate_link(
  1443. GURL("https://folder_alternate_link/" + title));
  1444. } else {
  1445. new_file->set_alternate_link(GURL("https://file_alternate_link/" + title));
  1446. }
  1447. // Set parents.
  1448. if (!parent_resource_id.empty()) {
  1449. ParentReference parent;
  1450. parent.set_file_id(parent_resource_id);
  1451. std::vector<ParentReference> parents;
  1452. parents.push_back(parent);
  1453. *new_file->mutable_parents() = parents;
  1454. }
  1455. AddNewChangestamp(new_change, team_drive_id);
  1456. UpdateETag(new_file);
  1457. new_file->set_created_date(base::Time() + base::Milliseconds(++date_seq_));
  1458. new_file->set_modified_by_me_date(base::Time() +
  1459. base::Milliseconds(++date_seq_));
  1460. new_file->set_modified_date(base::Time() + base::Milliseconds(++date_seq_));
  1461. EntryInfo* raw_new_entry = new_entry.get();
  1462. entries_[resource_id] = std::move(new_entry);
  1463. return raw_new_entry;
  1464. }
  1465. const FakeDriveService::EntryInfo* FakeDriveService::AddNewTeamDriveEntry(
  1466. const std::string& team_drive_id,
  1467. const std::string& team_drive_name) {
  1468. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  1469. // Check we do not already have this entry.
  1470. if (entries_.count(team_drive_id) > 0) {
  1471. return nullptr;
  1472. }
  1473. std::unique_ptr<EntryInfo> new_entry = std::make_unique<EntryInfo>();
  1474. ChangeResource& change = new_entry->change_resource;
  1475. change.set_type(ChangeResource::TEAM_DRIVE);
  1476. change.set_team_drive_id(team_drive_id);
  1477. std::unique_ptr<TeamDriveResource> team_drive =
  1478. std::make_unique<TeamDriveResource>();
  1479. team_drive->set_id(team_drive_id);
  1480. team_drive->set_name(team_drive_name);
  1481. change.set_team_drive(std::move(team_drive));
  1482. AddNewChangestamp(&change, std::string());
  1483. change.set_modification_date(base::Time() + base::Milliseconds(++date_seq_));
  1484. EntryInfo* raw_new_entry = new_entry.get();
  1485. entries_[team_drive_id] = std::move(new_entry);
  1486. return raw_new_entry;
  1487. }
  1488. void FakeDriveService::GetChangeListInternal(
  1489. int64_t start_changestamp,
  1490. const std::string& search_query,
  1491. const std::string& directory_resource_id,
  1492. const std::string& team_drive_id,
  1493. int start_offset,
  1494. int max_results,
  1495. int* load_counter,
  1496. ChangeListOnceCallback callback) {
  1497. if (offline_) {
  1498. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1499. FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION,
  1500. std::unique_ptr<ChangeList>()));
  1501. return;
  1502. }
  1503. // Filter out entries per parameters like |directory_resource_id| and
  1504. // |search_query|.
  1505. std::vector<std::unique_ptr<ChangeResource>> entries;
  1506. int num_entries_matched = 0;
  1507. for (auto it = entries_.begin(); it != entries_.end(); ++it) {
  1508. const ChangeResource& entry = it->second->change_resource;
  1509. bool should_exclude = false;
  1510. // If |directory_resource_id| is set, exclude the entry if it's not in
  1511. // the target directory.
  1512. if (!directory_resource_id.empty()) {
  1513. // Get the parent resource ID of the entry.
  1514. std::string parent_resource_id;
  1515. if (entry.type() == ChangeResource::FILE && entry.file() &&
  1516. !entry.file()->parents().empty())
  1517. parent_resource_id = entry.file()->parents()[0].file_id();
  1518. if (directory_resource_id != parent_resource_id)
  1519. should_exclude = true;
  1520. }
  1521. // If |search_query| is set, exclude the entry if it does not contain the
  1522. // search query in the title.
  1523. if (!should_exclude && !search_query.empty() &&
  1524. !EntryMatchWithQuery(entry, search_query)) {
  1525. should_exclude = true;
  1526. }
  1527. // If the team drive does not match, then exclude the entry.
  1528. switch (entry.type()) {
  1529. case ChangeResource::FILE:
  1530. if (entry.file() && entry.file()->team_drive_id() != team_drive_id) {
  1531. should_exclude = true;
  1532. }
  1533. break;
  1534. case ChangeResource::TEAM_DRIVE:
  1535. // Only include TeamDrive change resources in the default change list.
  1536. if (!team_drive_id.empty()) {
  1537. should_exclude = true;
  1538. }
  1539. break;
  1540. case ChangeResource::UNKNOWN:
  1541. NOTREACHED();
  1542. break;
  1543. }
  1544. // If |start_changestamp| is set, exclude the entry if the
  1545. // changestamp is older than |largest_changestamp|.
  1546. // See https://developers.google.com/google-apps/documents-list/
  1547. // #retrieving_all_changes_since_a_given_changestamp
  1548. if (start_changestamp > 0 && entry.change_id() < start_changestamp)
  1549. should_exclude = true;
  1550. // If the caller requests other list than change list by specifying
  1551. // zero-|start_changestamp|, exclude deleted entry from the result.
  1552. const bool deleted = entry.is_deleted() ||
  1553. (entry.type() == ChangeResource::FILE &&
  1554. entry.file() && entry.file()->labels().is_trashed());
  1555. if (!start_changestamp && deleted)
  1556. should_exclude = true;
  1557. // The entry matched the criteria for inclusion.
  1558. if (!should_exclude)
  1559. ++num_entries_matched;
  1560. // If |start_offset| is set, exclude the entry if the entry is before the
  1561. // start index. <= instead of < as |num_entries_matched| was
  1562. // already incremented.
  1563. if (start_offset > 0 && num_entries_matched <= start_offset)
  1564. should_exclude = true;
  1565. if (!should_exclude) {
  1566. std::unique_ptr<ChangeResource> entry_copied(new ChangeResource);
  1567. entry_copied->set_type(entry.type());
  1568. entry_copied->set_change_id(entry.change_id());
  1569. entry_copied->set_deleted(entry.is_deleted());
  1570. if (entry.type() == ChangeResource::FILE) {
  1571. entry_copied->set_file_id(entry.file_id());
  1572. if (entry.file()) {
  1573. entry_copied->set_file(std::make_unique<FileResource>(*entry.file()));
  1574. }
  1575. }
  1576. if (entry.type() == ChangeResource::TEAM_DRIVE && entry.team_drive()) {
  1577. entry_copied->set_team_drive(
  1578. std::make_unique<TeamDriveResource>(*entry.team_drive()));
  1579. }
  1580. entry_copied->set_modification_date(entry.modification_date());
  1581. entries.push_back(std::move(entry_copied));
  1582. }
  1583. }
  1584. std::unique_ptr<ChangeList> change_list(new ChangeList);
  1585. if (start_changestamp > 0 && start_offset == 0) {
  1586. auto largest_change_id = about_resource_->largest_change_id();
  1587. change_list->set_largest_change_id(largest_change_id);
  1588. change_list->set_new_start_page_token(
  1589. drive::util::ConvertChangestampToStartPageToken(largest_change_id));
  1590. }
  1591. // If |max_results| is set, trim the entries if the number exceeded the max
  1592. // results.
  1593. if (max_results > 0 && entries.size() > static_cast<size_t>(max_results)) {
  1594. entries.erase(entries.begin() + max_results, entries.end());
  1595. // Adds the next URL.
  1596. // Here, we embed information which is needed for continuing the
  1597. // GetChangeList request in the next invocation into url query
  1598. // parameters.
  1599. GURL next_url(
  1600. base::StringPrintf("http://localhost/?start-offset=%d&max-results=%d",
  1601. start_offset + max_results, max_results));
  1602. if (start_changestamp > 0) {
  1603. next_url = net::AppendOrReplaceQueryParameter(
  1604. next_url, "changestamp", base::NumberToString(start_changestamp));
  1605. }
  1606. if (!search_query.empty()) {
  1607. next_url =
  1608. net::AppendOrReplaceQueryParameter(next_url, "q", search_query);
  1609. }
  1610. if (!directory_resource_id.empty()) {
  1611. next_url = net::AppendOrReplaceQueryParameter(next_url, "parent",
  1612. directory_resource_id);
  1613. }
  1614. if (!team_drive_id.empty()) {
  1615. next_url = net::AppendOrReplaceQueryParameter(next_url, "team-drive-id",
  1616. team_drive_id);
  1617. }
  1618. change_list->set_next_link(next_url);
  1619. }
  1620. *change_list->mutable_items() = std::move(entries);
  1621. if (load_counter)
  1622. *load_counter += 1;
  1623. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1624. FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
  1625. std::move(change_list)));
  1626. }
  1627. GURL FakeDriveService::GetNewUploadSessionUrl() {
  1628. return GURL("https://upload_session_url/" +
  1629. base::NumberToString(next_upload_sequence_number_++));
  1630. }
  1631. CancelCallbackOnce FakeDriveService::AddPermission(
  1632. const std::string& resource_id,
  1633. const std::string& email,
  1634. google_apis::drive::PermissionRole role,
  1635. google_apis::EntryActionCallback callback) {
  1636. DCHECK(thread_checker_.CalledOnValidThread());
  1637. DCHECK(callback);
  1638. NOTREACHED();
  1639. return CancelCallbackOnce();
  1640. }
  1641. std::unique_ptr<BatchRequestConfiguratorInterface>
  1642. FakeDriveService::StartBatchRequest() {
  1643. DCHECK(thread_checker_.CalledOnValidThread());
  1644. NOTREACHED();
  1645. return nullptr;
  1646. }
  1647. void FakeDriveService::NotifyObservers() {
  1648. for (auto& observer : change_observers_)
  1649. observer.OnNewChangeAvailable();
  1650. }
  1651. void FakeDriveService::UpdateLatestChangelistId(
  1652. int64_t change_list_id,
  1653. const std::string& team_drive_id) {
  1654. if (team_drive_id.empty()) {
  1655. about_resource_->set_largest_change_id(change_list_id);
  1656. start_page_token_->set_start_page_token(
  1657. drive::util::ConvertChangestampToStartPageToken(change_list_id));
  1658. } else {
  1659. DCHECK_GT(team_drive_start_page_tokens_.count(team_drive_id), 0UL);
  1660. team_drive_start_page_tokens_[team_drive_id]->set_start_page_token(
  1661. drive::util::ConvertChangestampToStartPageToken(change_list_id));
  1662. }
  1663. }
  1664. } // namespace drive