1// Copyright 2013 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 <string>
6
7#include "base/basictypes.h"
8#include "base/memory/scoped_vector.h"
9#include "base/metrics/field_trial.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/search/instant_service.h"
12#include "chrome/browser/search/instant_service_observer.h"
13#include "chrome/browser/search/instant_unittest_base.h"
14#include "chrome/browser/search/search.h"
15#include "chrome/browser/ui/browser_instant_controller.h"
16#include "chrome/browser/ui/tabs/tab_strip_model.h"
17#include "chrome/common/pref_names.h"
18#include "chrome/common/url_constants.h"
19#include "content/public/browser/navigation_controller.h"
20#include "content/public/browser/render_process_host.h"
21#include "content/public/browser/web_contents.h"
22#include "content/public/browser/web_contents_observer.h"
23
24namespace chrome {
25
26namespace {
27
28class BrowserInstantControllerTest : public InstantUnitTestBase {
29 public:
30  virtual void SetUp() OVERRIDE {
31    ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
32        "EmbeddedSearch", "Group1 use_cacheable_ntp:1"));
33    InstantUnitTestBase::SetUp();
34  }
35
36 protected:
37  friend class FakeWebContentsObserver;
38};
39
40const struct TabReloadTestCase {
41  const char* description;
42  const char* start_url;
43  bool start_in_instant_process;
44  bool should_reload;
45  bool end_in_instant_process;
46} kTabReloadTestCases[] = {
47    {"Local Embedded NTP", chrome::kChromeSearchLocalNtpUrl,
48     true, true, true},
49    {"Remote Embedded NTP", "https://www.google.com/instant?strk",
50     true, true, false},
51    {"Remote Embedded SERP", "https://www.google.com/url?strk&bar=search+terms",
52     true, true, false},
53    {"Other NTP", "https://bar.com/instant?strk",
54     false, false, false}
55};
56
57class FakeWebContentsObserver : public content::WebContentsObserver {
58 public:
59  explicit FakeWebContentsObserver(content::WebContents* contents)
60      : WebContentsObserver(contents),
61        contents_(contents),
62        url_(contents->GetURL()),
63        num_reloads_(0) {}
64
65  virtual void DidStartNavigationToPendingEntry(
66      const GURL& url,
67      content::NavigationController::ReloadType reload_type) OVERRIDE {
68    if (url_ == url)
69      num_reloads_++;
70  }
71
72  const GURL url() const {
73    return url_;
74  }
75
76  int num_reloads() const {
77    return num_reloads_;
78  }
79
80 protected:
81  friend class BrowserInstantControllerTest;
82  FRIEND_TEST_ALL_PREFIXES(BrowserInstantControllerTest,
83                           DefaultSearchProviderChanged);
84  FRIEND_TEST_ALL_PREFIXES(BrowserInstantControllerTest,
85                           GoogleBaseURLUpdated);
86
87 private:
88  content::WebContents* contents_;
89  const GURL& url_;
90  int num_reloads_;
91};
92
93TEST_F(BrowserInstantControllerTest, DefaultSearchProviderChanged) {
94  size_t num_tests = arraysize(kTabReloadTestCases);
95  ScopedVector<FakeWebContentsObserver> observers;
96  for (size_t i = 0; i < num_tests; ++i) {
97    const TabReloadTestCase& test = kTabReloadTestCases[i];
98    AddTab(browser(), GURL(test.start_url));
99    content::WebContents* contents =
100      browser()->tab_strip_model()->GetActiveWebContents();
101
102    // Validate initial instant state.
103    EXPECT_EQ(test.start_in_instant_process,
104        instant_service_->IsInstantProcess(
105          contents->GetRenderProcessHost()->GetID()))
106      << test.description;
107
108    // Setup an observer to verify reload or absence thereof.
109    observers.push_back(new FakeWebContentsObserver(contents));
110  }
111
112  SetUserSelectedDefaultSearchProvider("https://bar.com/");
113
114  for (size_t i = 0; i < num_tests; ++i) {
115    FakeWebContentsObserver* observer = observers[i];
116    const TabReloadTestCase& test = kTabReloadTestCases[i];
117
118    if (test.should_reload) {
119      // Validate final instant state.
120      EXPECT_EQ(
121          test.end_in_instant_process,
122          chrome::ShouldAssignURLToInstantRenderer(observer->url(), profile()))
123        << test.description;
124    }
125
126    // Ensure only the expected tabs(contents) reloaded.
127    EXPECT_EQ(test.should_reload ? 1 : 0, observer->num_reloads())
128      << test.description;
129  }
130}
131
132TEST_F(BrowserInstantControllerTest, GoogleBaseURLUpdated) {
133  const size_t num_tests = arraysize(kTabReloadTestCases);
134  ScopedVector<FakeWebContentsObserver> observers;
135  for (size_t i = 0; i < num_tests; ++i) {
136    const TabReloadTestCase& test = kTabReloadTestCases[i];
137    AddTab(browser(), GURL(test.start_url));
138    content::WebContents* contents =
139      browser()->tab_strip_model()->GetActiveWebContents();
140
141    // Validate initial instant state.
142    EXPECT_EQ(test.start_in_instant_process,
143        instant_service_->IsInstantProcess(
144          contents->GetRenderProcessHost()->GetID()))
145      << test.description;
146
147    // Setup an observer to verify reload or absence thereof.
148    observers.push_back(new FakeWebContentsObserver(contents));
149  }
150
151  NotifyGoogleBaseURLUpdate("https://www.google.es/");
152
153  for (size_t i = 0; i < num_tests; ++i) {
154    const TabReloadTestCase& test = kTabReloadTestCases[i];
155    FakeWebContentsObserver* observer = observers[i];
156
157    if (test.should_reload) {
158      // Validate final instant state.
159      EXPECT_EQ(
160          test.end_in_instant_process,
161          chrome::ShouldAssignURLToInstantRenderer(observer->url(), profile()))
162        << test.description;
163    }
164
165    // Ensure only the expected tabs(contents) reloaded.
166    EXPECT_EQ(test.should_reload ? 1 : 0, observer->num_reloads())
167      << test.description;
168  }
169}
170
171TEST_F(BrowserInstantControllerTest, BrowserWindowLifecycle) {
172  scoped_ptr<BrowserWindow> window(CreateBrowserWindow());
173  Browser::CreateParams params(profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
174  params.window = window.get();
175  scoped_ptr<Browser> browser(new Browser(params));
176  InstantServiceObserver* bic;
177  bic = browser->instant_controller();
178  EXPECT_TRUE(IsInstantServiceObserver(bic))
179    << "New BrowserInstantController should register as InstantServiceObserver";
180
181  browser.reset(NULL);
182  window.reset(NULL);
183  EXPECT_FALSE(IsInstantServiceObserver(bic))
184    << "New BrowserInstantController should register as InstantServiceObserver";
185}
186
187}  // namespace
188
189}  // namespace chrome
190