1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <map>
6
7#include "base/file_util.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/stl_util-inl.h"
10#include "base/string_number_conversions.h"
11#include "base/string_split.h"
12#include "base/string_util.h"
13#include "base/stringprintf.h"
14#include "base/threading/thread.h"
15#include "base/version.h"
16#include "chrome/browser/extensions/extension_error_reporter.h"
17#include "chrome/browser/extensions/extension_updater.h"
18#include "chrome/browser/extensions/extension_service.h"
19#include "chrome/browser/extensions/test_extension_prefs.h"
20#include "chrome/browser/prefs/pref_service.h"
21#include "chrome/common/extensions/extension.h"
22#include "chrome/common/extensions/extension_constants.h"
23#include "chrome/common/pref_names.h"
24#include "chrome/common/net/test_url_fetcher_factory.h"
25#include "chrome/test/testing_profile.h"
26#include "content/browser/browser_thread.h"
27#include "net/base/escape.h"
28#include "net/base/load_flags.h"
29#include "net/url_request/url_request_status.h"
30#include "testing/gtest/include/gtest/gtest.h"
31#include "libxml/globals.h"
32
33using base::Time;
34using base::TimeDelta;
35
36namespace {
37
38const char kEmptyUpdateUrlData[] = "";
39
40int expected_load_flags =
41    net::LOAD_DO_NOT_SEND_COOKIES |
42    net::LOAD_DO_NOT_SAVE_COOKIES |
43    net::LOAD_DISABLE_CACHE;
44
45const ManifestFetchData::PingData kNeverPingedData(
46    ManifestFetchData::kNeverPinged, ManifestFetchData::kNeverPinged);
47
48}  // namespace
49
50// Base class for further specialized test classes.
51class MockService : public ExtensionServiceInterface {
52 public:
53  MockService()
54      : pending_extension_manager_(ALLOW_THIS_IN_INITIALIZER_LIST(*this)) {}
55  virtual ~MockService() {}
56
57  virtual const ExtensionList* extensions() const {
58    ADD_FAILURE();
59    return NULL;
60  }
61
62  virtual const ExtensionList* disabled_extensions() const {
63    ADD_FAILURE();
64    return NULL;
65  }
66
67  virtual void UpdateExtension(const std::string& id,
68                               const FilePath& path,
69                               const GURL& download_url) {
70    FAIL();
71  }
72
73  virtual const Extension* GetExtensionById(const std::string& id,
74                                            bool include_disabled) const {
75    ADD_FAILURE();
76    return NULL;
77  }
78
79  virtual bool UninstallExtension(const std::string& extension_id,
80                                  bool external_uninstall,
81                                  std::string* error) {
82    ADD_FAILURE();
83    return false;
84  }
85
86  virtual bool IsExtensionEnabled(const std::string& extension_id) const {
87    ADD_FAILURE();
88    return false;
89  }
90
91  virtual bool IsExternalExtensionUninstalled(
92      const std::string& extension_id) const {
93    ADD_FAILURE();
94    return false;
95  }
96
97  virtual void EnableExtension(const std::string& extension_id) {
98    FAIL();
99  }
100
101  virtual void DisableExtension(const std::string& extension_id) {
102    FAIL();
103  }
104
105
106  virtual void UpdateExtensionBlacklist(
107      const std::vector<std::string>& blacklist) {
108    FAIL();
109  }
110
111  virtual void CheckAdminBlacklist() {
112    FAIL();
113  }
114
115  virtual bool IsIncognitoEnabled(const std::string& id) const {
116    ADD_FAILURE();
117    return false;
118  }
119
120  virtual void SetIsIncognitoEnabled(const std::string& id,
121                                     bool enabled) {
122    FAIL();
123  }
124
125  virtual void CheckForUpdatesSoon() {
126    FAIL();
127  }
128
129  virtual PendingExtensionManager* pending_extension_manager() {
130    ADD_FAILURE() << "Subclass should override this if it will "
131                  << "be accessed by a test.";
132    return &pending_extension_manager_;
133  }
134
135  virtual void ProcessSyncData(
136      const ExtensionSyncData& extension_sync_data,
137      PendingExtensionInfo::ShouldAllowInstallPredicate
138          should_allow_install) {
139    FAIL();
140  }
141
142  Profile* profile() { return &profile_; }
143
144  ExtensionPrefs* extension_prefs() { return prefs_.prefs(); }
145
146  PrefService* pref_service() { return prefs_.pref_service(); }
147
148  // Creates test extensions and inserts them into list. The name and
149  // version are all based on their index. If |update_url| is non-null, it
150  // will be used as the update_url for each extension.
151  // The |id| is used to distinguish extension names and make sure that
152  // no two extensions share the same name.
153  void CreateTestExtensions(int id, int count, ExtensionList *list,
154                            const std::string* update_url,
155                            Extension::Location location) {
156    for (int i = 1; i <= count; i++) {
157      DictionaryValue manifest;
158      manifest.SetString(extension_manifest_keys::kVersion,
159                         base::StringPrintf("%d.0.0.0", i));
160      manifest.SetString(extension_manifest_keys::kName,
161                         base::StringPrintf("Extension %d.%d", id, i));
162      if (update_url)
163        manifest.SetString(extension_manifest_keys::kUpdateURL, *update_url);
164      scoped_refptr<Extension> e =
165          prefs_.AddExtensionWithManifest(manifest, location);
166      ASSERT_TRUE(e != NULL);
167      list->push_back(e);
168    }
169  }
170
171 protected:
172  PendingExtensionManager pending_extension_manager_;
173  TestExtensionPrefs prefs_;
174  TestingProfile profile_;
175
176 private:
177  DISALLOW_COPY_AND_ASSIGN(MockService);
178};
179
180
181std::string GenerateId(std::string input) {
182  std::string result;
183  EXPECT_TRUE(Extension::GenerateId(input, &result));
184  return result;
185}
186
187bool ShouldInstallExtensionsOnly(const Extension& extension) {
188  return extension.GetType() == Extension::TYPE_EXTENSION;
189}
190
191bool ShouldInstallThemesOnly(const Extension& extension) {
192  return extension.is_theme();
193}
194
195bool ShouldAlwaysInstall(const Extension& extension) {
196  return true;
197}
198
199// Loads some pending extension records into a pending extension manager.
200void SetupPendingExtensionManagerForTest(
201    int count,
202    const GURL& update_url,
203    PendingExtensionManager* pending_extension_manager) {
204  for (int i = 1; i <= count; i++) {
205    PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install =
206        (i % 2 == 0) ? &ShouldInstallThemesOnly : &ShouldInstallExtensionsOnly;
207    const bool kIsFromSync = true;
208    const bool kInstallSilently = true;
209    const Extension::State kInitialState = Extension::ENABLED;
210    const bool kInitialIncognitoEnabled = false;
211    std::string id = GenerateId(base::StringPrintf("extension%i", i));
212
213    pending_extension_manager->AddForTesting(
214        id,
215        PendingExtensionInfo(update_url,
216                             should_allow_install,
217                             kIsFromSync,
218                             kInstallSilently,
219                             kInitialState,
220                             kInitialIncognitoEnabled,
221                             Extension::INTERNAL));
222  }
223}
224
225class ServiceForManifestTests : public MockService {
226 public:
227  ServiceForManifestTests() {}
228
229  virtual ~ServiceForManifestTests() {}
230
231  virtual const Extension* GetExtensionById(const std::string& id,
232                                            bool include_disabled) const {
233    for (ExtensionList::const_iterator iter = extensions_.begin();
234        iter != extensions_.end(); ++iter) {
235      if ((*iter)->id() == id) {
236        return *iter;
237      }
238    }
239    return NULL;
240  }
241
242  virtual const ExtensionList* extensions() const { return &extensions_; }
243
244  virtual PendingExtensionManager* pending_extension_manager() {
245    return &pending_extension_manager_;
246  }
247
248  void set_extensions(ExtensionList extensions) {
249    extensions_ = extensions;
250  }
251
252 private:
253  ExtensionList extensions_;
254};
255
256class ServiceForDownloadTests : public MockService {
257 public:
258  virtual void UpdateExtension(const std::string& id,
259                               const FilePath& extension_path,
260                               const GURL& download_url) {
261    extension_id_ = id;
262    install_path_ = extension_path;
263    download_url_ = download_url;
264  }
265
266  virtual PendingExtensionManager* pending_extension_manager() {
267    return &pending_extension_manager_;
268  }
269
270  virtual const Extension* GetExtensionById(const std::string& id, bool) const {
271    last_inquired_extension_id_ = id;
272    return NULL;
273  }
274
275  const std::string& extension_id() const { return extension_id_; }
276  const FilePath& install_path() const { return install_path_; }
277  const GURL& download_url() const { return download_url_; }
278  const std::string& last_inquired_extension_id() const {
279    return last_inquired_extension_id_;
280  }
281
282 private:
283  std::string extension_id_;
284  FilePath install_path_;
285  GURL download_url_;
286
287  // The last extension ID that GetExtensionById was called with.
288  // Mutable because the method that sets it (GetExtensionById) is const
289  // in the actual extension service, but must record the last extension
290  // ID in this test class.
291  mutable std::string last_inquired_extension_id_;
292};
293
294class ServiceForBlacklistTests : public MockService {
295 public:
296  ServiceForBlacklistTests()
297     : MockService(),
298       processed_blacklist_(false) {
299  }
300  virtual void UpdateExtensionBlacklist(
301    const std::vector<std::string>& blacklist) {
302    processed_blacklist_ = true;
303    return;
304  }
305  bool processed_blacklist() { return processed_blacklist_; }
306  const std::string& extension_id() { return extension_id_; }
307
308 private:
309  bool processed_blacklist_;
310  std::string extension_id_;
311  FilePath install_path_;
312};
313
314static const int kUpdateFrequencySecs = 15;
315
316// Takes a string with KEY=VALUE parameters separated by '&' in |params| and
317// puts the key/value pairs into |result|. For keys with no value, the empty
318// string is used. So for "a=1&b=foo&c", result would map "a" to "1", "b" to
319// "foo", and "c" to "".
320static void ExtractParameters(const std::string& params,
321                              std::map<std::string, std::string>* result) {
322  std::vector<std::string> pairs;
323  base::SplitString(params, '&', &pairs);
324  for (size_t i = 0; i < pairs.size(); i++) {
325    std::vector<std::string> key_val;
326    base::SplitString(pairs[i], '=', &key_val);
327    if (!key_val.empty()) {
328      std::string key = key_val[0];
329      EXPECT_TRUE(result->find(key) == result->end());
330      (*result)[key] = (key_val.size() == 2) ? key_val[1] : "";
331    } else {
332      NOTREACHED();
333    }
334  }
335}
336
337// All of our tests that need to use private APIs of ExtensionUpdater live
338// inside this class (which is a friend to ExtensionUpdater).
339class ExtensionUpdaterTest : public testing::Test {
340 public:
341  static void SimulateTimerFired(ExtensionUpdater* updater) {
342    EXPECT_TRUE(updater->timer_.IsRunning());
343    updater->timer_.Stop();
344    updater->TimerFired();
345  }
346
347  static void SimulateCheckSoon(const ExtensionUpdater& updater,
348                                MessageLoop* message_loop) {
349    EXPECT_TRUE(updater.will_check_soon_);
350    message_loop->RunAllPending();
351  }
352
353  // Adds a Result with the given data to results.
354  static void AddParseResult(
355      const std::string& id,
356      const std::string& version,
357      const std::string& url,
358      UpdateManifest::Results* results) {
359    UpdateManifest::Result result;
360    result.extension_id = id;
361    result.version = version;
362    result.crx_url = GURL(url);
363    results->list.push_back(result);
364  }
365
366  static void TestExtensionUpdateCheckRequests(bool pending) {
367    MessageLoop message_loop;
368    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
369    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
370    BrowserThread io_thread(BrowserThread::IO);
371    io_thread.Start();
372
373    // Create an extension with an update_url.
374    ServiceForManifestTests service;
375    std::string update_url("http://foo.com/bar");
376    ExtensionList extensions;
377    PendingExtensionManager* pending_extension_manager =
378        service.pending_extension_manager();
379    if (pending) {
380      SetupPendingExtensionManagerForTest(1, GURL(update_url),
381                                          pending_extension_manager);
382    } else {
383      service.CreateTestExtensions(1, 1, &extensions, &update_url,
384                                   Extension::INTERNAL);
385      service.set_extensions(extensions);
386    }
387
388    // Set up and start the updater.
389    TestURLFetcherFactory factory;
390    URLFetcher::set_factory(&factory);
391    ExtensionUpdater updater(
392        &service, service.extension_prefs(), service.pref_service(),
393        service.profile(), 60*60*24);
394    updater.Start();
395    // Disable blacklist checks (tested elsewhere) so that we only see the
396    // update HTTP request.
397    updater.set_blacklist_checks_enabled(false);
398
399    // Tell the update that it's time to do update checks.
400    SimulateTimerFired(&updater);
401
402    // Get the url our mock fetcher was asked to fetch.
403    TestURLFetcher* fetcher =
404        factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
405    const GURL& url = fetcher->original_url();
406    EXPECT_FALSE(url.is_empty());
407    EXPECT_TRUE(url.is_valid());
408    EXPECT_TRUE(url.SchemeIs("http"));
409    EXPECT_EQ("foo.com", url.host());
410    EXPECT_EQ("/bar", url.path());
411
412    // Validate the extension request parameters in the query. It should
413    // look something like "?x=id%3D<id>%26v%3D<version>%26uc".
414    EXPECT_TRUE(url.has_query());
415    std::vector<std::string> parts;
416    base::SplitString(url.query(), '=', &parts);
417    EXPECT_EQ(2u, parts.size());
418    EXPECT_EQ("x", parts[0]);
419    std::string decoded = UnescapeURLComponent(parts[1],
420                                               UnescapeRule::URL_SPECIAL_CHARS);
421    std::map<std::string, std::string> params;
422    ExtractParameters(decoded, &params);
423    if (pending) {
424      EXPECT_EQ(pending_extension_manager->begin()->first, params["id"]);
425      EXPECT_EQ("0.0.0.0", params["v"]);
426    } else {
427      EXPECT_EQ(extensions[0]->id(), params["id"]);
428      EXPECT_EQ(extensions[0]->VersionString(), params["v"]);
429    }
430    EXPECT_EQ("", params["uc"]);
431  }
432
433  static void TestBlacklistUpdateCheckRequests() {
434    ServiceForManifestTests service;
435
436    // Setup and start the updater.
437    MessageLoop message_loop;
438    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
439    BrowserThread io_thread(BrowserThread::IO);
440    io_thread.Start();
441
442    TestURLFetcherFactory factory;
443    URLFetcher::set_factory(&factory);
444    ExtensionUpdater updater(
445        &service, service.extension_prefs(), service.pref_service(),
446        service.profile(), 60*60*24);
447    updater.Start();
448
449    // Tell the updater that it's time to do update checks.
450    SimulateTimerFired(&updater);
451
452    // Get the url our mock fetcher was asked to fetch.
453    TestURLFetcher* fetcher =
454        factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
455    ASSERT_FALSE(fetcher == NULL);
456    const GURL& url = fetcher->original_url();
457
458    EXPECT_FALSE(url.is_empty());
459    EXPECT_TRUE(url.is_valid());
460    EXPECT_TRUE(url.SchemeIs("https"));
461    EXPECT_EQ("clients2.google.com", url.host());
462    EXPECT_EQ("/service/update2/crx", url.path());
463
464    // Validate the extension request parameters in the query. It should
465    // look something like "?x=id%3D<id>%26v%3D<version>%26uc".
466    EXPECT_TRUE(url.has_query());
467    std::vector<std::string> parts;
468    base::SplitString(url.query(), '=', &parts);
469    EXPECT_EQ(2u, parts.size());
470    EXPECT_EQ("x", parts[0]);
471    std::string decoded = UnescapeURLComponent(parts[1],
472                                               UnescapeRule::URL_SPECIAL_CHARS);
473    std::map<std::string, std::string> params;
474    ExtractParameters(decoded, &params);
475    EXPECT_EQ("com.google.crx.blacklist", params["id"]);
476    EXPECT_EQ("0", params["v"]);
477    EXPECT_EQ("", params["uc"]);
478    EXPECT_TRUE(ContainsKey(params, "ping"));
479  }
480
481  static void TestUpdateUrlDataEmpty() {
482    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
483    const std::string version = "1.0";
484
485    // Make sure that an empty update URL data string does not cause a ap=
486    // option to appear in the x= parameter.
487    ManifestFetchData fetch_data(GURL("http://localhost/foo"));
488    fetch_data.AddExtension(id, version,
489                            kNeverPingedData, "");
490    EXPECT_EQ("http://localhost/foo\?x=id%3Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
491              "%26v%3D1.0%26uc",
492              fetch_data.full_url().spec());
493  }
494
495  static void TestUpdateUrlDataSimple() {
496    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
497    const std::string version = "1.0";
498
499    // Make sure that an update URL data string causes an appropriate ap=
500    // option to appear in the x= parameter.
501    ManifestFetchData fetch_data(GURL("http://localhost/foo"));
502    fetch_data.AddExtension(id, version,
503                            kNeverPingedData, "bar");
504    EXPECT_EQ("http://localhost/foo\?x=id%3Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
505              "%26v%3D1.0%26uc%26ap%3Dbar",
506              fetch_data.full_url().spec());
507  }
508
509  static void TestUpdateUrlDataCompound() {
510    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
511    const std::string version = "1.0";
512
513    // Make sure that an update URL data string causes an appropriate ap=
514    // option to appear in the x= parameter.
515    ManifestFetchData fetch_data(GURL("http://localhost/foo"));
516    fetch_data.AddExtension(id, version,
517                            kNeverPingedData, "a=1&b=2&c");
518    EXPECT_EQ("http://localhost/foo\?x=id%3Daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
519              "%26v%3D1.0%26uc%26ap%3Da%253D1%2526b%253D2%2526c",
520              fetch_data.full_url().spec());
521  }
522
523  static void TestUpdateUrlDataFromGallery(const std::string& gallery_url) {
524    MockService service;
525    ManifestFetchesBuilder builder(&service, service.extension_prefs());
526    ExtensionList extensions;
527    std::string url(gallery_url);
528
529    service.CreateTestExtensions(1, 1, &extensions, &url, Extension::INTERNAL);
530    builder.AddExtension(*extensions[0]);
531    std::vector<ManifestFetchData*> fetches = builder.GetFetches();
532    EXPECT_EQ(1u, fetches.size());
533    scoped_ptr<ManifestFetchData> fetch(fetches[0]);
534    fetches.clear();
535
536    // Make sure that extensions that update from the gallery ignore any
537    // update URL data.
538    const std::string& update_url = fetch->full_url().spec();
539    std::string::size_type x = update_url.find("x=");
540    EXPECT_NE(std::string::npos, x);
541    std::string::size_type ap = update_url.find("ap%3D", x);
542    EXPECT_EQ(std::string::npos, ap);
543  }
544
545  static void TestDetermineUpdates() {
546    MessageLoop message_loop;
547    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
548    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
549
550    // Create a set of test extensions
551    ServiceForManifestTests service;
552    ExtensionList tmp;
553    service.CreateTestExtensions(1, 3, &tmp, NULL, Extension::INTERNAL);
554    service.set_extensions(tmp);
555
556    ExtensionUpdater updater(
557        &service, service.extension_prefs(), service.pref_service(),
558        service.profile(), kUpdateFrequencySecs);
559    updater.Start();
560
561    // Check passing an empty list of parse results to DetermineUpdates
562    ManifestFetchData fetch_data(GURL("http://localhost/foo"));
563    UpdateManifest::Results updates;
564    std::vector<int> updateable = updater.DetermineUpdates(fetch_data,
565                                                           updates);
566    EXPECT_TRUE(updateable.empty());
567
568    // Create two updates - expect that DetermineUpdates will return the first
569    // one (v1.0 installed, v1.1 available) but not the second one (both
570    // installed and available at v2.0).
571    scoped_ptr<Version> one(Version::GetVersionFromString("1.0"));
572    EXPECT_TRUE(tmp[0]->version()->Equals(*one));
573    fetch_data.AddExtension(tmp[0]->id(), tmp[0]->VersionString(),
574                            kNeverPingedData,
575                            kEmptyUpdateUrlData);
576    AddParseResult(tmp[0]->id(),
577        "1.1", "http://localhost/e1_1.1.crx", &updates);
578    fetch_data.AddExtension(tmp[1]->id(), tmp[1]->VersionString(),
579                            kNeverPingedData,
580                            kEmptyUpdateUrlData);
581    AddParseResult(tmp[1]->id(),
582        tmp[1]->VersionString(), "http://localhost/e2_2.0.crx", &updates);
583    updateable = updater.DetermineUpdates(fetch_data, updates);
584    EXPECT_EQ(1u, updateable.size());
585    EXPECT_EQ(0, updateable[0]);
586  }
587
588  static void TestDetermineUpdatesPending() {
589    // Create a set of test extensions
590    ServiceForManifestTests service;
591    PendingExtensionManager* pending_extension_manager =
592        service.pending_extension_manager();
593    SetupPendingExtensionManagerForTest(3, GURL(), pending_extension_manager);
594
595    MessageLoop message_loop;
596    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
597    ExtensionUpdater updater(
598        &service, service.extension_prefs(), service.pref_service(),
599        service.profile(), kUpdateFrequencySecs);
600    updater.Start();
601
602    ManifestFetchData fetch_data(GURL("http://localhost/foo"));
603    UpdateManifest::Results updates;
604    PendingExtensionManager::const_iterator it;
605    for (it = pending_extension_manager->begin();
606         it != pending_extension_manager->end(); ++it) {
607      fetch_data.AddExtension(it->first, "1.0.0.0",
608                              kNeverPingedData,
609                              kEmptyUpdateUrlData);
610      AddParseResult(it->first,
611                     "1.1", "http://localhost/e1_1.1.crx", &updates);
612    }
613    std::vector<int> updateable =
614        updater.DetermineUpdates(fetch_data, updates);
615    // All the apps should be updateable.
616    EXPECT_EQ(3u, updateable.size());
617    for (std::vector<int>::size_type i = 0; i < updateable.size(); ++i) {
618      EXPECT_EQ(static_cast<int>(i), updateable[i]);
619    }
620  }
621
622  static void TestMultipleManifestDownloading() {
623    MessageLoop ui_loop;
624    BrowserThread ui_thread(BrowserThread::UI, &ui_loop);
625    BrowserThread file_thread(BrowserThread::FILE);
626    file_thread.Start();
627    BrowserThread io_thread(BrowserThread::IO);
628    io_thread.Start();
629
630    TestURLFetcherFactory factory;
631    TestURLFetcher* fetcher = NULL;
632    URLFetcher::set_factory(&factory);
633    scoped_ptr<ServiceForDownloadTests> service(new ServiceForDownloadTests);
634    ExtensionUpdater updater(service.get(), service->extension_prefs(),
635                             service->pref_service(),
636                             service->profile(),
637                             kUpdateFrequencySecs);
638    updater.Start();
639
640    GURL url1("http://localhost/manifest1");
641    GURL url2("http://localhost/manifest2");
642
643    // Request 2 update checks - the first should begin immediately and the
644    // second one should be queued up.
645    ManifestFetchData* fetch1 = new ManifestFetchData(url1);
646    ManifestFetchData* fetch2 = new ManifestFetchData(url2);
647    ManifestFetchData::PingData zeroDays(0, 0);
648    fetch1->AddExtension("1111", "1.0", zeroDays, kEmptyUpdateUrlData);
649    fetch2->AddExtension("12345", "2.0", kNeverPingedData,
650                         kEmptyUpdateUrlData);
651    updater.StartUpdateCheck(fetch1);
652    updater.StartUpdateCheck(fetch2);
653
654    std::string invalid_xml = "invalid xml";
655    fetcher = factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
656    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
657    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
658    fetcher->delegate()->OnURLFetchComplete(
659        fetcher, url1, net::URLRequestStatus(), 200, ResponseCookies(),
660        invalid_xml);
661
662    // Now that the first request is complete, make sure the second one has
663    // been started.
664    const std::string kValidXml =
665        "<?xml version='1.0' encoding='UTF-8'?>"
666        "<gupdate xmlns='http://www.google.com/update2/response'"
667        "                protocol='2.0'>"
668        " <app appid='12345'>"
669        "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
670        "               version='1.2.3.4' prodversionmin='2.0.143.0' />"
671        " </app>"
672        "</gupdate>";
673    fetcher = factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
674    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
675    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
676    fetcher->delegate()->OnURLFetchComplete(
677        fetcher, url2, net::URLRequestStatus(), 200, ResponseCookies(),
678        kValidXml);
679
680    // This should run the manifest parsing, then we want to make sure that our
681    // service was called with GetExtensionById with the matching id from
682    // kValidXml.
683    file_thread.Stop();
684    io_thread.Stop();
685    ui_loop.RunAllPending();
686    EXPECT_EQ("12345", service->last_inquired_extension_id());
687    xmlCleanupGlobals();
688
689    // The FILE thread is needed for |service|'s cleanup,
690    // because of ImportantFileWriter.
691    file_thread.Start();
692    service.reset();
693  }
694
695  static void TestSingleExtensionDownloading(bool pending) {
696    MessageLoop ui_loop;
697    BrowserThread ui_thread(BrowserThread::UI, &ui_loop);
698    BrowserThread file_thread(BrowserThread::FILE);
699    file_thread.Start();
700    BrowserThread io_thread(BrowserThread::IO);
701    io_thread.Start();
702
703    TestURLFetcherFactory factory;
704    TestURLFetcher* fetcher = NULL;
705    URLFetcher::set_factory(&factory);
706    scoped_ptr<ServiceForDownloadTests> service(new ServiceForDownloadTests);
707    ExtensionUpdater updater(service.get(), service->extension_prefs(),
708                             service->pref_service(),
709                             service->profile(),
710                             kUpdateFrequencySecs);
711    updater.Start();
712
713    GURL test_url("http://localhost/extension.crx");
714
715    std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
716    std::string hash = "";
717    scoped_ptr<Version> version(Version::GetVersionFromString("0.0.1"));
718    ASSERT_TRUE(version.get());
719    updater.FetchUpdatedExtension(id, test_url, hash, version->GetString());
720
721    if (pending) {
722      const bool kIsFromSync = true;
723      const bool kInstallSilently = true;
724      const Extension::State kInitialState = Extension::ENABLED;
725      const bool kInitialIncognitoEnabled = false;
726      PendingExtensionManager* pending_extension_manager =
727          service->pending_extension_manager();
728      pending_extension_manager->AddForTesting(
729          id,
730          PendingExtensionInfo(test_url, &ShouldAlwaysInstall, kIsFromSync,
731                               kInstallSilently, kInitialState,
732                               kInitialIncognitoEnabled, Extension::INTERNAL));
733    }
734
735    // Call back the ExtensionUpdater with a 200 response and some test data
736    std::string extension_data("whatever");
737    fetcher = factory.GetFetcherByID(ExtensionUpdater::kExtensionFetcherId);
738    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
739    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
740    fetcher->delegate()->OnURLFetchComplete(
741        fetcher, test_url, net::URLRequestStatus(), 200, ResponseCookies(),
742        extension_data);
743
744    file_thread.Stop();
745    ui_loop.RunAllPending();
746
747    // Expect that ExtensionUpdater asked the mock extensions service to install
748    // a file with the test data for the right id.
749    EXPECT_EQ(id, service->extension_id());
750    FilePath tmpfile_path = service->install_path();
751    EXPECT_FALSE(tmpfile_path.empty());
752    EXPECT_EQ(test_url, service->download_url());
753    std::string file_contents;
754    EXPECT_TRUE(file_util::ReadFileToString(tmpfile_path, &file_contents));
755    EXPECT_TRUE(extension_data == file_contents);
756
757    // The FILE thread is needed for |service|'s cleanup,
758    // because of ImportantFileWriter.
759    file_thread.Start();
760    service.reset();
761
762    file_util::Delete(tmpfile_path, false);
763    URLFetcher::set_factory(NULL);
764  }
765
766  static void TestBlacklistDownloading() {
767    MessageLoop message_loop;
768    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
769    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
770    BrowserThread io_thread(BrowserThread::IO);
771    io_thread.Start();
772
773    TestURLFetcherFactory factory;
774    TestURLFetcher* fetcher = NULL;
775    URLFetcher::set_factory(&factory);
776    ServiceForBlacklistTests service;
777    ExtensionUpdater updater(
778        &service, service.extension_prefs(), service.pref_service(),
779        service.profile(), kUpdateFrequencySecs);
780    updater.Start();
781    GURL test_url("http://localhost/extension.crx");
782
783    std::string id = "com.google.crx.blacklist";
784
785    std::string hash =
786      "2CE109E9D0FAF820B2434E166297934E6177B65AB9951DBC3E204CAD4689B39C";
787
788    std::string version = "0.0.1";
789    updater.FetchUpdatedExtension(id, test_url, hash, version);
790
791    // Call back the ExtensionUpdater with a 200 response and some test data
792    std::string extension_data("aaabbb");
793    fetcher = factory.GetFetcherByID(ExtensionUpdater::kExtensionFetcherId);
794    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
795    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
796    fetcher->delegate()->OnURLFetchComplete(
797        fetcher, test_url, net::URLRequestStatus(), 200, ResponseCookies(),
798        extension_data);
799
800    message_loop.RunAllPending();
801
802    // The updater should have called extension service to process the
803    // blacklist.
804    EXPECT_TRUE(service.processed_blacklist());
805
806    EXPECT_EQ(version, service.pref_service()->
807      GetString(prefs::kExtensionBlacklistUpdateVersion));
808
809    URLFetcher::set_factory(NULL);
810  }
811
812  static void TestMultipleExtensionDownloading() {
813    MessageLoopForUI message_loop;
814    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
815    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
816    BrowserThread io_thread(BrowserThread::IO);
817    io_thread.Start();
818
819    TestURLFetcherFactory factory;
820    TestURLFetcher* fetcher = NULL;
821    URLFetcher::set_factory(&factory);
822    ServiceForDownloadTests service;
823    ExtensionUpdater updater(
824        &service, service.extension_prefs(), service.pref_service(),
825        service.profile(), kUpdateFrequencySecs);
826    updater.Start();
827
828    GURL url1("http://localhost/extension1.crx");
829    GURL url2("http://localhost/extension2.crx");
830
831    std::string id1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
832    std::string id2 = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
833
834    std::string hash1 = "";
835    std::string hash2 = "";
836
837    std::string version1 = "0.1";
838    std::string version2 = "0.1";
839    // Start two fetches
840    updater.FetchUpdatedExtension(id1, url1, hash1, version1);
841    updater.FetchUpdatedExtension(id2, url2, hash2, version2);
842
843    // Make the first fetch complete.
844    std::string extension_data1("whatever");
845    fetcher = factory.GetFetcherByID(ExtensionUpdater::kExtensionFetcherId);
846    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
847    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
848    fetcher->delegate()->OnURLFetchComplete(
849        fetcher, url1, net::URLRequestStatus(), 200, ResponseCookies(),
850        extension_data1);
851    message_loop.RunAllPending();
852
853    // Expect that the service was asked to do an install with the right data.
854    FilePath tmpfile_path = service.install_path();
855    EXPECT_FALSE(tmpfile_path.empty());
856    EXPECT_EQ(id1, service.extension_id());
857    EXPECT_EQ(url1, service.download_url());
858    message_loop.RunAllPending();
859    file_util::Delete(tmpfile_path, false);
860
861    // Make sure the second fetch finished and asked the service to do an
862    // update.
863    std::string extension_data2("whatever2");
864    fetcher = factory.GetFetcherByID(ExtensionUpdater::kExtensionFetcherId);
865    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
866    EXPECT_TRUE(fetcher->load_flags() == expected_load_flags);
867    fetcher->delegate()->OnURLFetchComplete(
868        fetcher, url2, net::URLRequestStatus(), 200, ResponseCookies(),
869        extension_data2);
870    message_loop.RunAllPending();
871    EXPECT_EQ(id2, service.extension_id());
872    EXPECT_EQ(url2, service.download_url());
873    EXPECT_FALSE(service.install_path().empty());
874
875    // Make sure the correct crx contents were passed for the update call.
876    std::string file_contents;
877    EXPECT_TRUE(file_util::ReadFileToString(service.install_path(),
878                                            &file_contents));
879    EXPECT_TRUE(extension_data2 == file_contents);
880    file_util::Delete(service.install_path(), false);
881  }
882
883  // Test requests to both a Google server and a non-google server. This allows
884  // us to test various combinations of installed (ie roll call) and active
885  // (ie app launch) ping scenarios. The invariant is that each type of ping
886  // value should be present at most once per day, and can be calculated based
887  // on the delta between now and the last ping time (or in the case of active
888  // pings, that delta plus whether the app has been active).
889  static void TestGalleryRequests(int rollcall_ping_days,
890                                  int active_ping_days,
891                                  bool active_bit) {
892    MessageLoop message_loop;
893    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
894    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
895
896    TestURLFetcherFactory factory;
897    URLFetcher::set_factory(&factory);
898
899    // Set up 2 mock extensions, one with a google.com update url and one
900    // without.
901    ServiceForManifestTests service;
902    ExtensionList tmp;
903    GURL url1("http://clients2.google.com/service/update2/crx");
904    GURL url2("http://www.somewebsite.com");
905    service.CreateTestExtensions(1, 1, &tmp, &url1.possibly_invalid_spec(),
906                                 Extension::INTERNAL);
907    service.CreateTestExtensions(2, 1, &tmp, &url2.possibly_invalid_spec(),
908                                 Extension::INTERNAL);
909    EXPECT_EQ(2u, tmp.size());
910    service.set_extensions(tmp);
911
912    ExtensionPrefs* prefs = service.extension_prefs();
913    const std::string& id = tmp[0]->id();
914    Time now = Time::Now();
915    if (rollcall_ping_days == 0) {
916      prefs->SetLastPingDay(id, now - TimeDelta::FromSeconds(15));
917    } else if (rollcall_ping_days > 0) {
918      Time last_ping_day = now -
919                           TimeDelta::FromDays(rollcall_ping_days) -
920                           TimeDelta::FromSeconds(15);
921      prefs->SetLastPingDay(id, last_ping_day);
922    }
923
924    // Store a value for the last day we sent an active ping.
925    if (active_ping_days == 0) {
926      prefs->SetLastActivePingDay(id, now - TimeDelta::FromSeconds(15));
927    } else if (active_ping_days > 0) {
928      Time last_active_ping_day = now -
929                                  TimeDelta::FromDays(active_ping_days) -
930                                  TimeDelta::FromSeconds(15);
931      prefs->SetLastActivePingDay(id, last_active_ping_day);
932    }
933    if (active_bit)
934      prefs->SetActiveBit(id, true);
935
936    ExtensionUpdater updater(
937        &service, service.extension_prefs(), service.pref_service(),
938        service.profile(), kUpdateFrequencySecs);
939    updater.Start();
940    updater.set_blacklist_checks_enabled(false);
941
942    // Make the updater do manifest fetching, and note the urls it tries to
943    // fetch.
944    std::vector<GURL> fetched_urls;
945    updater.CheckNow();
946    TestURLFetcher* fetcher =
947      factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
948    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
949    fetched_urls.push_back(fetcher->original_url());
950    fetcher->delegate()->OnURLFetchComplete(
951      fetcher, fetched_urls[0], net::URLRequestStatus(), 500,
952      ResponseCookies(), "");
953    fetcher =
954      factory.GetFetcherByID(ExtensionUpdater::kManifestFetcherId);
955    fetched_urls.push_back(fetcher->original_url());
956
957    // The urls could have been fetched in either order, so use the host to
958    // tell them apart and note the query each used.
959    std::string url1_query;
960    std::string url2_query;
961    if (fetched_urls[0].host() == url1.host()) {
962      url1_query = fetched_urls[0].query();
963      url2_query = fetched_urls[1].query();
964    } else if (fetched_urls[0].host() == url2.host()) {
965      url1_query = fetched_urls[1].query();
966      url2_query = fetched_urls[0].query();
967    } else {
968      NOTREACHED();
969    }
970
971    // First make sure the non-google query had no ping parameter.
972    std::string search_string = "ping%3D";
973    EXPECT_TRUE(url2_query.find(search_string) == std::string::npos);
974
975    // Now make sure the google query had the correct ping parameter.
976    bool ping_expected = false;
977    bool did_rollcall = false;
978    if (rollcall_ping_days != 0) {
979      search_string += "r%253D" + base::IntToString(rollcall_ping_days);
980      did_rollcall = true;
981      ping_expected = true;
982    }
983    if (active_bit && active_ping_days != 0) {
984      if (did_rollcall)
985        search_string += "%2526";
986      search_string += "a%253D" + base::IntToString(active_ping_days);
987      ping_expected = true;
988    }
989    bool ping_found = url1_query.find(search_string) != std::string::npos;
990    EXPECT_EQ(ping_expected, ping_found) << "query was: " << url1_query
991        << " was looking for " << search_string;
992  }
993
994  // This makes sure that the extension updater properly stores the results
995  // of a <daystart> tag from a manifest fetch in one of two cases: 1) This is
996  // the first time we fetched the extension, or 2) We sent a ping value of
997  // >= 1 day for the extension.
998  static void TestHandleManifestResults() {
999    ServiceForManifestTests service;
1000    MessageLoop message_loop;
1001    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
1002    ExtensionUpdater updater(
1003        &service, service.extension_prefs(), service.pref_service(),
1004        service.profile(), kUpdateFrequencySecs);
1005    updater.Start();
1006
1007    GURL update_url("http://www.google.com/manifest");
1008    ExtensionList tmp;
1009    service.CreateTestExtensions(1, 1, &tmp, &update_url.spec(),
1010                                 Extension::INTERNAL);
1011    service.set_extensions(tmp);
1012
1013    ManifestFetchData fetch_data(update_url);
1014    const Extension* extension = tmp[0];
1015    fetch_data.AddExtension(extension->id(), extension->VersionString(),
1016                            kNeverPingedData,
1017                            kEmptyUpdateUrlData);
1018    UpdateManifest::Results results;
1019    results.daystart_elapsed_seconds = 750;
1020
1021    updater.HandleManifestResults(fetch_data, &results);
1022    Time last_ping_day =
1023        service.extension_prefs()->LastPingDay(extension->id());
1024    EXPECT_FALSE(last_ping_day.is_null());
1025    int64 seconds_diff = (Time::Now() - last_ping_day).InSeconds();
1026    EXPECT_LT(seconds_diff - results.daystart_elapsed_seconds, 5);
1027  }
1028};
1029
1030// Because we test some private methods of ExtensionUpdater, it's easer for the
1031// actual test code to live in ExtenionUpdaterTest methods instead of TEST_F
1032// subclasses where friendship with ExtenionUpdater is not inherited.
1033
1034TEST(ExtensionUpdaterTest, TestExtensionUpdateCheckRequests) {
1035  ExtensionUpdaterTest::TestExtensionUpdateCheckRequests(false);
1036}
1037
1038TEST(ExtensionUpdaterTest, TestExtensionUpdateCheckRequestsPending) {
1039  ExtensionUpdaterTest::TestExtensionUpdateCheckRequests(true);
1040}
1041
1042// This test is disabled on Mac, see http://crbug.com/26035.
1043TEST(ExtensionUpdaterTest, TestBlacklistUpdateCheckRequests) {
1044  ExtensionUpdaterTest::TestBlacklistUpdateCheckRequests();
1045}
1046
1047TEST(ExtensionUpdaterTest, TestUpdateUrlData) {
1048  MessageLoop message_loop;
1049  BrowserThread file_thread(BrowserThread::FILE, &message_loop);
1050
1051  ExtensionUpdaterTest::TestUpdateUrlDataEmpty();
1052  ExtensionUpdaterTest::TestUpdateUrlDataSimple();
1053  ExtensionUpdaterTest::TestUpdateUrlDataCompound();
1054  ExtensionUpdaterTest::TestUpdateUrlDataFromGallery(
1055      Extension::GalleryUpdateUrl(false).spec());
1056  ExtensionUpdaterTest::TestUpdateUrlDataFromGallery(
1057      Extension::GalleryUpdateUrl(true).spec());
1058}
1059
1060TEST(ExtensionUpdaterTest, TestDetermineUpdates) {
1061  ExtensionUpdaterTest::TestDetermineUpdates();
1062}
1063
1064TEST(ExtensionUpdaterTest, TestDetermineUpdatesPending) {
1065  ExtensionUpdaterTest::TestDetermineUpdatesPending();
1066}
1067
1068TEST(ExtensionUpdaterTest, TestMultipleManifestDownloading) {
1069  ExtensionUpdaterTest::TestMultipleManifestDownloading();
1070}
1071
1072TEST(ExtensionUpdaterTest, TestSingleExtensionDownloading) {
1073  ExtensionUpdaterTest::TestSingleExtensionDownloading(false);
1074}
1075
1076TEST(ExtensionUpdaterTest, TestSingleExtensionDownloadingPending) {
1077  ExtensionUpdaterTest::TestSingleExtensionDownloading(true);
1078}
1079
1080// This test is disabled on Mac, see http://crbug.com/26035.
1081TEST(ExtensionUpdaterTest, TestBlacklistDownloading) {
1082  ExtensionUpdaterTest::TestBlacklistDownloading();
1083}
1084
1085TEST(ExtensionUpdaterTest, TestMultipleExtensionDownloading) {
1086  ExtensionUpdaterTest::TestMultipleExtensionDownloading();
1087}
1088
1089TEST(ExtensionUpdaterTest, TestGalleryRequests) {
1090  // We want to test a variety of combinations of expected ping conditions for
1091  // rollcall and active pings.
1092  int ping_cases[] = { ManifestFetchData::kNeverPinged, 0, 1, 5 };
1093
1094  for (size_t i = 0; i < arraysize(ping_cases); i++) {
1095    for (size_t j = 0; j < arraysize(ping_cases); j++) {
1096      for (size_t k = 0; k < 2; k++) {
1097        int rollcall_ping_days = ping_cases[i];
1098        int active_ping_days = ping_cases[j];
1099        // Skip cases where rollcall_ping_days == -1, but active_ping_days > 0,
1100        // because rollcall_ping_days == -1 means the app was just installed and
1101        // this is the first update check after installation.
1102        if (rollcall_ping_days == ManifestFetchData::kNeverPinged &&
1103            active_ping_days > 0)
1104          continue;
1105
1106        bool active_bit = k > 0;
1107        ExtensionUpdaterTest::TestGalleryRequests(
1108            rollcall_ping_days, active_ping_days, active_bit);
1109        ASSERT_FALSE(HasFailure()) <<
1110          " rollcall_ping_days=" << ping_cases[i] <<
1111          " active_ping_days=" << ping_cases[j] <<
1112          " active_bit=" << active_bit;
1113      }
1114    }
1115  }
1116}
1117
1118TEST(ExtensionUpdaterTest, TestHandleManifestResults) {
1119  ExtensionUpdaterTest::TestHandleManifestResults();
1120}
1121
1122TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
1123  MessageLoop message_loop;
1124  BrowserThread file_thread(BrowserThread::FILE, &message_loop);
1125
1126  MockService service;
1127  ManifestFetchesBuilder builder(&service, service.extension_prefs());
1128
1129  // Non-internal non-external extensions should be rejected.
1130  {
1131    ExtensionList extensions;
1132    service.CreateTestExtensions(1, 1, &extensions, NULL, Extension::INVALID);
1133    ASSERT_FALSE(extensions.empty());
1134    builder.AddExtension(*extensions[0]);
1135    EXPECT_TRUE(builder.GetFetches().empty());
1136  }
1137
1138  // Extensions with invalid update URLs should be rejected.
1139  builder.AddPendingExtension(
1140      GenerateId("foo"), PendingExtensionInfo(GURL("http:google.com:foo"),
1141                                              &ShouldInstallExtensionsOnly,
1142                                              false, false, true, false,
1143                                              Extension::INTERNAL));
1144  EXPECT_TRUE(builder.GetFetches().empty());
1145
1146  // Extensions with empty IDs should be rejected.
1147  builder.AddPendingExtension(
1148      "", PendingExtensionInfo(GURL(), &ShouldInstallExtensionsOnly,
1149                               false, false, true, false,
1150                               Extension::INTERNAL));
1151  EXPECT_TRUE(builder.GetFetches().empty());
1152
1153  // TODO(akalin): Test that extensions with empty update URLs
1154  // converted from user scripts are rejected.
1155
1156  // Extensions with empty update URLs should have a default one
1157  // filled in.
1158  builder.AddPendingExtension(
1159      GenerateId("foo"), PendingExtensionInfo(GURL(),
1160                                              &ShouldInstallExtensionsOnly,
1161                                              false, false, true, false,
1162                                              Extension::INTERNAL));
1163  std::vector<ManifestFetchData*> fetches = builder.GetFetches();
1164  ASSERT_EQ(1u, fetches.size());
1165  scoped_ptr<ManifestFetchData> fetch(fetches[0]);
1166  fetches.clear();
1167  EXPECT_FALSE(fetch->base_url().is_empty());
1168  EXPECT_FALSE(fetch->full_url().is_empty());
1169}
1170
1171TEST(ExtensionUpdaterTest, TestStartUpdateCheckMemory) {
1172    MessageLoop message_loop;
1173    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
1174    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
1175
1176    ServiceForManifestTests service;
1177    TestURLFetcherFactory factory;
1178    URLFetcher::set_factory(&factory);
1179    ExtensionUpdater updater(
1180        &service, service.extension_prefs(), service.pref_service(),
1181        service.profile(), kUpdateFrequencySecs);
1182    updater.Start();
1183    updater.StartUpdateCheck(new ManifestFetchData(GURL()));
1184    // This should delete the newly-created ManifestFetchData.
1185    updater.StartUpdateCheck(new ManifestFetchData(GURL()));
1186    // This should add into |manifests_pending_|.
1187    updater.StartUpdateCheck(new ManifestFetchData(
1188        GURL("http://www.google.com")));
1189    // This should clear out |manifests_pending_|.
1190    updater.Stop();
1191}
1192
1193TEST(ExtensionUpdaterTest, TestCheckSoon) {
1194    MessageLoop message_loop;
1195    BrowserThread ui_thread(BrowserThread::UI, &message_loop);
1196    BrowserThread file_thread(BrowserThread::FILE, &message_loop);
1197
1198    ServiceForManifestTests service;
1199    TestURLFetcherFactory factory;
1200    URLFetcher::set_factory(&factory);
1201    ExtensionUpdater updater(
1202        &service, service.extension_prefs(), service.pref_service(),
1203        service.profile(), kUpdateFrequencySecs);
1204    EXPECT_FALSE(updater.WillCheckSoon());
1205    updater.Start();
1206    EXPECT_FALSE(updater.WillCheckSoon());
1207    updater.CheckSoon();
1208    EXPECT_TRUE(updater.WillCheckSoon());
1209    updater.CheckSoon();
1210    EXPECT_TRUE(updater.WillCheckSoon());
1211    ExtensionUpdaterTest::SimulateCheckSoon(updater, &message_loop);
1212    EXPECT_FALSE(updater.WillCheckSoon());
1213    updater.CheckSoon();
1214    EXPECT_TRUE(updater.WillCheckSoon());
1215    updater.Stop();
1216    EXPECT_FALSE(updater.WillCheckSoon());
1217}
1218
1219// TODO(asargent) - (http://crbug.com/12780) add tests for:
1220// -prodversionmin (shouldn't update if browser version too old)
1221// -manifests & updates arriving out of order / interleaved
1222// -malformed update url (empty, file://, has query, has a # fragment, etc.)
1223// -An extension gets uninstalled while updates are in progress (so it doesn't
1224//  "come back from the dead")
1225// -An extension gets manually updated to v3 while we're downloading v2 (ie
1226//  you don't get downgraded accidentally)
1227// -An update manifest mentions multiple updates
1228