fake_drive_service.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/drive_api_parser.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/gdata_wapi_parser.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/google_apis/test_util.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/google_apis/time_util.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/escape.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/url_util.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace google_apis {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Rel property of upload link in the entries dictionary value.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUploadUrlRel[] =
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "http://schemas.google.com/g/2005#resumable-create-media";
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if a resource entry matches with the search query.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Supports queries consist of following format.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Phrases quoted by double/single quotes
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - AND search for multiple words/phrases segmented by space
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// - Limited attribute search.  Only "title:" is supported.
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool EntryMatchWithQuery(const ResourceEntry& entry,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const std::string& query) {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokenizer(query, " ");
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tokenizer.set_quote_chars("\"'");
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (tokenizer.GetNext()) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string key, value;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& token = tokenizer.token();
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (token.find(':') == std::string::npos) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(token, "\"'", &value);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringTokenizer key_value(token, ":");
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_value.set_quote_chars("\"'");
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = key_value.token();
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!key_value.GetNext())
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TrimString(key_value.token(), "\"'", &value);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(peria): Deal with other attributes than title.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!key.empty() && key != "title")
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Search query in the title.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry.title().find(value) == std::string::npos)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Gets the upload URL from the given entry. Returns an empty URL if not
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL GetUploadUrl(const base::DictionaryValue& entry) {
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string upload_url;
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::ListValue* links = NULL;
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (entry.GetList("link", &links) && links) {
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t link_index = 0;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         link_index < links->GetSize();
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         ++link_index) {
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::DictionaryValue* link = NULL;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string rel;
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (links->GetDictionary(link_index, &link) &&
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          link && link->GetString("rel", &rel) &&
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          rel == kUploadUrlRel &&
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          link->GetString("href", &upload_url)) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return GURL(upload_url);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns |url| without query parameter.
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)GURL RemoveQueryParameter(const GURL& url) {
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL::Replacements replacements;
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  replacements.ClearQuery();
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return url.ReplaceComponents(replacements);
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::FakeDriveService()
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : largest_changestamp_(0),
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      published_date_seq_(0),
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default_max_results_(0),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_id_count_(0),
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_list_load_count_(0),
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      change_list_load_count_(0),
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directory_load_count_(0),
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      about_resource_load_count_(0),
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      offline_(false) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FakeDriveService::~FakeDriveService() {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadResourceListForWapi(
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Value> raw_value = test_util::LoadJSONFile(relative_path);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* as_dict = NULL;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Value* feed = NULL;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* feed_as_dict = NULL;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Extract the "feed" from the raw value and take the ownership.
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that Remove() transfers the ownership to |feed|.
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (raw_value->GetAsDictionary(&as_dict) &&
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      as_dict->Remove("feed", &feed) &&
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      feed->GetAsDictionary(&feed_as_dict)) {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resource_list_value_.reset(feed_as_dict);
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Go through entries and convert test$data from a string to a binary blob.
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::ListValue* entries = NULL;
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (feed_as_dict->GetList("entry", &entries)) {
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::string content_data;
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (entries->GetDictionary(i, &entry) &&
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            entry->GetString("test$data", &content_data)) {
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          entry->Set("test$data", base::BinaryValue::CreateWithCopiedBuffer(
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  content_data.c_str(), content_data.size()));
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return resource_list_value_;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAccountMetadataForWapi(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  account_metadata_value_ = test_util::LoadJSONFile(relative_path);
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Update the largest_changestamp_.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AccountMetadata> account_metadata =
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AccountMetadata::CreateFrom(*account_metadata_value_);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  largest_changestamp_ = account_metadata->largest_changestamp();
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add the largest changestamp to the existing entries.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This will be used to generate change lists in GetResourceList().
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resource_list_value_) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* entries = NULL;
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (resource_list_value_->GetList("entry", &entries)) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < entries->GetSize(); ++i) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* entry = NULL;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (entries->GetDictionary(i, &entry)) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->SetString("docs$changestamp.value",
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Int64ToString(largest_changestamp_));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return account_metadata_value_;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::LoadAppListForDriveApi(
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& relative_path) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_info_value_ = test_util::LoadJSONFile(relative_path);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app_info_value_;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GURL FakeDriveService::GetFakeLinkUrl(const std::string& resource_id) {
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return GURL("https://fake_server/" + net::EscapePath(resource_id));
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::Initialize(Profile* profile) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::AddObserver(DriveServiceObserver* observer) {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::RemoveObserver(DriveServiceObserver* observer) {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FakeDriveService::CanSendRequest() const {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string FakeDriveService::CanonicalizeResourceId(
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id) const {
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return resource_id;
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasAccessToken() const {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FakeDriveService::HasRefreshToken() const {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearAccessToken() {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::ClearRefreshToken() {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetRootResourceId() const {
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "fake_root";
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAllResourceList(
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &resource_list_load_count_,
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
2457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceListInDirectory(
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_resource_id,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceListCallback& callback) {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!directory_resource_id.empty());
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &directory_load_count_,
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::Search(
2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& search_query,
2677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!search_query.empty());
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          search_query,
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
2797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::SearchByTitle(
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!title.empty());
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: the search implementation here doesn't support quotation unescape,
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so don't escape here.
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(0,  // start changestamp
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          base::StringPrintf("title:'%s'", title.c_str()),
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          directory_resource_id,
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          NULL,
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetChangeList(
3037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int64 start_changestamp,
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetResourceListCallback& callback) {
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(start_changestamp,
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // empty search query
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          std::string(),  // no directory resource id,
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          0,  // start offset
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          default_max_results_,
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &change_list_load_count_,
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          callback);
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ContinueGetResourceList(
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& override_url,
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!override_url.is_empty());
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // "changestamp", "q", "parent" and "start-offset" are parameters to
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // implement "paging" of the result on FakeDriveService.
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The URL should be the one filled in GetResourceListInternal of the
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // previous method invocation, so it should start with "http://localhost/?".
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // See also GetResourceListInternal.
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.host(), "localhost");
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(override_url.path(), "/");
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int64 start_changestamp = 0;
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string search_query;
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string directory_resource_id;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start_offset = 0;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int max_results = default_max_results_;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<std::string, std::string> > parameters;
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::SplitStringIntoKeyValuePairs(
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          override_url.query(), '=', '&', &parameters)) {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < parameters.size(); ++i) {
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parameters[i].first == "changestamp") {
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::StringToInt64(parameters[i].second, &start_changestamp);
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "q") {
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        search_query =
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "parent") {
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        directory_resource_id =
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            net::UnescapeURLComponent(parameters[i].second,
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "start-offset") {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &start_offset);
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else if (parameters[i].first == "max-results") {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringToInt(parameters[i].second, &max_results);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetResourceListInternal(
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_changestamp, search_query, directory_resource_id,
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      start_offset, max_results, NULL, callback);
3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetResourceEntry(
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
3797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> resource_entry =
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ResourceEntry::CreateFrom(*entry);
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAboutResource(
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetAboutResourceCallback& callback) {
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AboutResource> null;
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION, base::Passed(&null)));
4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++about_resource_load_count_;
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AboutResource> about_resource(
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AboutResource::CreateFromAccountMetadata(
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *AccountMetadata::CreateFrom(*account_metadata_value_),
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetRootResourceId()));
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overwrite the change id.
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  about_resource->set_largest_change_id(largest_changestamp_);
42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback,
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 HTTP_SUCCESS, base::Passed(&about_resource)));
4277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetAppList(
4317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const GetAppListCallback& callback) {
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(app_info_value_);
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<AppList> null;
43890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
4437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_));
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list)));
4507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DeleteResource(
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
4637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and remove the one that matches |resource_id|.
468868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        entries->Remove(i, NULL);
47690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
4787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(satorux): Add support for returning "deleted" entries in
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // changelists from GetResourceList().
48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
4877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::DownloadFile(
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& virtual_path,
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_cache_path,
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& download_url,
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DownloadActionCallback& download_action_callback,
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetContentCallback& get_content_callback,
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ProgressCallback& progress_callback) {
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!download_action_callback.is_null());
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback,
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::FilePath()));
5067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The field content.src is the URL to download the file.
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByContentUrl(download_url);
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath()));
5157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Write "x"s of the file size specified in the entry.
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string file_size_string;
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("docs$size.$t", &file_size_string);
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(satorux): To be correct, we should update docs$md5Checksum.$t here.
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 file_size = 0;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::StringToInt64(file_size_string, &file_size)) {
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::BinaryValue* content_binary_data;
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string content_data;
52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (entry->GetBinary("test$data", &content_binary_data)) {
52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_data = std::string(content_binary_data->GetBuffer(),
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          content_binary_data->GetSize());
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_EQ(static_cast<size_t>(file_size), content_data.size());
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!get_content_callback.is_null()) {
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const int64 kBlockSize = 5;
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int64 i = 0; i < file_size; i += kBlockSize) {
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        const int64 size = std::min(kBlockSize, file_size - i);
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<std::string> content_for_callback(
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            new std::string(content_data.substr(i, size)));
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(get_content_callback, HTTP_SUCCESS,
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::Passed(&content_for_callback)));
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (test_util::WriteStringToFile(local_cache_path, content_data)) {
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!progress_callback.is_null()) {
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // See also the comment in ResumeUpload(). For testing that clients
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // can handle the case progress_callback is called multiple times,
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // here we invoke the callback twice.
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size / 2, file_size));
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::MessageLoopProxy::current()->PostTask(
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            FROM_HERE,
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(progress_callback, file_size, file_size));
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::MessageLoopProxy::current()->PostTask(
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          FROM_HERE,
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(download_action_callback,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     HTTP_SUCCESS,
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     local_cache_path));
5627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return CancelCallback();
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Failed to write the content.
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoopProxy::current()->PostTask(
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath()));
5707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyResource(
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
57590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& in_parent_resource_id,
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& new_name,
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
58390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
5887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const std::string& parent_resource_id = in_parent_resource_id.empty() ?
59290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetRootResourceId() : in_parent_resource_id;
59390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and copy the one that matches |resource_id|.
596868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
60290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          resource_id == current_resource_id) {
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Make a copy and set the new resource ID and the new title.
60490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<DictionaryValue> copied_entry(entry->DeepCopy());
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("gd$resourceId.$t",
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                resource_id + "_copied");
60790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        copied_entry->SetString("title.$t", new_name);
60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Reset parent directory.
61090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::ListValue* links = NULL;
61190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!entry->GetList("link", &links)) {
61290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          links = new base::ListValue;
61390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          entry->Set("link", links);
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
61590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Clear();
61690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
61790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::DictionaryValue* link = new base::DictionaryValue;
61890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString(
61990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "rel", "http://schemas.google.com/docs/2007#parent");
62090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
62190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        links->Append(link);
62290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
62390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        AddNewChangestamp(copied_entry.get());
62490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
62590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Parse the new entry.
62690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scoped_ptr<ResourceEntry> resource_entry =
62790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ResourceEntry::CreateFrom(*copied_entry);
62890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Add it to the resource list.
62990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        entries->Append(copied_entry.release());
63090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
63190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostTask(
63290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            FROM_HERE,
63390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            base::Bind(callback,
63490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       HTTP_SUCCESS,
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       base::Passed(&resource_entry)));
6367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return CancelCallback();
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> null;
64290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
6457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::CopyHostedDocument(
64990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
65090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& new_name,
65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
65490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CopyResource(resource_id, std::string(), new_name, callback);
65690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
65790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RenameResource(
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& new_name,
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
66690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
6687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry->SetString("title.$t", new_name);
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddNewChangestamp(entry);
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
6777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
6827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::TouchResource(
68690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& resource_id,
68790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& modified_date,
68890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Time& last_viewed_by_me_date,
68990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
69090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
69190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!modified_date.is_null());
69290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!last_viewed_by_me_date.is_null());
69390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback.is_null());
69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (offline_) {
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
69790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
69890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION,
69990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
7007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
70190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
70290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
70390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
70490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!entry) {
70590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
70690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
70790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND,
70890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Passed(scoped_ptr<ResourceEntry>())));
7097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
71090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
71190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
71290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("updated.$t",
71390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(modified_date));
71490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry->SetString("gd$lastViewed.$t",
71590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   util::FormatTimeAsString(last_viewed_by_me_date));
71690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AddNewChangestamp(entry);
71790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
71890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*entry));
71990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
72090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      FROM_HERE,
72190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
7227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
72390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
72490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddResourceToDirectory(
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
73390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
7357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!entry->GetList("link", &links)) {
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      links = new base::ListValue;
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->Set("link", links);
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // On the real Drive server, resources do not necessary shape a tree
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // structure. That is, each resource can have multiple parent.
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We mimic the behavior here; AddResourceToDirectoy just adds
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one more parent link, not overwriting old links.
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* link = new base::DictionaryValue;
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    link->SetString(
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "href", GetFakeLinkUrl(parent_resource_id).spec());
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    links->Append(link);
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddNewChangestamp(entry);
75790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
7597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
76290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
7647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::RemoveResourceFromDirectory(
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const EntryActionCallback& callback) {
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
77590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
7777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (entry) {
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* links = NULL;
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry->GetList("link", &links)) {
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL parent_content_url = GetFakeLinkUrl(parent_resource_id);
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < links->GetSize(); ++i) {
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::DictionaryValue* link = NULL;
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string rel;
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string href;
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (links->GetDictionary(i, &link) &&
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("rel", &rel) &&
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link->GetString("href", &href) &&
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            rel == "http://schemas.google.com/docs/2007#parent" &&
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            GURL(href) == parent_content_url) {
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          links->Remove(i, NULL);
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          AddNewChangestamp(entry);
79690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::MessageLoop::current()->PostTask(
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
7987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          return CancelCallback();
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
80490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
8067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AddNewDirectory(
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& directory_name,
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
81890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   GDATA_NO_CONNECTION,
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&null)));
8237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
826c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char kContentType[] = "application/atom+xml;type=feed";
827c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(kContentType,
82890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       "",  // content_data
829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
830c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       directory_name,
831c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       false,  // shared_with_me
832c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       "folder");
833c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
834c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
83590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
836c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
837c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
8387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
841c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry));
84290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
844c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
8457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadNewFile(
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& drive_file_path,
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& parent_resource_id,
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& title,
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
85990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
8627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Content length should be zero, as we'll create an empty file first. The
866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // content will be added in ResumeUpload().
867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
86890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       "",  // content_data
869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       title,
871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       false,  // shared_with_me
872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       "file");
873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
87490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
8777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const GURL upload_url = GetUploadUrl(*new_entry);
880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(upload_url.is_valid());
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
88290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
88490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS,
88590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 net::AppendQueryParameter(upload_url, "mode", "newfile")));
8867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::InitiateUploadExistingFile(
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& drive_file_path,
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& content_type,
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id,
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& etag,
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const InitiateUploadCallback& callback) {
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
90090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
9037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* entry = FindEntryByResourceId(resource_id);
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
90890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, GURL()));
9117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string entry_etag;
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetString("gd$etag", &entry_etag);
916c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!etag.empty() && etag != entry_etag) {
91790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback, HTTP_PRECONDITION, GURL()));
9207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
922c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  entry->SetString("docs$size.$t", "0");
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
924c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const GURL upload_url = GetUploadUrl(*entry);
925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(upload_url.is_valid());
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
92990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS,
93090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 net::AppendQueryParameter(upload_url, "mode", "existing")));
9317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::GetUploadStatus(
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& drive_file_path,
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url,
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 content_length,
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UploadRangeCallback& callback) {
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::ResumeUpload(
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const base::FilePath& drive_file_path,
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& upload_url,
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 start_position,
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 end_position,
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int64 content_length,
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& content_type,
951a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      const base::FilePath& local_file_path,
952c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const UploadRangeCallback& callback,
953c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ProgressCallback& progress_callback) {
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ResourceEntry> result_entry;
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (offline_) {
96090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   UploadRangeResponse(GDATA_NO_CONNECTION,
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       start_position,
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       end_position),
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&result_entry)));
9677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* entry = NULL;
97190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  entry = FindEntryByUploadUrl(RemoveQueryParameter(upload_url));
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry) {
97390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   UploadRangeResponse(HTTP_NOT_FOUND,
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       start_position,
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       end_position),
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Passed(&result_entry)));
9807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
983c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Chunks are required to be sent in such a ways that they fill from the start
984c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // of the not-yet-uploaded part with no gaps nor overlaps.
985c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string current_size_string;
986c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int64 current_size;
987c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry->GetString("docs$size.$t", &current_size_string) ||
988c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !base::StringToInt64(current_size_string, &current_size) ||
989c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      current_size != start_position) {
99090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
991c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
992c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
993c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   UploadRangeResponse(HTTP_BAD_REQUEST,
994c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       start_position,
995c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       end_position),
996c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&result_entry)));
9977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
998c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
999c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->SetString("docs$size.$t", base::Int64ToString(end_position));
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!progress_callback.is_null()) {
1003c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // In the real GDataWapi/Drive DriveService, progress is reported in
1004c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // nondeterministic timing. In this fake implementation, we choose to call
1005c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // it twice per one ResumeUpload. This is for making sure that client code
1006c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // works fine even if the callback is invoked more than once; it is the
1007c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // crucial difference of the progress callback from others.
1008c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Note that progress is notified in the relative offset in each chunk.
1009c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 chunk_size = end_position - start_position;
101090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1011c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size / 2, chunk_size));
101290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1013c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE, base::Bind(progress_callback, chunk_size, chunk_size));
1014c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1015c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (content_length != end_position) {
101790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   UploadRangeResponse(HTTP_RESUME_INCOMPLETE,
10212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       start_position,
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       end_position),
10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    base::Passed(&result_entry)));
10247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return CancelCallback();
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AddNewChangestamp(entry);
10282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result_entry = ResourceEntry::CreateFrom(*entry).Pass();
10292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string upload_mode;
103190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool upload_mode_found =
103290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      net::GetValueForKeyInQuery(upload_url, "mode", &upload_mode);
103390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(upload_mode_found &&
103490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         (upload_mode == "newfile" || upload_mode == "existing"));
103590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
103690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GDataErrorCode return_code =
103790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      upload_mode == "newfile" ? HTTP_CREATED : HTTP_SUCCESS;
10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
10402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
10412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(callback,
10422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 UploadRangeResponse(return_code,
10432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     start_position,
10442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     end_position),
10452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Passed(&result_entry)));
10467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)CancelCallback FakeDriveService::AuthorizeApp(
10507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& resource_id,
10517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& app_id,
10527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AuthorizeAppCallback& callback) {
10532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
10557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return CancelCallback();
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1058c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::AddNewFile(const std::string& content_type,
105990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const std::string& content_data,
1060c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& parent_resource_id,
1061c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const std::string& title,
1062c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  bool shared_with_me,
1063c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  const GetResourceEntryCallback& callback) {
1064c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1065c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1066c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1067c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1068c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
106990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1070c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1071c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1072c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1073c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1074c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1075c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1076c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1077c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Prepare "kind" for hosted documents. This only supports Google Document.
1078c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string entry_kind;
1079c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (content_type == "application/vnd.google-apps.document")
1080c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "document";
1081c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
1082c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry_kind = "file";
1083c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1084c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* new_entry = AddNewEntry(content_type,
108590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                       content_data,
1086c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       parent_resource_id,
1087c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       title,
1088c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       shared_with_me,
1089c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                       entry_kind);
1090c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!new_entry) {
1091c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
109290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1093c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1094c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1095c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1096c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1097c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1098c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1099c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*new_entry));
110090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry)));
1103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::SetLastModifiedTime(
1106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& resource_id,
1107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Time& last_modified_time,
1108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceEntryCallback& callback) {
1109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!callback.is_null());
1111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
111490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!entry) {
1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceEntry> null;
112590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null)));
1128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (last_modified_time.is_null()) {
1132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->Remove("updated.$t", NULL);
1133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->SetString("updated.$t",
1135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     util::FormatTimeAsString(last_modified_time));
1136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceEntry> parsed_entry(
1139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceEntry::CreateFrom(*entry));
114090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry)));
1143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByResourceId(
11462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& resource_id) {
11472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
11502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |resource_id|.
1151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
11522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
11542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_resource_id;
11552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
11562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("gd$resourceId.$t", &current_resource_id) &&
11572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource_id == current_resource_id) {
11582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
11592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
11602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
11642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByContentUrl(
11672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& content_url) {
11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
11712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |content_url|.
1172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
11732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
11742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
11752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string current_content_url;
11762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
11772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetString("content.src", &current_content_url) &&
11782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content_url == GURL(current_content_url)) {
11792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return entry;
11802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
11812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
11852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* FakeDriveService::FindEntryByUploadUrl(
11882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& upload_url) {
11892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* entries = NULL;
11922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Go through entries and return the one that matches |upload_url|.
1193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries)) {
11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < entries->GetSize(); ++i) {
11952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* entry = NULL;
11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::ListValue* links = NULL;
11972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (entries->GetDictionary(i, &entry) &&
11982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          entry->GetList("link", &links) &&
11992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          links) {
12002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (size_t link_index = 0;
12012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            link_index < links->GetSize();
12022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ++link_index) {
12032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::DictionaryValue* link = NULL;
12042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          std::string rel;
12052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          std::string found_upload_url;
12062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (links->GetDictionary(link_index, &link) &&
12072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              link && link->GetString("rel", &rel) &&
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              rel == kUploadUrlRel &&
12092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              link->GetString("href", &found_upload_url) &&
12102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              GURL(found_upload_url) == upload_url) {
12112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return entry;
12122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
12132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
12142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
12152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
12162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string FakeDriveService::GetNewResourceId() {
12222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++resource_id_count_;
12252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf("resource_id_%d", resource_id_count_);
12262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) {
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++largest_changestamp_;
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->SetString("docs$changestamp.value",
12312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Int64ToString(largest_changestamp_));
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::DictionaryValue* FakeDriveService::AddNewEntry(
1235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& content_type,
123690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& content_data,
1237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& parent_resource_id,
1238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& title,
1239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool shared_with_me,
1240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& entry_kind) {
1241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (parent_resource_id != GetRootResourceId() &&
1244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !FindEntryByResourceId(parent_resource_id)) {
1245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
1246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string resource_id = GetNewResourceId();
1249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL upload_url = GURL("https://xxx/upload/" + resource_id);
1250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
1252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the resource ID and the title
1253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("gd$resourceId.$t", resource_id);
1254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("title.$t", title);
1255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->SetString("docs$filename", title);
125690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set the contents, size and MD5 for a file.
1257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (entry_kind == "file") {
125890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->Set("test$data",
125990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::BinaryValue::CreateWithCopiedBuffer(
126090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            content_data.c_str(), content_data.size()));
126190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    new_entry->SetString("docs$size.$t",
126290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         base::Int64ToString(content_data.size()));
1263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // TODO(satorux): Set the correct MD5 here.
1264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    new_entry->SetString("docs$md5Checksum.$t",
1265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         "3b4385ebefec6e743574c76bbd0575de");
1266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "category" which sets the resource type to |entry_kind|.
1269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* categories = new base::ListValue;
1270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* category = new base::DictionaryValue;
1271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("scheme", "http://schemas.google.com/g/2005#kind");
1272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  category->SetString("term", "http://schemas.google.com/docs/2007#" +
1273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      entry_kind);
1274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  categories->Append(category);
1275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("category", categories);
1276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (shared_with_me) {
1277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::DictionaryValue* shared_with_me_label = new base::DictionaryValue;
1278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("label", "shared-with-me");
1279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString("scheme",
1280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    "http://schemas.google.com/g/2005/labels");
1281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shared_with_me_label->SetString(
1282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "term", "http://schemas.google.com/g/2005/labels#shared");
1283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    categories->Append(shared_with_me_label);
1284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string escaped_resource_id = net::EscapePath(resource_id);
1287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "content" which sets the content URL.
1289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* content = new base::DictionaryValue;
1290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content->SetString("src", "https://xxx/content/" + escaped_resource_id);
1291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content->SetString("type", content_type);
1292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("content", content);
1293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Add "link" which sets the parent URL, the edit URL and the upload URL.
1295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* links = new base::ListValue;
1296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* parent_link = new base::DictionaryValue;
1298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec());
1299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent_link->SetString("rel",
1300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         "http://schemas.google.com/docs/2007#parent");
1301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(parent_link);
1302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* edit_link = new base::DictionaryValue;
1304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id);
1305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  edit_link->SetString("rel", "edit");
1306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(edit_link);
1307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* upload_link = new base::DictionaryValue;
1309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("href", upload_url.spec());
1310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  upload_link->SetString("rel", kUploadUrlRel);
1311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  links->Append(upload_link);
1312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  new_entry->Set("link", links);
1313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AddNewChangestamp(new_entry.get());
1315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::Time published_date =
13177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_);
13187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  new_entry->SetString("published.$t",
13197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                       util::FormatTimeAsString(published_date));
13207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If there are no entries, prepare an empty entry to add.
1322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!resource_list_value_->HasKey("entry"))
1323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    resource_list_value_->Set("entry", new ListValue);
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* raw_new_entry = new_entry.release();
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* entries = NULL;
1327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (resource_list_value_->GetList("entry", &entries))
1328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->Append(raw_new_entry);
1329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return raw_new_entry;
1331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FakeDriveService::GetResourceListInternal(
1334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 start_changestamp,
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& search_query,
1336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& directory_resource_id,
1337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int start_offset,
1338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int max_results,
1339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int* load_counter,
1340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GetResourceListCallback& callback) {
1341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (offline_) {
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ResourceList> null;
134390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FROM_HERE,
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(callback,
1346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   GDATA_NO_CONNECTION,
1347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   base::Passed(&null)));
1348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ResourceList> resource_list =
1352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ResourceList::CreateFrom(*resource_list_value_);
1353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Filter out entries per parameters like |directory_resource_id| and
1355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |search_query|.
1356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries();
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int num_entries_matched = 0;
1359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < entries->size();) {
1360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ResourceEntry* entry = (*entries)[i];
1361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool should_exclude = false;
1362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |directory_resource_id| is set, exclude the entry if it's not in
1364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the target directory.
1365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Get the parent resource ID of the entry.
1367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string parent_resource_id;
1368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const google_apis::Link* parent_link =
1369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          entry->GetLinkByType(Link::LINK_PARENT);
1370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (parent_link) {
1371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        parent_resource_id =
1372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            net::UnescapeURLComponent(parent_link->href().ExtractFileName(),
1373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      net::UnescapeRule::URL_SPECIAL_CHARS);
1374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (directory_resource_id != parent_resource_id)
1376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        should_exclude = true;
1377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |search_query| is set, exclude the entry if it does not contain the
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // search query in the title.
1381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude && !search_query.empty() &&
1382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !EntryMatchWithQuery(*entry, search_query)) {
1383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_changestamp| is set, exclude the entry if the
1387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // changestamp is older than |largest_changestamp|.
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // See https://developers.google.com/google-apps/documents-list/
1389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // #retrieving_all_changes_since_a_given_changestamp
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0 && entry->changestamp() < start_changestamp)
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The entry matched the criteria for inclusion.
1394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!should_exclude)
1395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++num_entries_matched;
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If |start_offset| is set, exclude the entry if the entry is before the
1398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // start index. <= instead of < as |num_entries_matched| was
1399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // already incremented.
1400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_offset > 0 && num_entries_matched <= start_offset)
1401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      should_exclude = true;
1402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (should_exclude)
1404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entries->erase(entries->begin() + i);
1405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
1406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++i;
1407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If |max_results| is set, trim the entries if the number exceeded the max
1410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // results.
1411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) {
1412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entries->erase(entries->begin() + max_results, entries->end());
1413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Adds the next URL.
1414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Here, we embed information which is needed for continuing the
1415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // GetResourceList request in the next invocation into url query
1416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // parameters.
1417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GURL next_url(base::StringPrintf(
1418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "http://localhost/?start-offset=%d&max-results=%d",
1419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        start_offset + max_results,
1420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        max_results));
1421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (start_changestamp > 0) {
1422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "changestamp",
1424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Int64ToString(start_changestamp).c_str());
1425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!search_query.empty()) {
1427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "q", search_query);
1429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!directory_resource_id.empty()) {
1431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      next_url = net::AppendOrReplaceQueryParameter(
1432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          next_url, "parent", directory_resource_id);
1433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Link* link = new Link;
1436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_type(Link::LINK_NEXT);
1437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    link->set_href(next_url);
1438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resource_list->mutable_links()->push_back(link);
1439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (load_counter)
1442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *load_counter += 1;
144390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
1445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(callback,
1446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 HTTP_SUCCESS,
1447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Passed(&resource_list)));
1448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace google_apis
1451