fake_drive_service.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/drive_api_parser.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/gdata_wapi_parser.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/test_util.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/google_apis/time_util.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/escape.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/url_util.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AboutResource;
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::AboutResourceCallback;
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AccountMetadata;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AppList;
32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::AppListCallback;
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing google_apis::AuthStatusCallback;
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AuthorizeAppCallback;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::CancelCallback;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::DownloadActionCallback;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::EntryActionCallback;
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_FILE_ERROR;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_NO_CONNECTION;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_OTHER_ERROR;
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)using google_apis::GDataErrorCode;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetContentCallback;
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceEntryCallback;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceListCallback;
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochusing google_apis::GetShareUrlCallback;
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_BAD_REQUEST;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_CREATED;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_NOT_FOUND;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_PRECONDITION;
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_RESUME_INCOMPLETE;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_SUCCESS;
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::InitiateUploadCallback;
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::Link;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ProgressCallback;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceEntry;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceList;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeCallback;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeResponse;
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace test_util = google_apis::test_util;
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace util = google_apis::util;
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Rel property of an upload link in the entries dictionary value.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUploadUrlRel[] =
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "http://schemas.google.com/g/2005#resumable-create-media";
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Rel property of a share link in the entries dictionary value.
702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochconst char kShareUrlRel[] =
712385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    "http://schemas.google.com/docs/2007#share";
722385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if a resource entry matches with the search query.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Supports queries consist of following format.
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Phrases quoted by double/single quotes
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - AND search for multiple words/phrases segmented by space
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Limited attribute search.  Only "title:" is supported.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool EntryMatchWithQuery(const ResourceEntry& entry,
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const std::string& query) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokenizer(query, " ");
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tokenizer.set_quote_chars("\"'");
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (tokenizer.GetNext()) {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string key, value;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& token = tokenizer.token();
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (token.find(':') == std::string::npos) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(token, "\"'", &value);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringTokenizer key_value(token, ":");
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_value.set_quote_chars("\"'");
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = key_value.token();
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(key_value.token(), "\"'", &value);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(peria): Deal with other attributes than title.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!key.empty() && key != "title")
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Search query in the title.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry.title().find(value) == std::string::npos)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns |url| without query parameter.
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)GURL RemoveQueryParameter(const GURL& url) {
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL::Replacements replacements;
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  replacements.ClearQuery();
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return url.ReplaceComponents(replacements);
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 start_position,
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 end_position,
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 GDataErrorCode error,
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 scoped_ptr<ResourceEntry> entry) {
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::MessageLoop::current()->PostTask(
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FROM_HERE,
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback,
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 UploadRangeResponse(error,
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     start_position,
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     end_position),
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Passed(&entry)));
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void EntryActionCallbackAdapter(
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const EntryActionCallback& callback,
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) {
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  callback.Run(error);
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct FakeDriveService::UploadSession {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_type;
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 content_length;
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string parent_resource_id;
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string resource_id;
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string etag;
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string title;
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 uploaded_size;
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession()
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : content_length(0),
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        uploaded_size(0) {}
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession(
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string content_type,
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int64 content_length,
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string parent_resource_id,
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string resource_id,
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string etag,
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string title)
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : content_type(content_type),
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      content_length(content_length),
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      parent_resource_id(parent_resource_id),
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      resource_id(resource_id),
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      etag(etag),
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      title(title),
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uploaded_size(0) {
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::FakeDriveService()
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : largest_changestamp_(0),
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      published_date_seq_(0),
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      next_upload_sequence_number_(0),
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default_max_results_(0),
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id_count_(0),
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_list_load_count_(0),
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      change_list_load_count_(0),
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directory_load_count_(0),
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      about_resource_load_count_(0),
1782385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      app_list_load_count_(0),
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      offline_(false) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::~FakeDriveService() {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadResourceListForWapi(
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Value> raw_value = test_util::LoadJSONFile(relative_path);
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* as_dict = NULL;
1923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  scoped_ptr<base::Value> feed;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* feed_as_dict = NULL;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Extract the "feed" from the raw value and take the ownership.
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that Remove() transfers the ownership to |feed|.
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (raw_value->GetAsDictionary(&as_dict) &&
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      as_dict->Remove("feed", &feed) &&
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      feed->GetAsDictionary(&feed_as_dict)) {
2003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    ignore_result(feed.release());
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resource_list_value_.reset(feed_as_dict);
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Go through entries and convert test$data from a string to a binary blob.
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::ListValue* entries = NULL;
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (feed_as_dict->GetList("entry", &entries)) {
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::string content_data;
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (entries->GetDictionary(i, &entry) &&
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            entry->GetString("test$data", &content_data)) {
2113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          entry->Set("test$data",
2123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                     base::BinaryValue::CreateWithCopiedBuffer(
2133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                         content_data.c_str(), content_data.size()));
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return resource_list_value_;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAccountMetadataForWapi(
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Load JSON data, which must be a dictionary.
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path);
228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_.reset(
230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      static_cast<base::DictionaryValue*>(value.release()));
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the largest_changestamp_.
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AccountMetadata> account_metadata =
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AccountMetadata::CreateFrom(*account_metadata_value_);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  largest_changestamp_ = account_metadata->largest_changestamp();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add the largest changestamp to the existing entries.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This will be used to generate change lists in GetResourceList().
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resource_list_value_) {
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* entries = NULL;
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (resource_list_value_->GetList("entry", &entries)) {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (entries->GetDictionary(i, &entry)) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->SetString("docs$changestamp.value",
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Int64ToString(largest_changestamp_));
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return account_metadata_value_;
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAppListForDriveApi(
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_info_value_ = test_util::LoadJSONFile(relative_path);
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app_info_value_;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
261ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
262ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid FakeDriveService::SetQuotaValue(int64 used, int64 total) {
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
264ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(account_metadata_value_);
265ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
266ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_->SetString("entry.gd$quotaBytesUsed.$t",
267ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     base::Int64ToString16(used));
268ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  account_metadata_value_->SetString("entry.gd$quotaBytesTotal.$t",
269ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                     base::Int64ToString16(total));
270ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GURL FakeDriveService::GetFakeLinkUrl(const std::string& resource_id) {
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return GURL("https://fake_server/" + net::EscapePath(resource_id));
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
276558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid FakeDriveService::Initialize() {
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::AddObserver(DriveServiceObserver* observer) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FakeDriveService::CanSendRequest() const {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string FakeDriveService::CanonicalizeResourceId(
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id) const {
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return resource_id;
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasAccessToken() const {
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid FakeDriveService::RequestAccessToken(const AuthStatusCallback& callback) {
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!callback.is_null());
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  callback.Run(google_apis::HTTP_NOT_MODIFIED, "fake_access_token");
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasRefreshToken() const {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearAccessToken() {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearRefreshToken() {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetRootResourceId() const {
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "fake_root";
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAllResourceList(
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &resource_list_load_count_,
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceListInDirectory(
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &directory_load_count_,
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::Search(
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          search_query,
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::SearchByTitle(
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: the search implementation here doesn't support quotation unescape,
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so don't escape here.
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          base::StringPrintf("title:'%s'", title.c_str()),
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetChangeList(
3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(start_changestamp,
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &change_list_load_count_,
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ContinueGetResourceList(
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& override_url,
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!override_url.is_empty());
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // "changestamp", "q", "parent" and "start-offset" are parameters to
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // implement "paging" of the result on FakeDriveService.
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The URL should be the one filled in GetResourceListInternal of the
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // previous method invocation, so it should start with "http://localhost/?".
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // See also GetResourceListInternal.
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.host(), "localhost");
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.path(), "/");
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int64 start_changestamp = 0;
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string search_query;
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string directory_resource_id;
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start_offset = 0;
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int max_results = default_max_results_;
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<std::string, std::string> > parameters;
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::SplitStringIntoKeyValuePairs(
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          override_url.query(), '=', '&', &parameters)) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < parameters.size(); ++i) {
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parameters[i].first == "changestamp") {
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::StringToInt64(parameters[i].second, &start_changestamp);
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "q") {
438868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        search_query =
439868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
440868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "parent") {
442868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        directory_resource_id =
443868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
444868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "start-offset") {
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &start_offset);
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "max-results") {
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &max_results);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_changestamp, search_query, directory_resource_id,
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_offset, max_results, NULL, callback);
4567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
459424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetRemainingChangeList(
460424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string& page_token,
461424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const GetResourceListCallback& callback) {
462424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
463424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!page_token.empty());
464424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
465424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
466424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return ContinueGetResourceList(GURL(page_token), callback);
467424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
468424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
469424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetRemainingFileList(
470424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string& page_token,
471424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const GetResourceListCallback& callback) {
472424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!page_token.empty());
474424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!callback.is_null());
475424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
476424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return ContinueGetResourceList(GURL(page_token), callback);
477424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
478424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceEntry(
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
4927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
5027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
5097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochCancelCallback FakeDriveService::GetShareUrl(
513bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const std::string& resource_id,
514bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GURL& /* embed_origin */,
515bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const GetShareUrlCallback& callback) {
516bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
517bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(!callback.is_null());
518bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
519bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (offline_) {
520bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    scoped_ptr<ResourceEntry> null;
521bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    base::MessageLoop::current()->PostTask(
522bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        FROM_HERE,
523bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        base::Bind(callback,
524bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                   GDATA_NO_CONNECTION,
525bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                   GURL()));
526bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    return CancelCallback();
527bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
528bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
529bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
530bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (entry) {
531bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // Share urls are stored in the resource entry, and they do not rely on the
532bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    // embedding origin.
533bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    scoped_ptr<ResourceEntry> resource_entry =
534bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        ResourceEntry::CreateFrom(*entry);
535bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const Link* share_url = resource_entry->GetLinkByType(Link::LINK_SHARE);
536bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    if (share_url) {
537bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::MessageLoop::current()->PostTask(
538bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          FROM_HERE,
539bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          base::Bind(callback, HTTP_SUCCESS, share_url->href()));
540bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    } else {
541bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::MessageLoop::current()->PostTask(
542bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          FROM_HERE,
543bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          base::Bind(callback, HTTP_SUCCESS, GURL()));
544bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
545bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    return CancelCallback();
546bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
547bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
548bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  scoped_ptr<ResourceEntry> null;
549bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::MessageLoop::current()->PostTask(
550bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      FROM_HERE,
551bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::Bind(callback, HTTP_NOT_FOUND, GURL()));
552bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return CancelCallback();
553bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
554bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAboutResource(
556424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const AboutResourceCallback& callback) {
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AboutResource> null;
56590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION, base::Passed(&null)));
5697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++about_resource_load_count_;
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AboutResource> about_resource(
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AboutResource::CreateFromAccountMetadata(
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *AccountMetadata::CreateFrom(*account_metadata_value_),
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetRootResourceId()));
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overwrite the change id.
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  about_resource->set_largest_change_id(largest_changestamp_);
57990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 HTTP_SUCCESS, base::Passed(&about_resource)));
5837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
586424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)CancelCallback FakeDriveService::GetAppList(const AppListCallback& callback) {
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
58990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(app_info_value_);
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AppList> null;
59390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
5987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6012385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  ++app_list_load_count_;
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_));
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list)));
6067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DeleteResource(
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
61790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
6197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and remove the one that matches |resource_id|.
624868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if (entry->HasKey("gd$deleted")) {
633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_NOT_FOUND;
634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        } else {
635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          entry->Set("gd$deleted", new DictionaryValue);
636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          AddNewChangestampAndETag(entry);
637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_SUCCESS;
638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        }
63990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            FROM_HERE, base::Bind(callback, error));
6417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
6487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DownloadFile(
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& resource_id,
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
66190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback,
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::FilePath()));
6667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The field content.src is the URL to download the file.
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
6757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Write "x"s of the file size specified in the entry.
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string file_size_string;
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("docs$size.$t", &file_size_string);
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 file_size = 0;
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::StringToInt64(file_size_string, &file_size)) {
68390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::BinaryValue* content_binary_data;
68490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string content_data;
68590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (entry->GetBinary("test$data", &content_binary_data)) {
68690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_data = std::string(content_binary_data->GetBuffer(),
68790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          content_binary_data->GetSize());
68890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
68990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!get_content_callback.is_null()) {
692c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const int64 kBlockSize = 5;
693c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int64 i = 0; i < file_size; i += kBlockSize) {
694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        const int64 size = std::min(kBlockSize, file_size - i);
695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<std::string> content_for_callback(
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            new std::string(content_data.substr(i, size)));
697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(get_content_callback, HTTP_SUCCESS,
700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::Passed(&content_for_callback)));
701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
70490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (test_util::WriteStringToFile(local_cache_path, content_data)) {
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!progress_callback.is_null()) {
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // See also the comment in ResumeUpload(). For testing that clients
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // can handle the case progress_callback is called multiple times,
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // here we invoke the callback twice.
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size / 2, file_size));
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
714c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size, file_size));
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::MessageLoopProxy::current()->PostTask(
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          FROM_HERE,
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(download_action_callback,
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     HTTP_SUCCESS,
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     local_cache_path));
7217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return CancelCallback();
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Failed to write the content.
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoopProxy::current()->PostTask(
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath()));
7297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyResource(
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
73490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& in_parent_resource_id,
7357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
74290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
7477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const std::string& parent_resource_id = in_parent_resource_id.empty() ?
75190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetRootResourceId() : in_parent_resource_id;
75290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and copy the one that matches |resource_id|.
755868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
76190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id == current_resource_id) {
76290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Make a copy and set the new resource ID and the new title.
76390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<DictionaryValue> copied_entry(entry->DeepCopy());
76490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("gd$resourceId.$t",
76590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                resource_id + "_copied");
7667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        copied_entry->SetString("title.$t", new_title);
76790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
76890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Reset parent directory.
76990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::ListValue* links = NULL;
7703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (!copied_entry->GetList("link", &links)) {
77190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          links = new base::ListValue;
7723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          copied_entry->Set("link", links);
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
77490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Clear();
77590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
77690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* link = new base::DictionaryValue;
77790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString(
77890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "rel", "http://schemas.google.com/docs/2007#parent");
77990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Append(link);
78190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
782eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        AddNewChangestampAndETag(copied_entry.get());
78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
78490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Parse the new entry.
78590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<ResourceEntry> resource_entry =
78690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ResourceEntry::CreateFrom(*copied_entry);
78790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Add it to the resource list.
78890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        entries->Append(copied_entry.release());
78990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
79090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
79190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            FROM_HERE,
79290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            base::Bind(callback,
79390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       HTTP_SUCCESS,
79490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       base::Passed(&resource_entry)));
7957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
80190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
8047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyHostedDocument(
80890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
8097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
81090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
81190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
81390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return CopyResource(resource_id, std::string(), new_title, callback);
81590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
81690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)CancelCallback FakeDriveService::MoveResource(
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
8193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& parent_resource_id,
8207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& new_title,
8213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const google_apis::GetResourceEntryCallback& callback) {
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
82690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION,
8283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                              base::Passed(scoped_ptr<ResourceEntry>())));
8297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
8347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    entry->SetString("title.$t", new_title);
8353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Set parent if necessary.
8373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!parent_resource_id.empty()) {
8383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::ListValue* links = NULL;
8393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!entry->GetList("link", &links)) {
8403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        links = new base::ListValue;
8413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        entry->Set("link", links);
8423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
8433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Remove old parent(s).
8453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ) {
8463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::DictionaryValue* link = NULL;
8473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        std::string rel;
8483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        std::string href;
8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (links->GetDictionary(i, &link) &&
8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            link->GetString("rel", &rel) &&
8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            link->GetString("href", &href) &&
8523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent") {
8533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          links->Remove(i, NULL);
8543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } else {
8553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          ++i;
8563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
8583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::DictionaryValue* link = new base::DictionaryValue;
8603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      link->SetString(
8623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          "href", GetFakeLinkUrl(parent_resource_id).spec());
8633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      links->Append(link);
8643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
866eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    AddNewChangestampAndETag(entry);
8673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Parse the new entry.
8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
8703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
87190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE,
8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
8747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
87790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
8793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND,
8803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Passed(scoped_ptr<ResourceEntry>())));
8817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)CancelCallback FakeDriveService::RenameResource(
8853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& resource_id,
8863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& new_title,
8873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const EntryActionCallback& callback) {
8883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!callback.is_null());
8903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return MoveResource(
8923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      resource_id, std::string(), new_title,
8933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&EntryActionCallbackAdapter, callback));
8943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::TouchResource(
89790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
89890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& modified_date,
89990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& last_viewed_by_me_date,
90090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
90190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!modified_date.is_null());
90390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!last_viewed_by_me_date.is_null());
90490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
90590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
90690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (offline_) {
90790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
90890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
90990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION,
91090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
9117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
91290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
91390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
91490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
91590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!entry) {
91690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
91790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
91890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND,
91990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
9207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
92190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
92290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
92390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("updated.$t",
92490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(modified_date));
92590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("gd$lastViewed.$t",
92690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(last_viewed_by_me_date));
927eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(entry);
92890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
92990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
93090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
93190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      FROM_HERE,
93290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
9337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
93490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
93590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddResourceToDirectory(
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
94490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
9467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!entry->GetList("link", &links)) {
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      links = new base::ListValue;
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->Set("link", links);
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // On the real Drive server, resources do not necessary shape a tree
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // structure. That is, each resource can have multiple parent.
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We mimic the behavior here; AddResourceToDirectoy just adds
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one more parent link, not overwriting old links.
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* link = new base::DictionaryValue;
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString(
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "href", GetFakeLinkUrl(parent_resource_id).spec());
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    links->Append(link);
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
967eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    AddNewChangestampAndETag(entry);
96890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
9707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
9757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RemoveResourceFromDirectory(
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
98690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
9887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
9932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
9942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry->GetList("link", &links)) {
9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL parent_content_url = GetFakeLinkUrl(parent_resource_id);
9962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ++i) {
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* link = NULL;
9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string rel;
9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string href;
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (links->GetDictionary(i, &link) &&
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("rel", &rel) &&
10022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("href", &href) &&
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent" &&
10042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            GURL(href) == parent_content_url) {
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          links->Remove(i, NULL);
1006eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          AddNewChangestampAndETag(entry);
100790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::MessageLoop::current()->PostTask(
10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
10097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          return CancelCallback();
10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
101590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
10177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddNewDirectory(
10212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
10227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& directory_title,
10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
10282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
102990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
10322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
10332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
10347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char kContentType[] = "application/atom+xml;type=feed";
1038c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(kContentType,
103990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       "",  // content_data
1040c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
10417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                       directory_title,
1042c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       false,  // shared_with_me
1043c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       "folder");
1044c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1045c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
104690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1047c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1048c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
10497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry));
105390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1055c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
10567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadNewFile(
10602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
10622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
10632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
10642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
106990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
10727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1075eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (parent_resource_id != GetRootResourceId() &&
1076eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      !FindEntryByResourceId(parent_resource_id)) {
107790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
10807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1082eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1083eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
1084eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
1085eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
1086eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    parent_resource_id,
1087eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // resource_id
1088eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // etag
1089eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    title);
10902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
109190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1093eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
10947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadExistingFile(
10982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
11012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
11022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
11032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
110790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
11082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
11107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* entry = FindEntryByResourceId(resource_id);
11142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
111590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
11172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
11187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string entry_etag;
11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("gd$etag", &entry_etag);
1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!etag.empty() && etag != entry_etag) {
112490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_PRECONDITION, GURL()));
11277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
1131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
1132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
1133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // parent_resource_id
1134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    resource_id,
1135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    entry_etag,
1136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "" /* title */);
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
113890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
11417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetUploadStatus(
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
11462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
11472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
11482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ResumeUpload(
11542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& upload_url,
11552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 start_position,
11562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 end_position,
11572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 content_length,
11582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& content_type,
1159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      const base::FilePath& local_file_path,
1160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const UploadRangeCallback& callback,
1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ProgressCallback& progress_callback) {
11622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GetResourceEntryCallback completion_callback
1166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      = base::Bind(&ScheduleUploadRangeCallback,
1167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   callback, start_position, end_position);
11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
1170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
11717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!upload_sessions_.count(upload_url)) {
1175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
11767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
11772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession* session = &upload_sessions_[upload_url];
1180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Chunks are required to be sent in such a ways that they fill from the start
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // of the not-yet-uploaded part with no gaps nor overlaps.
1183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->uploaded_size != start_position) {
1184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
11857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!progress_callback.is_null()) {
1189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // In the real GDataWapi/Drive DriveService, progress is reported in
1190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // nondeterministic timing. In this fake implementation, we choose to call
1191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // it twice per one ResumeUpload. This is for making sure that client code
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // works fine even if the callback is invoked more than once; it is the
1193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // crucial difference of the progress callback from others.
1194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Note that progress is notified in the relative offset in each chunk.
1195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 chunk_size = end_position - start_position;
119690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
119890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (content_length != end_position) {
1203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_RESUME_INCOMPLETE,
1205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_ptr<ResourceEntry>());
12067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
12072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_data;
1210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!file_util::ReadFileToString(local_file_path, &content_data)) {
1211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
1213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  session->uploaded_size = end_position;
1216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |resource_id| is empty if the upload is for new file.
1218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->resource_id.empty()) {
1219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->parent_resource_id.empty());
1220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->title.empty());
1221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const DictionaryValue* new_entry = AddNewEntry(
1222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->content_type,
1223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        content_data,
1224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->parent_resource_id,
1225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->title,
1226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        false,  // shared_with_me
1227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "file");
1228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!new_entry) {
1229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return CancelCallback();
1231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_CREATED,
1234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            ResourceEntry::CreateFrom(*new_entry));
1235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
1239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!entry) {
1240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
124390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string entry_etag;
1245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->GetString("gd$etag", &entry_etag);
1246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (entry_etag.empty() || session->etag != entry_etag) {
1247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
1248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
1252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->Set("test$data",
1253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch             base::BinaryValue::CreateWithCopiedBuffer(
1254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content_data.data(), content_data.size()));
1255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(entry);
1257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
12597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
12602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AuthorizeApp(
12637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& resource_id,
12647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& app_id,
12657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AuthorizeAppCallback& callback) {
12662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
12687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
12692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::AddNewFile(const std::string& content_type,
127290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const std::string& content_data,
1273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& parent_resource_id,
1274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& title,
1275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  bool shared_with_me,
1276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const GetResourceEntryCallback& callback) {
1277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
128290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Prepare "kind" for hosted documents. This only supports Google Document.
1291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string entry_kind;
1292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (content_type == "application/vnd.google-apps.document")
1293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "document";
1294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
1295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "file";
1296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
129890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       content_data,
1299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
1300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       title,
1301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       shared_with_me,
1302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       entry_kind);
1303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
130590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*new_entry));
131390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::SetLastModifiedTime(
1319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& resource_id,
1320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Time& last_modified_time,
1321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
1322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
132790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
1336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry) {
1337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
133890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (last_modified_time.is_null()) {
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->Remove("updated.$t", NULL);
1346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->SetString("updated.$t",
1348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     util::FormatTimeAsString(last_modified_time));
1349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*entry));
135390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
1356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByResourceId(
13592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id) {
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
13632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |resource_id|.
1364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
13672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
13702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
13712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
13722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
13742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
13772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
13802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& content_url) {
13812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
13822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
13842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |content_url|.
1385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
13862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
13872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
13882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_content_url;
13892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
13902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("content.src", &current_content_url) &&
13912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_url == GURL(current_content_url)) {
13922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
13932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
13952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
13982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetNewResourceId() {
14012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++resource_id_count_;
14042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf("resource_id_%d", resource_id_count_);
14052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
14082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++largest_changestamp_;
14092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->SetString("docs$changestamp.value",
14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Int64ToString(largest_changestamp_));
1411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("gd$etag",
1412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   "etag_" + base::Int64ToString(largest_changestamp_));
14132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::DictionaryValue* FakeDriveService::AddNewEntry(
1416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& content_type,
141790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& content_data,
1418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
1419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
1420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool shared_with_me,
1421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& entry_kind) {
1422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (parent_resource_id != GetRootResourceId() &&
1425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !FindEntryByResourceId(parent_resource_id)) {
1426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
1427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string resource_id = GetNewResourceId();
1430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL upload_url = GURL("https://xxx/upload/" + resource_id);
1431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
1433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the resource ID and the title
1434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("gd$resourceId.$t", resource_id);
1435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("title.$t", title);
1436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("docs$filename", title);
143790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set the contents, size and MD5 for a file.
1438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (entry_kind == "file") {
143990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->Set("test$data",
144090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::BinaryValue::CreateWithCopiedBuffer(
144190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            content_data.c_str(), content_data.size()));
144290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->SetString("docs$size.$t",
144390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         base::Int64ToString(content_data.size()));
1444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    new_entry->SetString("docs$md5Checksum.$t",
1445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         base::MD5String(content_data));
1446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "category" which sets the resource type to |entry_kind|.
1449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* categories = new base::ListValue;
1450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* category = new base::DictionaryValue;
1451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("term", "http://schemas.google.com/docs/2007#" +
1453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      entry_kind);
1454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  categories->Append(category);
1455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("category", categories);
1456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (shared_with_me) {
1457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::DictionaryValue* shared_with_me_label = new base::DictionaryValue;
1458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("label", "shared-with-me");
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("scheme",
1460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    "http://schemas.google.com/g/2005/labels");
1461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString(
1462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "term", "http://schemas.google.com/g/2005/labels#shared");
1463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    categories->Append(shared_with_me_label);
1464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1466868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string escaped_resource_id = net::EscapePath(resource_id);
1467868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "content" which sets the content URL.
1469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* content = new base::DictionaryValue;
1470868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content->SetString("src", "https://xxx/content/" + escaped_resource_id);
1471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content->SetString("type", content_type);
1472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("content", content);
1473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "link" which sets the parent URL, the edit URL and the upload URL.
1475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* links = new base::ListValue;
1476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* parent_link = new base::DictionaryValue;
1478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
1479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("rel",
1480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         "http://schemas.google.com/docs/2007#parent");
1481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(parent_link);
1482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* edit_link = new base::DictionaryValue;
1484868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  edit_link->SetString("rel", "edit");
1486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(edit_link);
1487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* upload_link = new base::DictionaryValue;
1489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("href", upload_url.spec());
1490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("rel", kUploadUrlRel);
1491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(upload_link);
14922385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
14932385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  const GURL share_url = net::AppendOrReplaceQueryParameter(
14942385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      share_url_base_, "name", title);
14952385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  base::DictionaryValue* share_link = new base::DictionaryValue;
14962385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  upload_link->SetString("href", share_url.spec());
14972385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  upload_link->SetString("rel", kShareUrlRel);
14982385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  links->Append(share_link);
1499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("link", links);
1500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(new_entry.get());
1502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::Time published_date =
15047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
15057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  new_entry->SetString("published.$t",
15067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                       util::FormatTimeAsString(published_date));
15077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If there are no entries, prepare an empty entry to add.
1509868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!resource_list_value_->HasKey("entry"))
1510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    resource_list_value_->Set("entry", new ListValue);
1511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* raw_new_entry = new_entry.release();
1513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* entries = NULL;
1514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries))
1515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->Append(raw_new_entry);
1516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return raw_new_entry;
1518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::GetResourceListInternal(
1521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 start_changestamp,
1522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& search_query,
1523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
1524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int start_offset,
1525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int max_results,
1526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int* load_counter,
1527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
1528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
152990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
15337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                   base::Passed(scoped_ptr<ResourceList>())));
1534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceList> resource_list =
1538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceList::CreateFrom(*resource_list_value_);
1539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(hashimoto): Drive API always provides largest changestamp. Remove this
15417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // if-statement after API switch.
15427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (start_changestamp > 0 && start_offset == 0)
15437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    resource_list->set_largest_changestamp(largest_changestamp_);
15447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Filter out entries per parameters like |directory_resource_id| and
1546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |search_query|.
1547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries();
1548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int num_entries_matched = 0;
1550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < entries->size();) {
1551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ResourceEntry* entry = (*entries)[i];
1552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool should_exclude = false;
1553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |directory_resource_id| is set, exclude the entry if it's not in
1555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the target directory.
1556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Get the parent resource ID of the entry.
1558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string parent_resource_id;
1559c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const google_apis::Link* parent_link =
1560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          entry->GetLinkByType(Link::LINK_PARENT);
1561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parent_link) {
1562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        parent_resource_id =
1563c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            net::UnescapeURLComponent(parent_link->href().ExtractFileName(),
1564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
1565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (directory_resource_id != parent_resource_id)
1567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        should_exclude = true;
1568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |search_query| is set, exclude the entry if it does not contain the
1571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // search query in the title.
1572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude && !search_query.empty() &&
1573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !EntryMatchWithQuery(*entry, search_query)) {
1574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_changestamp| is set, exclude the entry if the
1578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // changestamp is older than |largest_changestamp|.
1579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // See https://developers.google.com/google-apps/documents-list/
1580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // #retrieving_all_changes_since_a_given_changestamp
1581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0 && entry->changestamp() < start_changestamp)
1582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // If the caller requests other list than change list by specifying
1585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // zero-|start_changestamp|, exclude deleted entry from the result.
1586eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!start_changestamp && entry->deleted())
1587eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      should_exclude = true;
1588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The entry matched the criteria for inclusion.
1590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude)
1591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_entries_matched;
1592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_offset| is set, exclude the entry if the entry is before the
1594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // start index. <= instead of < as |num_entries_matched| was
1595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // already incremented.
1596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_offset > 0 && num_entries_matched <= start_offset)
1597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (should_exclude)
1600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entries->erase(entries->begin() + i);
1601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
1602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++i;
1603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If |max_results| is set, trim the entries if the number exceeded the max
1606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // results.
1607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) {
1608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->erase(entries->begin() + max_results, entries->end());
1609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Adds the next URL.
1610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Here, we embed information which is needed for continuing the
1611868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // GetResourceList request in the next invocation into url query
1612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // parameters.
1613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GURL next_url(base::StringPrintf(
1614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "http://localhost/?start-offset=%d&max-results=%d",
1615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        start_offset + max_results,
1616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        max_results));
1617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0) {
1618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "changestamp",
1620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Int64ToString(start_changestamp).c_str());
1621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!search_query.empty()) {
1623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "q", search_query);
1625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "parent", directory_resource_id);
1629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Link* link = new Link;
1632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_type(Link::LINK_NEXT);
1633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_href(next_url);
1634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_list->mutable_links()->push_back(link);
1635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (load_counter)
1638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *load_counter += 1;
163990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
16417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list)));
1642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGURL FakeDriveService::GetNewUploadSessionUrl() {
1645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GURL("https://upload_session_url/" +
1646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              base::Int64ToString(next_upload_sequence_number_++));
1647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive
1650