1// Copyright (c) 2012 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 "base/command_line.h"
6#include "base/format_macros.h"
7#include "base/memory/scoped_vector.h"
8#include "base/message_loop/message_loop.h"
9#include "base/strings/stringprintf.h"
10#include "base/time/time.h"
11#include "chrome/browser/prerender/prerender_contents.h"
12#include "chrome/browser/prerender/prerender_handle.h"
13#include "chrome/browser/prerender/prerender_link_manager.h"
14#include "chrome/browser/prerender/prerender_manager.h"
15#include "chrome/browser/prerender/prerender_origin.h"
16#include "chrome/common/chrome_switches.h"
17#include "chrome/test/base/testing_browser_process.h"
18#include "chrome/test/base/testing_profile.h"
19#include "content/public/browser/render_view_host.h"
20#include "content/public/test/test_browser_thread.h"
21#include "testing/gtest/include/gtest/gtest.h"
22#include "ui/gfx/size.h"
23#include "url/gurl.h"
24
25using base::Time;
26using base::TimeDelta;
27using base::TimeTicks;
28using content::BrowserThread;
29using content::Referrer;
30
31namespace prerender {
32
33class UnitTestPrerenderManager;
34
35namespace {
36
37class DummyPrerenderContents : public PrerenderContents {
38 public:
39  DummyPrerenderContents(UnitTestPrerenderManager* test_prerender_manager,
40                         PrerenderTracker* prerender_tracker,
41                         const GURL& url,
42                         Origin origin,
43                         FinalStatus expected_final_status);
44
45  virtual ~DummyPrerenderContents() {
46    EXPECT_EQ(expected_final_status_, final_status());
47  }
48
49  virtual void StartPrerendering(
50      int ALLOW_UNUSED creator_child_id,
51      const gfx::Size& ALLOW_UNUSED size,
52      content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace)
53      OVERRIDE;
54
55  virtual bool GetChildId(int* child_id) const OVERRIDE {
56    // Having a default child_id of -1 forces pending prerenders not to fail
57    // on session storage and cross domain checking.
58    *child_id = -1;
59    return true;
60  }
61
62  virtual bool GetRouteId(int* route_id) const OVERRIDE {
63    *route_id = route_id_;
64    return true;
65  }
66
67  FinalStatus expected_final_status() const { return expected_final_status_; }
68
69  bool prerendering_has_been_cancelled() const {
70    return PrerenderContents::prerendering_has_been_cancelled();
71  }
72
73 private:
74  static int g_next_route_id_;
75  int route_id_;
76
77  UnitTestPrerenderManager* test_prerender_manager_;
78  FinalStatus expected_final_status_;
79};
80
81int DummyPrerenderContents::g_next_route_id_ = 0;
82
83const gfx::Size kSize(640, 480);
84
85}  // namespace
86
87class UnitTestPrerenderManager : public PrerenderManager {
88 public:
89  using PrerenderManager::kMinTimeBetweenPrerendersMs;
90  using PrerenderManager::kNavigationRecordWindowMs;
91
92  explicit UnitTestPrerenderManager(Profile* profile,
93                                    PrerenderTracker* prerender_tracker)
94      : PrerenderManager(profile, prerender_tracker),
95        time_(Time::Now()),
96        time_ticks_(TimeTicks::Now()),
97        prerender_tracker_(prerender_tracker) {
98    set_rate_limit_enabled(false);
99  }
100
101  virtual ~UnitTestPrerenderManager() {
102  }
103
104  // From BrowserContextKeyedService, via PrererenderManager:
105  virtual void Shutdown() OVERRIDE {
106    if (next_prerender_contents())
107      next_prerender_contents_->Destroy(FINAL_STATUS_MANAGER_SHUTDOWN);
108    PrerenderManager::Shutdown();
109  }
110
111  // From PrerenderManager:
112  virtual void MoveEntryToPendingDelete(PrerenderContents* entry,
113                                        FinalStatus final_status) OVERRIDE {
114    if (entry == next_prerender_contents_.get())
115      return;
116    PrerenderManager::MoveEntryToPendingDelete(entry, final_status);
117  }
118
119  PrerenderContents* FindEntry(const GURL& url) {
120    DeleteOldEntries();
121    to_delete_prerenders_.clear();
122    if (PrerenderData* data = FindPrerenderData(url, NULL))
123      return data->contents();
124    return NULL;
125  }
126
127  PrerenderContents* FindAndUseEntry(const GURL& url) {
128    PrerenderData* prerender_data = FindPrerenderData(url, NULL);
129    if (!prerender_data)
130      return NULL;
131    ScopedVector<PrerenderData>::iterator to_erase =
132        FindIteratorForPrerenderContents(prerender_data->contents());
133    CHECK(to_erase != active_prerenders_.end());
134    PrerenderContents* prerender_contents = prerender_data->ReleaseContents();
135    active_prerenders_.erase(to_erase);
136
137    prerender_contents->SetFinalStatus(FINAL_STATUS_USED);
138    prerender_contents->PrepareForUse();
139    return prerender_contents;
140  }
141
142  void AdvanceTime(TimeDelta delta) {
143    time_ += delta;
144  }
145
146  void AdvanceTimeTicks(TimeDelta delta) {
147    time_ticks_ += delta;
148  }
149
150  DummyPrerenderContents* CreateNextPrerenderContents(
151      const GURL& url,
152      FinalStatus expected_final_status) {
153    DummyPrerenderContents* prerender_contents =
154        new DummyPrerenderContents(this, prerender_tracker_, url,
155                                   ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN,
156                                   expected_final_status);
157    SetNextPrerenderContents(prerender_contents);
158    return prerender_contents;
159  }
160
161  DummyPrerenderContents* CreateNextPrerenderContents(
162      const GURL& url,
163      Origin origin,
164      FinalStatus expected_final_status) {
165    DummyPrerenderContents* prerender_contents =
166        new DummyPrerenderContents(this, prerender_tracker_, url,
167                                   origin, expected_final_status);
168    SetNextPrerenderContents(prerender_contents);
169    return prerender_contents;
170  }
171
172  DummyPrerenderContents* CreateNextPrerenderContents(
173      const GURL& url,
174      const std::vector<GURL>& alias_urls,
175      FinalStatus expected_final_status) {
176    DummyPrerenderContents* prerender_contents =
177        new DummyPrerenderContents(this, prerender_tracker_, url,
178                                   ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN,
179                                   expected_final_status);
180    for (std::vector<GURL>::const_iterator it = alias_urls.begin();
181         it != alias_urls.end();
182         ++it) {
183      EXPECT_TRUE(prerender_contents->AddAliasURL(*it));
184    }
185    SetNextPrerenderContents(prerender_contents);
186    return prerender_contents;
187  }
188
189  void set_rate_limit_enabled(bool enabled) {
190    mutable_config().rate_limit_enabled = enabled;
191  }
192
193  PrerenderContents* next_prerender_contents() {
194    return next_prerender_contents_.get();
195  }
196
197  // from PrerenderManager
198  virtual Time GetCurrentTime() const OVERRIDE {
199    return time_;
200  }
201
202  virtual TimeTicks GetCurrentTimeTicks() const OVERRIDE {
203    return time_ticks_;
204  }
205
206 private:
207  void SetNextPrerenderContents(DummyPrerenderContents* prerender_contents) {
208    CHECK(!next_prerender_contents_.get());
209    next_prerender_contents_.reset(prerender_contents);
210    if (prerender_contents->expected_final_status() == FINAL_STATUS_USED)
211      used_prerender_contents_.push_back(prerender_contents);
212  }
213
214
215  virtual PrerenderContents* CreatePrerenderContents(
216      const GURL& url,
217      const Referrer& referrer,
218      Origin origin,
219      uint8 experiment_id) OVERRIDE {
220    CHECK(next_prerender_contents_.get());
221    EXPECT_EQ(url, next_prerender_contents_->prerender_url());
222    EXPECT_EQ(origin, next_prerender_contents_->origin());
223    return next_prerender_contents_.release();
224  }
225
226  Time time_;
227  TimeTicks time_ticks_;
228  scoped_ptr<PrerenderContents> next_prerender_contents_;
229  // PrerenderContents with an |expected_final_status| of FINAL_STATUS_USED,
230  // tracked so they will be automatically deleted.
231  ScopedVector<PrerenderContents> used_prerender_contents_;
232
233  PrerenderTracker* prerender_tracker_;
234};
235
236class RestorePrerenderMode {
237 public:
238  RestorePrerenderMode() : prev_mode_(PrerenderManager::GetMode()) {
239  }
240
241  ~RestorePrerenderMode() { PrerenderManager::SetMode(prev_mode_); }
242 private:
243  PrerenderManager::PrerenderManagerMode prev_mode_;
244};
245
246DummyPrerenderContents::DummyPrerenderContents(
247    UnitTestPrerenderManager* test_prerender_manager,
248    PrerenderTracker* prerender_tracker,
249    const GURL& url,
250    Origin origin,
251    FinalStatus expected_final_status)
252    : PrerenderContents(test_prerender_manager,
253                        NULL, url, Referrer(), origin,
254                        PrerenderManager::kNoExperiment),
255      route_id_(g_next_route_id_++),
256      test_prerender_manager_(test_prerender_manager),
257      expected_final_status_(expected_final_status) {
258}
259
260void DummyPrerenderContents::StartPrerendering(
261    int ALLOW_UNUSED creator_child_id,
262    const gfx::Size& ALLOW_UNUSED size,
263    content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace) {
264  // In the base PrerenderContents implementation, StartPrerendering will
265  // be called even when the PrerenderManager is part of the control group,
266  // but it will early exit before actually creating a new RenderView if
267  // |is_control_group| is true;
268  load_start_time_ = test_prerender_manager_->GetCurrentTimeTicks();
269  if (!test_prerender_manager_->IsControlGroup(experiment_id())) {
270    prerendering_has_started_ = true;
271    NotifyPrerenderStart();
272  }
273}
274
275class PrerenderTest : public testing::Test {
276 public:
277  static const int kDefaultChildId = -1;
278  static const int kDefaultRenderViewRouteId = -1;
279
280  PrerenderTest() : ui_thread_(BrowserThread::UI, &message_loop_),
281                    prerender_manager_(new UnitTestPrerenderManager(
282                        &profile_, prerender_tracker())),
283                    prerender_link_manager_(
284                        new PrerenderLinkManager(prerender_manager_.get())),
285                    last_prerender_id_(0) {
286    // Enable omnibox prerendering.
287    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
288        switches::kPrerenderFromOmnibox,
289        switches::kPrerenderFromOmniboxSwitchValueEnabled);
290  }
291
292  virtual ~PrerenderTest() {
293    prerender_link_manager_->OnChannelClosing(kDefaultChildId);
294    prerender_link_manager_->Shutdown();
295    prerender_manager_->Shutdown();
296  }
297
298  UnitTestPrerenderManager* prerender_manager() {
299    return prerender_manager_.get();
300  }
301
302  PrerenderLinkManager* prerender_link_manager() {
303    return prerender_link_manager_.get();
304  }
305
306  void SetConcurrency(size_t concurrency) {
307    prerender_manager()->mutable_config().max_link_concurrency_per_launcher =
308        concurrency;
309    prerender_manager()->mutable_config().max_link_concurrency =
310        std::max(prerender_manager()->mutable_config().max_link_concurrency,
311                 concurrency);
312  }
313
314  bool IsEmptyPrerenderLinkManager() const {
315    return prerender_link_manager_->IsEmpty();
316  }
317
318  int last_prerender_id() const {
319    return last_prerender_id_;
320  }
321
322  int GetNextPrerenderID() {
323    return ++last_prerender_id_;
324  }
325
326  bool LauncherHasRunningPrerender(int child_id, int prerender_id) {
327    PrerenderLinkManager::LinkPrerender* prerender =
328        prerender_link_manager()->FindByLauncherChildIdAndPrerenderId(
329            child_id, prerender_id);
330    return prerender && prerender->handle;
331  }
332
333  // Shorthand to add a simple prerender with a reasonable source. Returns
334  // true iff the prerender has been added to the PrerenderManager by the
335  // PrerenderLinkManager and the PrerenderManager returned a handle.
336  bool AddSimplePrerender(const GURL& url) {
337    prerender_link_manager()->OnAddPrerender(kDefaultChildId,
338                                             GetNextPrerenderID(),
339                                             url, content::Referrer(),
340                                             kSize, kDefaultRenderViewRouteId);
341    return LauncherHasRunningPrerender(kDefaultChildId, last_prerender_id());
342  }
343
344 private:
345  PrerenderTracker* prerender_tracker() {
346    return g_browser_process->prerender_tracker();
347  }
348
349  // Needed to pass PrerenderManager's DCHECKs.
350  TestingProfile profile_;
351  base::MessageLoop message_loop_;
352  content::TestBrowserThread ui_thread_;
353  scoped_ptr<UnitTestPrerenderManager> prerender_manager_;
354  scoped_ptr<PrerenderLinkManager> prerender_link_manager_;
355  int last_prerender_id_;
356};
357
358TEST_F(PrerenderTest, FoundTest) {
359  GURL url("http://www.google.com/");
360  DummyPrerenderContents* prerender_contents =
361      prerender_manager()->CreateNextPrerenderContents(
362          url,
363          FINAL_STATUS_USED);
364  EXPECT_TRUE(AddSimplePrerender(url));
365  EXPECT_TRUE(prerender_contents->prerendering_has_started());
366  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
367}
368
369// Make sure that if queue a request, and a second prerender request for the
370// same URL comes in, that the second request attaches to the first prerender,
371// and we don't use the second prerender contents.
372TEST_F(PrerenderTest, DuplicateTest) {
373  SetConcurrency(2);
374  GURL url("http://www.google.com/");
375  DummyPrerenderContents* prerender_contents =
376      prerender_manager()->CreateNextPrerenderContents(
377          url,
378          FINAL_STATUS_USED);
379  DummyPrerenderContents* null = NULL;
380  EXPECT_TRUE(AddSimplePrerender(url));
381  EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
382  EXPECT_TRUE(prerender_contents->prerendering_has_started());
383
384  DummyPrerenderContents* prerender_contents1 =
385      prerender_manager()->CreateNextPrerenderContents(
386          url,
387          FINAL_STATUS_MANAGER_SHUTDOWN);
388  EXPECT_TRUE(AddSimplePrerender(url));
389  EXPECT_EQ(prerender_contents1,
390            prerender_manager()->next_prerender_contents());
391  EXPECT_FALSE(prerender_contents1->prerendering_has_started());
392
393  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
394}
395
396// Ensure that we expire a prerendered page after the max. permitted time.
397TEST_F(PrerenderTest, ExpireTest) {
398  GURL url("http://www.google.com/");
399  DummyPrerenderContents* prerender_contents =
400      prerender_manager()->CreateNextPrerenderContents(
401          url,
402          FINAL_STATUS_TIMED_OUT);
403  DummyPrerenderContents* null = NULL;
404  EXPECT_TRUE(AddSimplePrerender(url));
405  EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
406  EXPECT_TRUE(prerender_contents->prerendering_has_started());
407  prerender_manager()->AdvanceTimeTicks(
408      prerender_manager()->config().time_to_live + TimeDelta::FromSeconds(1));
409  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
410}
411
412// Ensure that we don't launch prerenders of bad urls (in this case, a mailto:
413// url)
414TEST_F(PrerenderTest, BadURLTest) {
415  GURL url("mailto:test@gmail.com");
416  DummyPrerenderContents* prerender_contents =
417      prerender_manager()->CreateNextPrerenderContents(
418          url,
419          FINAL_STATUS_UNSUPPORTED_SCHEME);
420  EXPECT_FALSE(AddSimplePrerender(url));
421  EXPECT_FALSE(prerender_contents->prerendering_has_started());
422  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
423  DummyPrerenderContents* null = NULL;
424  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
425}
426
427// When the user navigates away from a page, the prerenders it launched should
428// have their time to expiry shortened from the default time to live.
429TEST_F(PrerenderTest, LinkManagerNavigateAwayExpire) {
430  const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
431  const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
432  const TimeDelta test_advance = TimeDelta::FromSeconds(22);
433  ASSERT_LT(test_advance, time_to_live);
434  ASSERT_LT(abandon_time_to_live, test_advance);
435
436  prerender_manager()->mutable_config().time_to_live = time_to_live;
437  prerender_manager()->mutable_config().abandon_time_to_live =
438      abandon_time_to_live;
439
440  GURL url("http://example.com");
441  DummyPrerenderContents* prerender_contents =
442      prerender_manager()->CreateNextPrerenderContents(url,
443                                                       FINAL_STATUS_TIMED_OUT);
444  EXPECT_TRUE(AddSimplePrerender(url));
445  EXPECT_TRUE(prerender_contents->prerendering_has_started());
446  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
447  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
448  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
449                                               last_prerender_id());
450  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
451  DummyPrerenderContents* null = NULL;
452  EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
453  prerender_manager()->AdvanceTimeTicks(test_advance);
454
455  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
456}
457
458// But when we navigate away very close to the original expiry of a prerender,
459// we shouldn't expect it to be extended.
460TEST_F(PrerenderTest, LinkManagerNavigateAwayNearExpiry) {
461  const TimeDelta time_to_live = TimeDelta::FromSeconds(300);
462  const TimeDelta abandon_time_to_live = TimeDelta::FromSeconds(20);
463
464  // We will expect the prerender to still be alive after advancing the clock
465  // by first_advance. But, after second_advance, we expect it to have timed
466  // out, demonstrating that you can't extend a prerender by navigating away
467  // from its launcher.
468  const TimeDelta first_advance = TimeDelta::FromSeconds(298);
469  const TimeDelta second_advance = TimeDelta::FromSeconds(4);
470  ASSERT_LT(first_advance, time_to_live);
471  ASSERT_LT(time_to_live - first_advance, abandon_time_to_live);
472  ASSERT_LT(time_to_live, first_advance + second_advance);
473
474  prerender_manager()->mutable_config().time_to_live = time_to_live;
475  prerender_manager()->mutable_config().abandon_time_to_live =
476      abandon_time_to_live;
477
478  GURL url("http://example2.com");
479  DummyPrerenderContents* prerender_contents =
480      prerender_manager()->CreateNextPrerenderContents(url,
481                                                       FINAL_STATUS_TIMED_OUT);
482  EXPECT_TRUE(AddSimplePrerender(url));
483  EXPECT_TRUE(prerender_contents->prerendering_has_started());
484  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
485  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
486
487  prerender_manager()->AdvanceTimeTicks(first_advance);
488  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
489
490  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
491                                               last_prerender_id());
492  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
493
494  DummyPrerenderContents* null = NULL;
495  EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
496
497  prerender_manager()->AdvanceTimeTicks(second_advance);
498  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
499}
500
501// Make sure that if we prerender more requests than we support, that we launch
502// them in the order given up until we reach MaxConcurrency, at which point we
503// queue them and launch them in the order given. As well, insure that limits
504// are enforced for the system as a whole and on a per launcher basis.
505TEST_F(PrerenderTest, MaxConcurrencyTest) {
506  struct TestConcurrency {
507    size_t max_link_concurrency;
508    size_t max_link_concurrency_per_launcher;
509  };
510
511  TestConcurrency concurrencies_to_test[] = {
512    { prerender_manager()->config().max_link_concurrency,
513      prerender_manager()->config().max_link_concurrency_per_launcher},
514
515    // With the system limit higher than the per launcher limit, the per
516    // launcher limit should be in effect.
517    { 2, 1 },
518
519    // With the per launcher limit higher than system limit, the system limit
520    // should be in effect.
521    { 2, 4 },
522  };
523
524  DummyPrerenderContents* null = NULL;
525  GURL url_to_delay("http://www.google.com/delayme");
526
527  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(concurrencies_to_test); ++i) {
528    prerender_manager()->mutable_config().max_link_concurrency =
529        concurrencies_to_test[i].max_link_concurrency;
530    prerender_manager()->mutable_config().max_link_concurrency_per_launcher =
531        concurrencies_to_test[i].max_link_concurrency_per_launcher;
532
533    const size_t effective_max_link_concurrency =
534        std::min(concurrencies_to_test[i].max_link_concurrency,
535                 concurrencies_to_test[i].max_link_concurrency_per_launcher);
536
537    std::vector<GURL> urls;
538    std::vector<PrerenderContents*> prerender_contentses;
539
540    // Launch prerenders up to the maximum this launcher can support.
541    for (size_t j = 0; j < effective_max_link_concurrency; ++j) {
542      urls.push_back(
543          GURL(base::StringPrintf("http://google.com/use#%" PRIuS, j)));
544      prerender_contentses.push_back(
545          prerender_manager()->CreateNextPrerenderContents(urls.back(),
546                                                           FINAL_STATUS_USED));
547      EXPECT_TRUE(AddSimplePrerender(urls.back()));
548      EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
549      EXPECT_TRUE(prerender_contentses.back()->prerendering_has_started());
550    }
551
552    if (concurrencies_to_test[i].max_link_concurrency >
553            effective_max_link_concurrency) {
554      // We should be able to launch more prerenders on this system, but not for
555      // our current launcher.
556      int child_id;
557      int route_id;
558      ASSERT_TRUE(prerender_contentses.back()->GetChildId(&child_id));
559      ASSERT_TRUE(prerender_contentses.back()->GetRouteId(&route_id));
560
561      GURL extra_url("http://google.com/extraurl");
562      prerender_link_manager()->OnAddPrerender(child_id,
563                                               GetNextPrerenderID(),
564                                               extra_url, content::Referrer(),
565                                               kSize, route_id);
566      const int prerender_id = last_prerender_id();
567      EXPECT_TRUE(LauncherHasRunningPrerender(child_id, prerender_id));
568      prerender_link_manager()->OnCancelPrerender(child_id, prerender_id);
569      EXPECT_FALSE(LauncherHasRunningPrerender(child_id, prerender_id));
570    }
571
572    DummyPrerenderContents* prerender_contents_to_delay =
573        prerender_manager()->CreateNextPrerenderContents(url_to_delay,
574                                                         FINAL_STATUS_USED);
575    EXPECT_FALSE(AddSimplePrerender(url_to_delay));
576    EXPECT_FALSE(prerender_contents_to_delay->prerendering_has_started());
577    EXPECT_NE(null, prerender_manager()->next_prerender_contents());
578    EXPECT_EQ(null, prerender_manager()->FindEntry(url_to_delay));
579    for (size_t j = 0; j < effective_max_link_concurrency; ++j) {
580      EXPECT_EQ(prerender_contentses[j],
581                prerender_manager()->FindAndUseEntry(urls[j]));
582      EXPECT_TRUE(prerender_contents_to_delay->prerendering_has_started());
583    }
584
585    EXPECT_EQ(prerender_contents_to_delay,
586              prerender_manager()->FindAndUseEntry(url_to_delay));
587    EXPECT_EQ(null, prerender_manager()->next_prerender_contents());
588  }
589}
590
591TEST_F(PrerenderTest, AliasURLTest) {
592  SetConcurrency(7);
593
594  GURL url("http://www.google.com/");
595  GURL alias_url1("http://www.google.com/index.html");
596  GURL alias_url2("http://google.com/");
597  GURL not_an_alias_url("http://google.com/index.html");
598  std::vector<GURL> alias_urls;
599  alias_urls.push_back(alias_url1);
600  alias_urls.push_back(alias_url2);
601
602  // Test that all of the aliases work, but not_an_alias_url does not.
603  DummyPrerenderContents* prerender_contents =
604      prerender_manager()->CreateNextPrerenderContents(
605          url, alias_urls, FINAL_STATUS_USED);
606  EXPECT_TRUE(AddSimplePrerender(url));
607  ASSERT_EQ(NULL, prerender_manager()->FindEntry(not_an_alias_url));
608  ASSERT_EQ(prerender_contents,
609            prerender_manager()->FindAndUseEntry(alias_url1));
610  prerender_contents = prerender_manager()->CreateNextPrerenderContents(
611          url, alias_urls, FINAL_STATUS_USED);
612  EXPECT_TRUE(AddSimplePrerender(url));
613  ASSERT_EQ(prerender_contents,
614            prerender_manager()->FindAndUseEntry(alias_url2));
615  prerender_contents = prerender_manager()->CreateNextPrerenderContents(
616          url, alias_urls, FINAL_STATUS_USED);
617  EXPECT_TRUE(AddSimplePrerender(url));
618  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
619
620  // Test that alias URLs can not be added.
621  prerender_contents = prerender_manager()->CreateNextPrerenderContents(
622          url, alias_urls, FINAL_STATUS_USED);
623  EXPECT_TRUE(AddSimplePrerender(url));
624  EXPECT_TRUE(AddSimplePrerender(url));
625  EXPECT_TRUE(AddSimplePrerender(alias_url1));
626  EXPECT_TRUE(AddSimplePrerender(alias_url2));
627  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
628}
629
630TEST_F(PrerenderTest, PendingPrerenderTest) {
631  GURL url("http://www.google.com/");
632  DummyPrerenderContents* prerender_contents =
633      prerender_manager()->CreateNextPrerenderContents(
634          url,
635          FINAL_STATUS_USED);
636  EXPECT_TRUE(AddSimplePrerender(url));
637
638  int child_id;
639  int route_id;
640  ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
641  ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
642
643  GURL pending_url("http://news.google.com/");
644
645  DummyPrerenderContents* pending_prerender_contents =
646      prerender_manager()->CreateNextPrerenderContents(
647          pending_url,
648          ORIGIN_GWS_PRERENDER,
649          FINAL_STATUS_USED);
650  scoped_ptr<PrerenderHandle> pending_prerender_handle(
651      prerender_manager()->AddPrerenderFromLinkRelPrerender(
652          child_id, route_id, pending_url,
653          Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
654  CHECK(pending_prerender_handle.get());
655  EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
656
657  EXPECT_TRUE(prerender_contents->prerendering_has_started());
658  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
659
660  EXPECT_TRUE(pending_prerender_handle->IsPrerendering());
661  ASSERT_EQ(pending_prerender_contents,
662            prerender_manager()->FindAndUseEntry(pending_url));
663  EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
664}
665
666TEST_F(PrerenderTest, InvalidPendingPrerenderTest) {
667  GURL url("http://www.google.com/");
668  DummyPrerenderContents* prerender_contents =
669      prerender_manager()->CreateNextPrerenderContents(
670          url,
671          FINAL_STATUS_USED);
672  EXPECT_TRUE(AddSimplePrerender(url));
673
674  int child_id;
675  int route_id;
676  ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
677  ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
678
679  // This pending URL has an unsupported scheme, and won't be able
680  // to start.
681  GURL pending_url("ftp://news.google.com/");
682
683  prerender_manager()->CreateNextPrerenderContents(
684      pending_url,
685      ORIGIN_GWS_PRERENDER,
686      FINAL_STATUS_UNSUPPORTED_SCHEME);
687  scoped_ptr<PrerenderHandle> pending_prerender_handle(
688      prerender_manager()->AddPrerenderFromLinkRelPrerender(
689          child_id, route_id, pending_url,
690          Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
691  DCHECK(pending_prerender_handle.get());
692  EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
693
694  EXPECT_TRUE(prerender_contents->prerendering_has_started());
695  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
696
697  EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
698}
699
700TEST_F(PrerenderTest, CancelPendingPrerenderTest) {
701  GURL url("http://www.google.com/");
702  DummyPrerenderContents* prerender_contents =
703      prerender_manager()->CreateNextPrerenderContents(
704          url,
705          FINAL_STATUS_USED);
706  EXPECT_TRUE(AddSimplePrerender(url));
707
708  int child_id;
709  int route_id;
710  ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
711  ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
712
713  GURL pending_url("http://news.google.com/");
714
715  scoped_ptr<PrerenderHandle> pending_prerender_handle(
716      prerender_manager()->AddPrerenderFromLinkRelPrerender(
717          child_id, route_id, pending_url,
718          Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
719  CHECK(pending_prerender_handle.get());
720  EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
721
722  EXPECT_TRUE(prerender_contents->prerendering_has_started());
723
724  pending_prerender_handle.reset();
725
726  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
727}
728
729// Tests that a PrerenderManager created for a browser session in the control
730// group works as expected.
731TEST_F(PrerenderTest, ControlGroup) {
732  RestorePrerenderMode restore_prerender_mode;
733  PrerenderManager::SetMode(
734      PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
735  GURL url("http://www.google.com/");
736  DummyPrerenderContents* prerender_contents =
737      prerender_manager()->CreateNextPrerenderContents(
738          url,
739          FINAL_STATUS_MANAGER_SHUTDOWN);
740  EXPECT_TRUE(AddSimplePrerender(url));
741  EXPECT_FALSE(prerender_contents->prerendering_has_started());
742}
743
744// Tests that prerendering is cancelled when the source render view does not
745// exist.  On failure, the DCHECK in CreatePrerenderContents() above should be
746// triggered.
747TEST_F(PrerenderTest, SourceRenderViewClosed) {
748  GURL url("http://www.google.com/");
749  prerender_manager()->CreateNextPrerenderContents(
750      url,
751      FINAL_STATUS_MANAGER_SHUTDOWN);
752  prerender_link_manager()->OnAddPrerender(100, GetNextPrerenderID(), url,
753                                           Referrer(), kSize, 200);
754  EXPECT_FALSE(LauncherHasRunningPrerender(100, last_prerender_id()));
755}
756
757// Tests that prerendering is cancelled when we launch a second prerender of
758// the same target within a short time interval.
759TEST_F(PrerenderTest, RecentlyVisited) {
760  GURL url("http://www.google.com/");
761
762  prerender_manager()->RecordNavigation(url);
763
764  DummyPrerenderContents* prerender_contents =
765      prerender_manager()->CreateNextPrerenderContents(
766          url, FINAL_STATUS_RECENTLY_VISITED);
767  EXPECT_FALSE(AddSimplePrerender(url));
768  EXPECT_FALSE(prerender_contents->prerendering_has_started());
769}
770
771TEST_F(PrerenderTest, NotSoRecentlyVisited) {
772  GURL url("http://www.google.com/");
773
774  prerender_manager()->RecordNavigation(url);
775  prerender_manager()->AdvanceTimeTicks(
776      TimeDelta::FromMilliseconds(
777          UnitTestPrerenderManager::kNavigationRecordWindowMs + 500));
778
779  DummyPrerenderContents* prerender_contents =
780      prerender_manager()->CreateNextPrerenderContents(
781          url, FINAL_STATUS_USED);
782  EXPECT_TRUE(AddSimplePrerender(url));
783  EXPECT_TRUE(prerender_contents->prerendering_has_started());
784  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
785}
786
787// Tests that our PPLT dummy prerender gets created properly.
788TEST_F(PrerenderTest, PPLTDummy) {
789  GURL url("http://www.google.com/");
790  DummyPrerenderContents* prerender_contents =
791      prerender_manager()->CreateNextPrerenderContents(
792          url, FINAL_STATUS_UNSUPPORTED_SCHEME);
793  EXPECT_TRUE(AddSimplePrerender(url));
794  EXPECT_TRUE(prerender_contents->prerendering_has_started());
795  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
796
797  DummyPrerenderContents* pplt_dummy_contents =
798      prerender_manager()->CreateNextPrerenderContents(url,
799                                                       FINAL_STATUS_USED);
800  GURL ftp_url("ftp://ftp.google.com/");
801  // Adding this ftp URL will force the expected unsupported scheme error.
802  prerender_contents->AddAliasURL(ftp_url);
803  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
804
805  ASSERT_EQ(pplt_dummy_contents, prerender_manager()->FindAndUseEntry(url));
806  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
807}
808
809// Tests that our PPLT dummy prerender gets created properly, even
810// when navigating to a page that has been recently navigated to.
811TEST_F(PrerenderTest, RecentlyVisitedPPLTDummy) {
812  GURL url("http://www.google.com/");
813  DummyPrerenderContents* prerender_contents =
814      prerender_manager()->CreateNextPrerenderContents(
815          url, FINAL_STATUS_UNSUPPORTED_SCHEME);
816  EXPECT_TRUE(AddSimplePrerender(url));
817  EXPECT_TRUE(prerender_contents->prerendering_has_started());
818
819  DummyPrerenderContents* pplt_dummy_contents =
820      prerender_manager()->CreateNextPrerenderContents(url,
821                                                       FINAL_STATUS_USED);
822  prerender_manager()->RecordNavigation(url);
823  GURL ftp_url("ftp://ftp.google.com/");
824  prerender_contents->AddAliasURL(ftp_url);
825
826  ASSERT_EQ(pplt_dummy_contents, prerender_manager()->FindAndUseEntry(url));
827}
828
829TEST_F(PrerenderTest, PPLTLateCancel) {
830  GURL url("http://www.google.com");
831  DummyPrerenderContents* prerender_contents =
832      prerender_manager()->CreateNextPrerenderContents(
833          url, FINAL_STATUS_JAVASCRIPT_ALERT);
834  EXPECT_TRUE(AddSimplePrerender(url));
835  EXPECT_TRUE(prerender_contents->prerendering_has_started());
836  // Force the creation of a match complete dummy.
837  DummyPrerenderContents* duplicate_prerender_contents =
838      prerender_manager()->CreateNextPrerenderContents(url,
839                                                       FINAL_STATUS_CANCELLED);
840  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
841  prerender_contents->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT);
842  ASSERT_EQ(duplicate_prerender_contents, prerender_manager()->FindEntry(url));
843
844  // Make sure that events on prerender handles propogate to the match
845  // complete replacement.
846  DummyPrerenderContents* null = NULL;
847  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
848                                              last_prerender_id());
849  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
850}
851
852// Tests that the prerender manager matches include the fragment.
853TEST_F(PrerenderTest, FragmentMatchesTest) {
854  GURL fragment_url("http://www.google.com/#test");
855
856  DummyPrerenderContents* prerender_contents =
857      prerender_manager()->CreateNextPrerenderContents(fragment_url,
858                                                       FINAL_STATUS_USED);
859  EXPECT_TRUE(AddSimplePrerender(fragment_url));
860  EXPECT_TRUE(prerender_contents->prerendering_has_started());
861  ASSERT_EQ(prerender_contents,
862            prerender_manager()->FindAndUseEntry(fragment_url));
863}
864
865// Tests that the prerender manager uses fragment references when matching
866// prerender URLs in the case a different fragment is in both URLs.
867TEST_F(PrerenderTest, FragmentsDifferTest) {
868  GURL fragment_url("http://www.google.com/#test");
869  GURL other_fragment_url("http://www.google.com/#other_test");
870
871  DummyPrerenderContents* prerender_contents =
872      prerender_manager()->CreateNextPrerenderContents(fragment_url,
873                                                       FINAL_STATUS_USED);
874  EXPECT_TRUE(AddSimplePrerender(fragment_url));
875  EXPECT_TRUE(prerender_contents->prerendering_has_started());
876
877  DummyPrerenderContents* null = NULL;
878  ASSERT_EQ(null, prerender_manager()->FindEntry(other_fragment_url));
879
880  ASSERT_EQ(prerender_contents,
881            prerender_manager()->FindAndUseEntry(fragment_url));
882}
883
884// Make sure that clearing works as expected.
885TEST_F(PrerenderTest, ClearTest) {
886  GURL url("http://www.google.com/");
887  DummyPrerenderContents* prerender_contents =
888      prerender_manager()->CreateNextPrerenderContents(
889          url,
890          FINAL_STATUS_CACHE_OR_HISTORY_CLEARED);
891  EXPECT_TRUE(AddSimplePrerender(url));
892  EXPECT_TRUE(prerender_contents->prerendering_has_started());
893  prerender_manager()->ClearData(PrerenderManager::CLEAR_PRERENDER_CONTENTS);
894  DummyPrerenderContents* null = NULL;
895  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
896}
897
898// Make sure canceling works as expected.
899TEST_F(PrerenderTest, CancelAllTest) {
900  GURL url("http://www.google.com/");
901  DummyPrerenderContents* prerender_contents =
902      prerender_manager()->CreateNextPrerenderContents(
903          url, FINAL_STATUS_CANCELLED);
904  EXPECT_TRUE(AddSimplePrerender(url));
905  EXPECT_TRUE(prerender_contents->prerendering_has_started());
906  prerender_manager()->CancelAllPrerenders();
907  const DummyPrerenderContents* null = NULL;
908  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
909}
910
911TEST_F(PrerenderTest, OmniboxNotAllowedWhenDisabled) {
912  prerender_manager()->set_enabled(false);
913  EXPECT_FALSE(prerender_manager()->AddPrerenderFromOmnibox(
914      GURL("http://www.example.com"), NULL, gfx::Size()));
915}
916
917TEST_F(PrerenderTest, LinkRelNotAllowedWhenDisabled) {
918  prerender_manager()->set_enabled(false);
919  EXPECT_FALSE(AddSimplePrerender(
920      GURL("http://www.example.com")));
921}
922
923TEST_F(PrerenderTest, LinkManagerCancel) {
924  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
925  GURL url("http://www.myexample.com");
926  DummyPrerenderContents* prerender_contents =
927      prerender_manager()->CreateNextPrerenderContents(
928          url, FINAL_STATUS_CANCELLED);
929
930  EXPECT_TRUE(AddSimplePrerender(url));
931
932  EXPECT_TRUE(prerender_contents->prerendering_has_started());
933  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
934  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
935  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
936  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
937                                              last_prerender_id());
938
939  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
940  DummyPrerenderContents* null = NULL;
941  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
942  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
943}
944
945TEST_F(PrerenderTest, LinkManagerCancelThenAbandon) {
946  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
947  GURL url("http://www.myexample.com");
948  DummyPrerenderContents* prerender_contents =
949      prerender_manager()->CreateNextPrerenderContents(
950          url, FINAL_STATUS_CANCELLED);
951
952  EXPECT_TRUE(AddSimplePrerender(url));
953
954  EXPECT_TRUE(prerender_contents->prerendering_has_started());
955  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
956  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
957  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
958  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
959                                              last_prerender_id());
960
961  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
962  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
963  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
964                                               last_prerender_id());
965
966  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
967  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
968  DummyPrerenderContents* null = NULL;
969  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
970}
971
972TEST_F(PrerenderTest, LinkManagerAbandon) {
973  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
974  GURL url("http://www.myexample.com");
975  DummyPrerenderContents* prerender_contents =
976      prerender_manager()->CreateNextPrerenderContents(
977          url, FINAL_STATUS_USED);
978
979  EXPECT_TRUE(AddSimplePrerender(url));
980
981  EXPECT_TRUE(prerender_contents->prerendering_has_started());
982  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
983  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
984  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
985  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
986                                               last_prerender_id());
987
988  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
989  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
990}
991
992TEST_F(PrerenderTest, LinkManagerAbandonThenCancel) {
993  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
994  GURL url("http://www.myexample.com");
995  DummyPrerenderContents* prerender_contents =
996      prerender_manager()->CreateNextPrerenderContents(
997          url, FINAL_STATUS_CANCELLED);
998
999  EXPECT_TRUE(AddSimplePrerender(url));
1000
1001  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1002  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1003  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1004  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
1005  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1006                                               last_prerender_id());
1007
1008  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1009  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1010
1011  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1012                                              last_prerender_id());
1013  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1014  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1015  DummyPrerenderContents* null = NULL;
1016  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1017}
1018
1019TEST_F(PrerenderTest, LinkManagerCancelTwice) {
1020  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1021  GURL url("http://www.myexample.com");
1022  DummyPrerenderContents* prerender_contents =
1023      prerender_manager()->CreateNextPrerenderContents(
1024          url, FINAL_STATUS_CANCELLED);
1025
1026  EXPECT_TRUE(AddSimplePrerender(url));
1027  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1028  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1029  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1030  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1031                                              last_prerender_id());
1032
1033  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1034  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1035  DummyPrerenderContents* null = NULL;
1036  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1037  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1038                                              last_prerender_id());
1039}
1040
1041TEST_F(PrerenderTest, LinkManagerAddTwiceCancelTwice) {
1042  SetConcurrency(2);
1043  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1044  GURL url("http://www.myexample.com");
1045  DummyPrerenderContents* prerender_contents =
1046      prerender_manager()->CreateNextPrerenderContents(
1047          url, FINAL_STATUS_CANCELLED);
1048
1049  EXPECT_TRUE(AddSimplePrerender(url));
1050
1051  const int first_prerender_id = last_prerender_id();
1052  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1053  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1054  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1055  EXPECT_TRUE(AddSimplePrerender(url));
1056
1057  const int second_prerender_id = last_prerender_id();
1058  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1059  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1060  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1061  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1062                                              first_prerender_id);
1063
1064  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1065  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1066  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1067                                              second_prerender_id);
1068
1069  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1070  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1071  DummyPrerenderContents* null = NULL;
1072  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1073}
1074
1075TEST_F(PrerenderTest, LinkManagerAddTwiceCancelTwiceThenAbandonTwice) {
1076  SetConcurrency(2);
1077  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1078  GURL url("http://www.myexample.com");
1079  DummyPrerenderContents* prerender_contents =
1080      prerender_manager()->CreateNextPrerenderContents(
1081          url, FINAL_STATUS_CANCELLED);
1082
1083  EXPECT_TRUE(AddSimplePrerender(url));
1084
1085  const int first_prerender_id = last_prerender_id();
1086  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1087  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1088  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1089  EXPECT_TRUE(AddSimplePrerender(url));
1090
1091  const int second_prerender_id = last_prerender_id();
1092  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1093  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1094  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1095  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1096                                              first_prerender_id);
1097
1098  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1099  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1100  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1101                                              second_prerender_id);
1102
1103  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1104  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1105  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1106                                               first_prerender_id);
1107
1108  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1109  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1110  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1111                                               second_prerender_id);
1112
1113  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1114  EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
1115  DummyPrerenderContents* null = NULL;
1116  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1117}
1118
1119// TODO(gavinp): Update this test after abandon has an effect on Prerenders,
1120// like shortening the timeouts.
1121TEST_F(PrerenderTest, LinkManagerAddTwiceAbandonTwiceUseTwice) {
1122  SetConcurrency(2);
1123  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1124  GURL url("http://www.myexample.com");
1125  DummyPrerenderContents* prerender_contents =
1126      prerender_manager()->CreateNextPrerenderContents(
1127          url, FINAL_STATUS_USED);
1128
1129  EXPECT_TRUE(AddSimplePrerender(url));
1130
1131  const int first_prerender_id = last_prerender_id();
1132  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1133  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1134  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1135  EXPECT_TRUE(AddSimplePrerender(url));
1136
1137  const int second_prerender_id = last_prerender_id();
1138  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1139  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1140  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1141  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1142                                               first_prerender_id);
1143
1144  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1145  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1146  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1147                                               second_prerender_id);
1148
1149  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1150  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
1151  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1152}
1153
1154// TODO(gavinp): After abandon shortens the expire time on a Prerender,
1155// add a series of tests testing advancing the time by either the abandon
1156// or normal expire, and verifying the expected behaviour with groups
1157// of links.
1158TEST_F(PrerenderTest, LinkManagerExpireThenCancel) {
1159  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1160  GURL url("http://www.myexample.com");
1161  DummyPrerenderContents* prerender_contents =
1162      prerender_manager()->CreateNextPrerenderContents(
1163          url, FINAL_STATUS_TIMED_OUT);
1164
1165  EXPECT_TRUE(AddSimplePrerender(url));
1166
1167  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1168  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1169  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1170  prerender_manager()->AdvanceTimeTicks(
1171      prerender_manager()->config().time_to_live + TimeDelta::FromSeconds(1));
1172
1173  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
1174  DummyPrerenderContents* null = NULL;
1175  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1176  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1177                                              last_prerender_id());
1178
1179  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1180  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1181}
1182
1183TEST_F(PrerenderTest, LinkManagerExpireThenAddAgain) {
1184  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1185  GURL url("http://www.myexample.com");
1186  DummyPrerenderContents* first_prerender_contents =
1187      prerender_manager()->CreateNextPrerenderContents(
1188          url, FINAL_STATUS_TIMED_OUT);
1189  EXPECT_TRUE(AddSimplePrerender(url));
1190  EXPECT_TRUE(first_prerender_contents->prerendering_has_started());
1191  EXPECT_FALSE(first_prerender_contents->prerendering_has_been_cancelled());
1192  ASSERT_EQ(first_prerender_contents,
1193            prerender_manager()->FindEntry(url));
1194  prerender_manager()->AdvanceTimeTicks(
1195      prerender_manager()->config().time_to_live + TimeDelta::FromSeconds(1));
1196  DummyPrerenderContents* null = NULL;
1197  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1198  DummyPrerenderContents* second_prerender_contents =
1199      prerender_manager()->CreateNextPrerenderContents(
1200          url, FINAL_STATUS_USED);
1201  EXPECT_TRUE(AddSimplePrerender(url));
1202  EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
1203  ASSERT_EQ(second_prerender_contents,
1204            prerender_manager()->FindAndUseEntry(url));
1205}
1206
1207TEST_F(PrerenderTest, LinkManagerCancelThenAddAgain) {
1208  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1209  GURL url("http://www.myexample.com");
1210  DummyPrerenderContents* first_prerender_contents =
1211      prerender_manager()->CreateNextPrerenderContents(
1212          url, FINAL_STATUS_CANCELLED);
1213  EXPECT_TRUE(AddSimplePrerender(url));
1214  EXPECT_TRUE(first_prerender_contents->prerendering_has_started());
1215  EXPECT_FALSE(first_prerender_contents->prerendering_has_been_cancelled());
1216  ASSERT_EQ(first_prerender_contents, prerender_manager()->FindEntry(url));
1217  prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
1218                                              last_prerender_id());
1219  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1220  EXPECT_TRUE(first_prerender_contents->prerendering_has_been_cancelled());
1221  DummyPrerenderContents* null = NULL;
1222  ASSERT_EQ(null, prerender_manager()->FindEntry(url));
1223  DummyPrerenderContents* second_prerender_contents =
1224      prerender_manager()->CreateNextPrerenderContents(
1225          url, FINAL_STATUS_USED);
1226  EXPECT_TRUE(AddSimplePrerender(url));
1227  EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
1228  ASSERT_EQ(second_prerender_contents,
1229            prerender_manager()->FindAndUseEntry(url));
1230}
1231
1232TEST_F(PrerenderTest, LinkManagerChannelClosing) {
1233  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1234  GURL url("http://www.myexample.com");
1235  DummyPrerenderContents* prerender_contents =
1236      prerender_manager()->CreateNextPrerenderContents(
1237          url, FINAL_STATUS_TIMED_OUT);
1238
1239  EXPECT_TRUE(AddSimplePrerender(url));
1240  EXPECT_TRUE(prerender_contents->prerendering_has_started());
1241  EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
1242  ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
1243
1244  prerender_link_manager()->OnChannelClosing(kDefaultChildId);
1245
1246  prerender_manager()->AdvanceTimeTicks(
1247      prerender_manager()->config().abandon_time_to_live +
1248      TimeDelta::FromSeconds(1));
1249
1250  DummyPrerenderContents* null = NULL;
1251  EXPECT_EQ(null, prerender_manager()->FindEntry(url));
1252  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1253}
1254
1255// Creates two prerenders, one of which should be blocked by the
1256// max_link_concurrency; abandons both of them and waits to make sure both
1257// are cleared from the PrerenderLinkManager.
1258TEST_F(PrerenderTest, LinkManagerAbandonInactivePrerender) {
1259  SetConcurrency(1);
1260  ASSERT_LT(prerender_manager()->config().abandon_time_to_live,
1261            prerender_manager()->config().time_to_live);
1262  GURL first_url("http://www.myexample.com");
1263  DummyPrerenderContents* prerender_contents =
1264      prerender_manager()->CreateNextPrerenderContents(
1265          first_url, FINAL_STATUS_TIMED_OUT);
1266  EXPECT_TRUE(AddSimplePrerender(first_url));
1267  const int first_prerender_id = last_prerender_id();
1268
1269  GURL second_url("http://www.neverlaunched.com");
1270  EXPECT_FALSE(AddSimplePrerender(second_url));
1271  const int second_prerender_id = last_prerender_id();
1272
1273  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
1274
1275  DummyPrerenderContents* null = NULL;
1276  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
1277  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1278
1279  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1280                                               first_prerender_id);
1281  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1282                                               second_prerender_id);
1283
1284  prerender_manager()->AdvanceTimeTicks(
1285      prerender_manager()->config().abandon_time_to_live +
1286      TimeDelta::FromSeconds(1));
1287  EXPECT_EQ(null, prerender_manager()->FindEntry(first_url));
1288  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1289  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1290}
1291
1292// Creates two prerenders, the second one started by the first, both of which
1293// should be blocked by max_concurrency; abandons both of them and waits to make
1294// sure both are cleared from the PrerenderLinkManager.
1295TEST_F(PrerenderTest, LinkManagerClearOnPendingAbandon) {
1296  SetConcurrency(1);
1297  ASSERT_LT(prerender_manager()->config().abandon_time_to_live,
1298            prerender_manager()->config().time_to_live);
1299  GURL first_url("http://www.myexample.com");
1300  DummyPrerenderContents* prerender_contents =
1301      prerender_manager()->CreateNextPrerenderContents(
1302          first_url, FINAL_STATUS_TIMED_OUT);
1303  EXPECT_TRUE(AddSimplePrerender(first_url));
1304  const int first_prerender_id = last_prerender_id();
1305
1306  int child_id;
1307  int route_id;
1308  ASSERT_TRUE(prerender_contents->GetChildId(&child_id));
1309  ASSERT_TRUE(prerender_contents->GetRouteId(&route_id));
1310
1311  GURL pending_url("http://www.neverlaunched.com");
1312  prerender_link_manager()->OnAddPrerender(child_id,
1313                                           GetNextPrerenderID(),
1314                                           pending_url, content::Referrer(),
1315                                           kSize, route_id);
1316  const int second_prerender_id = last_prerender_id();
1317
1318  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
1319
1320  DummyPrerenderContents* null = NULL;
1321  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
1322  EXPECT_EQ(null, prerender_manager()->FindEntry(pending_url));
1323
1324  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1325                                               first_prerender_id);
1326  prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
1327                                               second_prerender_id);
1328
1329  prerender_manager()->AdvanceTimeTicks(
1330      prerender_manager()->config().abandon_time_to_live +
1331      TimeDelta::FromSeconds(1));
1332  EXPECT_EQ(null, prerender_manager()->FindEntry(first_url));
1333  EXPECT_EQ(null, prerender_manager()->FindEntry(pending_url));
1334  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1335}
1336
1337// Creates two prerenders, one of which should be blocked by the
1338// max_link_concurrency; uses one after the max wait to launch, and
1339// ensures the second prerender does not start.
1340TEST_F(PrerenderTest, LinkManagerWaitToLaunchNotLaunched) {
1341  SetConcurrency(1);
1342  ASSERT_LT(prerender_manager()->config().max_wait_to_launch,
1343            prerender_manager()->config().time_to_live);
1344  GURL first_url("http://www.myexample.com");
1345  DummyPrerenderContents* prerender_contents =
1346      prerender_manager()->CreateNextPrerenderContents(
1347          first_url, FINAL_STATUS_USED);
1348  EXPECT_TRUE(AddSimplePrerender(first_url));
1349
1350  GURL second_url("http://www.neverlaunched.com");
1351  EXPECT_FALSE(AddSimplePrerender(second_url));
1352
1353  EXPECT_FALSE(IsEmptyPrerenderLinkManager());
1354
1355  DummyPrerenderContents* null = NULL;
1356  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
1357  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1358
1359  prerender_manager()->AdvanceTimeTicks(
1360      prerender_manager()->config().max_wait_to_launch +
1361      TimeDelta::FromSeconds(1));
1362  EXPECT_EQ(prerender_contents, prerender_manager()->FindEntry(first_url));
1363  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1364
1365  EXPECT_EQ(prerender_contents,
1366            prerender_manager()->FindAndUseEntry(first_url));
1367
1368  EXPECT_EQ(null, prerender_manager()->FindEntry(first_url));
1369  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1370  EXPECT_TRUE(IsEmptyPrerenderLinkManager());
1371}
1372
1373// Creates two prerenders, one of which should start when the first one expires.
1374TEST_F(PrerenderTest, LinkManagerExpireRevealingLaunch) {
1375  SetConcurrency(1);
1376  ASSERT_LT(prerender_manager()->config().max_wait_to_launch,
1377            prerender_manager()->config().time_to_live);
1378
1379  GURL first_url("http://www.willexpire.com");
1380  DummyPrerenderContents* first_prerender_contents =
1381      prerender_manager()->CreateNextPrerenderContents(
1382          first_url, FINAL_STATUS_TIMED_OUT);
1383  EXPECT_TRUE(AddSimplePrerender(first_url));
1384  EXPECT_EQ(first_prerender_contents,
1385            prerender_manager()->FindEntry(first_url));
1386
1387  // Insert the second prerender so it will be still be launchable when the
1388  // first expires.
1389  const TimeDelta wait_to_launch_second_prerender =
1390      prerender_manager()->config().time_to_live -
1391      prerender_manager()->config().max_wait_to_launch +
1392      TimeDelta::FromSeconds(2);
1393  const TimeDelta wait_for_first_prerender_to_expire =
1394      prerender_manager()->config().time_to_live -
1395      wait_to_launch_second_prerender +
1396      TimeDelta::FromSeconds(1);
1397  ASSERT_LT(prerender_manager()->config().time_to_live,
1398            wait_to_launch_second_prerender +
1399            wait_for_first_prerender_to_expire);
1400  ASSERT_GT(prerender_manager()->config().max_wait_to_launch.InSeconds(),
1401            wait_for_first_prerender_to_expire.InSeconds());
1402
1403  prerender_manager()->AdvanceTimeTicks(wait_to_launch_second_prerender);
1404  GURL second_url("http://www.willlaunch.com");
1405  DummyPrerenderContents* second_prerender_contents =
1406      prerender_manager()->CreateNextPrerenderContents(
1407          second_url, FINAL_STATUS_USED);
1408  EXPECT_FALSE(AddSimplePrerender(second_url));
1409
1410  // The first prerender is still running, but the second has not yet launched.
1411  EXPECT_EQ(first_prerender_contents,
1412            prerender_manager()->FindEntry(first_url));
1413  PrerenderContents* null = NULL;
1414  EXPECT_EQ(null, prerender_manager()->FindEntry(second_url));
1415
1416  // The first prerender should have died, giving life to the second one.
1417  prerender_manager()->AdvanceTimeTicks(wait_for_first_prerender_to_expire);
1418  EXPECT_EQ(null, prerender_manager()->FindEntry(first_url));
1419  EXPECT_EQ(second_prerender_contents,
1420            prerender_manager()->FindAndUseEntry(second_url));
1421}
1422
1423}  // namespace prerender
1424