12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/drive/fake_drive_service.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/file_util.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/md5.h"
129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/drive/drive_api_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/drive_api_parser.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/gdata_wapi_parser.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/test_util.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/time_util.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/escape.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/url_util.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AboutResource;
30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::AboutResourceCallback;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AccountMetadata;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AppList;
33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::AppListCallback;
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing google_apis::AuthStatusCallback;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AuthorizeAppCallback;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::CancelCallback;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::DownloadActionCallback;
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::EntryActionCallback;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_FILE_ERROR;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_NO_CONNECTION;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_OTHER_ERROR;
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::GDataErrorCode;
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetContentCallback;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceEntryCallback;
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceListCallback;
46bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochusing google_apis::GetShareUrlCallback;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_BAD_REQUEST;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_CREATED;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_NOT_FOUND;
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using google_apis::HTTP_NO_CONTENT;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_PRECONDITION;
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_RESUME_INCOMPLETE;
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_SUCCESS;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::InitiateUploadCallback;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::Link;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ProgressCallback;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceEntry;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceList;
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeCallback;
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeResponse;
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace test_util = google_apis::test_util;
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Rel property of an upload link in the entries dictionary value.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUploadUrlRel[] =
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "http://schemas.google.com/g/2005#resumable-create-media";
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Rel property of a share link in the entries dictionary value.
712385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochconst char kShareUrlRel[] =
722385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    "http://schemas.google.com/docs/2007#share";
732385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if a resource entry matches with the search query.
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Supports queries consist of following format.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Phrases quoted by double/single quotes
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - AND search for multiple words/phrases segmented by space
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Limited attribute search.  Only "title:" is supported.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool EntryMatchWithQuery(const ResourceEntry& entry,
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const std::string& query) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokenizer(query, " ");
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tokenizer.set_quote_chars("\"'");
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (tokenizer.GetNext()) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string key, value;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& token = tokenizer.token();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (token.find(':') == std::string::npos) {
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::TrimString(token, "\"'", &value);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringTokenizer key_value(token, ":");
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_value.set_quote_chars("\"'");
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = key_value.token();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::TrimString(key_value.token(), "\"'", &value);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(peria): Deal with other attributes than title.
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!key.empty() && key != "title")
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Search query in the title.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry.title().find(value) == std::string::npos)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 start_position,
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 end_position,
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 GDataErrorCode error,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 scoped_ptr<ResourceEntry> entry) {
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::MessageLoop::current()->PostTask(
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FROM_HERE,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback,
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 UploadRangeResponse(error,
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     start_position,
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     end_position),
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Passed(&entry)));
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void EntryActionCallbackAdapter(
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const EntryActionCallback& callback,
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) {
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  callback.Run(error);
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
129d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)void ClearPropatiesForPermanentDelete(DictionaryValue* entry) {
130d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  scoped_ptr<DictionaryValue> new_entry(new DictionaryValue);
131d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  const char* kPreservedProperties[] = {
132d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    "docs$removed", "docs$changestamp", "gd$resourceId", "id", "updated"
133d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  };
134d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
135d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kPreservedProperties); ++i) {
136d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    const char* key = kPreservedProperties[i];
137d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    scoped_ptr<Value> value;
138d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    if (entry->Remove(key, &value))
139d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      new_entry->Set(key, value.release());
140d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  }
141d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
142d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  entry->Swap(new_entry.get());
143d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)}
144d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct FakeDriveService::UploadSession {
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_type;
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 content_length;
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string parent_resource_id;
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string resource_id;
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string etag;
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string title;
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 uploaded_size;
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession()
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : content_length(0),
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        uploaded_size(0) {}
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession(
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string content_type,
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int64 content_length,
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string parent_resource_id,
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string resource_id,
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string etag,
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string title)
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : content_type(content_type),
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      content_length(content_length),
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      parent_resource_id(parent_resource_id),
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      resource_id(resource_id),
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      etag(etag),
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      title(title),
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uploaded_size(0) {
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::FakeDriveService()
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : largest_changestamp_(0),
1807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      published_date_seq_(0),
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      next_upload_sequence_number_(0),
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default_max_results_(0),
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id_count_(0),
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_list_load_count_(0),
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      change_list_load_count_(0),
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directory_load_count_(0),
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      about_resource_load_count_(0),
1882385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      app_list_load_count_(0),
18958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      blocked_resource_list_load_count_(0),
19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      offline_(false),
19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      never_return_all_resource_list_(false) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::~FakeDriveService() {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadResourceListForWapi(
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Value> raw_value = test_util::LoadJSONFile(relative_path);
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* as_dict = NULL;
2043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  scoped_ptr<base::Value> feed;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* feed_as_dict = NULL;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Extract the "feed" from the raw value and take the ownership.
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that Remove() transfers the ownership to |feed|.
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (raw_value->GetAsDictionary(&as_dict) &&
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      as_dict->Remove("feed", &feed) &&
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      feed->GetAsDictionary(&feed_as_dict)) {
2123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    ignore_result(feed.release());
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resource_list_value_.reset(feed_as_dict);
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Go through entries and convert test$data from a string to a binary blob.
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::ListValue* entries = NULL;
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (feed_as_dict->GetList("entry", &entries)) {
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::string content_data;
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (entries->GetDictionary(i, &entry) &&
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            entry->GetString("test$data", &content_data)) {
2233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          entry->Set("test$data",
2243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                     base::BinaryValue::CreateWithCopiedBuffer(
2253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                         content_data.c_str(), content_data.size()));
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return resource_list_value_;
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAccountMetadataForWapi(
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Load JSON data, which must be a dictionary.
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path);
240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_.reset(
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      static_cast<base::DictionaryValue*>(value.release()));
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the largest_changestamp_.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AccountMetadata> account_metadata =
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AccountMetadata::CreateFrom(*account_metadata_value_);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  largest_changestamp_ = account_metadata->largest_changestamp();
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add the largest changestamp to the existing entries.
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This will be used to generate change lists in GetResourceList().
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resource_list_value_) {
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* entries = NULL;
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (resource_list_value_->GetList("entry", &entries)) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (entries->GetDictionary(i, &entry)) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->SetString("docs$changestamp.value",
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Int64ToString(largest_changestamp_));
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return account_metadata_value_;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAppListForDriveApi(
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_info_value_ = test_util::LoadJSONFile(relative_path);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app_info_value_;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
274ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid FakeDriveService::SetQuotaValue(int64 used, int64 total) {
275ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(account_metadata_value_);
277ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
278ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_->SetString("entry.gd$quotaBytesUsed.$t",
279ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     base::Int64ToString16(used));
280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_->SetString("entry.gd$quotaBytesTotal.$t",
281ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     base::Int64ToString16(total));
282ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GURL FakeDriveService::GetFakeLinkUrl(const std::string& resource_id) {
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return GURL("https://fake_server/" + net::EscapePath(resource_id));
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void FakeDriveService::Initialize(const std::string& account_id) {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::AddObserver(DriveServiceObserver* observer) {
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FakeDriveService::CanSendRequest() const {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
305d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)ResourceIdCanonicalizer FakeDriveService::GetResourceIdCanonicalizer() const {
3068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return util::GetIdentityResourceIdCanonicalizer();
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasAccessToken() const {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid FakeDriveService::RequestAccessToken(const AuthStatusCallback& callback) {
3157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!callback.is_null());
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  callback.Run(google_apis::HTTP_NOT_MODIFIED, "fake_access_token");
3187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasRefreshToken() const {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearAccessToken() {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearRefreshToken() {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetRootResourceId() const {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "fake_root";
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAllResourceList(
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (never_return_all_resource_list_) {
34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ++blocked_resource_list_load_count_;
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return CancelCallback();
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &resource_list_load_count_,
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceListInDirectory(
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &directory_load_count_,
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::Search(
3757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
3767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          search_query,
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::SearchByTitle(
392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: the search implementation here doesn't support quotation unescape,
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so don't escape here.
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          base::StringPrintf("title:'%s'", title.c_str()),
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetChangeList(
4127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(start_changestamp,
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &change_list_load_count_,
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
427424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetRemainingChangeList(
42858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& next_link,
429424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const GetResourceListCallback& callback) {
430424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!next_link.is_empty());
432424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
433424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return GetRemainingResourceList(next_link, callback);
435424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
436424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
437424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetRemainingFileList(
43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& next_link,
439424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const GetResourceListCallback& callback) {
440424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!next_link.is_empty());
442424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
443424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
44458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return GetRemainingResourceList(next_link, callback);
445424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
446424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceEntry(
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
4607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
4707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
4777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
480bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochCancelCallback FakeDriveService::GetShareUrl(
481bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const std::string& resource_id,
482bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GURL& /* embed_origin */,
483bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GetShareUrlCallback& callback) {
484bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
485bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(!callback.is_null());
486bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
487bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (offline_) {
488bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    scoped_ptr<ResourceEntry> null;
489bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    base::MessageLoop::current()->PostTask(
490bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        FROM_HERE,
491bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        base::Bind(callback,
492bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                   GDATA_NO_CONNECTION,
493bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                   GURL()));
494bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    return CancelCallback();
495bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
496bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
497bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
498bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (entry) {
499bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // Share urls are stored in the resource entry, and they do not rely on the
500bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // embedding origin.
501bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    scoped_ptr<ResourceEntry> resource_entry =
502bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        ResourceEntry::CreateFrom(*entry);
503bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const Link* share_url = resource_entry->GetLinkByType(Link::LINK_SHARE);
504bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (share_url) {
505bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::MessageLoop::current()->PostTask(
506bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          FROM_HERE,
507bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          base::Bind(callback, HTTP_SUCCESS, share_url->href()));
508bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    } else {
509bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::MessageLoop::current()->PostTask(
510bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          FROM_HERE,
511bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          base::Bind(callback, HTTP_SUCCESS, GURL()));
512bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
513bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    return CancelCallback();
514bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
515bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
516bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  scoped_ptr<ResourceEntry> null;
517bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::MessageLoop::current()->PostTask(
518bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FROM_HERE,
519bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::Bind(callback, HTTP_NOT_FOUND, GURL()));
520bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return CancelCallback();
521bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
522bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAboutResource(
524424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const AboutResourceCallback& callback) {
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AboutResource> null;
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION, base::Passed(&null)));
5347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++about_resource_load_count_;
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AboutResource> about_resource(
539d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      util::ConvertAccountMetadataToAboutResource(
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *AccountMetadata::CreateFrom(*account_metadata_value_),
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetRootResourceId()));
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overwrite the change id.
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  about_resource->set_largest_change_id(largest_changestamp_);
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback,
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 HTTP_SUCCESS, base::Passed(&about_resource)));
5487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
551424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetAppList(const AppListCallback& callback) {
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(app_info_value_);
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AppList> null;
55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
5637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5662385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  ++app_list_load_count_;
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_));
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list)));
5717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DeleteResource(
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
58290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
5847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
588d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
589d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
590d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      base::DictionaryValue* entry = NULL;
591d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      std::string current_resource_id;
592d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
593d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
594d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          resource_id == current_resource_id) {
595d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        if (entry->HasKey("docs$removed")) {
596d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          base::MessageLoop::current()->PostTask(
597d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
598d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          return CancelCallback();
599d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        }
600d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
601d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        std::string entry_etag;
602d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        entry->GetString("gd$etag", &entry_etag);
603d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        if (!etag.empty() && entry_etag != etag) {
604d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          base::MessageLoop::current()->PostTask(
605d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_PRECONDITION));
606d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)          return CancelCallback();
607d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        }
608d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
609d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        entry->Set("docs$removed", new DictionaryValue);
610d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        AddNewChangestamp(entry);
611d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        ClearPropatiesForPermanentDelete(entry);
612d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        base::MessageLoop::current()->PostTask(
613d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)            FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT));
614d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        return CancelCallback();
615d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      }
616d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    }
617d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  }
618d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
619d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  base::MessageLoop::current()->PostTask(
620d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
621d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  return CancelCallback();
622d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)}
623d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
624d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)CancelCallback FakeDriveService::TrashResource(
625d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    const std::string& resource_id,
626d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    const EntryActionCallback& callback) {
627d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
628d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  DCHECK(!callback.is_null());
629d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
630d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  if (offline_) {
631d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
632d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
633d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    return CancelCallback();
634d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  }
635d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
636d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  base::ListValue* entries = NULL;
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and remove the one that matches |resource_id|.
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
646d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)        if (entry->HasKey("gd$deleted") || entry->HasKey("docs$removed")) {
647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_NOT_FOUND;
648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        } else {
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          entry->Set("gd$deleted", new DictionaryValue);
650a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          AddNewChangestamp(entry);
651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_SUCCESS;
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        }
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            FROM_HERE, base::Bind(callback, error));
6557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
66090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
6627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DownloadFile(
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& resource_id,
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback,
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::FilePath()));
6807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The field content.src is the URL to download the file.
684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
6897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Write "x"s of the file size specified in the entry.
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string file_size_string;
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("docs$size.$t", &file_size_string);
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 file_size = 0;
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::StringToInt64(file_size_string, &file_size)) {
69790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::BinaryValue* content_binary_data;
69890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string content_data;
69990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (entry->GetBinary("test$data", &content_binary_data)) {
70090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_data = std::string(content_binary_data->GetBuffer(),
70190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          content_binary_data->GetSize());
70290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
70390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!get_content_callback.is_null()) {
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const int64 kBlockSize = 5;
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int64 i = 0; i < file_size; i += kBlockSize) {
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        const int64 size = std::min(kBlockSize, file_size - i);
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<std::string> content_for_callback(
71090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            new std::string(content_data.substr(i, size)));
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(get_content_callback, HTTP_SUCCESS,
714c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::Passed(&content_for_callback)));
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
717c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
71890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (test_util::WriteStringToFile(local_cache_path, content_data)) {
719c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!progress_callback.is_null()) {
720c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // See also the comment in ResumeUpload(). For testing that clients
721c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // can handle the case progress_callback is called multiple times,
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // here we invoke the callback twice.
723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
724c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
725c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size / 2, file_size));
726c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
727c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
728c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size, file_size));
729c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::MessageLoopProxy::current()->PostTask(
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          FROM_HERE,
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(download_action_callback,
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     HTTP_SUCCESS,
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     local_cache_path));
7357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return CancelCallback();
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Failed to write the content.
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoopProxy::current()->PostTask(
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath()));
7437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyResource(
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
74890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& in_parent_resource_id,
7497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
75068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const base::Time& last_modified,
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
75790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
7627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
76590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const std::string& parent_resource_id = in_parent_resource_id.empty() ?
76690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetRootResourceId() : in_parent_resource_id;
76790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and copy the one that matches |resource_id|.
770868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
77690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id == current_resource_id) {
77790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Make a copy and set the new resource ID and the new title.
77890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<DictionaryValue> copied_entry(entry->DeepCopy());
77990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("gd$resourceId.$t",
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                resource_id + "_copied");
7817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        copied_entry->SetString("title.$t", new_title);
78290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Reset parent directory.
78490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::ListValue* links = NULL;
7853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (!copied_entry->GetList("link", &links)) {
78690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          links = new base::ListValue;
7873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          copied_entry->Set("link", links);
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
78990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Clear();
79090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
79190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* link = new base::DictionaryValue;
79290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString(
79390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "rel", "http://schemas.google.com/docs/2007#parent");
79490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
79590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Append(link);
79690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
79768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (!last_modified.is_null()) {
79868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          copied_entry->SetString(
79968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              "updated.$t",
80068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              google_apis::util::FormatTimeAsString(last_modified));
80168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
80268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        AddNewChangestamp(copied_entry.get());
804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        UpdateETag(copied_entry.get());
80590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
80690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Parse the new entry.
80790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<ResourceEntry> resource_entry =
80890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ResourceEntry::CreateFrom(*copied_entry);
80990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Add it to the resource list.
81090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        entries->Append(copied_entry.release());
81190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
81290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
81390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            FROM_HERE,
81490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            base::Bind(callback,
81590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       HTTP_SUCCESS,
81690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       base::Passed(&resource_entry)));
8177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
82390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
8267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
829f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)CancelCallback FakeDriveService::UpdateResource(
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
8313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& parent_resource_id,
8327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
83368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const base::Time& last_modified,
834f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::Time& last_viewed_by_me,
8353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const google_apis::GetResourceEntryCallback& callback) {
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
84090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION,
8423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                              base::Passed(scoped_ptr<ResourceEntry>())));
8437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
8487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    entry->SetString("title.$t", new_title);
8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Set parent if necessary.
8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!parent_resource_id.empty()) {
8523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::ListValue* links = NULL;
8533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!entry->GetList("link", &links)) {
8543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        links = new base::ListValue;
8553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        entry->Set("link", links);
8563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
8573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Remove old parent(s).
8593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ) {
8603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::DictionaryValue* link = NULL;
8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        std::string rel;
8623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        std::string href;
8633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (links->GetDictionary(i, &link) &&
8643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            link->GetString("rel", &rel) &&
8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            link->GetString("href", &href) &&
8663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent") {
8673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          links->Remove(i, NULL);
8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } else {
8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          ++i;
8703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::DictionaryValue* link = new base::DictionaryValue;
8743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
8753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      link->SetString(
8763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          "href", GetFakeLinkUrl(parent_resource_id).spec());
8773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      links->Append(link);
8783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
8793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
88068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!last_modified.is_null()) {
88168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      entry->SetString(
88268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          "updated.$t",
88368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          google_apis::util::FormatTimeAsString(last_modified));
88468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
88568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
886f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!last_viewed_by_me.is_null()) {
887f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      entry->SetString(
888f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          "gd$lastViewed.$t",
889f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          google_apis::util::FormatTimeAsString(last_viewed_by_me));
890f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
891f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    AddNewChangestamp(entry);
893a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UpdateETag(entry);
8943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Parse the new entry.
8963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
8973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
89890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE,
9003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
9017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
90490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
9063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND,
9073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Passed(scoped_ptr<ResourceEntry>())));
9087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)CancelCallback FakeDriveService::RenameResource(
9123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& resource_id,
9133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& new_title,
9143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const EntryActionCallback& callback) {
9153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!callback.is_null());
9173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
918f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return UpdateResource(
919f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      resource_id, std::string(), new_title, base::Time(), base::Time(),
9203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&EntryActionCallbackAdapter, callback));
9213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddResourceToDirectory(
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
93190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
9337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!entry->GetList("link", &links)) {
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      links = new base::ListValue;
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->Set("link", links);
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // On the real Drive server, resources do not necessary shape a tree
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // structure. That is, each resource can have multiple parent.
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We mimic the behavior here; AddResourceToDirectoy just adds
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one more parent link, not overwriting old links.
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* link = new base::DictionaryValue;
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString(
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "href", GetFakeLinkUrl(parent_resource_id).spec());
9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    links->Append(link);
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
954a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    AddNewChangestamp(entry);
95590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
9577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
96090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
9627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RemoveResourceFromDirectory(
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
97390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
9757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry->GetList("link", &links)) {
9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL parent_content_url = GetFakeLinkUrl(parent_resource_id);
9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ++i) {
9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* link = NULL;
9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string rel;
9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string href;
9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (links->GetDictionary(i, &link) &&
9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("rel", &rel) &&
9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("href", &href) &&
9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent" &&
9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            GURL(href) == parent_content_url) {
9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          links->Remove(i, NULL);
993a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          AddNewChangestamp(entry);
99490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::MessageLoop::current()->PostTask(
995a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT));
9967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          return CancelCallback();
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
100290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
10047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddNewDirectory(
10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
10097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& directory_title,
10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
101690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
10217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1024c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char kContentType[] = "application/atom+xml;type=feed";
1025c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(kContentType,
102690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       "",  // content_data
1027c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
10287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                       directory_title,
1029c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       false,  // shared_with_me
1030c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       "folder");
1031c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1032c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
103390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1034c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1035c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
10367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1039c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry));
104090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1042c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
10437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadNewFile(
10472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
10482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
10492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
10502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
10522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
105690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
10597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (parent_resource_id != GetRootResourceId() &&
1063eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      !FindEntryByResourceId(parent_resource_id)) {
106490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
10677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1069eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
1071eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
1072eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
1073eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    parent_resource_id,
1074eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // resource_id
1075eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // etag
1076eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    title);
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
107890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1080eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
10817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadExistingFile(
10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
10892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
10902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
109490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
10977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* entry = FindEntryByResourceId(resource_id);
11012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
110290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
11032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
11042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
11057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string entry_etag;
11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("gd$etag", &entry_etag);
1110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!etag.empty() && etag != entry_etag) {
111190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
11122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
11132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_PRECONDITION, GURL()));
11147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
1118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
1119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
1120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // parent_resource_id
1121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    resource_id,
1122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    entry_etag,
1123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "" /* title */);
11242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
11287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetUploadStatus(
11322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ResumeUpload(
11412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& upload_url,
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 start_position,
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 end_position,
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 content_length,
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& content_type,
1146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      const base::FilePath& local_file_path,
1147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const UploadRangeCallback& callback,
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ProgressCallback& progress_callback) {
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GetResourceEntryCallback completion_callback
1153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      = base::Bind(&ScheduleUploadRangeCallback,
1154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   callback, start_position, end_position);
11552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
1157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
11587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!upload_sessions_.count(upload_url)) {
1162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
11637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession* session = &upload_sessions_[upload_url];
1167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Chunks are required to be sent in such a ways that they fill from the start
1169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // of the not-yet-uploaded part with no gaps nor overlaps.
1170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->uploaded_size != start_position) {
1171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
11727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!progress_callback.is_null()) {
1176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // In the real GDataWapi/Drive DriveService, progress is reported in
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // nondeterministic timing. In this fake implementation, we choose to call
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // it twice per one ResumeUpload. This is for making sure that client code
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // works fine even if the callback is invoked more than once; it is the
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // crucial difference of the progress callback from others.
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Note that progress is notified in the relative offset in each chunk.
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 chunk_size = end_position - start_position;
118390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
118590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (content_length != end_position) {
1190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_RESUME_INCOMPLETE,
1192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_ptr<ResourceEntry>());
11937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_data;
119758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::ReadFileToString(local_file_path, &content_data)) {
1198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
1200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  session->uploaded_size = end_position;
1203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |resource_id| is empty if the upload is for new file.
1205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->resource_id.empty()) {
1206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->parent_resource_id.empty());
1207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->title.empty());
1208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const DictionaryValue* new_entry = AddNewEntry(
1209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->content_type,
1210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        content_data,
1211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->parent_resource_id,
1212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->title,
1213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        false,  // shared_with_me
1214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "file");
1215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!new_entry) {
1216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return CancelCallback();
1218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_CREATED,
1221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            ResourceEntry::CreateFrom(*new_entry));
1222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
1226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!entry) {
1227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
123090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string entry_etag;
1232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->GetString("gd$etag", &entry_etag);
1233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (entry_etag.empty() || session->etag != entry_etag) {
1234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
1235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
1239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->Set("test$data",
1240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch             base::BinaryValue::CreateWithCopiedBuffer(
1241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content_data.data(), content_data.size()));
1242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AddNewChangestamp(entry);
1244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateETag(entry);
1245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
12477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AuthorizeApp(
12517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& resource_id,
12527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& app_id,
12537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AuthorizeAppCallback& callback) {
12542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
12567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)CancelCallback FakeDriveService::GetResourceListInDirectoryByWapi(
126058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& directory_resource_id,
126158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const google_apis::GetResourceListCallback& callback) {
126258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return GetResourceListInDirectory(
126358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      directory_resource_id == util::kWapiRootDirectoryResourceId ?
126458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          GetRootResourceId() :
126558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          directory_resource_id,
126658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      callback);
126758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
126858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
126958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)CancelCallback FakeDriveService::GetRemainingResourceList(
127058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& next_link,
127158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const google_apis::GetResourceListCallback& callback) {
127258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
127358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!next_link.is_empty());
127458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!callback.is_null());
127558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
127658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // "changestamp", "q", "parent" and "start-offset" are parameters to
127758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // implement "paging" of the result on FakeDriveService.
127858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // The URL should be the one filled in GetResourceListInternal of the
127958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // previous method invocation, so it should start with "http://localhost/?".
128058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // See also GetResourceListInternal.
128158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK_EQ(next_link.host(), "localhost");
128258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK_EQ(next_link.path(), "/");
128358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
128458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int64 start_changestamp = 0;
128558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string search_query;
128658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string directory_resource_id;
128758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int start_offset = 0;
128858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int max_results = default_max_results_;
128958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::vector<std::pair<std::string, std::string> > parameters;
129058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (base::SplitStringIntoKeyValuePairs(
129158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          next_link.query(), '=', '&', &parameters)) {
129258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (size_t i = 0; i < parameters.size(); ++i) {
129358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (parameters[i].first == "changestamp") {
129458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::StringToInt64(parameters[i].second, &start_changestamp);
129558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      } else if (parameters[i].first == "q") {
129658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        search_query =
129758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
129858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
129958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      } else if (parameters[i].first == "parent") {
130058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        directory_resource_id =
130158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
130258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
130358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      } else if (parameters[i].first == "start-offset") {
130458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::StringToInt(parameters[i].second, &start_offset);
130558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      } else if (parameters[i].first == "max-results") {
130658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::StringToInt(parameters[i].second, &max_results);
130758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
130858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
130958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
131058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
131158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetResourceListInternal(
131258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      start_changestamp, search_query, directory_resource_id,
131358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      start_offset, max_results, NULL, callback);
131458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return CancelCallback();
131558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
131658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::AddNewFile(const std::string& content_type,
131890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const std::string& content_data,
1319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& parent_resource_id,
1320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& title,
1321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  bool shared_with_me,
1322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const GetResourceEntryCallback& callback) {
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
132890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Prepare "kind" for hosted documents. This only supports Google Document.
1337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string entry_kind;
1338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (content_type == "application/vnd.google-apps.document")
1339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "document";
1340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
1341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "file";
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
134490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       content_data,
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
1346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       title,
1347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       shared_with_me,
1348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       entry_kind);
1349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
135190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*new_entry));
135990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::SetLastModifiedTime(
1365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& resource_id,
1366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Time& last_modified_time,
1367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
1368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
137390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
1382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry) {
1383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
138490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (last_modified_time.is_null()) {
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->Remove("updated.$t", NULL);
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
139358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    entry->SetString(
139458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        "updated.$t",
139558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        google_apis::util::FormatTimeAsString(last_modified_time));
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*entry));
140090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
1403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByResourceId(
14062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id) {
14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |resource_id|.
1411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
14122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
14132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
14142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
14152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
14162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
14172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
14182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
14192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
14202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
14212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
14242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
14272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& content_url) {
14282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
14312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |content_url|.
1432868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
14332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
14342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
14352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_content_url;
14362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
14372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("content.src", &current_content_url) &&
14382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_url == GURL(current_content_url)) {
14392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
14402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
14412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
14422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
14452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetNewResourceId() {
14482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++resource_id_count_;
14512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf("resource_id_%d", resource_id_count_);
14522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void FakeDriveService::UpdateETag(base::DictionaryValue* entry) {
1455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  entry->SetString("gd$etag",
1456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   "etag_" + base::Int64ToString(largest_changestamp_));
1457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) {
14602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++largest_changestamp_;
14612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->SetString("docs$changestamp.value",
14622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Int64ToString(largest_changestamp_));
14632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::DictionaryValue* FakeDriveService::AddNewEntry(
1466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& content_type,
146790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& content_data,
1468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
1469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
1470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool shared_with_me,
1471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& entry_kind) {
1472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1474d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!parent_resource_id.empty() &&
1475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      parent_resource_id != GetRootResourceId() &&
1476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !FindEntryByResourceId(parent_resource_id)) {
1477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
1478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string resource_id = GetNewResourceId();
1481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL upload_url = GURL("https://xxx/upload/" + resource_id);
1482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
1484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the resource ID and the title
1485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("gd$resourceId.$t", resource_id);
1486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("title.$t", title);
1487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("docs$filename", title);
148890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set the contents, size and MD5 for a file.
1489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (entry_kind == "file") {
149090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->Set("test$data",
149190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::BinaryValue::CreateWithCopiedBuffer(
149290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            content_data.c_str(), content_data.size()));
149390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->SetString("docs$size.$t",
149490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         base::Int64ToString(content_data.size()));
1495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    new_entry->SetString("docs$md5Checksum.$t",
1496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         base::MD5String(content_data));
1497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "category" which sets the resource type to |entry_kind|.
1500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* categories = new base::ListValue;
1501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* category = new base::DictionaryValue;
1502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("term", "http://schemas.google.com/docs/2007#" +
1504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      entry_kind);
1505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  categories->Append(category);
1506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("category", categories);
1507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (shared_with_me) {
1508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::DictionaryValue* shared_with_me_label = new base::DictionaryValue;
1509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("label", "shared-with-me");
1510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("scheme",
1511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    "http://schemas.google.com/g/2005/labels");
1512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString(
1513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "term", "http://schemas.google.com/g/2005/labels#shared");
1514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    categories->Append(shared_with_me_label);
1515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1517868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string escaped_resource_id = net::EscapePath(resource_id);
1518868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "content" which sets the content URL.
1520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* content = new base::DictionaryValue;
1521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content->SetString("src", "https://xxx/content/" + escaped_resource_id);
1522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content->SetString("type", content_type);
1523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("content", content);
1524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "link" which sets the parent URL, the edit URL and the upload URL.
1526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* links = new base::ListValue;
1527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* parent_link = new base::DictionaryValue;
1529d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (parent_resource_id.empty())
1530d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    parent_link->SetString("href", GetFakeLinkUrl(GetRootResourceId()).spec());
1531d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  else
1532d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
1533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("rel",
1534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         "http://schemas.google.com/docs/2007#parent");
1535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(parent_link);
1536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* edit_link = new base::DictionaryValue;
1538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  edit_link->SetString("rel", "edit");
1540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(edit_link);
1541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* upload_link = new base::DictionaryValue;
1543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("href", upload_url.spec());
1544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("rel", kUploadUrlRel);
1545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(upload_link);
15462385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
15472385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  const GURL share_url = net::AppendOrReplaceQueryParameter(
15482385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      share_url_base_, "name", title);
15492385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  base::DictionaryValue* share_link = new base::DictionaryValue;
15502385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  upload_link->SetString("href", share_url.spec());
15512385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  upload_link->SetString("rel", kShareUrlRel);
15522385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  links->Append(share_link);
1553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("link", links);
1554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1555a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AddNewChangestamp(new_entry.get());
1556a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateETag(new_entry.get());
1557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::Time published_date =
15597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
156058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  new_entry->SetString(
156158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      "published.$t",
156258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      google_apis::util::FormatTimeAsString(published_date));
15637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If there are no entries, prepare an empty entry to add.
1565868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!resource_list_value_->HasKey("entry"))
1566868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    resource_list_value_->Set("entry", new ListValue);
1567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* raw_new_entry = new_entry.release();
1569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* entries = NULL;
1570868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries))
1571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->Append(raw_new_entry);
1572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return raw_new_entry;
1574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::GetResourceListInternal(
1577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 start_changestamp,
1578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& search_query,
1579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
1580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int start_offset,
1581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int max_results,
1582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int* load_counter,
1583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
1584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
158590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
15897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                   base::Passed(scoped_ptr<ResourceList>())));
1590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceList> resource_list =
1594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceList::CreateFrom(*resource_list_value_);
1595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(hashimoto): Drive API always provides largest changestamp. Remove this
15977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // if-statement after API switch.
15987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (start_changestamp > 0 && start_offset == 0)
15997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    resource_list->set_largest_changestamp(largest_changestamp_);
16007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Filter out entries per parameters like |directory_resource_id| and
1602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |search_query|.
1603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries();
1604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int num_entries_matched = 0;
1606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < entries->size();) {
1607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ResourceEntry* entry = (*entries)[i];
1608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool should_exclude = false;
1609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |directory_resource_id| is set, exclude the entry if it's not in
1611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the target directory.
1612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Get the parent resource ID of the entry.
1614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string parent_resource_id;
1615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const google_apis::Link* parent_link =
1616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          entry->GetLinkByType(Link::LINK_PARENT);
1617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parent_link) {
1618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        parent_resource_id =
1619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            net::UnescapeURLComponent(parent_link->href().ExtractFileName(),
1620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
1621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (directory_resource_id != parent_resource_id)
1623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        should_exclude = true;
1624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |search_query| is set, exclude the entry if it does not contain the
1627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // search query in the title.
1628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude && !search_query.empty() &&
1629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !EntryMatchWithQuery(*entry, search_query)) {
1630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_changestamp| is set, exclude the entry if the
1634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // changestamp is older than |largest_changestamp|.
1635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // See https://developers.google.com/google-apps/documents-list/
1636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // #retrieving_all_changes_since_a_given_changestamp
1637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0 && entry->changestamp() < start_changestamp)
1638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // If the caller requests other list than change list by specifying
1641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // zero-|start_changestamp|, exclude deleted entry from the result.
1642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!start_changestamp && entry->deleted())
1643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      should_exclude = true;
1644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The entry matched the criteria for inclusion.
1646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude)
1647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_entries_matched;
1648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_offset| is set, exclude the entry if the entry is before the
1650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // start index. <= instead of < as |num_entries_matched| was
1651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // already incremented.
1652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_offset > 0 && num_entries_matched <= start_offset)
1653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (should_exclude)
1656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entries->erase(entries->begin() + i);
1657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
1658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++i;
1659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If |max_results| is set, trim the entries if the number exceeded the max
1662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // results.
1663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) {
1664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->erase(entries->begin() + max_results, entries->end());
1665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Adds the next URL.
1666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Here, we embed information which is needed for continuing the
1667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // GetResourceList request in the next invocation into url query
1668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // parameters.
1669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GURL next_url(base::StringPrintf(
1670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "http://localhost/?start-offset=%d&max-results=%d",
1671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        start_offset + max_results,
1672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        max_results));
1673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0) {
1674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "changestamp",
1676c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Int64ToString(start_changestamp).c_str());
1677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1678c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!search_query.empty()) {
1679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "q", search_query);
1681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1684c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "parent", directory_resource_id);
1685c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Link* link = new Link;
1688c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_type(Link::LINK_NEXT);
1689c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_href(next_url);
1690c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_list->mutable_links()->push_back(link);
1691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1692c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1693c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (load_counter)
1694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *load_counter += 1;
169590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
16977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list)));
1698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1700eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGURL FakeDriveService::GetNewUploadSessionUrl() {
1701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GURL("https://upload_session_url/" +
1702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              base::Int64ToString(next_upload_sequence_number_++));
1703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive
1706