fake_drive_service.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/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;
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AccountMetadata;
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AppList;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::AuthorizeAppCallback;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::CancelCallback;
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::DownloadActionCallback;
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::EntryActionCallback;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDataErrorCode;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_FILE_ERROR;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_NO_CONNECTION;
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GDATA_OTHER_ERROR;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetAboutResourceCallback;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetAppListCallback;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetContentCallback;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceEntryCallback;
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::GetResourceListCallback;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_BAD_REQUEST;
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_CREATED;
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_NOT_FOUND;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_PRECONDITION;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_RESUME_INCOMPLETE;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::HTTP_SUCCESS;
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::InitiateUploadCallback;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::Link;
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ProgressCallback;
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceEntry;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::ResourceList;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeCallback;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing google_apis::UploadRangeResponse;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace test_util = google_apis::test_util;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace util = google_apis::util;
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace drive {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Rel property of upload link in the entries dictionary value.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUploadUrlRel[] =
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "http://schemas.google.com/g/2005#resumable-create-media";
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if a resource entry matches with the search query.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Supports queries consist of following format.
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Phrases quoted by double/single quotes
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - AND search for multiple words/phrases segmented by space
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Limited attribute search.  Only "title:" is supported.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool EntryMatchWithQuery(const ResourceEntry& entry,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const std::string& query) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokenizer(query, " ");
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tokenizer.set_quote_chars("\"'");
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (tokenizer.GetNext()) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string key, value;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& token = tokenizer.token();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (token.find(':') == std::string::npos) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(token, "\"'", &value);
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringTokenizer key_value(token, ":");
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_value.set_quote_chars("\"'");
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = key_value.token();
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(key_value.token(), "\"'", &value);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(peria): Deal with other attributes than title.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!key.empty() && key != "title")
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Search query in the title.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry.title().find(value) == std::string::npos)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns |url| without query parameter.
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)GURL RemoveQueryParameter(const GURL& url) {
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL::Replacements replacements;
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  replacements.ClearQuery();
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return url.ReplaceComponents(replacements);
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ScheduleUploadRangeCallback(const UploadRangeCallback& callback,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 start_position,
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 int64 end_position,
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 GDataErrorCode error,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 scoped_ptr<ResourceEntry> entry) {
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::MessageLoop::current()->PostTask(
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FROM_HERE,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback,
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 UploadRangeResponse(error,
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     start_position,
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     end_position),
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Passed(&entry)));
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct FakeDriveService::UploadSession {
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_type;
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 content_length;
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string parent_resource_id;
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string resource_id;
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string etag;
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string title;
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 uploaded_size;
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession()
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : content_length(0),
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        uploaded_size(0) {}
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession(
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string content_type,
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      int64 content_length,
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string parent_resource_id,
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string resource_id,
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string etag,
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string title)
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : content_type(content_type),
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      content_length(content_length),
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      parent_resource_id(parent_resource_id),
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      resource_id(resource_id),
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      etag(etag),
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      title(title),
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uploaded_size(0) {
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::FakeDriveService()
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : largest_changestamp_(0),
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      published_date_seq_(0),
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      next_upload_sequence_number_(0),
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default_max_results_(0),
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id_count_(0),
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_list_load_count_(0),
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      change_list_load_count_(0),
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directory_load_count_(0),
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      about_resource_load_count_(0),
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      offline_(false) {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::~FakeDriveService() {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadResourceListForWapi(
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Value> raw_value = test_util::LoadJSONFile(relative_path);
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* as_dict = NULL;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Value* feed = NULL;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* feed_as_dict = NULL;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Extract the "feed" from the raw value and take the ownership.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that Remove() transfers the ownership to |feed|.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (raw_value->GetAsDictionary(&as_dict) &&
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      as_dict->Remove("feed", &feed) &&
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      feed->GetAsDictionary(&feed_as_dict)) {
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resource_list_value_.reset(feed_as_dict);
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Go through entries and convert test$data from a string to a binary blob.
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::ListValue* entries = NULL;
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (feed_as_dict->GetList("entry", &entries)) {
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::string content_data;
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (entries->GetDictionary(i, &entry) &&
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            entry->GetString("test$data", &content_data)) {
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          entry->Set("test$data", base::BinaryValue::CreateWithCopiedBuffer(
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  content_data.c_str(), content_data.size()));
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return resource_list_value_;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAccountMetadataForWapi(
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  account_metadata_value_ = test_util::LoadJSONFile(relative_path);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the largest_changestamp_.
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AccountMetadata> account_metadata =
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AccountMetadata::CreateFrom(*account_metadata_value_);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  largest_changestamp_ = account_metadata->largest_changestamp();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add the largest changestamp to the existing entries.
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This will be used to generate change lists in GetResourceList().
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resource_list_value_) {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* entries = NULL;
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (resource_list_value_->GetList("entry", &entries)) {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (entries->GetDictionary(i, &entry)) {
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->SetString("docs$changestamp.value",
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Int64ToString(largest_changestamp_));
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return account_metadata_value_;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAppListForDriveApi(
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_info_value_ = test_util::LoadJSONFile(relative_path);
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app_info_value_;
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GURL FakeDriveService::GetFakeLinkUrl(const std::string& resource_id) {
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return GURL("https://fake_server/" + net::EscapePath(resource_id));
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::Initialize(Profile* profile) {
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::AddObserver(DriveServiceObserver* observer) {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) {
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FakeDriveService::CanSendRequest() const {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string FakeDriveService::CanonicalizeResourceId(
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id) const {
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return resource_id;
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasAccessToken() const {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasRefreshToken() const {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearAccessToken() {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearRefreshToken() {
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetRootResourceId() const {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "fake_root";
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAllResourceList(
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &resource_list_load_count_,
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceListInDirectory(
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &directory_load_count_,
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::Search(
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          search_query,
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::SearchByTitle(
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: the search implementation here doesn't support quotation unescape,
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so don't escape here.
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          base::StringPrintf("title:'%s'", title.c_str()),
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetChangeList(
3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(start_changestamp,
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty 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)                          &change_list_load_count_,
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ContinueGetResourceList(
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& override_url,
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!override_url.is_empty());
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // "changestamp", "q", "parent" and "start-offset" are parameters to
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // implement "paging" of the result on FakeDriveService.
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The URL should be the one filled in GetResourceListInternal of the
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // previous method invocation, so it should start with "http://localhost/?".
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // See also GetResourceListInternal.
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.host(), "localhost");
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.path(), "/");
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int64 start_changestamp = 0;
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string search_query;
392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string directory_resource_id;
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start_offset = 0;
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int max_results = default_max_results_;
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<std::string, std::string> > parameters;
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::SplitStringIntoKeyValuePairs(
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          override_url.query(), '=', '&', &parameters)) {
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < parameters.size(); ++i) {
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parameters[i].first == "changestamp") {
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::StringToInt64(parameters[i].second, &start_changestamp);
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "q") {
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        search_query =
403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "parent") {
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        directory_resource_id =
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "start-offset") {
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &start_offset);
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "max-results") {
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &max_results);
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_changestamp, search_query, directory_resource_id,
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_offset, max_results, NULL, callback);
4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceEntry(
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
4367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
4467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
4537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAboutResource(
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetAboutResourceCallback& callback) {
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AboutResource> null;
46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION, base::Passed(&null)));
4707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++about_resource_load_count_;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AboutResource> about_resource(
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AboutResource::CreateFromAccountMetadata(
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *AccountMetadata::CreateFrom(*account_metadata_value_),
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetRootResourceId()));
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overwrite the change id.
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  about_resource->set_largest_change_id(largest_changestamp_);
48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 HTTP_SUCCESS, base::Passed(&about_resource)));
4847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAppList(
4887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetAppListCallback& callback) {
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(app_info_value_);
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AppList> null;
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
5007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_));
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list)));
5077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DeleteResource(
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
5207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and remove the one that matches |resource_id|.
525868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if (entry->HasKey("gd$deleted")) {
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_NOT_FOUND;
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        } else {
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          entry->Set("gd$deleted", new DictionaryValue);
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          AddNewChangestampAndETag(entry);
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          error = HTTP_SUCCESS;
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        }
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            FROM_HERE, base::Bind(callback, error));
5427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
5497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DownloadFile(
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& resource_id,
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback,
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::FilePath()));
5677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The field content.src is the URL to download the file.
571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
5767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Write "x"s of the file size specified in the entry.
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string file_size_string;
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("docs$size.$t", &file_size_string);
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 file_size = 0;
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::StringToInt64(file_size_string, &file_size)) {
58490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::BinaryValue* content_binary_data;
58590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string content_data;
58690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (entry->GetBinary("test$data", &content_binary_data)) {
58790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_data = std::string(content_binary_data->GetBuffer(),
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          content_binary_data->GetSize());
58990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
59090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!get_content_callback.is_null()) {
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const int64 kBlockSize = 5;
594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int64 i = 0; i < file_size; i += kBlockSize) {
595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        const int64 size = std::min(kBlockSize, file_size - i);
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<std::string> content_for_callback(
59790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            new std::string(content_data.substr(i, size)));
598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(get_content_callback, HTTP_SUCCESS,
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::Passed(&content_for_callback)));
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (test_util::WriteStringToFile(local_cache_path, content_data)) {
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!progress_callback.is_null()) {
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // See also the comment in ResumeUpload(). For testing that clients
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // can handle the case progress_callback is called multiple times,
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // here we invoke the callback twice.
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size / 2, file_size));
613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size, file_size));
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::MessageLoopProxy::current()->PostTask(
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          FROM_HERE,
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(download_action_callback,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     HTTP_SUCCESS,
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     local_cache_path));
6227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return CancelCallback();
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Failed to write the content.
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoopProxy::current()->PostTask(
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath()));
6307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyResource(
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& in_parent_resource_id,
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& new_name,
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
6487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const std::string& parent_resource_id = in_parent_resource_id.empty() ?
65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetRootResourceId() : in_parent_resource_id;
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and copy the one that matches |resource_id|.
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
66290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id == current_resource_id) {
66390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Make a copy and set the new resource ID and the new title.
66490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<DictionaryValue> copied_entry(entry->DeepCopy());
66590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("gd$resourceId.$t",
66690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                resource_id + "_copied");
66790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("title.$t", new_name);
66890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
66990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Reset parent directory.
67090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::ListValue* links = NULL;
67190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!entry->GetList("link", &links)) {
67290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          links = new base::ListValue;
67390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          entry->Set("link", links);
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Clear();
67690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
67790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* link = new base::DictionaryValue;
67890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString(
67990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "rel", "http://schemas.google.com/docs/2007#parent");
68090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
68190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Append(link);
68290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        AddNewChangestampAndETag(copied_entry.get());
68490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
68590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Parse the new entry.
68690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<ResourceEntry> resource_entry =
68790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ResourceEntry::CreateFrom(*copied_entry);
68890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Add it to the resource list.
68990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        entries->Append(copied_entry.release());
69090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
69190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
69290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            FROM_HERE,
69390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            base::Bind(callback,
69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       HTTP_SUCCESS,
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       base::Passed(&resource_entry)));
6967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
70290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
7057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyHostedDocument(
70990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
71090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& new_name,
71190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
71290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
71390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
71490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CopyResource(resource_id, std::string(), new_name, callback);
71690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
71790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RenameResource(
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& new_name,
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
72690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
7287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry->SetString("title.$t", new_name);
734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    AddNewChangestampAndETag(entry);
73590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
7377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
74090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
7427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::TouchResource(
74690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
74790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& modified_date,
74890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& last_viewed_by_me_date,
74990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
75090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
75190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!modified_date.is_null());
75290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!last_viewed_by_me_date.is_null());
75390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
75490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
75590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (offline_) {
75690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
75790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
75890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION,
75990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
7607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
76190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
76290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
76390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
76490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!entry) {
76590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
76690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
76790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND,
76890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
7697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
77090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
77190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
77290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("updated.$t",
77390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(modified_date));
77490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("gd$lastViewed.$t",
77590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(last_viewed_by_me_date));
776eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(entry);
77790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
77890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
77990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      FROM_HERE,
78190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
7827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
78490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddResourceToDirectory(
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
79390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
7957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!entry->GetList("link", &links)) {
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      links = new base::ListValue;
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->Set("link", links);
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // On the real Drive server, resources do not necessary shape a tree
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // structure. That is, each resource can have multiple parent.
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We mimic the behavior here; AddResourceToDirectoy just adds
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one more parent link, not overwriting old links.
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* link = new base::DictionaryValue;
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString(
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "href", GetFakeLinkUrl(parent_resource_id).spec());
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    links->Append(link);
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
816eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    AddNewChangestampAndETag(entry);
81790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
8197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
8247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RemoveResourceFromDirectory(
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
83590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
8377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry->GetList("link", &links)) {
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL parent_content_url = GetFakeLinkUrl(parent_resource_id);
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ++i) {
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* link = NULL;
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string rel;
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string href;
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (links->GetDictionary(i, &link) &&
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("rel", &rel) &&
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("href", &href) &&
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent" &&
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            GURL(href) == parent_content_url) {
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          links->Remove(i, NULL);
855eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          AddNewChangestampAndETag(entry);
85690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::MessageLoop::current()->PostTask(
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
8587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          return CancelCallback();
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
8667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddNewDirectory(
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_name,
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
87890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
8837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
886c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char kContentType[] = "application/atom+xml;type=feed";
887c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(kContentType,
88890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       "",  // content_data
889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       directory_name,
891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       false,  // shared_with_me
892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       "folder");
893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
89590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
896c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
897c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
8987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
901c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry));
90290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
904c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
9057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadNewFile(
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
91890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
9217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
924eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (parent_resource_id != GetRootResourceId() &&
925eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      !FindEntryByResourceId(parent_resource_id)) {
92690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
9297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
931eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
932eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
933eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
934eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    parent_resource_id,
936eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // resource_id
937eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // etag
938eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    title);
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
94090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
9437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadExistingFile(
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
95690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
9597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* entry = FindEntryByResourceId(resource_id);
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
96490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
9677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string entry_etag;
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("gd$etag", &entry_etag);
972c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!etag.empty() && etag != entry_etag) {
97390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_PRECONDITION, GURL()));
9767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
979eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GURL session_url = GetNewUploadSessionUrl();
980eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  upload_sessions_[session_url] =
981eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      UploadSession(content_type, content_length,
982eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "",  // parent_resource_id
983eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    resource_id,
984eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    entry_etag,
985eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    "" /* title */);
9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
98790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
989eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(callback, HTTP_SUCCESS, session_url));
9907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetUploadStatus(
9942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
9962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ResumeUpload(
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& upload_url,
10042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 start_position,
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 end_position,
10062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 content_length,
10072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& content_type,
1008a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      const base::FilePath& local_file_path,
1009c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const UploadRangeCallback& callback,
1010c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ProgressCallback& progress_callback) {
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1014eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GetResourceEntryCallback completion_callback
1015eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      = base::Bind(&ScheduleUploadRangeCallback,
1016eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   callback, start_position, end_position);
10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
1019eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_NO_CONNECTION, scoped_ptr<ResourceEntry>());
10207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1023eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!upload_sessions_.count(upload_url)) {
1024eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
10257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1028eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  UploadSession* session = &upload_sessions_[upload_url];
1029eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1030c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Chunks are required to be sent in such a ways that they fill from the start
1031c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // of the not-yet-uploaded part with no gaps nor overlaps.
1032eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->uploaded_size != start_position) {
1033eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_BAD_REQUEST, scoped_ptr<ResourceEntry>());
10347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
1035c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1036c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!progress_callback.is_null()) {
1038c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // In the real GDataWapi/Drive DriveService, progress is reported in
1039c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // nondeterministic timing. In this fake implementation, we choose to call
1040c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // it twice per one ResumeUpload. This is for making sure that client code
1041c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // works fine even if the callback is invoked more than once; it is the
1042c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // crucial difference of the progress callback from others.
1043c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Note that progress is notified in the relative offset in each chunk.
1044c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 chunk_size = end_position - start_position;
104590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1046c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
104790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1048c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1049c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1050c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (content_length != end_position) {
1052eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1053eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_RESUME_INCOMPLETE,
1054eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_ptr<ResourceEntry>());
10557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1058eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string content_data;
1059eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!file_util::ReadFileToString(local_file_path, &content_data)) {
1060eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    session->uploaded_size = end_position;
1061eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>());
1062eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1063eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1064eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  session->uploaded_size = end_position;
1065eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1066eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |resource_id| is empty if the upload is for new file.
1067eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (session->resource_id.empty()) {
1068eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->parent_resource_id.empty());
1069eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(!session->title.empty());
1070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const DictionaryValue* new_entry = AddNewEntry(
1071eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->content_type,
1072eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        content_data,
1073eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->parent_resource_id,
1074eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        session->title,
1075eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        false,  // shared_with_me
1076eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "file");
1077eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!new_entry) {
1078eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1079eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return CancelCallback();
1080eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
10812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_CREATED,
1083eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            ResourceEntry::CreateFrom(*new_entry));
1084eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1085eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1086eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1087eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DictionaryValue* entry = FindEntryByResourceId(session->resource_id);
1088eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!entry) {
1089eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>());
1090eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1091eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
109290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1093eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string entry_etag;
1094eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->GetString("gd$etag", &entry_etag);
1095eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (entry_etag.empty() || session->etag != entry_etag) {
1096eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>());
1097eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return CancelCallback();
1098eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data));
1101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->Set("test$data",
1102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch             base::BinaryValue::CreateWithCopiedBuffer(
1103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content_data.data(), content_data.size()));
1104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
1105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(entry);
1106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry));
11087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AuthorizeApp(
11127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& resource_id,
11137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& app_id,
11147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AuthorizeAppCallback& callback) {
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
11177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
11182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::AddNewFile(const std::string& content_type,
112190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const std::string& content_data,
1122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& parent_resource_id,
1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& title,
1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  bool shared_with_me,
1125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const GetResourceEntryCallback& callback) {
1126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
113190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Prepare "kind" for hosted documents. This only supports Google Document.
1140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string entry_kind;
1141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (content_type == "application/vnd.google-apps.document")
1142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "document";
1143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
1144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "file";
1145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
114790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       content_data,
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
1149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       title,
1150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       shared_with_me,
1151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       entry_kind);
1152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
115490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*new_entry));
116290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::SetLastModifiedTime(
1168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& resource_id,
1169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Time& last_modified_time,
1170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
1171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
117690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
1185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry) {
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
118790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (last_modified_time.is_null()) {
1194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->Remove("updated.$t", NULL);
1195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->SetString("updated.$t",
1197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     util::FormatTimeAsString(last_modified_time));
1198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*entry));
120290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
1205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByResourceId(
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id) {
12092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
12122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |resource_id|.
1213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
12142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
12152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
12162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
12172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
12182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
12212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
12222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
12232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
12262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& content_url) {
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |content_url|.
1234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
12362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_content_url;
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("content.src", &current_content_url) &&
12402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_url == GURL(current_content_url)) {
12412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
12422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
12432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
12472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetNewResourceId() {
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++resource_id_count_;
12532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf("resource_id_%d", resource_id_count_);
12542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid FakeDriveService::AddNewChangestampAndETag(base::DictionaryValue* entry) {
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++largest_changestamp_;
12582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->SetString("docs$changestamp.value",
12592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Int64ToString(largest_changestamp_));
1260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->SetString("gd$etag",
1261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   "etag_" + base::Int64ToString(largest_changestamp_));
12622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::DictionaryValue* FakeDriveService::AddNewEntry(
1265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& content_type,
126690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& content_data,
1267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
1268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
1269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool shared_with_me,
1270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& entry_kind) {
1271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (parent_resource_id != GetRootResourceId() &&
1274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !FindEntryByResourceId(parent_resource_id)) {
1275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
1276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string resource_id = GetNewResourceId();
1279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL upload_url = GURL("https://xxx/upload/" + resource_id);
1280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
1282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the resource ID and the title
1283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("gd$resourceId.$t", resource_id);
1284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("title.$t", title);
1285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("docs$filename", title);
128690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set the contents, size and MD5 for a file.
1287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (entry_kind == "file") {
128890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->Set("test$data",
128990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::BinaryValue::CreateWithCopiedBuffer(
129090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            content_data.c_str(), content_data.size()));
129190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->SetString("docs$size.$t",
129290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         base::Int64ToString(content_data.size()));
1293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    new_entry->SetString("docs$md5Checksum.$t",
1294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         base::MD5String(content_data));
1295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "category" which sets the resource type to |entry_kind|.
1298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* categories = new base::ListValue;
1299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* category = new base::DictionaryValue;
1300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("term", "http://schemas.google.com/docs/2007#" +
1302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      entry_kind);
1303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  categories->Append(category);
1304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("category", categories);
1305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (shared_with_me) {
1306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::DictionaryValue* shared_with_me_label = new base::DictionaryValue;
1307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("label", "shared-with-me");
1308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("scheme",
1309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    "http://schemas.google.com/g/2005/labels");
1310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString(
1311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "term", "http://schemas.google.com/g/2005/labels#shared");
1312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    categories->Append(shared_with_me_label);
1313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string escaped_resource_id = net::EscapePath(resource_id);
1316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "content" which sets the content URL.
1318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* content = new base::DictionaryValue;
1319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content->SetString("src", "https://xxx/content/" + escaped_resource_id);
1320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content->SetString("type", content_type);
1321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("content", content);
1322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "link" which sets the parent URL, the edit URL and the upload URL.
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* links = new base::ListValue;
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* parent_link = new base::DictionaryValue;
1327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
1328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("rel",
1329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         "http://schemas.google.com/docs/2007#parent");
1330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(parent_link);
1331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* edit_link = new base::DictionaryValue;
1333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  edit_link->SetString("rel", "edit");
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(edit_link);
1336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* upload_link = new base::DictionaryValue;
1338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("href", upload_url.spec());
1339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("rel", kUploadUrlRel);
1340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(upload_link);
1341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("link", links);
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  AddNewChangestampAndETag(new_entry.get());
1344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::Time published_date =
13467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
13477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  new_entry->SetString("published.$t",
13487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                       util::FormatTimeAsString(published_date));
13497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If there are no entries, prepare an empty entry to add.
1351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!resource_list_value_->HasKey("entry"))
1352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    resource_list_value_->Set("entry", new ListValue);
1353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* raw_new_entry = new_entry.release();
1355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* entries = NULL;
1356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries))
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->Append(raw_new_entry);
1358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return raw_new_entry;
1360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::GetResourceListInternal(
1363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 start_changestamp,
1364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& search_query,
1365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
1366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int start_offset,
1367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int max_results,
1368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int* load_counter,
1369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
1370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceList> null;
137290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceList> resource_list =
1381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceList::CreateFrom(*resource_list_value_);
1382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Filter out entries per parameters like |directory_resource_id| and
1384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |search_query|.
1385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries();
1386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int num_entries_matched = 0;
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < entries->size();) {
1389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ResourceEntry* entry = (*entries)[i];
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool should_exclude = false;
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |directory_resource_id| is set, exclude the entry if it's not in
1393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the target directory.
1394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Get the parent resource ID of the entry.
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string parent_resource_id;
1397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const google_apis::Link* parent_link =
1398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          entry->GetLinkByType(Link::LINK_PARENT);
1399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parent_link) {
1400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        parent_resource_id =
1401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            net::UnescapeURLComponent(parent_link->href().ExtractFileName(),
1402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
1403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (directory_resource_id != parent_resource_id)
1405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        should_exclude = true;
1406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |search_query| is set, exclude the entry if it does not contain the
1409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // search query in the title.
1410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude && !search_query.empty() &&
1411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !EntryMatchWithQuery(*entry, search_query)) {
1412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_changestamp| is set, exclude the entry if the
1416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // changestamp is older than |largest_changestamp|.
1417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // See https://developers.google.com/google-apps/documents-list/
1418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // #retrieving_all_changes_since_a_given_changestamp
1419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0 && entry->changestamp() < start_changestamp)
1420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // If the caller requests other list than change list by specifying
1423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // zero-|start_changestamp|, exclude deleted entry from the result.
1424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!start_changestamp && entry->deleted())
1425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      should_exclude = true;
1426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The entry matched the criteria for inclusion.
1428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude)
1429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_entries_matched;
1430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_offset| is set, exclude the entry if the entry is before the
1432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // start index. <= instead of < as |num_entries_matched| was
1433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // already incremented.
1434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_offset > 0 && num_entries_matched <= start_offset)
1435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (should_exclude)
1438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entries->erase(entries->begin() + i);
1439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
1440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++i;
1441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If |max_results| is set, trim the entries if the number exceeded the max
1444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // results.
1445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) {
1446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->erase(entries->begin() + max_results, entries->end());
1447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Adds the next URL.
1448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Here, we embed information which is needed for continuing the
1449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // GetResourceList request in the next invocation into url query
1450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // parameters.
1451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GURL next_url(base::StringPrintf(
1452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "http://localhost/?start-offset=%d&max-results=%d",
1453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        start_offset + max_results,
1454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        max_results));
1455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0) {
1456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "changestamp",
1458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Int64ToString(start_changestamp).c_str());
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!search_query.empty()) {
1461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "q", search_query);
1463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "parent", directory_resource_id);
1467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Link* link = new Link;
1470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_type(Link::LINK_NEXT);
1471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_href(next_url);
1472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_list->mutable_links()->push_back(link);
1473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (load_counter)
1476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *load_counter += 1;
147790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback,
1480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 HTTP_SUCCESS,
1481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Passed(&resource_list)));
1482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGURL FakeDriveService::GetNewUploadSessionUrl() {
1485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GURL("https://upload_session_url/" +
1486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              base::Int64ToString(next_upload_sequence_number_++));
1487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace drive
1490