• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include <algorithm>
6 #include <list>
7 
8 #include "include/base/cef_callback.h"
9 #include "include/cef_callback.h"
10 #include "include/cef_scheme.h"
11 #include "include/wrapper/cef_closure_task.h"
12 #include "tests/ceftests/test_handler.h"
13 #include "tests/ceftests/test_util.h"
14 #include "tests/gtest/include/gtest/gtest.h"
15 #include "tests/shared/browser/client_app_browser.h"
16 #include "tests/shared/renderer/client_app_renderer.h"
17 
18 using client::ClientAppBrowser;
19 using client::ClientAppRenderer;
20 
21 namespace {
22 
23 const char kHNav1[] = "http://tests-hnav.com/nav1.html";
24 const char kHNav2[] = "http://tests-hnav.com/nav2.html";
25 const char kHNav3[] = "http://tests-hnav.com/nav3.html";
26 const char kHistoryNavMsg[] = "NavigationTest.HistoryNav";
27 const char kHistoryNavTestCmdKey[] = "nav-history-test";
28 
29 const cef_transition_type_t kTransitionExplicitLoad =
30     static_cast<cef_transition_type_t>(TT_EXPLICIT | TT_DIRECT_LOAD_FLAG);
31 
32 // TT_FORWARD_BACK_FLAG is added to the original transition flags.
33 const cef_transition_type_t kTransitionExplicitForwardBack =
34     static_cast<cef_transition_type_t>(kTransitionExplicitLoad |
35                                        TT_FORWARD_BACK_FLAG);
36 
37 enum NavAction { NA_LOAD = 1, NA_BACK, NA_FORWARD, NA_CLEAR };
38 
39 typedef struct {
40   NavAction action;     // What to do
41   const char* target;   // Where to be after navigation
42   bool can_go_back;     // After navigation, can go back?
43   bool can_go_forward;  // After navigation, can go forward?
44 } NavListItem;
45 
46 // Array of navigation actions: X = current page, . = history exists
47 static NavListItem kHNavList[] = {
48     // kHNav1 | kHNav2 | kHNav3
49     {NA_LOAD, kHNav1, false, false},    //   X
50     {NA_LOAD, kHNav2, true, false},     //   .        X
51     {NA_BACK, kHNav1, false, true},     //   X        .
52     {NA_FORWARD, kHNav2, true, false},  //   .        X
53     {NA_LOAD, kHNav3, true, false},     //   .        .        X
54     {NA_BACK, kHNav2, true, true},      //   .        X        .
55     // TODO(cef): Enable once ClearHistory is implemented
56     // {NA_CLEAR, kHNav2, false, false},   //            X
57 };
58 
59 #define NAV_LIST_SIZE() (sizeof(kHNavList) / sizeof(NavListItem))
60 
61 // Renderer side.
62 class HistoryNavRendererTest : public ClientAppRenderer::Delegate,
63                                public CefLoadHandler {
64  public:
HistoryNavRendererTest()65   HistoryNavRendererTest() : run_test_(false), nav_(0) {}
66 
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)67   void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
68                         CefRefPtr<CefBrowser> browser,
69                         CefRefPtr<CefDictionaryValue> extra_info) override {
70     run_test_ = extra_info && extra_info->HasKey(kHistoryNavTestCmdKey);
71   }
72 
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)73   CefRefPtr<CefLoadHandler> GetLoadHandler(
74       CefRefPtr<ClientAppRenderer> app) override {
75     if (!run_test_)
76       return nullptr;
77 
78     return this;
79   }
80 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)81   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
82                             bool isLoading,
83                             bool canGoBack,
84                             bool canGoForward) override {
85     const NavListItem& item = kHNavList[nav_];
86 
87     const std::string& url = browser->GetMainFrame()->GetURL();
88     EXPECT_STREQ(item.target, url.c_str());
89 
90     EXPECT_EQ(item.can_go_back, browser->CanGoBack())
91         << "nav: " << nav_ << " isLoading: " << isLoading;
92     EXPECT_EQ(item.can_go_back, canGoBack)
93         << "nav: " << nav_ << " isLoading: " << isLoading;
94     EXPECT_EQ(item.can_go_forward, browser->CanGoForward())
95         << "nav: " << nav_ << " isLoading: " << isLoading;
96     EXPECT_EQ(item.can_go_forward, canGoForward)
97         << "nav: " << nav_ << " isLoading: " << isLoading;
98 
99     if (isLoading) {
100       got_loading_state_start_.yes();
101     } else {
102       got_loading_state_end_.yes();
103       SendTestResultsIfDone(browser, browser->GetMainFrame());
104     }
105   }
106 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)107   void OnLoadStart(CefRefPtr<CefBrowser> browser,
108                    CefRefPtr<CefFrame> frame,
109                    TransitionType transition_type) override {
110     const NavListItem& item = kHNavList[nav_];
111 
112     got_load_start_.yes();
113 
114     const std::string& url = frame->GetURL();
115     EXPECT_STREQ(item.target, url.c_str());
116 
117     EXPECT_EQ(TT_EXPLICIT, transition_type);
118 
119     EXPECT_EQ(item.can_go_back, browser->CanGoBack());
120     EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
121   }
122 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)123   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
124                  CefRefPtr<CefFrame> frame,
125                  int httpStatusCode) override {
126     const NavListItem& item = kHNavList[nav_];
127 
128     got_load_end_.yes();
129 
130     const std::string& url = frame->GetURL();
131     EXPECT_STREQ(item.target, url.c_str());
132 
133     EXPECT_EQ(item.can_go_back, browser->CanGoBack());
134     EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
135 
136     SendTestResultsIfDone(browser, frame);
137   }
138 
139  protected:
SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)140   void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
141                              CefRefPtr<CefFrame> frame) {
142     if (got_load_end_ && got_loading_state_end_)
143       SendTestResults(browser, frame);
144   }
145 
146   // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)147   void SendTestResults(CefRefPtr<CefBrowser> browser,
148                        CefRefPtr<CefFrame> frame) {
149     EXPECT_TRUE(got_loading_state_start_);
150     EXPECT_TRUE(got_loading_state_end_);
151     EXPECT_TRUE(got_load_start_);
152     EXPECT_TRUE(got_load_end_);
153 
154     // Check if the test has failed.
155     bool result = !TestFailed();
156 
157     // Return the result to the browser process.
158     CefRefPtr<CefProcessMessage> return_msg =
159         CefProcessMessage::Create(kHistoryNavMsg);
160     CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
161     EXPECT_TRUE(args.get());
162     EXPECT_TRUE(args->SetInt(0, nav_));
163     EXPECT_TRUE(args->SetBool(1, result));
164     frame->SendProcessMessage(PID_BROWSER, return_msg);
165 
166     // Reset the test results for the next navigation.
167     got_loading_state_start_.reset();
168     got_loading_state_end_.reset();
169     got_load_start_.reset();
170     got_load_end_.reset();
171 
172     nav_++;
173   }
174 
175   bool run_test_;
176   int nav_;
177 
178   TrackCallback got_loading_state_start_;
179   TrackCallback got_loading_state_end_;
180   TrackCallback got_load_start_;
181   TrackCallback got_load_end_;
182 
183   IMPLEMENT_REFCOUNTING(HistoryNavRendererTest);
184 };
185 
186 class NavigationEntryVisitor : public CefNavigationEntryVisitor {
187  public:
NavigationEntryVisitor(int nav,TrackCallback * callback)188   NavigationEntryVisitor(int nav, TrackCallback* callback)
189       : nav_(nav),
190         callback_(callback),
191         expected_total_(0),
192         expected_current_index_(-1),
193         expected_forwardback_(),
194         callback_count_(0) {
195     // Determine the expected values.
196     for (int i = 0; i <= nav_; ++i) {
197       if (kHNavList[i].action == NA_LOAD) {
198         expected_total_++;
199         expected_current_index_++;
200       } else if (kHNavList[i].action == NA_BACK) {
201         expected_current_index_--;
202       } else if (kHNavList[i].action == NA_FORWARD) {
203         expected_current_index_++;
204       }
205       expected_forwardback_[expected_current_index_] =
206           (kHNavList[i].action != NA_LOAD);
207     }
208   }
209 
~NavigationEntryVisitor()210   ~NavigationEntryVisitor() override {
211     EXPECT_EQ(callback_count_, expected_total_);
212     callback_->yes();
213   }
214 
Visit(CefRefPtr<CefNavigationEntry> entry,bool current,int index,int total)215   bool Visit(CefRefPtr<CefNavigationEntry> entry,
216              bool current,
217              int index,
218              int total) override {
219     // Only 3 loads total.
220     EXPECT_LT(index, 3);
221     EXPECT_LE(total, 3);
222 
223     EXPECT_EQ((expected_current_index_ == index), current);
224     EXPECT_EQ(callback_count_, index);
225     EXPECT_EQ(expected_total_, total);
226 
227     std::string expected_url;
228     std::string expected_title;
229     if (index == 0) {
230       expected_url = kHNav1;
231       expected_title = "Nav1";
232     } else if (index == 1) {
233       expected_url = kHNav2;
234       expected_title = "Nav2";
235     } else if (index == 2) {
236       expected_url = kHNav3;
237       expected_title = "Nav3";
238     }
239 
240     EXPECT_TRUE(entry->IsValid());
241     EXPECT_STREQ(expected_url.c_str(), entry->GetURL().ToString().c_str());
242     EXPECT_STREQ(expected_url.c_str(),
243                  entry->GetDisplayURL().ToString().c_str());
244     EXPECT_STREQ(expected_url.c_str(),
245                  entry->GetOriginalURL().ToString().c_str());
246     EXPECT_STREQ(expected_title.c_str(), entry->GetTitle().ToString().c_str());
247 
248     const auto transition_type = entry->GetTransitionType();
249     if (expected_forwardback_[index])
250       EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
251     else
252       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
253 
254     EXPECT_FALSE(entry->HasPostData());
255     EXPECT_GT(entry->GetCompletionTime().GetTimeT(), 0);
256     EXPECT_EQ(200, entry->GetHttpStatusCode());
257 
258     callback_count_++;
259     return true;
260   }
261 
262  private:
263   const int nav_;
264   TrackCallback* callback_;
265   int expected_total_;
266   int expected_current_index_;
267   bool expected_forwardback_[3];  // Only 3 loads total.
268   int callback_count_;
269 
270   IMPLEMENT_REFCOUNTING(NavigationEntryVisitor);
271 };
272 
273 // Browser side.
274 class HistoryNavTestHandler : public TestHandler {
275  public:
HistoryNavTestHandler()276   HistoryNavTestHandler()
277       : nav_(0),
278         load_end_confirmation_(false),
279         load_state_change_loaded_confirmation_(false),
280         renderer_confirmation_(false) {}
281 
RunTest()282   void RunTest() override {
283     // Add the resources that we will navigate to/from.
284     AddResource(
285         kHNav1,
286         "<html><head><title>Nav1</title></head><body>Nav1</body></html>",
287         "text/html");
288     AddResource(kHNav2,
289                 "<html><head><title>Nav2</title><body>Nav2</body></html>",
290                 "text/html");
291     AddResource(kHNav3,
292                 "<html><head><title>Nav3</title><body>Nav3</body></html>",
293                 "text/html");
294 
295     CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
296     extra_info->SetBool(kHistoryNavTestCmdKey, true);
297 
298     // Create the browser.
299     CreateBrowser(CefString(), nullptr, extra_info);
300 
301     // Time out the test after a reasonable period of time.
302     SetTestTimeout();
303   }
304 
RunNav(CefRefPtr<CefBrowser> browser)305   void RunNav(CefRefPtr<CefBrowser> browser) {
306     if (nav_ == NAV_LIST_SIZE()) {
307       // End of the nav list.
308       DestroyTest();
309       return;
310     }
311 
312     const NavListItem& item = kHNavList[nav_];
313 
314     // Perform the action.
315     switch (item.action) {
316       case NA_LOAD:
317         browser->GetMainFrame()->LoadURL(item.target);
318         break;
319       case NA_BACK:
320         browser->GoBack();
321         break;
322       case NA_FORWARD:
323         browser->GoForward();
324         break;
325       case NA_CLEAR:
326         // TODO(cef): Enable once ClearHistory is implemented
327         // browser->GetHost()->ClearHistory();
328         // Not really a navigation action so go to the next one.
329         nav_++;
330         RunNav(browser);
331         break;
332       default:
333         break;
334     }
335   }
336 
RunNextNavIfReady(CefRefPtr<CefBrowser> browser)337   void RunNextNavIfReady(CefRefPtr<CefBrowser> browser) {
338     if (load_end_confirmation_ && load_state_change_loaded_confirmation_ &&
339         renderer_confirmation_) {
340       load_end_confirmation_ = false;
341       load_state_change_loaded_confirmation_ = false;
342       renderer_confirmation_ = false;
343       nav_++;
344       RunNav(browser);
345     }
346   }
347 
OnAfterCreated(CefRefPtr<CefBrowser> browser)348   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
349     TestHandler::OnAfterCreated(browser);
350 
351     RunNav(browser);
352   }
353 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)354   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
355                       CefRefPtr<CefFrame> frame,
356                       CefRefPtr<CefRequest> request,
357                       bool user_gesture,
358                       bool is_redirect) override {
359     const NavListItem& item = kHNavList[nav_];
360 
361     got_before_browse_[nav_].yes();
362 
363     std::string url = request->GetURL();
364     EXPECT_STREQ(item.target, url.c_str());
365 
366     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
367 
368     const auto transition_type = request->GetTransitionType();
369     if (item.action == NA_LOAD) {
370       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
371     } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
372       EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
373     }
374 
375     if (nav_ > 0) {
376       const NavListItem& last_item = kHNavList[nav_ - 1];
377       EXPECT_EQ(last_item.can_go_back, browser->CanGoBack());
378       EXPECT_EQ(last_item.can_go_forward, browser->CanGoForward());
379     } else {
380       EXPECT_FALSE(browser->CanGoBack());
381       EXPECT_FALSE(browser->CanGoForward());
382     }
383 
384     return false;
385   }
386 
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)387   cef_return_value_t OnBeforeResourceLoad(
388       CefRefPtr<CefBrowser> browser,
389       CefRefPtr<CefFrame> frame,
390       CefRefPtr<CefRequest> request,
391       CefRefPtr<CefCallback> callback) override {
392     if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
393       // Ignore favicon requests.
394       return RV_CANCEL;
395     }
396 
397     const NavListItem& item = kHNavList[nav_];
398     const std::string& url = request->GetURL();
399 
400     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType())
401         << "nav=" << nav_ << " url=" << url;
402 
403     const auto transition_type = request->GetTransitionType();
404     if (item.action == NA_LOAD) {
405       EXPECT_EQ(kTransitionExplicitLoad, transition_type)
406           << "nav=" << nav_ << " url=" << url;
407     } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
408       EXPECT_EQ(kTransitionExplicitForwardBack, transition_type)
409           << "nav=" << nav_ << " url=" << url;
410     }
411 
412     got_before_resource_load_[nav_].yes();
413 
414     if (url == item.target)
415       got_correct_target_[nav_].yes();
416 
417     return RV_CONTINUE;
418   }
419 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)420   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
421                             bool isLoading,
422                             bool canGoBack,
423                             bool canGoForward) override {
424     if (isLoading)
425       return;
426 
427     const NavListItem& item = kHNavList[nav_];
428 
429     got_loading_state_change_[nav_].yes();
430 
431     if (item.can_go_back == canGoBack)
432       got_correct_can_go_back_[nav_].yes();
433     if (item.can_go_forward == canGoForward)
434       got_correct_can_go_forward_[nav_].yes();
435 
436     load_state_change_loaded_confirmation_ = true;
437     RunNextNavIfReady(browser);
438   }
439 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)440   void OnLoadStart(CefRefPtr<CefBrowser> browser,
441                    CefRefPtr<CefFrame> frame,
442                    TransitionType transition_type) override {
443     if (browser->IsPopup() || !frame->IsMain())
444       return;
445 
446     const NavListItem& item = kHNavList[nav_];
447 
448     got_load_start_[nav_].yes();
449 
450     if (item.action == NA_LOAD) {
451       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
452     } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
453       EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
454     }
455 
456     std::string url1 = browser->GetMainFrame()->GetURL();
457     std::string url2 = frame->GetURL();
458     if (url1 == item.target && url2 == item.target)
459       got_correct_load_start_url_[nav_].yes();
460   }
461 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)462   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
463                  CefRefPtr<CefFrame> frame,
464                  int httpStatusCode) override {
465     if (browser->IsPopup() || !frame->IsMain())
466       return;
467 
468     const NavListItem& item = kHNavList[nav_];
469 
470     got_load_end_[nav_].yes();
471 
472     // Test that navigation entries are correct.
473     CefRefPtr<NavigationEntryVisitor> visitor =
474         new NavigationEntryVisitor(nav_, &got_correct_history_[nav_]);
475     browser->GetHost()->GetNavigationEntries(visitor.get(), false);
476     visitor = nullptr;
477 
478     std::string url1 = browser->GetMainFrame()->GetURL();
479     std::string url2 = frame->GetURL();
480     if (url1 == item.target && url2 == item.target)
481       got_correct_load_end_url_[nav_].yes();
482 
483     load_end_confirmation_ = true;
484     RunNextNavIfReady(browser);
485   }
486 
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)487   bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
488                                 CefRefPtr<CefFrame> frame,
489                                 CefProcessId source_process,
490                                 CefRefPtr<CefProcessMessage> message) override {
491     if (message->GetName().ToString() == kHistoryNavMsg) {
492       got_before_navigation_[nav_].yes();
493 
494       // Test that the renderer side succeeded.
495       CefRefPtr<CefListValue> args = message->GetArgumentList();
496       EXPECT_TRUE(args.get());
497       EXPECT_EQ(nav_, args->GetInt(0));
498       EXPECT_TRUE(args->GetBool(1));
499 
500       renderer_confirmation_ = true;
501       RunNextNavIfReady(browser);
502       return true;
503     }
504 
505     // Message not handled.
506     return false;
507   }
508 
509   int nav_;
510   bool load_end_confirmation_;
511   bool load_state_change_loaded_confirmation_;
512   bool renderer_confirmation_;
513 
514   TrackCallback got_before_browse_[NAV_LIST_SIZE()];
515   TrackCallback got_before_navigation_[NAV_LIST_SIZE()];
516   TrackCallback got_before_resource_load_[NAV_LIST_SIZE()];
517   TrackCallback got_correct_target_[NAV_LIST_SIZE()];
518   TrackCallback got_loading_state_change_[NAV_LIST_SIZE()];
519   TrackCallback got_correct_can_go_back_[NAV_LIST_SIZE()];
520   TrackCallback got_correct_can_go_forward_[NAV_LIST_SIZE()];
521   TrackCallback got_load_start_[NAV_LIST_SIZE()];
522   TrackCallback got_correct_load_start_url_[NAV_LIST_SIZE()];
523   TrackCallback got_load_end_[NAV_LIST_SIZE()];
524   TrackCallback got_correct_history_[NAV_LIST_SIZE()];
525   TrackCallback got_correct_load_end_url_[NAV_LIST_SIZE()];
526 
527   IMPLEMENT_REFCOUNTING(HistoryNavTestHandler);
528 };
529 
530 }  // namespace
531 
532 // Verify history navigation.
TEST(NavigationTest,History)533 TEST(NavigationTest, History) {
534   CefRefPtr<HistoryNavTestHandler> handler = new HistoryNavTestHandler();
535   handler->ExecuteTest();
536 
537   for (size_t i = 0; i < NAV_LIST_SIZE(); ++i) {
538     if (kHNavList[i].action != NA_CLEAR) {
539       ASSERT_TRUE(handler->got_before_browse_[i]) << "i = " << i;
540       ASSERT_TRUE(handler->got_before_navigation_[i]) << "i = " << i;
541       ASSERT_TRUE(handler->got_before_resource_load_[i]) << "i = " << i;
542       ASSERT_TRUE(handler->got_correct_target_[i]) << "i = " << i;
543       ASSERT_TRUE(handler->got_load_start_[i]) << "i = " << i;
544       ASSERT_TRUE(handler->got_correct_load_start_url_[i]) << "i = " << i;
545     }
546 
547     ASSERT_TRUE(handler->got_loading_state_change_[i]) << "i = " << i;
548     ASSERT_TRUE(handler->got_correct_can_go_back_[i]) << "i = " << i;
549     ASSERT_TRUE(handler->got_correct_can_go_forward_[i]) << "i = " << i;
550 
551     if (kHNavList[i].action != NA_CLEAR) {
552       ASSERT_TRUE(handler->got_load_end_[i]) << "i = " << i;
553       ASSERT_TRUE(handler->got_correct_history_[i]) << "i = " << i;
554       ASSERT_TRUE(handler->got_correct_load_end_url_[i]) << "i = " << i;
555     }
556   }
557 
558   ReleaseAndWaitForDestructor(handler);
559 }
560 
561 namespace {
562 
563 const char kDynIfrNav1[] = "http://tests-dynframe/nav1.html";
564 const char kDynIfrNav2[] = "http://tests-dynframe/nav2.html";
565 
566 // Browser side.
567 class HistoryDynamicIFramesNavTestHandler : public TestHandler {
568  public:
HistoryDynamicIFramesNavTestHandler()569   HistoryDynamicIFramesNavTestHandler() : nav_(-1) {}
570 
RunTest()571   void RunTest() override {
572     // Add the resources that we will navigate to/from.
573     AddResource(kDynIfrNav1,
574                 "<html>"
575                 " <head>"
576                 "  <title>Nav1</title>"
577                 "  <script language='javascript'>"
578                 "    function onload() {"
579                 "      fr = Math.floor(Math.random() * 10);"
580                 "      if(fr == 0) "
581                 "        fr = 1;"
582                 "      console.log('fr=' + fr);"
583                 "      for(i = 1; i <= fr; i++) {"
584                 "        try {"
585                 "          var n = 'DYN_' + Math.floor(Math.random() * 10000);"
586                 "  "
587                 "          d = document.createElement('div');"
588                 "          d.id = 'sf' + i; "
589                 "          d.innerText = n; "
590                 "          document.body.appendChild(d); "
591                 " "
592                 "          f = document.createElement('iframe'); "
593                 "          f.id = 'f_' + i; "
594                 "          f.name = n; "
595                 "          f.src = 'nav2.html'; "
596                 "          document.body.appendChild(f); "
597                 "        } catch(e) { "
598                 "          console.log('frame[' + i + ']: ' + e); "
599                 "        } "
600                 "      } "
601                 "    } "
602                 "  </script> "
603                 " </head> "
604                 " <body onload='onload();'> "
605                 "  Nav1 "
606                 " </body> "
607                 "</html>",
608                 "text/html");
609     AddResource(
610         kDynIfrNav2,
611         "<html><head><title>Nav2</title></head><body>Nav2</body></html>",
612         "text/html");
613 
614     // Create the browser.
615     CreateBrowser(CefString());
616 
617     // Time out the test after a reasonable period of time.
618     SetTestTimeout();
619   }
620 
RunNav(CefRefPtr<CefBrowser> browser)621   void RunNav(CefRefPtr<CefBrowser> browser) {
622     EXPECT_LE(nav_, 3);
623     EXPECT_FALSE(got_load_start_[nav_]);
624     EXPECT_FALSE(got_load_end_[nav_]);
625 
626     if (nav_ == 0) {
627       browser->GetMainFrame()->LoadURL(kDynIfrNav1);
628     } else if (nav_ == 1) {
629       browser->GetMainFrame()->LoadURL(kDynIfrNav2);
630     } else if (nav_ == 2) {
631       browser->GoBack();
632     } else if (nav_ == 3) {
633       browser->Reload();
634     }
635   }
636 
OnAfterCreated(CefRefPtr<CefBrowser> browser)637   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
638     TestHandler::OnAfterCreated(browser);
639 
640     nav_ = 0;
641     RunNav(browser);
642   }
643 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)644   void OnLoadStart(CefRefPtr<CefBrowser> browser,
645                    CefRefPtr<CefFrame> frame,
646                    TransitionType transition_type) override {
647     if (!frame->IsMain())
648       return;
649     got_load_start_[nav_].yes();
650   }
651 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)652   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
653                  CefRefPtr<CefFrame> frame,
654                  int httpStatusCode) override {
655     if (!frame->IsMain())
656       return;
657     CefString url = browser->GetMainFrame()->GetURL();
658     got_load_end_[nav_].yes();
659 
660     if (nav_ == 3) {
661       EXPECT_STREQ(url.ToString().c_str(), kDynIfrNav1);
662       DestroyTest();
663       return;
664     }
665 
666     nav_++;
667     RunNav(browser);
668   }
669 
670   int nav_;
671   TrackCallback got_load_start_[4];
672   TrackCallback got_load_end_[4];
673 
674   IMPLEMENT_REFCOUNTING(HistoryDynamicIFramesNavTestHandler);
675 };
676 
677 }  // namespace
678 
679 // Verify history navigation of pages containing dynamically created iframes.
680 // See issue #2022 for background.
TEST(NavigationTest,HistoryDynamicIFrames)681 TEST(NavigationTest, HistoryDynamicIFrames) {
682   CefRefPtr<HistoryDynamicIFramesNavTestHandler> handler =
683       new HistoryDynamicIFramesNavTestHandler();
684   handler->ExecuteTest();
685 
686   for (int i = 0; i < 4; ++i) {
687     EXPECT_TRUE(handler->got_load_start_[i]);
688     EXPECT_TRUE(handler->got_load_end_[i]);
689   }
690 
691   ReleaseAndWaitForDestructor(handler);
692 }
693 
694 namespace {
695 
696 const char kRNav1[] = "http://tests/nav1.html";
697 const char kRNav2[] = "http://tests/nav2.html";
698 const char kRNav3[] = "http://tests/nav3.html";
699 const char kRNav4[] = "http://tests/nav4.html";
700 
701 bool g_got_nav1_request = false;
702 bool g_got_nav3_request = false;
703 bool g_got_nav4_request = false;
704 bool g_got_invalid_request = false;
705 
706 class RedirectSchemeHandler : public CefResourceHandler {
707  public:
RedirectSchemeHandler()708   RedirectSchemeHandler() : offset_(0), status_(0) {}
709 
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)710   bool Open(CefRefPtr<CefRequest> request,
711             bool& handle_request,
712             CefRefPtr<CefCallback> callback) override {
713     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
714 
715     std::string url = request->GetURL();
716     if (url == kRNav1) {
717       // Redirect using HTTP 302
718       g_got_nav1_request = true;
719       status_ = 302;
720       location_ = kRNav2;
721       content_ = "<html><body>Redirected Nav1</body></html>";
722     } else if (url == kRNav3) {
723       // Redirect using redirectUrl
724       g_got_nav3_request = true;
725       status_ = -1;
726       location_ = kRNav4;
727       content_ = "<html><body>Redirected Nav3</body></html>";
728     } else if (url == kRNav4) {
729       g_got_nav4_request = true;
730       status_ = 200;
731       content_ = "<html><body>Nav4</body></html>";
732     }
733 
734     handle_request = true;
735 
736     if (status_ != 0) {
737       // Continue request.
738       return true;
739     }
740 
741     // Cancel request.
742     g_got_invalid_request = true;
743     return false;
744   }
745 
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)746   void GetResponseHeaders(CefRefPtr<CefResponse> response,
747                           int64& response_length,
748                           CefString& redirectUrl) override {
749     EXPECT_TRUE(CefCurrentlyOn(TID_IO));
750 
751     EXPECT_NE(status_, 0);
752 
753     response->SetStatus(status_);
754     response->SetMimeType("text/html");
755     response_length = content_.size();
756 
757     if (status_ == 302) {
758       // Redirect using HTTP 302
759       EXPECT_GT(location_.size(), static_cast<size_t>(0));
760       response->SetStatusText("Found");
761       CefResponse::HeaderMap headers;
762       response->GetHeaderMap(headers);
763       headers.insert(std::make_pair("Location", location_));
764       response->SetHeaderMap(headers);
765     } else if (status_ == -1) {
766       // Rdirect using redirectUrl
767       EXPECT_GT(location_.size(), static_cast<size_t>(0));
768       redirectUrl = location_;
769     }
770   }
771 
Cancel()772   void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
773 
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)774   bool Read(void* data_out,
775             int bytes_to_read,
776             int& bytes_read,
777             CefRefPtr<CefResourceReadCallback> callback) override {
778     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
779 
780     bytes_read = 0;
781     bool has_data = false;
782 
783     size_t size = content_.size();
784     if (offset_ < size) {
785       int transfer_size =
786           std::min(bytes_to_read, static_cast<int>(size - offset_));
787       memcpy(data_out, content_.c_str() + offset_, transfer_size);
788       offset_ += transfer_size;
789 
790       bytes_read = transfer_size;
791       has_data = true;
792     }
793 
794     return has_data;
795   }
796 
797  protected:
798   std::string content_;
799   size_t offset_;
800   int status_;
801   std::string location_;
802 
803   IMPLEMENT_REFCOUNTING(RedirectSchemeHandler);
804   DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandler);
805 };
806 
807 class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory {
808  public:
RedirectSchemeHandlerFactory()809   RedirectSchemeHandlerFactory() {
810     g_got_nav1_request = false;
811     g_got_nav3_request = false;
812     g_got_nav4_request = false;
813     g_got_invalid_request = false;
814   }
815 
Create(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & scheme_name,CefRefPtr<CefRequest> request)816   CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
817                                        CefRefPtr<CefFrame> frame,
818                                        const CefString& scheme_name,
819                                        CefRefPtr<CefRequest> request) override {
820     EXPECT_TRUE(CefCurrentlyOn(TID_IO));
821     return new RedirectSchemeHandler();
822   }
823 
824   IMPLEMENT_REFCOUNTING(RedirectSchemeHandlerFactory);
825   DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandlerFactory);
826 };
827 
828 class RedirectTestHandler : public TestHandler {
829  public:
RedirectTestHandler()830   RedirectTestHandler() {}
831 
RunTest()832   void RunTest() override {
833     // Create the browser.
834     CreateBrowser(kRNav1);
835 
836     // Time out the test after a reasonable period of time.
837     SetTestTimeout();
838   }
839 
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)840   cef_return_value_t OnBeforeResourceLoad(
841       CefRefPtr<CefBrowser> browser,
842       CefRefPtr<CefFrame> frame,
843       CefRefPtr<CefRequest> request,
844       CefRefPtr<CefCallback> callback) override {
845     if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
846       // Ignore favicon requests.
847       return RV_CANCEL;
848     }
849 
850     // Should be called for all but the second URL.
851     std::string url = request->GetURL();
852 
853     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
854     EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
855 
856     if (url == kRNav1) {
857       got_nav1_before_resource_load_.yes();
858     } else if (url == kRNav3) {
859       got_nav3_before_resource_load_.yes();
860     } else if (url == kRNav4) {
861       got_nav4_before_resource_load_.yes();
862     } else {
863       got_invalid_before_resource_load_.yes();
864     }
865 
866     return RV_CONTINUE;
867   }
868 
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)869   void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
870                           CefRefPtr<CefFrame> frame,
871                           CefRefPtr<CefRequest> request,
872                           CefRefPtr<CefResponse> response,
873                           CefString& new_url) override {
874     // Should be called for each redirected URL.
875 
876     const std::string& old_url = request->GetURL();
877     if (old_url == kRNav1 && new_url == kRNav2) {
878       // Called due to the nav1 redirect response.
879       got_nav1_redirect_.yes();
880 
881       EXPECT_EQ(302, response->GetStatus());
882       EXPECT_STREQ("Found", response->GetStatusText().ToString().c_str());
883       EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
884       EXPECT_STREQ(kRNav2,
885                    response->GetHeaderByName("Location").ToString().c_str());
886 
887       // Change the redirect to the 3rd URL.
888       new_url = kRNav3;
889     } else if (old_url == kRNav1 && new_url == kRNav3) {
890       // Called due to the redirect change above.
891       got_nav2_redirect_.yes();
892 
893       EXPECT_EQ(307, response->GetStatus());
894       EXPECT_STREQ("Internal Redirect",
895                    response->GetStatusText().ToString().c_str());
896       EXPECT_TRUE(response->GetMimeType().empty());
897       EXPECT_STREQ(kRNav3,
898                    response->GetHeaderByName("Location").ToString().c_str());
899     } else if (old_url == kRNav3 && new_url == kRNav4) {
900       // Called due to the nav3 redirect response.
901       got_nav3_redirect_.yes();
902 
903       EXPECT_EQ(307, response->GetStatus());
904       EXPECT_STREQ("Temporary Redirect",
905                    response->GetStatusText().ToString().c_str());
906       EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
907     } else {
908       got_invalid_redirect_.yes();
909     }
910   }
911 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)912   void OnLoadStart(CefRefPtr<CefBrowser> browser,
913                    CefRefPtr<CefFrame> frame,
914                    TransitionType transition_type) override {
915     // Should only be called for the final loaded URL.
916     std::string url = frame->GetURL();
917 
918     EXPECT_EQ(kTransitionExplicitLoad, transition_type);
919 
920     if (url == kRNav4) {
921       got_nav4_load_start_.yes();
922     } else {
923       got_invalid_load_start_.yes();
924     }
925   }
926 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)927   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
928                  CefRefPtr<CefFrame> frame,
929                  int httpStatusCode) override {
930     // Should only be called for the final loaded URL.
931     std::string url = frame->GetURL();
932 
933     if (url == kRNav4) {
934       got_nav4_load_end_.yes();
935       DestroyTest();
936     } else {
937       got_invalid_load_end_.yes();
938     }
939   }
940 
941   TrackCallback got_nav1_before_resource_load_;
942   TrackCallback got_nav3_before_resource_load_;
943   TrackCallback got_nav4_before_resource_load_;
944   TrackCallback got_invalid_before_resource_load_;
945   TrackCallback got_nav4_load_start_;
946   TrackCallback got_invalid_load_start_;
947   TrackCallback got_nav4_load_end_;
948   TrackCallback got_invalid_load_end_;
949   TrackCallback got_nav1_redirect_;
950   TrackCallback got_nav2_redirect_;
951   TrackCallback got_nav3_redirect_;
952   TrackCallback got_invalid_redirect_;
953 
954   IMPLEMENT_REFCOUNTING(RedirectTestHandler);
955 };
956 
957 // Like above but destroy the WebContents while the redirect is in-progress.
958 class RedirectDestroyTestHandler : public TestHandler {
959  public:
RedirectDestroyTestHandler()960   RedirectDestroyTestHandler() {}
961 
RunTest()962   void RunTest() override {
963     // Create the browser.
964     CreateBrowser(kRNav1);
965 
966     // Time out the test after a reasonable period of time.
967     SetTestTimeout();
968   }
969 
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)970   void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
971                           CefRefPtr<CefFrame> frame,
972                           CefRefPtr<CefRequest> request,
973                           CefRefPtr<CefResponse> response,
974                           CefString& new_url) override {
975     const std::string& old_url = request->GetURL();
976     if (old_url == kRNav1 && new_url == kRNav2) {
977       // Called due to the nav1 redirect response.
978       got_nav1_redirect_.yes();
979 
980       new_url = "about:blank";
981 
982       // Destroy the test (and the underlying WebContents) while the redirect
983       // is still pending.
984       DestroyTest();
985     }
986   }
987 
988   TrackCallback got_nav1_redirect_;
989 
990   IMPLEMENT_REFCOUNTING(RedirectDestroyTestHandler);
991 };
992 
993 }  // namespace
994 
995 // Verify frame names and identifiers.
TEST(NavigationTest,Redirect)996 TEST(NavigationTest, Redirect) {
997   CefRegisterSchemeHandlerFactory("http", "tests",
998                                   new RedirectSchemeHandlerFactory());
999   WaitForIOThread();
1000 
1001   CefRefPtr<RedirectTestHandler> handler = new RedirectTestHandler();
1002   handler->ExecuteTest();
1003 
1004   CefClearSchemeHandlerFactories();
1005   WaitForIOThread();
1006 
1007   ASSERT_TRUE(handler->got_nav1_before_resource_load_);
1008   ASSERT_TRUE(handler->got_nav3_before_resource_load_);
1009   ASSERT_TRUE(handler->got_nav4_before_resource_load_);
1010   ASSERT_FALSE(handler->got_invalid_before_resource_load_);
1011   ASSERT_TRUE(handler->got_nav4_load_start_);
1012   ASSERT_FALSE(handler->got_invalid_load_start_);
1013   ASSERT_TRUE(handler->got_nav4_load_end_);
1014   ASSERT_FALSE(handler->got_invalid_load_end_);
1015   ASSERT_TRUE(handler->got_nav1_redirect_);
1016   ASSERT_FALSE(handler->got_nav2_redirect_);
1017   ASSERT_TRUE(handler->got_nav3_redirect_);
1018   ASSERT_FALSE(handler->got_invalid_redirect_);
1019   ASSERT_TRUE(g_got_nav1_request);
1020   ASSERT_TRUE(g_got_nav3_request);
1021   ASSERT_TRUE(g_got_nav4_request);
1022   ASSERT_FALSE(g_got_invalid_request);
1023 
1024   ReleaseAndWaitForDestructor(handler);
1025 }
1026 
1027 // Verify that destroying the WebContents while the redirect is in-progress does
1028 // not result in a crash.
TEST(NavigationTest,RedirectDestroy)1029 TEST(NavigationTest, RedirectDestroy) {
1030   CefRegisterSchemeHandlerFactory("http", "tests",
1031                                   new RedirectSchemeHandlerFactory());
1032   WaitForIOThread();
1033 
1034   CefRefPtr<RedirectDestroyTestHandler> handler =
1035       new RedirectDestroyTestHandler();
1036   handler->ExecuteTest();
1037 
1038   CefClearSchemeHandlerFactories();
1039   WaitForIOThread();
1040 
1041   ASSERT_TRUE(handler->got_nav1_redirect_);
1042   ASSERT_TRUE(g_got_nav1_request);
1043   ASSERT_FALSE(g_got_nav3_request);
1044   ASSERT_FALSE(g_got_nav4_request);
1045   ASSERT_FALSE(g_got_invalid_request);
1046 
1047   ReleaseAndWaitForDestructor(handler);
1048 }
1049 
1050 namespace {
1051 
1052 const char KONav1[] = "http://tests-onav.com/nav1.html";
1053 const char KONav2[] = "http://tests-onav.com/nav2.html";
1054 const char kOrderNavMsg[] = "NavigationTest.OrderNav";
1055 const char kOrderNavClosedMsg[] = "NavigationTest.OrderNavClosed";
1056 const char kOrderNavTestCmdKey[] = "nav-order-test";
1057 
1058 class OrderNavLoadState {
1059  public:
OrderNavLoadState(bool is_popup,bool browser_side)1060   OrderNavLoadState(bool is_popup, bool browser_side)
1061       : is_popup_(is_popup), browser_side_(browser_side) {}
1062 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1063   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1064                             bool isLoading,
1065                             bool canGoBack,
1066                             bool canGoForward) {
1067     if (isLoading) {
1068       EXPECT_TRUE(Verify(false, false, false, false));
1069 
1070       got_loading_state_start_.yes();
1071     } else {
1072       EXPECT_TRUE(Verify(true, false, true, true));
1073 
1074       got_loading_state_end_.yes();
1075     }
1076   }
1077 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1078   void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
1079     EXPECT_TRUE(Verify(true, false, false, false));
1080 
1081     got_load_start_.yes();
1082   }
1083 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1084   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1085                  CefRefPtr<CefFrame> frame,
1086                  int httpStatusCode) {
1087     EXPECT_TRUE(Verify(true, false, true, false));
1088 
1089     got_load_end_.yes();
1090   }
1091 
IsStarted() const1092   bool IsStarted() const {
1093     return got_loading_state_start_ || got_loading_state_end_ ||
1094            got_load_start_ || got_load_end_;
1095   }
1096 
IsDone() const1097   bool IsDone() const {
1098     return got_loading_state_start_ && got_loading_state_end_ &&
1099            got_load_start_ && got_load_end_;
1100   }
1101 
Verify(bool got_loading_state_start,bool got_loading_state_end,bool got_load_start,bool got_load_end) const1102   bool Verify(bool got_loading_state_start,
1103               bool got_loading_state_end,
1104               bool got_load_start,
1105               bool got_load_end) const {
1106     EXPECT_EQ(got_loading_state_start, got_loading_state_start_)
1107         << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1108     EXPECT_EQ(got_loading_state_end, got_loading_state_end_)
1109         << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1110     EXPECT_EQ(got_load_start, got_load_start_)
1111         << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1112     EXPECT_EQ(got_load_end, got_load_end_)
1113         << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1114 
1115     return got_loading_state_start == got_loading_state_start_ &&
1116            got_loading_state_end == got_loading_state_end_ &&
1117            got_load_start == got_load_start_ && got_load_end == got_load_end_;
1118   }
1119 
1120  private:
1121   bool is_popup_;
1122   bool browser_side_;
1123 
1124   TrackCallback got_loading_state_start_;
1125   TrackCallback got_loading_state_end_;
1126   TrackCallback got_load_start_;
1127   TrackCallback got_load_end_;
1128 };
1129 
1130 // Renderer side.
1131 class OrderNavRendererTest : public ClientAppRenderer::Delegate,
1132                              public CefLoadHandler {
1133  public:
OrderNavRendererTest()1134   OrderNavRendererTest()
1135       : run_test_(false),
1136         browser_id_main_(0),
1137         browser_id_popup_(0),
1138         state_main_(false, false),
1139         state_popup_(true, false) {}
1140 
OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app)1141   void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override {
1142     EXPECT_FALSE(got_webkit_initialized_);
1143 
1144     got_webkit_initialized_.yes();
1145   }
1146 
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)1147   void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
1148                         CefRefPtr<CefBrowser> browser,
1149                         CefRefPtr<CefDictionaryValue> extra_info) override {
1150     run_test_ = extra_info && extra_info->HasKey(kOrderNavTestCmdKey);
1151     if (!run_test_)
1152       return;
1153 
1154     EXPECT_TRUE(got_webkit_initialized_);
1155 
1156     if (browser->IsPopup()) {
1157       EXPECT_FALSE(got_browser_created_popup_);
1158       EXPECT_FALSE(got_browser_destroyed_popup_);
1159       EXPECT_FALSE(state_popup_.IsStarted());
1160 
1161       got_browser_created_popup_.yes();
1162       browser_id_popup_ = browser->GetIdentifier();
1163       EXPECT_GT(browser->GetIdentifier(), 0);
1164     } else {
1165       EXPECT_FALSE(got_browser_created_main_);
1166       EXPECT_FALSE(got_browser_destroyed_main_);
1167       EXPECT_FALSE(state_main_.IsStarted());
1168 
1169       got_browser_created_main_.yes();
1170       browser_id_main_ = browser->GetIdentifier();
1171       EXPECT_GT(browser->GetIdentifier(), 0);
1172 
1173       browser_main_ = browser;
1174     }
1175   }
1176 
OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser)1177   void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
1178                           CefRefPtr<CefBrowser> browser) override {
1179     if (!run_test_)
1180       return;
1181 
1182     EXPECT_TRUE(got_webkit_initialized_);
1183 
1184     if (browser->IsPopup()) {
1185       EXPECT_TRUE(got_browser_created_popup_);
1186       EXPECT_FALSE(got_browser_destroyed_popup_);
1187       EXPECT_TRUE(state_popup_.IsDone());
1188 
1189       got_browser_destroyed_popup_.yes();
1190       EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1191       EXPECT_GT(browser->GetIdentifier(), 0);
1192 
1193       // Use |browser_main_| to send the message otherwise it will fail.
1194       SendTestResults(browser_main_, browser_main_->GetMainFrame(),
1195                       kOrderNavClosedMsg);
1196     } else {
1197       EXPECT_TRUE(got_browser_created_main_);
1198       EXPECT_FALSE(got_browser_destroyed_main_);
1199       EXPECT_TRUE(state_main_.IsDone());
1200 
1201       got_browser_destroyed_main_.yes();
1202       EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1203       EXPECT_GT(browser->GetIdentifier(), 0);
1204 
1205       browser_main_ = nullptr;
1206     }
1207   }
1208 
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)1209   CefRefPtr<CefLoadHandler> GetLoadHandler(
1210       CefRefPtr<ClientAppRenderer> app) override {
1211     if (!run_test_)
1212       return nullptr;
1213 
1214     return this;
1215   }
1216 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1217   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1218                             bool isLoading,
1219                             bool canGoBack,
1220                             bool canGoForward) override {
1221     EXPECT_TRUE(got_webkit_initialized_);
1222 
1223     if (browser->IsPopup()) {
1224       EXPECT_TRUE(got_browser_created_popup_);
1225       EXPECT_FALSE(got_browser_destroyed_popup_);
1226 
1227       state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
1228                                         canGoForward);
1229     } else {
1230       EXPECT_TRUE(got_browser_created_main_);
1231       EXPECT_FALSE(got_browser_destroyed_main_);
1232 
1233       state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
1234                                        canGoForward);
1235     }
1236 
1237     if (!isLoading)
1238       SendTestResultsIfDone(browser, browser->GetMainFrame());
1239   }
1240 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1241   void OnLoadStart(CefRefPtr<CefBrowser> browser,
1242                    CefRefPtr<CefFrame> frame,
1243                    TransitionType transition_type) override {
1244     EXPECT_TRUE(got_webkit_initialized_);
1245 
1246     if (browser->IsPopup()) {
1247       EXPECT_TRUE(got_browser_created_popup_);
1248       EXPECT_FALSE(got_browser_destroyed_popup_);
1249 
1250       state_popup_.OnLoadStart(browser, frame);
1251     } else {
1252       EXPECT_TRUE(got_browser_created_main_);
1253       EXPECT_FALSE(got_browser_destroyed_main_);
1254 
1255       state_main_.OnLoadStart(browser, frame);
1256     }
1257   }
1258 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1259   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1260                  CefRefPtr<CefFrame> frame,
1261                  int httpStatusCode) override {
1262     EXPECT_TRUE(got_webkit_initialized_);
1263 
1264     if (browser->IsPopup()) {
1265       EXPECT_TRUE(got_browser_created_popup_);
1266       EXPECT_FALSE(got_browser_destroyed_popup_);
1267 
1268       state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
1269     } else {
1270       EXPECT_TRUE(got_browser_created_main_);
1271       EXPECT_FALSE(got_browser_destroyed_main_);
1272 
1273       state_main_.OnLoadEnd(browser, frame, httpStatusCode);
1274     }
1275 
1276     SendTestResultsIfDone(browser, frame);
1277   }
1278 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)1279   void OnLoadError(CefRefPtr<CefBrowser> browser,
1280                    CefRefPtr<CefFrame> frame,
1281                    ErrorCode errorCode,
1282                    const CefString& errorText,
1283                    const CefString& failedUrl) override {
1284     ADD_FAILURE() << "renderer OnLoadError url: " << failedUrl.ToString()
1285                   << " error: " << errorCode;
1286   }
1287 
1288  protected:
SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1289   void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
1290                              CefRefPtr<CefFrame> frame) {
1291     bool done = false;
1292     if (browser->IsPopup())
1293       done = state_popup_.IsDone();
1294     else
1295       done = state_main_.IsDone();
1296 
1297     if (done)
1298       SendTestResults(browser, frame, kOrderNavMsg);
1299   }
1300 
1301   // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const char * msg_name)1302   void SendTestResults(CefRefPtr<CefBrowser> browser,
1303                        CefRefPtr<CefFrame> frame,
1304                        const char* msg_name) {
1305     // Check if the test has failed.
1306     bool result = !TestFailed();
1307 
1308     // Return the result to the browser process.
1309     CefRefPtr<CefProcessMessage> return_msg =
1310         CefProcessMessage::Create(msg_name);
1311     CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
1312     EXPECT_TRUE(args.get());
1313     EXPECT_TRUE(args->SetBool(0, result));
1314     if (browser->IsPopup())
1315       EXPECT_TRUE(args->SetInt(1, browser_id_popup_));
1316     else
1317       EXPECT_TRUE(args->SetInt(1, browser_id_main_));
1318     frame->SendProcessMessage(PID_BROWSER, return_msg);
1319   }
1320 
1321   bool run_test_;
1322 
1323   int browser_id_main_;
1324   int browser_id_popup_;
1325   CefRefPtr<CefBrowser> browser_main_;
1326   TrackCallback got_webkit_initialized_;
1327   TrackCallback got_browser_created_main_;
1328   TrackCallback got_browser_destroyed_main_;
1329   TrackCallback got_browser_created_popup_;
1330   TrackCallback got_browser_destroyed_popup_;
1331 
1332   OrderNavLoadState state_main_;
1333   OrderNavLoadState state_popup_;
1334 
1335   IMPLEMENT_REFCOUNTING(OrderNavRendererTest);
1336 };
1337 
1338 // Browser side.
1339 class OrderNavTestHandler : public TestHandler {
1340  public:
OrderNavTestHandler()1341   OrderNavTestHandler()
1342       : browser_id_main_(0),
1343         browser_id_popup_(0),
1344         state_main_(false, true),
1345         state_popup_(true, true),
1346         got_message_(false) {}
1347 
1348   // Returns state that will be checked in the renderer process via
1349   // OrderNavRendererTest::OnBrowserCreated.
GetExtraInfo()1350   CefRefPtr<CefDictionaryValue> GetExtraInfo() {
1351     CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
1352     extra_info->SetBool(kOrderNavTestCmdKey, true);
1353     return extra_info;
1354   }
1355 
RunTest()1356   void RunTest() override {
1357     // Add the resources that we will navigate to/from.
1358     AddResource(KONav1, "<html>Nav1</html>", "text/html");
1359     AddResource(KONav2, "<html>Nav2</html>", "text/html");
1360 
1361     // Create the browser.
1362     CreateBrowser(KONav1, nullptr, GetExtraInfo());
1363 
1364     // Time out the test after a reasonable period of time.
1365     SetTestTimeout();
1366   }
1367 
ContinueIfReady(CefRefPtr<CefBrowser> browser)1368   void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
1369     if (!got_message_)
1370       return;
1371 
1372     bool done = false;
1373     if (browser->IsPopup())
1374       done = state_popup_.IsDone();
1375     else
1376       done = state_main_.IsDone();
1377     if (!done)
1378       return;
1379 
1380     got_message_ = false;
1381 
1382     if (!browser->IsPopup()) {
1383       // Create the popup window.
1384       browser->GetMainFrame()->ExecuteJavaScript(
1385           "window.open('" + std::string(KONav2) + "');", CefString(), 0);
1386     } else {
1387       // Close the popup window.
1388       CloseBrowser(browser_popup_, false);
1389     }
1390   }
1391 
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,const CefString & target_frame_name,CefLifeSpanHandler::WindowOpenDisposition target_disposition,bool user_gesture,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)1392   bool OnBeforePopup(
1393       CefRefPtr<CefBrowser> browser,
1394       CefRefPtr<CefFrame> frame,
1395       const CefString& target_url,
1396       const CefString& target_frame_name,
1397       CefLifeSpanHandler::WindowOpenDisposition target_disposition,
1398       bool user_gesture,
1399       const CefPopupFeatures& popupFeatures,
1400       CefWindowInfo& windowInfo,
1401       CefRefPtr<CefClient>& client,
1402       CefBrowserSettings& settings,
1403       CefRefPtr<CefDictionaryValue>& extra_info,
1404       bool* no_javascript_access) override {
1405     extra_info = GetExtraInfo();
1406     return false;
1407   }
1408 
OnAfterCreated(CefRefPtr<CefBrowser> browser)1409   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1410     TestHandler::OnAfterCreated(browser);
1411 
1412     if (browser->IsPopup()) {
1413       browser_id_popup_ = browser->GetIdentifier();
1414       EXPECT_GT(browser_id_popup_, 0);
1415       browser_popup_ = browser;
1416     } else {
1417       browser_id_main_ = browser->GetIdentifier();
1418       EXPECT_GT(browser_id_main_, 0);
1419     }
1420   }
1421 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1422   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1423                       CefRefPtr<CefFrame> frame,
1424                       CefRefPtr<CefRequest> request,
1425                       bool user_gesture,
1426                       bool is_redirect) override {
1427     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1428 
1429     if (browser->IsPopup()) {
1430       EXPECT_EQ(TT_LINK, request->GetTransitionType());
1431       EXPECT_GT(browser->GetIdentifier(), 0);
1432       EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1433       got_before_browse_popup_.yes();
1434     } else {
1435       EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1436       EXPECT_GT(browser->GetIdentifier(), 0);
1437       EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1438       got_before_browse_main_.yes();
1439     }
1440 
1441     std::string url = request->GetURL();
1442     if (url == KONav1)
1443       EXPECT_FALSE(browser->IsPopup());
1444     else if (url == KONav2)
1445       EXPECT_TRUE(browser->IsPopup());
1446     else
1447       EXPECT_TRUE(false);  // not reached
1448 
1449     return false;
1450   }
1451 
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1452   cef_return_value_t OnBeforeResourceLoad(
1453       CefRefPtr<CefBrowser> browser,
1454       CefRefPtr<CefFrame> frame,
1455       CefRefPtr<CefRequest> request,
1456       CefRefPtr<CefCallback> callback) override {
1457     if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1458       // Ignore favicon requests.
1459       return RV_CANCEL;
1460     }
1461 
1462     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1463 
1464     if (browser->IsPopup()) {
1465       EXPECT_EQ(TT_LINK, request->GetTransitionType());
1466       EXPECT_GT(browser->GetIdentifier(), 0);
1467       EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1468     } else {
1469       EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1470       EXPECT_GT(browser->GetIdentifier(), 0);
1471       EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1472     }
1473 
1474     return RV_CONTINUE;
1475   }
1476 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1477   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1478                             bool isLoading,
1479                             bool canGoBack,
1480                             bool canGoForward) override {
1481     if (browser->IsPopup()) {
1482       state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
1483                                         canGoForward);
1484     } else {
1485       state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
1486                                        canGoForward);
1487     }
1488 
1489     if (!isLoading)
1490       ContinueIfReady(browser);
1491   }
1492 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1493   void OnLoadStart(CefRefPtr<CefBrowser> browser,
1494                    CefRefPtr<CefFrame> frame,
1495                    TransitionType transition_type) override {
1496     if (browser->IsPopup()) {
1497       EXPECT_EQ(TT_LINK, transition_type);
1498       state_popup_.OnLoadStart(browser, frame);
1499     } else {
1500       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1501       state_main_.OnLoadStart(browser, frame);
1502     }
1503   }
1504 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1505   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1506                  CefRefPtr<CefFrame> frame,
1507                  int httpStatusCode) override {
1508     if (browser->IsPopup()) {
1509       state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
1510     } else {
1511       state_main_.OnLoadEnd(browser, frame, httpStatusCode);
1512     }
1513 
1514     ContinueIfReady(browser);
1515   }
1516 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)1517   void OnLoadError(CefRefPtr<CefBrowser> browser,
1518                    CefRefPtr<CefFrame> frame,
1519                    ErrorCode errorCode,
1520                    const CefString& errorText,
1521                    const CefString& failedUrl) override {
1522     ADD_FAILURE() << "browser OnLoadError url: " << failedUrl.ToString()
1523                   << " error: " << errorCode;
1524   }
1525 
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)1526   bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
1527                                 CefRefPtr<CefFrame> frame,
1528                                 CefProcessId source_process,
1529                                 CefRefPtr<CefProcessMessage> message) override {
1530     if (browser->IsPopup()) {
1531       EXPECT_GT(browser->GetIdentifier(), 0);
1532       EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1533     } else {
1534       EXPECT_GT(browser->GetIdentifier(), 0);
1535       EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1536     }
1537 
1538     const std::string& msg_name = message->GetName();
1539     if (msg_name == kOrderNavMsg || msg_name == kOrderNavClosedMsg) {
1540       // Test that the renderer side succeeded.
1541       CefRefPtr<CefListValue> args = message->GetArgumentList();
1542       EXPECT_TRUE(args.get());
1543       EXPECT_TRUE(args->GetBool(0));
1544 
1545       if (browser->IsPopup()) {
1546         EXPECT_EQ(browser_id_popup_, args->GetInt(1));
1547       } else {
1548         EXPECT_EQ(browser_id_main_, args->GetInt(1));
1549       }
1550 
1551       if (msg_name == kOrderNavMsg) {
1552         // Continue with the test.
1553         got_message_ = true;
1554         ContinueIfReady(browser);
1555       } else {
1556         // Popup was closed. End the test.
1557         browser_popup_ = nullptr;
1558         DestroyTest();
1559       }
1560 
1561       return true;
1562     }
1563 
1564     // Message not handled.
1565     return false;
1566   }
1567 
1568  protected:
DestroyTest()1569   void DestroyTest() override {
1570     // Verify test expectations.
1571     EXPECT_TRUE(got_before_browse_main_);
1572     EXPECT_TRUE(got_before_browse_popup_);
1573 
1574     EXPECT_TRUE(state_main_.Verify(true, true, true, true));
1575     EXPECT_TRUE(state_popup_.Verify(true, true, true, true));
1576 
1577     TestHandler::DestroyTest();
1578   }
1579 
1580   int browser_id_main_;
1581   int browser_id_popup_;
1582   CefRefPtr<CefBrowser> browser_popup_;
1583 
1584   TrackCallback got_before_browse_main_;
1585   TrackCallback got_before_browse_popup_;
1586 
1587   OrderNavLoadState state_main_;
1588   OrderNavLoadState state_popup_;
1589 
1590   bool got_message_;
1591 
1592   IMPLEMENT_REFCOUNTING(OrderNavTestHandler);
1593 };
1594 
1595 }  // namespace
1596 
1597 // Verify the order of navigation-related callbacks.
TEST(NavigationTest,Order)1598 TEST(NavigationTest, Order) {
1599   CefRefPtr<OrderNavTestHandler> handler = new OrderNavTestHandler();
1600   handler->ExecuteTest();
1601   ReleaseAndWaitForDestructor(handler);
1602 }
1603 
1604 namespace {
1605 
1606 const char kLoadNav1[] = "http://tests-conav1.com/nav1.html";
1607 const char kLoadNavSameOrigin2[] = "http://tests-conav1.com/nav2.html";
1608 const char kLoadNavCrossOrigin2[] = "http://tests-conav2.com/nav2.html";
1609 const char kLoadNavMsg[] = "NavigationTest.LoadNav";
1610 const char kLoadNavTestCmdKey[] = "nav-load-test";
1611 
1612 // Renderer side.
1613 class LoadNavRendererTest : public ClientAppRenderer::Delegate,
1614                             public CefLoadHandler {
1615  public:
LoadNavRendererTest()1616   LoadNavRendererTest() : run_test_(false), browser_id_(0), load_ct_(0) {}
~LoadNavRendererTest()1617   ~LoadNavRendererTest() override { EXPECT_EQ(0, browser_id_); }
1618 
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)1619   void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
1620                         CefRefPtr<CefBrowser> browser,
1621                         CefRefPtr<CefDictionaryValue> extra_info) override {
1622     run_test_ = extra_info && extra_info->HasKey(kLoadNavTestCmdKey);
1623     if (!run_test_)
1624       return;
1625 
1626     EXPECT_EQ(0, browser_id_);
1627     browser_id_ = browser->GetIdentifier();
1628     EXPECT_GT(browser_id_, 0);
1629     got_browser_created_.yes();
1630   }
1631 
OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser)1632   void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
1633                           CefRefPtr<CefBrowser> browser) override {
1634     if (!run_test_)
1635       return;
1636 
1637     EXPECT_TRUE(got_browser_created_);
1638     EXPECT_TRUE(got_loading_state_end_);
1639 
1640     EXPECT_EQ(browser_id_, browser->GetIdentifier());
1641     browser_id_ = 0;
1642   }
1643 
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)1644   CefRefPtr<CefLoadHandler> GetLoadHandler(
1645       CefRefPtr<ClientAppRenderer> app) override {
1646     if (!run_test_)
1647       return nullptr;
1648 
1649     return this;
1650   }
1651 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1652   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1653                             bool isLoading,
1654                             bool canGoBack,
1655                             bool canGoForward) override {
1656     if (!isLoading) {
1657       EXPECT_TRUE(got_browser_created_);
1658 
1659       got_loading_state_end_.yes();
1660 
1661       EXPECT_EQ(browser_id_, browser->GetIdentifier());
1662 
1663       load_ct_++;
1664       SendTestResults(browser, browser->GetMainFrame());
1665     }
1666   }
1667 
1668  protected:
1669   // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1670   void SendTestResults(CefRefPtr<CefBrowser> browser,
1671                        CefRefPtr<CefFrame> frame) {
1672     // Check if the test has failed.
1673     bool result = !TestFailed();
1674 
1675     // Return the result to the browser process.
1676     CefRefPtr<CefProcessMessage> return_msg =
1677         CefProcessMessage::Create(kLoadNavMsg);
1678     CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
1679     EXPECT_TRUE(args.get());
1680     EXPECT_TRUE(args->SetBool(0, result));
1681     EXPECT_TRUE(args->SetInt(1, browser->GetIdentifier()));
1682     EXPECT_TRUE(args->SetInt(2, load_ct_));
1683     frame->SendProcessMessage(PID_BROWSER, return_msg);
1684   }
1685 
1686   bool run_test_;
1687 
1688   int browser_id_;
1689   int load_ct_;
1690   TrackCallback got_browser_created_;
1691   TrackCallback got_loading_state_end_;
1692 
1693   IMPLEMENT_REFCOUNTING(LoadNavRendererTest);
1694 };
1695 
1696 // Browser side.
1697 class LoadNavTestHandler : public TestHandler {
1698  public:
1699   enum TestMode {
1700     LOAD,
1701     LEFT_CLICK,
1702     MIDDLE_CLICK,
1703     CTRL_LEFT_CLICK,
1704   };
1705 
LoadNavTestHandler(TestMode mode,bool same_origin,bool cancel_in_open_url=false)1706   LoadNavTestHandler(TestMode mode,
1707                      bool same_origin,
1708                      bool cancel_in_open_url = false)
1709       : mode_(mode),
1710         same_origin_(same_origin),
1711         cancel_in_open_url_(cancel_in_open_url),
1712         browser_id_current_(0),
1713         renderer_load_ct_(0) {}
1714 
GetURL2() const1715   std::string GetURL2() const {
1716     return same_origin_ ? kLoadNavSameOrigin2 : kLoadNavCrossOrigin2;
1717   }
1718 
ExpectOpenURL() const1719   bool ExpectOpenURL() const {
1720     return mode_ == MIDDLE_CLICK || mode_ == CTRL_LEFT_CLICK;
1721   }
1722 
RunTest()1723   void RunTest() override {
1724     const std::string& url2 = GetURL2();
1725     std::string link;
1726     if (mode_ != LOAD)
1727       link = "<a href=\"" + url2 + "\">CLICK ME</a>";
1728 
1729     // Add the resources that we will navigate to/from.
1730     AddResource(kLoadNav1,
1731                 "<html><body><h1>" + link + "Nav1</h1></body></html>",
1732                 "text/html");
1733     AddResource(url2, "<html>Nav2</html>", "text/html");
1734 
1735     CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
1736     extra_info->SetBool(kLoadNavTestCmdKey, true);
1737 
1738     // Create the browser.
1739     CreateBrowser(kLoadNav1, nullptr, extra_info);
1740 
1741     // Time out the test after a reasonable period of time.
1742     SetTestTimeout();
1743   }
1744 
ContinueIfReady(CefRefPtr<CefBrowser> browser)1745   void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
1746     if (!got_message_ || !got_load_end_)
1747       return;
1748 
1749     std::string url = browser->GetMainFrame()->GetURL();
1750     if (url == kLoadNav1) {
1751       // Verify the behavior of the previous load.
1752       EXPECT_TRUE(got_before_browse_);
1753       EXPECT_TRUE(got_before_resource_load_);
1754       EXPECT_TRUE(got_load_start_);
1755       EXPECT_TRUE(got_load_end_);
1756       EXPECT_FALSE(got_open_url_from_tab_);
1757 
1758       got_before_browse_.reset();
1759       got_before_resource_load_.reset();
1760       got_load_start_.reset();
1761       got_load_end_.reset();
1762       got_message_.reset();
1763 
1764       EXPECT_EQ(1, renderer_load_ct_);
1765 
1766       // Load the next url.
1767       if (mode_ == LOAD) {
1768         browser->GetMainFrame()->LoadURL(GetURL2());
1769       } else {
1770         // Navigate to the URL by clicking a link.
1771         CefMouseEvent mouse_event;
1772         mouse_event.x = 20;
1773         mouse_event.y = 20;
1774 #if defined(OS_MAC)
1775         // Use cmd instead of ctrl on OS X.
1776         mouse_event.modifiers =
1777             (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_COMMAND_DOWN : 0);
1778 #else
1779         mouse_event.modifiers =
1780             (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_CONTROL_DOWN : 0);
1781 #endif
1782 
1783         cef_mouse_button_type_t button_type =
1784             (mode_ == MIDDLE_CLICK ? MBT_MIDDLE : MBT_LEFT);
1785         browser->GetHost()->SendMouseClickEvent(mouse_event, button_type, false,
1786                                                 1);
1787         browser->GetHost()->SendMouseClickEvent(mouse_event, button_type, true,
1788                                                 1);
1789       }
1790 
1791       if (cancel_in_open_url_) {
1792         // The next navigation should not occur. Therefore call DestroyTest()
1793         // after a reasonable timeout.
1794         CefPostDelayedTask(
1795             TID_UI, base::BindOnce(&LoadNavTestHandler::DestroyTest, this),
1796             500);
1797       }
1798     } else {
1799       // Done with the test.
1800       DestroyTest();
1801     }
1802   }
1803 
OnAfterCreated(CefRefPtr<CefBrowser> browser)1804   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1805     TestHandler::OnAfterCreated(browser);
1806 
1807     EXPECT_EQ(browser_id_current_, 0);
1808     browser_id_current_ = browser->GetIdentifier();
1809     EXPECT_GT(browser_id_current_, 0);
1810   }
1811 
ExpectedOpenURLTransitionType() const1812   cef_transition_type_t ExpectedOpenURLTransitionType() const {
1813     if (mode_ != LEFT_CLICK && IsChromeRuntimeEnabled()) {
1814       // Because we triggered the navigation with LoadURL in OnOpenURLFromTab.
1815       return kTransitionExplicitLoad;
1816     }
1817     return TT_LINK;
1818   }
1819 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1820   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1821                       CefRefPtr<CefFrame> frame,
1822                       CefRefPtr<CefRequest> request,
1823                       bool user_gesture,
1824                       bool is_redirect) override {
1825     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1826     if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1827       EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1828       if (IsChromeRuntimeEnabled()) {
1829         // With the Chrome runtime this is true on initial navigation via
1830         // chrome::AddTabAt() and also true for clicked links.
1831         EXPECT_TRUE(user_gesture);
1832       } else {
1833         EXPECT_FALSE(user_gesture);
1834       }
1835     } else {
1836       EXPECT_EQ(ExpectedOpenURLTransitionType(), request->GetTransitionType());
1837 
1838       if (mode_ == LEFT_CLICK || IsChromeRuntimeEnabled()) {
1839         EXPECT_TRUE(user_gesture);
1840       } else {
1841         EXPECT_FALSE(user_gesture);
1842       }
1843     }
1844 
1845     EXPECT_GT(browser_id_current_, 0);
1846     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1847 
1848     if (ExpectOpenURL() && request->GetURL() == GetURL2()) {
1849       // OnOpenURLFromTab should be called first for the file URL navigation.
1850       EXPECT_TRUE(got_open_url_from_tab_);
1851     } else {
1852       EXPECT_FALSE(got_open_url_from_tab_);
1853     }
1854 
1855     got_before_browse_.yes();
1856 
1857     return false;
1858   }
1859 
OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,cef_window_open_disposition_t target_disposition,bool user_gesture)1860   bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
1861                         CefRefPtr<CefFrame> frame,
1862                         const CefString& target_url,
1863                         cef_window_open_disposition_t target_disposition,
1864                         bool user_gesture) override {
1865     EXPECT_TRUE(CefCurrentlyOn(TID_UI));
1866 
1867     EXPECT_GT(browser_id_current_, 0);
1868     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1869 
1870     // OnOpenURLFromTab should only be called for the file URL.
1871     EXPECT_STREQ(GetURL2().c_str(), target_url.ToString().c_str());
1872 
1873     if (mode_ == LOAD)
1874       EXPECT_FALSE(user_gesture);
1875     else
1876       EXPECT_TRUE(user_gesture);
1877 
1878     EXPECT_EQ(WOD_NEW_BACKGROUND_TAB, target_disposition);
1879 
1880     // OnOpenURLFromTab should be called before OnBeforeBrowse for the file URL.
1881     EXPECT_FALSE(got_before_browse_);
1882 
1883     got_open_url_from_tab_.yes();
1884 
1885     if (!cancel_in_open_url_ && IsChromeRuntimeEnabled()) {
1886       // The chrome runtime may create a new popup window, which is not the
1887       // behavior that this test expects. Instead, match the alloy runtime
1888       // behavior by navigating in the current window.
1889       browser->GetMainFrame()->LoadURL(target_url);
1890       return true;
1891     }
1892 
1893     return cancel_in_open_url_;
1894   }
1895 
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1896   cef_return_value_t OnBeforeResourceLoad(
1897       CefRefPtr<CefBrowser> browser,
1898       CefRefPtr<CefFrame> frame,
1899       CefRefPtr<CefRequest> request,
1900       CefRefPtr<CefCallback> callback) override {
1901     if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1902       // Ignore favicon requests.
1903       return RV_CANCEL;
1904     }
1905 
1906     EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1907 
1908     const auto transition_type = request->GetTransitionType();
1909     if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1910       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1911     } else {
1912       EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1913     }
1914 
1915     EXPECT_GT(browser_id_current_, 0);
1916     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1917 
1918     got_before_resource_load_.yes();
1919 
1920     return RV_CONTINUE;
1921   }
1922 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1923   void OnLoadStart(CefRefPtr<CefBrowser> browser,
1924                    CefRefPtr<CefFrame> frame,
1925                    TransitionType transition_type) override {
1926     EXPECT_GT(browser_id_current_, 0);
1927     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1928 
1929     if (mode_ == LOAD || frame->GetURL() == kLoadNav1) {
1930       EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1931     } else {
1932       EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1933     }
1934 
1935     got_load_start_.yes();
1936   }
1937 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1938   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1939                  CefRefPtr<CefFrame> frame,
1940                  int httpStatusCode) override {
1941     EXPECT_GT(browser_id_current_, 0);
1942     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1943 
1944     got_load_end_.yes();
1945     ContinueIfReady(browser);
1946   }
1947 
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)1948   bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
1949                                 CefRefPtr<CefFrame> frame,
1950                                 CefProcessId source_process,
1951                                 CefRefPtr<CefProcessMessage> message) override {
1952     EXPECT_GT(browser_id_current_, 0);
1953     EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1954 
1955     const std::string& msg_name = message->GetName();
1956     if (msg_name == kLoadNavMsg) {
1957       // Test that the renderer side succeeded.
1958       CefRefPtr<CefListValue> args = message->GetArgumentList();
1959       EXPECT_TRUE(args.get());
1960       EXPECT_TRUE(args->GetBool(0));
1961 
1962       EXPECT_EQ(browser_id_current_, args->GetInt(1));
1963 
1964       renderer_load_ct_ = args->GetInt(2);
1965       EXPECT_GE(renderer_load_ct_, 1);
1966 
1967       // Continue with the test.
1968       got_message_.yes();
1969       ContinueIfReady(browser);
1970 
1971       return true;
1972     }
1973 
1974     // Message not handled.
1975     return false;
1976   }
1977 
DestroyTest()1978   void DestroyTest() override {
1979     if (cancel_in_open_url_) {
1980       EXPECT_FALSE(got_before_browse_);
1981       EXPECT_FALSE(got_before_resource_load_);
1982       EXPECT_FALSE(got_load_start_);
1983       EXPECT_FALSE(got_load_end_);
1984       EXPECT_FALSE(got_message_);
1985 
1986       // We should only navigate a single time if the 2nd load is canceled.
1987       EXPECT_EQ(1, renderer_load_ct_);
1988     } else {
1989       EXPECT_TRUE(got_before_browse_);
1990       EXPECT_TRUE(got_before_resource_load_);
1991       EXPECT_TRUE(got_load_start_);
1992       EXPECT_TRUE(got_load_end_);
1993       EXPECT_TRUE(got_message_);
1994 
1995       if (same_origin_) {
1996         // The renderer process should always be reused.
1997         EXPECT_EQ(2, renderer_load_ct_);
1998       } else {
1999         // Each renderer process is only used for a single navigation.
2000         EXPECT_EQ(1, renderer_load_ct_);
2001       }
2002     }
2003 
2004     if (ExpectOpenURL())
2005       EXPECT_TRUE(got_open_url_from_tab_);
2006     else
2007       EXPECT_FALSE(got_open_url_from_tab_);
2008 
2009     TestHandler::DestroyTest();
2010   }
2011 
2012  protected:
2013   const TestMode mode_;
2014   const bool same_origin_;
2015   const bool cancel_in_open_url_;
2016 
2017   int browser_id_current_;
2018   int renderer_load_ct_;
2019 
2020   TrackCallback got_before_browse_;
2021   TrackCallback got_open_url_from_tab_;
2022   TrackCallback got_before_resource_load_;
2023   TrackCallback got_load_start_;
2024   TrackCallback got_load_end_;
2025   TrackCallback got_message_;
2026 
2027   IMPLEMENT_REFCOUNTING(LoadNavTestHandler);
2028 };
2029 
2030 }  // namespace
2031 
2032 // Verify navigation-related callbacks when browsing same-origin via LoadURL().
TEST(NavigationTest,LoadSameOriginLoadURL)2033 TEST(NavigationTest, LoadSameOriginLoadURL) {
2034   CefRefPtr<LoadNavTestHandler> handler =
2035       new LoadNavTestHandler(LoadNavTestHandler::LOAD, true);
2036   handler->ExecuteTest();
2037   ReleaseAndWaitForDestructor(handler);
2038 }
2039 
2040 // Verify navigation-related callbacks when browsing same-origin via left-click.
TEST(NavigationTest,LoadSameOriginLeftClick)2041 TEST(NavigationTest, LoadSameOriginLeftClick) {
2042   CefRefPtr<LoadNavTestHandler> handler =
2043       new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, true);
2044   handler->ExecuteTest();
2045   ReleaseAndWaitForDestructor(handler);
2046 }
2047 
2048 // Verify navigation-related callbacks when browsing same-origin via middle-
2049 // click.
TEST(NavigationTest,LoadSameOriginMiddleClick)2050 TEST(NavigationTest, LoadSameOriginMiddleClick) {
2051   CefRefPtr<LoadNavTestHandler> handler =
2052       new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true);
2053   handler->ExecuteTest();
2054   ReleaseAndWaitForDestructor(handler);
2055 }
2056 
2057 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginMiddleClickCancel)2058 TEST(NavigationTest, LoadSameOriginMiddleClickCancel) {
2059   CefRefPtr<LoadNavTestHandler> handler =
2060       new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true, true);
2061   handler->ExecuteTest();
2062   ReleaseAndWaitForDestructor(handler);
2063 }
2064 
2065 // Verify navigation-related callbacks when browsing same-origin via ctrl+left-
2066 // click.
TEST(NavigationTest,LoadSameOriginCtrlLeftClick)2067 TEST(NavigationTest, LoadSameOriginCtrlLeftClick) {
2068   CefRefPtr<LoadNavTestHandler> handler =
2069       new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true);
2070   handler->ExecuteTest();
2071   ReleaseAndWaitForDestructor(handler);
2072 }
2073 
2074 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginCtrlLeftClickCancel)2075 TEST(NavigationTest, LoadSameOriginCtrlLeftClickCancel) {
2076   CefRefPtr<LoadNavTestHandler> handler =
2077       new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true, true);
2078   handler->ExecuteTest();
2079   ReleaseAndWaitForDestructor(handler);
2080 }
2081 
2082 // Verify navigation-related callbacks when browsing cross-origin via LoadURL().
TEST(NavigationTest,LoadCrossOriginLoadURL)2083 TEST(NavigationTest, LoadCrossOriginLoadURL) {
2084   CefRefPtr<LoadNavTestHandler> handler =
2085       new LoadNavTestHandler(LoadNavTestHandler::LOAD, false);
2086   handler->ExecuteTest();
2087   ReleaseAndWaitForDestructor(handler);
2088 }
2089 
2090 // Verify navigation-related callbacks when browsing cross-origin via left-
2091 // click.
TEST(NavigationTest,LoadCrossOriginLeftClick)2092 TEST(NavigationTest, LoadCrossOriginLeftClick) {
2093   CefRefPtr<LoadNavTestHandler> handler =
2094       new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, false);
2095   handler->ExecuteTest();
2096   ReleaseAndWaitForDestructor(handler);
2097 }
2098 
2099 // Verify navigation-related callbacks when browsing cross-origin via middle-
2100 // click.
TEST(NavigationTest,LoadCrossOriginMiddleClick)2101 TEST(NavigationTest, LoadCrossOriginMiddleClick) {
2102   CefRefPtr<LoadNavTestHandler> handler =
2103       new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false);
2104   handler->ExecuteTest();
2105   ReleaseAndWaitForDestructor(handler);
2106 }
2107 
2108 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginMiddleClickCancel)2109 TEST(NavigationTest, LoadCrossOriginMiddleClickCancel) {
2110   CefRefPtr<LoadNavTestHandler> handler =
2111       new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false, true);
2112   handler->ExecuteTest();
2113   ReleaseAndWaitForDestructor(handler);
2114 }
2115 
2116 // Verify navigation-related callbacks when browsing cross-origin via ctrl+left-
2117 // click.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClick)2118 TEST(NavigationTest, LoadCrossOriginCtrlLeftClick) {
2119   CefRefPtr<LoadNavTestHandler> handler =
2120       new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false);
2121   handler->ExecuteTest();
2122   ReleaseAndWaitForDestructor(handler);
2123 }
2124 
2125 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClickCancel)2126 TEST(NavigationTest, LoadCrossOriginCtrlLeftClickCancel) {
2127   CefRefPtr<LoadNavTestHandler> handler =
2128       new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false, true);
2129   handler->ExecuteTest();
2130   ReleaseAndWaitForDestructor(handler);
2131 }
2132 
2133 namespace {
2134 
2135 const char kSimultPopupMainUrl[] = "http://www.tests-sp.com/main.html";
2136 const char kSimultPopupPopupUrl[] = "http://www.tests-sp.com/popup";
2137 const size_t kSimultPopupCount = 5U;
2138 
2139 // Test multiple popups simultaniously.
2140 class PopupSimultaneousTestHandler : public TestHandler {
2141  public:
PopupSimultaneousTestHandler(bool same_url)2142   explicit PopupSimultaneousTestHandler(bool same_url)
2143       : same_url_(same_url),
2144         before_popup_ct_(0U),
2145         after_created_ct_(0U),
2146         before_close_ct_(0U) {}
2147 
RunTest()2148   void RunTest() override {
2149     std::string main_html = "<html><script>\n";
2150     for (size_t i = 0; i < kSimultPopupCount; ++i) {
2151       if (same_url_) {
2152         popup_url_[i] = std::string(kSimultPopupPopupUrl) + ".html";
2153       } else {
2154         std::stringstream ss;
2155         ss << kSimultPopupPopupUrl << i << ".html";
2156         popup_url_[i] = ss.str();
2157       }
2158       main_html += "window.open('" + popup_url_[i] + "');\n";
2159       AddResource(popup_url_[i], "<html>Popup " + popup_url_[i] + "</html>",
2160                   "text/html");
2161     }
2162     main_html += "</script></html>";
2163 
2164     AddResource(kSimultPopupMainUrl, main_html, "text/html");
2165 
2166     // Create the browser.
2167     CreateBrowser(kSimultPopupMainUrl);
2168 
2169     // Time out the test after a reasonable period of time.
2170     SetTestTimeout();
2171   }
2172 
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,const CefString & target_frame_name,cef_window_open_disposition_t target_disposition,bool user_gesture,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)2173   bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2174                      CefRefPtr<CefFrame> frame,
2175                      const CefString& target_url,
2176                      const CefString& target_frame_name,
2177                      cef_window_open_disposition_t target_disposition,
2178                      bool user_gesture,
2179                      const CefPopupFeatures& popupFeatures,
2180                      CefWindowInfo& windowInfo,
2181                      CefRefPtr<CefClient>& client,
2182                      CefBrowserSettings& settings,
2183                      CefRefPtr<CefDictionaryValue>& extra_info,
2184                      bool* no_javascript_access) override {
2185     const std::string& url = target_url;
2186     EXPECT_LT(before_popup_ct_, kSimultPopupCount);
2187     EXPECT_STREQ(popup_url_[before_popup_ct_].c_str(), url.c_str())
2188         << before_popup_ct_;
2189     before_popup_ct_++;
2190     return false;
2191   }
2192 
OnAfterCreated(CefRefPtr<CefBrowser> browser)2193   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2194     TestHandler::OnAfterCreated(browser);
2195 
2196     if (browser->IsPopup()) {
2197       EXPECT_LT(after_created_ct_, kSimultPopupCount);
2198       browser_id_[after_created_ct_] = browser->GetIdentifier();
2199       after_created_ct_++;
2200     }
2201   }
2202 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2203   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2204                             bool isLoading,
2205                             bool canGoBack,
2206                             bool canGoForward) override {
2207     if (isLoading)
2208       return;
2209 
2210     if (browser->IsPopup()) {
2211       const std::string& url = browser->GetMainFrame()->GetURL();
2212       for (size_t i = 0; i < kSimultPopupCount; ++i) {
2213         if (browser->GetIdentifier() == browser_id_[i]) {
2214           EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2215 
2216           got_loading_state_change_[i].yes();
2217           CloseBrowser(browser, true);
2218           return;
2219         }
2220       }
2221       EXPECT_FALSE(true);  // Not reached.
2222     }
2223   }
2224 
OnBeforeClose(CefRefPtr<CefBrowser> browser)2225   void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2226     TestHandler::OnBeforeClose(browser);
2227 
2228     if (browser->IsPopup()) {
2229       const std::string& url = browser->GetMainFrame()->GetURL();
2230       for (size_t i = 0; i < kSimultPopupCount; ++i) {
2231         if (browser->GetIdentifier() == browser_id_[i]) {
2232           EXPECT_TRUE(got_loading_state_change_[i]);
2233           EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2234 
2235           got_before_close_[i].yes();
2236 
2237           if (++before_close_ct_ == kSimultPopupCount)
2238             DestroyTest();
2239           return;
2240         }
2241       }
2242       EXPECT_FALSE(true);  // Not reached.
2243     }
2244   }
2245 
2246  private:
DestroyTest()2247   void DestroyTest() override {
2248     EXPECT_EQ(kSimultPopupCount, before_popup_ct_);
2249     EXPECT_EQ(kSimultPopupCount, after_created_ct_);
2250     EXPECT_EQ(kSimultPopupCount, before_close_ct_);
2251 
2252     for (size_t i = 0; i < kSimultPopupCount; ++i) {
2253       EXPECT_GT(browser_id_[i], 0) << i;
2254       EXPECT_TRUE(got_loading_state_change_[i]) << i;
2255       EXPECT_TRUE(got_before_close_[i]) << i;
2256     }
2257 
2258     TestHandler::DestroyTest();
2259   }
2260 
2261   const bool same_url_;
2262   std::string popup_url_[kSimultPopupCount];
2263   size_t before_popup_ct_;
2264   int browser_id_[kSimultPopupCount];
2265   size_t after_created_ct_;
2266   TrackCallback got_loading_state_change_[kSimultPopupCount];
2267   TrackCallback got_before_close_[kSimultPopupCount];
2268   size_t before_close_ct_;
2269 
2270   IMPLEMENT_REFCOUNTING(PopupSimultaneousTestHandler);
2271 };
2272 
2273 }  // namespace
2274 
2275 // Test simultaneous popups with different URLs.
TEST(NavigationTest,PopupSimultaneousDifferentUrl)2276 TEST(NavigationTest, PopupSimultaneousDifferentUrl) {
2277   CefRefPtr<PopupSimultaneousTestHandler> handler =
2278       new PopupSimultaneousTestHandler(false);
2279   handler->ExecuteTest();
2280   ReleaseAndWaitForDestructor(handler);
2281 }
2282 
2283 // Test simultaneous popups with the same URL.
TEST(NavigationTest,PopupSimultaneousSameUrl)2284 TEST(NavigationTest, PopupSimultaneousSameUrl) {
2285   CefRefPtr<PopupSimultaneousTestHandler> handler =
2286       new PopupSimultaneousTestHandler(true);
2287   handler->ExecuteTest();
2288   ReleaseAndWaitForDestructor(handler);
2289 }
2290 
2291 namespace {
2292 
2293 const char kPopupJSOpenMainUrl[] = "http://www.tests-pjso.com/main.html";
2294 const char kPopupJSOpenPopupUrl[] = "http://www.tests-pjso.com/popup.html";
2295 
2296 // Test a popup where the URL is a JavaScript URI that opens another popup.
2297 class PopupJSWindowOpenTestHandler : public TestHandler {
2298  public:
PopupJSWindowOpenTestHandler()2299   PopupJSWindowOpenTestHandler()
2300       : before_popup_ct_(0U),
2301         after_created_ct_(0U),
2302         load_end_ct_(0U),
2303         before_close_ct_(0U) {}
2304 
RunTest()2305   void RunTest() override {
2306     AddResource(kPopupJSOpenMainUrl, "<html>Main</html>", "text/html");
2307     AddResource(kPopupJSOpenPopupUrl, "<html>Popup</html>", "text/html");
2308 
2309     // Create the browser.
2310     CreateBrowser(kPopupJSOpenMainUrl);
2311 
2312     // Time out the test after a reasonable period of time.
2313     SetTestTimeout();
2314   }
2315 
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,const CefString & target_frame_name,cef_window_open_disposition_t target_disposition,bool user_gesture,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)2316   bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2317                      CefRefPtr<CefFrame> frame,
2318                      const CefString& target_url,
2319                      const CefString& target_frame_name,
2320                      cef_window_open_disposition_t target_disposition,
2321                      bool user_gesture,
2322                      const CefPopupFeatures& popupFeatures,
2323                      CefWindowInfo& windowInfo,
2324                      CefRefPtr<CefClient>& client,
2325                      CefBrowserSettings& settings,
2326                      CefRefPtr<CefDictionaryValue>& extra_info,
2327                      bool* no_javascript_access) override {
2328     before_popup_ct_++;
2329     return false;
2330   }
2331 
OnAfterCreated(CefRefPtr<CefBrowser> browser)2332   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2333     TestHandler::OnAfterCreated(browser);
2334 
2335     if (browser->IsPopup()) {
2336       after_created_ct_++;
2337       if (!popup1_)
2338         popup1_ = browser;
2339       else if (!popup2_)
2340         popup2_ = browser;
2341       else
2342         ADD_FAILURE();
2343     }
2344   }
2345 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2346   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2347                             bool isLoading,
2348                             bool canGoBack,
2349                             bool canGoForward) override {
2350     if (isLoading)
2351       return;
2352 
2353     if (browser->IsPopup()) {
2354       const std::string& url = browser->GetMainFrame()->GetURL();
2355       if (url == kPopupJSOpenPopupUrl) {
2356         EXPECT_TRUE(browser->IsSame(popup2_));
2357         popup2_ = nullptr;
2358 
2359         // OnLoadingStateChange is not currently called for browser-side
2360         // navigations of empty popups. See https://crbug.com/789252.
2361         // Explicitly close the empty popup here as a workaround.
2362         CloseBrowser(popup1_, true);
2363         popup1_ = nullptr;
2364       } else {
2365         // Empty popup.
2366         EXPECT_TRUE(url.empty());
2367         EXPECT_TRUE(browser->IsSame(popup1_));
2368         popup1_ = nullptr;
2369       }
2370 
2371       load_end_ct_++;
2372       CloseBrowser(browser, true);
2373     } else if (browser->GetMainFrame()->GetURL() == kPopupJSOpenMainUrl) {
2374       // Load the problematic JS URI.
2375       // This will result in 2 popups being created:
2376       // - An empty popup
2377       // - A popup that loads kPopupJSOpenPopupUrl
2378       browser->GetMainFrame()->LoadURL(
2379           "javascript:window.open(\"javascript:window.open('" +
2380           std::string(kPopupJSOpenPopupUrl) + "')\")");
2381     }
2382   }
2383 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2384   void OnLoadError(CefRefPtr<CefBrowser> browser,
2385                    CefRefPtr<CefFrame> frame,
2386                    ErrorCode errorCode,
2387                    const CefString& errorText,
2388                    const CefString& failedUrl) override {
2389     ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2390                   << " error: " << errorCode;
2391   }
2392 
OnBeforeClose(CefRefPtr<CefBrowser> browser)2393   void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2394     TestHandler::OnBeforeClose(browser);
2395 
2396     before_close_ct_++;
2397     if (before_close_ct_ == 2U)
2398       DestroyTest();
2399   }
2400 
2401  private:
DestroyTest()2402   void DestroyTest() override {
2403     EXPECT_EQ(2U, before_popup_ct_);
2404     EXPECT_EQ(2U, after_created_ct_);
2405     EXPECT_EQ(2U, before_close_ct_);
2406 
2407     // OnLoadingStateChange is not currently called for browser-side
2408     // navigations of empty popups. See https://crbug.com/789252.
2409     EXPECT_EQ(1U, load_end_ct_);
2410 
2411     TestHandler::DestroyTest();
2412   }
2413 
2414   CefRefPtr<CefBrowser> popup1_;
2415   CefRefPtr<CefBrowser> popup2_;
2416 
2417   size_t before_popup_ct_;
2418   size_t after_created_ct_;
2419   size_t load_end_ct_;
2420   size_t before_close_ct_;
2421 
2422   IMPLEMENT_REFCOUNTING(PopupJSWindowOpenTestHandler);
2423 };
2424 
2425 }  // namespace
2426 
2427 // Test a popup where the URL is a JavaScript URI that opens another popup.
TEST(NavigationTest,PopupJSWindowOpen)2428 TEST(NavigationTest, PopupJSWindowOpen) {
2429   CefRefPtr<PopupJSWindowOpenTestHandler> handler =
2430       new PopupJSWindowOpenTestHandler();
2431   handler->ExecuteTest();
2432   ReleaseAndWaitForDestructor(handler);
2433 }
2434 
2435 namespace {
2436 
2437 const char kPopupJSEmptyMainUrl[] = "http://www.tests-pjse.com/main.html";
2438 
2439 // Test creation of a popup where the URL is empty.
2440 class PopupJSWindowEmptyTestHandler : public TestHandler {
2441  public:
PopupJSWindowEmptyTestHandler()2442   PopupJSWindowEmptyTestHandler() {}
2443 
RunTest()2444   void RunTest() override {
2445     AddResource(kPopupJSEmptyMainUrl, "<html>Main</html>", "text/html");
2446 
2447     // Create the browser.
2448     CreateBrowser(kPopupJSEmptyMainUrl);
2449 
2450     // Time out the test after a reasonable period of time.
2451     SetTestTimeout();
2452   }
2453 
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,const CefString & target_frame_name,cef_window_open_disposition_t target_disposition,bool user_gesture,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)2454   bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2455                      CefRefPtr<CefFrame> frame,
2456                      const CefString& target_url,
2457                      const CefString& target_frame_name,
2458                      cef_window_open_disposition_t target_disposition,
2459                      bool user_gesture,
2460                      const CefPopupFeatures& popupFeatures,
2461                      CefWindowInfo& windowInfo,
2462                      CefRefPtr<CefClient>& client,
2463                      CefBrowserSettings& settings,
2464                      CefRefPtr<CefDictionaryValue>& extra_info,
2465                      bool* no_javascript_access) override {
2466     got_before_popup_.yes();
2467     return false;
2468   }
2469 
OnAfterCreated(CefRefPtr<CefBrowser> browser)2470   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2471     TestHandler::OnAfterCreated(browser);
2472 
2473     if (browser->IsPopup()) {
2474       got_after_created_popup_.yes();
2475     }
2476   }
2477 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2478   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2479                             bool isLoading,
2480                             bool canGoBack,
2481                             bool canGoForward) override {
2482     if (isLoading)
2483       return;
2484 
2485     if (browser->IsPopup()) {
2486       got_load_end_popup_.yes();
2487       CloseBrowser(browser, true);
2488     } else {
2489       browser->GetMainFrame()->LoadURL("javascript:window.open('')");
2490     }
2491   }
2492 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2493   void OnLoadError(CefRefPtr<CefBrowser> browser,
2494                    CefRefPtr<CefFrame> frame,
2495                    ErrorCode errorCode,
2496                    const CefString& errorText,
2497                    const CefString& failedUrl) override {
2498     ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2499                   << " error: " << errorCode;
2500   }
2501 
OnBeforeClose(CefRefPtr<CefBrowser> browser)2502   void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2503     TestHandler::OnBeforeClose(browser);
2504 
2505     if (browser->IsPopup()) {
2506       got_before_close_popup_.yes();
2507       DestroyTest();
2508     }
2509   }
2510 
2511  private:
DestroyTest()2512   void DestroyTest() override {
2513     EXPECT_TRUE(got_before_popup_);
2514     EXPECT_TRUE(got_after_created_popup_);
2515     EXPECT_TRUE(got_load_end_popup_);
2516     EXPECT_TRUE(got_before_close_popup_);
2517 
2518     TestHandler::DestroyTest();
2519   }
2520 
2521   TrackCallback got_before_popup_;
2522   TrackCallback got_after_created_popup_;
2523   TrackCallback got_load_end_popup_;
2524   TrackCallback got_before_close_popup_;
2525 
2526   IMPLEMENT_REFCOUNTING(PopupJSWindowEmptyTestHandler);
2527 };
2528 
2529 }  // namespace
2530 
2531 // Test creation of a popup where the URL is empty.
TEST(NavigationTest,PopupJSWindowEmpty)2532 TEST(NavigationTest, PopupJSWindowEmpty) {
2533   CefRefPtr<PopupJSWindowEmptyTestHandler> handler =
2534       new PopupJSWindowEmptyTestHandler();
2535   handler->ExecuteTest();
2536   ReleaseAndWaitForDestructor(handler);
2537 }
2538 
2539 namespace {
2540 
2541 const char kBrowseNavPageUrl[] = "http://tests-browsenav/nav.html";
2542 
2543 // Browser side.
2544 class BrowseNavTestHandler : public TestHandler {
2545  public:
BrowseNavTestHandler(bool allow)2546   BrowseNavTestHandler(bool allow) : allow_(allow), destroyed_(false) {}
2547 
RunTest()2548   void RunTest() override {
2549     AddResource(kBrowseNavPageUrl, "<html>Test</html>", "text/html");
2550 
2551     // Create the browser.
2552     CreateBrowser(kBrowseNavPageUrl);
2553 
2554     // Time out the test after a reasonable period of time.
2555     SetTestTimeout();
2556   }
2557 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2558   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2559                       CefRefPtr<CefFrame> frame,
2560                       CefRefPtr<CefRequest> request,
2561                       bool user_gesture,
2562                       bool is_redirect) override {
2563     const std::string& url = request->GetURL();
2564     EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2565     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2566     EXPECT_TRUE(frame->IsMain());
2567 
2568     got_before_browse_.yes();
2569 
2570     return !allow_;
2571   }
2572 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2573   void OnLoadStart(CefRefPtr<CefBrowser> browser,
2574                    CefRefPtr<CefFrame> frame,
2575                    TransitionType transition_type) override {
2576     const std::string& url = frame->GetURL();
2577     EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2578     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2579     EXPECT_TRUE(frame->IsMain());
2580 
2581     got_load_start_.yes();
2582   }
2583 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2584   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2585                  CefRefPtr<CefFrame> frame,
2586                  int httpStatusCode) override {
2587     const std::string& url = frame->GetURL();
2588     EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2589     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2590     EXPECT_TRUE(frame->IsMain());
2591 
2592     got_load_end_.yes();
2593     DestroyTestIfDone();
2594   }
2595 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2596   void OnLoadError(CefRefPtr<CefBrowser> browser,
2597                    CefRefPtr<CefFrame> frame,
2598                    ErrorCode errorCode,
2599                    const CefString& errorText,
2600                    const CefString& failedUrl) override {
2601     const std::string& url = frame->GetURL();
2602     EXPECT_STREQ("", url.c_str());
2603     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2604     EXPECT_TRUE(frame->IsMain());
2605 
2606     EXPECT_EQ(ERR_ABORTED, errorCode);
2607     EXPECT_STREQ(kBrowseNavPageUrl, failedUrl.ToString().c_str());
2608 
2609     got_load_error_.yes();
2610     DestroyTestIfDone();
2611   }
2612 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2613   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2614                             bool isLoading,
2615                             bool canGoBack,
2616                             bool canGoForward) override {
2617     const std::string& url = browser->GetMainFrame()->GetURL();
2618     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2619 
2620     if (isLoading) {
2621       EXPECT_STREQ("", url.c_str());
2622 
2623       got_loading_state_changed_start_.yes();
2624     } else {
2625       if (allow_)
2626         EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2627       else
2628         EXPECT_STREQ("", url.c_str());
2629 
2630       got_loading_state_changed_end_.yes();
2631       DestroyTestIfDone();
2632     }
2633   }
2634 
2635  private:
DestroyTestIfDone()2636   void DestroyTestIfDone() {
2637     if (destroyed_)
2638       return;
2639 
2640     if (got_loading_state_changed_end_) {
2641       if (allow_) {
2642         if (got_load_end_)
2643           DestroyTest();
2644       } else if (got_load_error_) {
2645         DestroyTest();
2646       }
2647     }
2648   }
2649 
DestroyTest()2650   void DestroyTest() override {
2651     if (destroyed_)
2652       return;
2653     destroyed_ = true;
2654 
2655     EXPECT_TRUE(got_before_browse_);
2656     EXPECT_TRUE(got_loading_state_changed_start_);
2657     EXPECT_TRUE(got_loading_state_changed_end_);
2658 
2659     if (allow_) {
2660       EXPECT_TRUE(got_load_start_);
2661       EXPECT_TRUE(got_load_end_);
2662       EXPECT_FALSE(got_load_error_);
2663     } else {
2664       EXPECT_FALSE(got_load_start_);
2665       EXPECT_FALSE(got_load_end_);
2666       EXPECT_TRUE(got_load_error_);
2667     }
2668 
2669     TestHandler::DestroyTest();
2670   }
2671 
2672   bool allow_;
2673   bool destroyed_;
2674 
2675   TrackCallback got_before_browse_;
2676   TrackCallback got_load_start_;
2677   TrackCallback got_load_end_;
2678   TrackCallback got_load_error_;
2679   TrackCallback got_loading_state_changed_start_;
2680   TrackCallback got_loading_state_changed_end_;
2681 
2682   IMPLEMENT_REFCOUNTING(BrowseNavTestHandler);
2683 };
2684 
2685 }  // namespace
2686 
2687 // Test allowing navigation.
TEST(NavigationTest,BrowseAllow)2688 TEST(NavigationTest, BrowseAllow) {
2689   CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(true);
2690   handler->ExecuteTest();
2691   ReleaseAndWaitForDestructor(handler);
2692 }
2693 
2694 // Test denying navigation.
TEST(NavigationTest,BrowseDeny)2695 TEST(NavigationTest, BrowseDeny) {
2696   CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(false);
2697   handler->ExecuteTest();
2698   ReleaseAndWaitForDestructor(handler);
2699 }
2700 
2701 namespace {
2702 
2703 const char kSameNavPageUrl[] = "http://tests-samenav/nav.html";
2704 
2705 // Browser side.
2706 class SameNavTestHandler : public TestHandler {
2707  public:
SameNavTestHandler()2708   SameNavTestHandler() : destroyed_(false), step_(0) {}
2709 
RunTest()2710   void RunTest() override {
2711     AddResource(kSameNavPageUrl, "<html>Test</html>", "text/html");
2712 
2713     // Create the browser.
2714     expected_url_ = kSameNavPageUrl;
2715     CreateBrowser(kSameNavPageUrl);
2716 
2717     // Time out the test after a reasonable period of time.
2718     SetTestTimeout();
2719   }
2720 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2721   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2722                       CefRefPtr<CefFrame> frame,
2723                       CefRefPtr<CefRequest> request,
2724                       bool user_gesture,
2725                       bool is_redirect) override {
2726     const std::string& url = request->GetURL();
2727     EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2728     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2729     EXPECT_TRUE(frame->IsMain());
2730 
2731     got_before_browse_.yes();
2732 
2733     return false;
2734   }
2735 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2736   void OnLoadStart(CefRefPtr<CefBrowser> browser,
2737                    CefRefPtr<CefFrame> frame,
2738                    TransitionType transition_type) override {
2739     const std::string& url = frame->GetURL();
2740     EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2741     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2742     EXPECT_TRUE(frame->IsMain());
2743 
2744     got_load_start_.yes();
2745   }
2746 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2747   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2748                  CefRefPtr<CefFrame> frame,
2749                  int httpStatusCode) override {
2750     const std::string& url = frame->GetURL();
2751     EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2752     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2753     EXPECT_TRUE(frame->IsMain());
2754 
2755     got_load_end_.yes();
2756     ContinueTestIfDone();
2757   }
2758 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2759   void OnLoadError(CefRefPtr<CefBrowser> browser,
2760                    CefRefPtr<CefFrame> frame,
2761                    ErrorCode errorCode,
2762                    const CefString& errorText,
2763                    const CefString& failedUrl) override {
2764     got_load_error_.yes();
2765   }
2766 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2767   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2768                             bool isLoading,
2769                             bool canGoBack,
2770                             bool canGoForward) override {
2771     const std::string& url = browser->GetMainFrame()->GetURL();
2772     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2773 
2774     if (isLoading) {
2775       // Verify the previous URL.
2776       if (step_ == 0)
2777         EXPECT_TRUE(url.empty());
2778       else
2779         EXPECT_STREQ(kSameNavPageUrl, url.c_str());
2780 
2781       got_loading_state_changed_start_.yes();
2782     } else {
2783       EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2784 
2785       got_loading_state_changed_end_.yes();
2786       ContinueTestIfDone();
2787     }
2788   }
2789 
2790  private:
ContinueTestIfDone()2791   void ContinueTestIfDone() {
2792     if (step_ == 0) {
2793       // First navigation should trigger all callbacks except OnLoadError.
2794       if (got_loading_state_changed_end_ && got_load_end_) {
2795         EXPECT_TRUE(got_before_browse_);
2796         EXPECT_TRUE(got_loading_state_changed_start_);
2797         EXPECT_TRUE(got_load_start_);
2798         EXPECT_FALSE(got_load_error_);
2799 
2800         got_before_browse_.reset();
2801         got_loading_state_changed_start_.reset();
2802         got_loading_state_changed_end_.reset();
2803         got_load_start_.reset();
2804         got_load_end_.reset();
2805 
2806         step_++;
2807         expected_url_ = kSameNavPageUrl + std::string("#fragment");
2808         GetBrowser()->GetMainFrame()->LoadURL(expected_url_);
2809       }
2810     } else if (step_ == 1) {
2811       step_++;
2812       DestroyTest();
2813     } else {
2814       EXPECT_TRUE(false);  // Not reached.
2815     }
2816   }
2817 
DestroyTest()2818   void DestroyTest() override {
2819     if (destroyed_)
2820       return;
2821     destroyed_ = true;
2822 
2823     EXPECT_EQ(2, step_);
2824 
2825     // Second (fragment) navigation should only trigger OnLoadingStateChange.
2826     EXPECT_FALSE(got_before_browse_);
2827     EXPECT_TRUE(got_loading_state_changed_start_);
2828     EXPECT_TRUE(got_loading_state_changed_end_);
2829     EXPECT_FALSE(got_load_start_);
2830     EXPECT_FALSE(got_load_end_);
2831     EXPECT_FALSE(got_load_error_);
2832 
2833     TestHandler::DestroyTest();
2834   }
2835 
2836   bool destroyed_;
2837   int step_;
2838   std::string expected_url_;
2839 
2840   TrackCallback got_before_browse_;
2841   TrackCallback got_load_start_;
2842   TrackCallback got_load_end_;
2843   TrackCallback got_load_error_;
2844   TrackCallback got_loading_state_changed_start_;
2845   TrackCallback got_loading_state_changed_end_;
2846 
2847   IMPLEMENT_REFCOUNTING(SameNavTestHandler);
2848 };
2849 
2850 }  // namespace
2851 
2852 // Test that same page navigation does not call OnLoadStart/OnLoadEnd.
TEST(NavigationTest,SamePage)2853 TEST(NavigationTest, SamePage) {
2854   CefRefPtr<SameNavTestHandler> handler = new SameNavTestHandler();
2855   handler->ExecuteTest();
2856   ReleaseAndWaitForDestructor(handler);
2857 }
2858 
2859 namespace {
2860 
2861 const char kCancelPageUrl[] = "http://tests-cancelnav/nav.html";
2862 
2863 // A scheme handler that never starts sending data.
2864 class UnstartedSchemeHandler : public CefResourceHandler {
2865  public:
UnstartedSchemeHandler()2866   UnstartedSchemeHandler() {}
2867 
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)2868   bool Open(CefRefPtr<CefRequest> request,
2869             bool& handle_request,
2870             CefRefPtr<CefCallback> callback) override {
2871     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2872 
2873     // Continue immediately.
2874     handle_request = true;
2875     return true;
2876   }
2877 
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)2878   void GetResponseHeaders(CefRefPtr<CefResponse> response,
2879                           int64& response_length,
2880                           CefString& redirectUrl) override {
2881     response->SetStatus(200);
2882     response->SetMimeType("text/html");
2883     response_length = 100;
2884   }
2885 
Cancel()2886   void Cancel() override { callback_ = nullptr; }
2887 
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)2888   bool Read(void* data_out,
2889             int bytes_to_read,
2890             int& bytes_read,
2891             CefRefPtr<CefResourceReadCallback> callback) override {
2892     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2893 
2894     callback_ = callback;
2895 
2896     // Pretend that we'll provide the data later.
2897     bytes_read = 0;
2898     return true;
2899   }
2900 
2901  protected:
2902   CefRefPtr<CefResourceReadCallback> callback_;
2903 
2904   IMPLEMENT_REFCOUNTING(UnstartedSchemeHandler);
2905   DISALLOW_COPY_AND_ASSIGN(UnstartedSchemeHandler);
2906 };
2907 
2908 // Browser side.
2909 class CancelBeforeNavTestHandler : public TestHandler {
2910  public:
CancelBeforeNavTestHandler()2911   CancelBeforeNavTestHandler() : destroyed_(false) {}
2912 
RunTest()2913   void RunTest() override {
2914     // Create the browser.
2915     CreateBrowser(kCancelPageUrl);
2916 
2917     // Time out the test after a reasonable period of time.
2918     SetTestTimeout();
2919   }
2920 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2921   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2922                       CefRefPtr<CefFrame> frame,
2923                       CefRefPtr<CefRequest> request,
2924                       bool user_gesture,
2925                       bool is_redirect) override {
2926     EXPECT_TRUE(got_loading_state_changed_start_);
2927     EXPECT_FALSE(got_before_browse_);
2928     EXPECT_FALSE(got_get_resource_handler_);
2929     EXPECT_FALSE(got_load_start_);
2930     EXPECT_FALSE(got_cancel_load_);
2931     EXPECT_FALSE(got_load_error_);
2932     EXPECT_FALSE(got_load_end_);
2933     EXPECT_FALSE(got_loading_state_changed_end_);
2934 
2935     const std::string& url = request->GetURL();
2936     EXPECT_STREQ(kCancelPageUrl, url.c_str());
2937     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2938     EXPECT_TRUE(frame->IsMain());
2939 
2940     got_before_browse_.yes();
2941 
2942     return false;
2943   }
2944 
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)2945   CefRefPtr<CefResourceHandler> GetResourceHandler(
2946       CefRefPtr<CefBrowser> browser,
2947       CefRefPtr<CefFrame> frame,
2948       CefRefPtr<CefRequest> request) override {
2949     EXPECT_TRUE(got_loading_state_changed_start_);
2950     EXPECT_TRUE(got_before_browse_);
2951     EXPECT_FALSE(got_get_resource_handler_);
2952     EXPECT_FALSE(got_load_start_);
2953     EXPECT_FALSE(got_cancel_load_);
2954     EXPECT_FALSE(got_load_error_);
2955     EXPECT_FALSE(got_load_end_);
2956     EXPECT_FALSE(got_loading_state_changed_end_);
2957 
2958     const std::string& url = request->GetURL();
2959     EXPECT_STREQ(kCancelPageUrl, url.c_str());
2960     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2961     EXPECT_TRUE(frame->IsMain());
2962 
2963     got_get_resource_handler_.yes();
2964 
2965     CefPostTask(TID_UI,
2966                 base::BindOnce(&CancelBeforeNavTestHandler::CancelLoad, this));
2967 
2968     return new UnstartedSchemeHandler();
2969   }
2970 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2971   void OnLoadStart(CefRefPtr<CefBrowser> browser,
2972                    CefRefPtr<CefFrame> frame,
2973                    TransitionType transition_type) override {
2974     EXPECT_TRUE(false);  // Not reached.
2975     got_load_start_.yes();
2976   }
2977 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2978   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2979                  CefRefPtr<CefFrame> frame,
2980                  int httpStatusCode) override {
2981     EXPECT_TRUE(false);  // Not reached.
2982     got_load_end_.yes();
2983   }
2984 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2985   void OnLoadError(CefRefPtr<CefBrowser> browser,
2986                    CefRefPtr<CefFrame> frame,
2987                    ErrorCode errorCode,
2988                    const CefString& errorText,
2989                    const CefString& failedUrl) override {
2990     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2991     EXPECT_STREQ("", frame->GetURL().ToString().c_str());
2992     EXPECT_EQ(ERR_ABORTED, errorCode);
2993     EXPECT_STREQ(kCancelPageUrl, failedUrl.ToString().c_str());
2994     got_load_error_.yes();
2995   }
2996 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2997   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2998                             bool isLoading,
2999                             bool canGoBack,
3000                             bool canGoForward) override {
3001     const std::string& url = browser->GetMainFrame()->GetURL();
3002     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3003     EXPECT_TRUE(url.empty());
3004 
3005     if (isLoading) {
3006       EXPECT_FALSE(got_loading_state_changed_start_);
3007       EXPECT_FALSE(got_before_browse_);
3008       EXPECT_FALSE(got_get_resource_handler_);
3009       EXPECT_FALSE(got_load_start_);
3010       EXPECT_FALSE(got_cancel_load_);
3011       EXPECT_FALSE(got_load_error_);
3012       EXPECT_FALSE(got_load_end_);
3013       EXPECT_FALSE(got_loading_state_changed_end_);
3014 
3015       got_loading_state_changed_start_.yes();
3016     } else {
3017       EXPECT_TRUE(got_loading_state_changed_start_);
3018       EXPECT_TRUE(got_before_browse_);
3019       EXPECT_TRUE(got_get_resource_handler_);
3020       EXPECT_FALSE(got_load_start_);
3021       EXPECT_TRUE(got_cancel_load_);
3022       EXPECT_TRUE(got_load_error_);
3023       EXPECT_FALSE(got_load_end_);
3024       EXPECT_FALSE(got_loading_state_changed_end_);
3025 
3026       got_loading_state_changed_end_.yes();
3027 
3028       DestroyTest();
3029     }
3030   }
3031 
3032  private:
CancelLoad()3033   void CancelLoad() {
3034     got_cancel_load_.yes();
3035     GetBrowser()->StopLoad();
3036   }
3037 
DestroyTest()3038   void DestroyTest() override {
3039     if (destroyed_)
3040       return;
3041     destroyed_ = true;
3042 
3043     EXPECT_TRUE(got_loading_state_changed_start_);
3044     EXPECT_TRUE(got_before_browse_);
3045     EXPECT_TRUE(got_get_resource_handler_);
3046     EXPECT_FALSE(got_load_start_);
3047     EXPECT_TRUE(got_cancel_load_);
3048     EXPECT_TRUE(got_load_error_);
3049     EXPECT_FALSE(got_load_end_);
3050     EXPECT_TRUE(got_loading_state_changed_end_);
3051 
3052     TestHandler::DestroyTest();
3053   }
3054 
3055   bool destroyed_;
3056 
3057   TrackCallback got_loading_state_changed_start_;
3058   TrackCallback got_before_browse_;
3059   TrackCallback got_get_resource_handler_;
3060   TrackCallback got_load_start_;
3061   TrackCallback got_cancel_load_;
3062   TrackCallback got_load_error_;
3063   TrackCallback got_load_end_;
3064   TrackCallback got_loading_state_changed_end_;
3065 
3066   IMPLEMENT_REFCOUNTING(CancelBeforeNavTestHandler);
3067 };
3068 
3069 }  // namespace
3070 
3071 // Test that navigation canceled before commit does not call
3072 // OnLoadStart/OnLoadEnd.
TEST(NavigationTest,CancelBeforeCommit)3073 TEST(NavigationTest, CancelBeforeCommit) {
3074   CefRefPtr<CancelBeforeNavTestHandler> handler =
3075       new CancelBeforeNavTestHandler();
3076   handler->ExecuteTest();
3077   ReleaseAndWaitForDestructor(handler);
3078 }
3079 
3080 namespace {
3081 
3082 // A scheme handler that stalls after writing some data.
3083 class StalledSchemeHandler : public CefResourceHandler {
3084  public:
StalledSchemeHandler()3085   StalledSchemeHandler() : offset_(0), write_size_(0) {}
3086 
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)3087   bool Open(CefRefPtr<CefRequest> request,
3088             bool& handle_request,
3089             CefRefPtr<CefCallback> callback) override {
3090     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3091 
3092     // Continue immediately.
3093     handle_request = true;
3094     return true;
3095   }
3096 
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)3097   void GetResponseHeaders(CefRefPtr<CefResponse> response,
3098                           int64& response_length,
3099                           CefString& redirectUrl) override {
3100     response->SetStatus(200);
3101     response->SetMimeType("text/html");
3102     content_ = "<html><body>Test</body></html>";
3103     // Write this number of bytes and then stall.
3104     write_size_ = content_.size() / 2U;
3105     response_length = content_.size();
3106   }
3107 
Cancel()3108   void Cancel() override { callback_ = nullptr; }
3109 
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)3110   bool Read(void* data_out,
3111             int bytes_to_read,
3112             int& bytes_read,
3113             CefRefPtr<CefResourceReadCallback> callback) override {
3114     EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3115 
3116     bytes_read = 0;
3117 
3118     size_t size = content_.size();
3119     if (offset_ >= write_size_) {
3120       // Now stall.
3121       callback_ = callback;
3122       return true;
3123     }
3124 
3125     bool has_data = false;
3126 
3127     if (offset_ < size) {
3128       // Write up to |write_size_| bytes.
3129       int transfer_size =
3130           std::min(bytes_to_read, std::min(static_cast<int>(write_size_),
3131                                            static_cast<int>(size - offset_)));
3132       memcpy(data_out, content_.c_str() + offset_, transfer_size);
3133       offset_ += transfer_size;
3134 
3135       bytes_read = transfer_size;
3136       has_data = true;
3137     }
3138 
3139     return has_data;
3140   }
3141 
3142  protected:
3143   std::string content_;
3144   size_t offset_;
3145   size_t write_size_;
3146   CefRefPtr<CefResourceReadCallback> callback_;
3147 
3148   IMPLEMENT_REFCOUNTING(StalledSchemeHandler);
3149   DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler);
3150 };
3151 
3152 // Browser side.
3153 class CancelAfterNavTestHandler : public TestHandler {
3154  public:
CancelAfterNavTestHandler()3155   CancelAfterNavTestHandler() : destroyed_(false) {}
3156 
RunTest()3157   void RunTest() override {
3158     // Create the browser.
3159     CreateBrowser(kCancelPageUrl);
3160 
3161     // Time out the test after a reasonable period of time.
3162     SetTestTimeout();
3163   }
3164 
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)3165   bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
3166                       CefRefPtr<CefFrame> frame,
3167                       CefRefPtr<CefRequest> request,
3168                       bool user_gesture,
3169                       bool is_redirect) override {
3170     EXPECT_TRUE(got_loading_state_changed_start_);
3171     EXPECT_FALSE(got_before_browse_);
3172     EXPECT_FALSE(got_get_resource_handler_);
3173     EXPECT_FALSE(got_load_start_);
3174     EXPECT_FALSE(got_cancel_load_);
3175     EXPECT_FALSE(got_load_error_);
3176     EXPECT_FALSE(got_load_end_);
3177     EXPECT_FALSE(got_loading_state_changed_end_);
3178 
3179     const std::string& url = request->GetURL();
3180     EXPECT_STREQ(kCancelPageUrl, url.c_str());
3181     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3182     EXPECT_TRUE(frame->IsMain());
3183 
3184     got_before_browse_.yes();
3185 
3186     return false;
3187   }
3188 
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)3189   CefRefPtr<CefResourceHandler> GetResourceHandler(
3190       CefRefPtr<CefBrowser> browser,
3191       CefRefPtr<CefFrame> frame,
3192       CefRefPtr<CefRequest> request) override {
3193     EXPECT_TRUE(got_loading_state_changed_start_);
3194     EXPECT_TRUE(got_before_browse_);
3195     EXPECT_FALSE(got_get_resource_handler_);
3196     EXPECT_FALSE(got_load_start_);
3197     EXPECT_FALSE(got_cancel_load_);
3198     EXPECT_FALSE(got_load_error_);
3199     EXPECT_FALSE(got_load_end_);
3200     EXPECT_FALSE(got_loading_state_changed_end_);
3201 
3202     const std::string& url = request->GetURL();
3203     EXPECT_STREQ(kCancelPageUrl, url.c_str());
3204     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3205     EXPECT_TRUE(frame->IsMain());
3206 
3207     got_get_resource_handler_.yes();
3208 
3209     // The required delay is longer when browser-side navigation is enabled.
3210     CefPostDelayedTask(
3211         TID_UI, base::BindOnce(&CancelAfterNavTestHandler::CancelLoad, this),
3212         1000);
3213 
3214     return new StalledSchemeHandler();
3215   }
3216 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)3217   void OnLoadStart(CefRefPtr<CefBrowser> browser,
3218                    CefRefPtr<CefFrame> frame,
3219                    TransitionType transition_type) override {
3220     EXPECT_TRUE(got_loading_state_changed_start_);
3221     EXPECT_TRUE(got_before_browse_);
3222     EXPECT_TRUE(got_get_resource_handler_);
3223     EXPECT_FALSE(got_load_start_);
3224     EXPECT_FALSE(got_cancel_load_);
3225     EXPECT_FALSE(got_load_error_);
3226     EXPECT_FALSE(got_load_end_);
3227     EXPECT_FALSE(got_loading_state_changed_end_);
3228 
3229     const std::string& url = frame->GetURL();
3230     EXPECT_STREQ(kCancelPageUrl, url.c_str());
3231     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3232     EXPECT_TRUE(frame->IsMain());
3233 
3234     got_load_start_.yes();
3235   }
3236 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3237   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3238                  CefRefPtr<CefFrame> frame,
3239                  int httpStatusCode) override {
3240     EXPECT_TRUE(got_loading_state_changed_start_);
3241     EXPECT_TRUE(got_before_browse_);
3242     EXPECT_TRUE(got_get_resource_handler_);
3243     EXPECT_TRUE(got_load_start_);
3244     EXPECT_TRUE(got_cancel_load_);
3245     EXPECT_TRUE(got_load_error_);
3246     EXPECT_FALSE(got_load_end_);
3247     EXPECT_FALSE(got_loading_state_changed_end_);
3248 
3249     const std::string& url = frame->GetURL();
3250     EXPECT_STREQ(kCancelPageUrl, url.c_str());
3251     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3252     EXPECT_TRUE(frame->IsMain());
3253 
3254     got_load_end_.yes();
3255     DestroyTestIfDone();
3256   }
3257 
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)3258   void OnLoadError(CefRefPtr<CefBrowser> browser,
3259                    CefRefPtr<CefFrame> frame,
3260                    ErrorCode errorCode,
3261                    const CefString& errorText,
3262                    const CefString& failedUrl) override {
3263     EXPECT_TRUE(got_loading_state_changed_start_);
3264     EXPECT_TRUE(got_before_browse_);
3265     EXPECT_TRUE(got_get_resource_handler_);
3266     EXPECT_TRUE(got_load_start_);
3267     EXPECT_TRUE(got_cancel_load_);
3268     EXPECT_FALSE(got_load_error_);
3269     EXPECT_FALSE(got_load_end_);
3270     EXPECT_FALSE(got_loading_state_changed_end_);
3271 
3272     const std::string& url = failedUrl;
3273     EXPECT_STREQ(kCancelPageUrl, url.c_str());
3274     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3275     EXPECT_TRUE(frame->IsMain());
3276 
3277     got_load_error_.yes();
3278   }
3279 
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)3280   void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
3281                             bool isLoading,
3282                             bool canGoBack,
3283                             bool canGoForward) override {
3284     const std::string& url = browser->GetMainFrame()->GetURL();
3285     EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3286 
3287     if (isLoading) {
3288       EXPECT_FALSE(got_loading_state_changed_start_);
3289       EXPECT_FALSE(got_before_browse_);
3290       EXPECT_FALSE(got_get_resource_handler_);
3291       EXPECT_FALSE(got_load_start_);
3292       EXPECT_FALSE(got_cancel_load_);
3293       EXPECT_FALSE(got_load_error_);
3294       EXPECT_FALSE(got_load_end_);
3295       EXPECT_FALSE(got_loading_state_changed_end_);
3296 
3297       EXPECT_TRUE(url.empty());
3298 
3299       got_loading_state_changed_start_.yes();
3300     } else {
3301       EXPECT_TRUE(got_loading_state_changed_start_);
3302       EXPECT_TRUE(got_before_browse_);
3303       EXPECT_TRUE(got_get_resource_handler_);
3304       EXPECT_TRUE(got_load_start_);
3305       EXPECT_TRUE(got_cancel_load_);
3306       EXPECT_TRUE(got_load_error_);
3307       EXPECT_TRUE(got_load_end_);
3308       EXPECT_FALSE(got_loading_state_changed_end_);
3309 
3310       EXPECT_STREQ(kCancelPageUrl, url.c_str());
3311 
3312       got_loading_state_changed_end_.yes();
3313       DestroyTestIfDone();
3314     }
3315   }
3316 
3317  private:
CancelLoad()3318   void CancelLoad() {
3319     got_cancel_load_.yes();
3320     GetBrowser()->StopLoad();
3321   }
3322 
DestroyTestIfDone()3323   void DestroyTestIfDone() {
3324     if (got_loading_state_changed_end_ && got_load_end_)
3325       DestroyTest();
3326   }
3327 
DestroyTest()3328   void DestroyTest() override {
3329     if (destroyed_)
3330       return;
3331     destroyed_ = true;
3332 
3333     EXPECT_TRUE(got_loading_state_changed_start_);
3334     EXPECT_TRUE(got_before_browse_);
3335     EXPECT_TRUE(got_get_resource_handler_);
3336     EXPECT_TRUE(got_load_start_);
3337     EXPECT_TRUE(got_cancel_load_);
3338     EXPECT_TRUE(got_load_error_);
3339     EXPECT_TRUE(got_load_end_);
3340     EXPECT_TRUE(got_loading_state_changed_end_);
3341 
3342     TestHandler::DestroyTest();
3343   }
3344 
3345   bool destroyed_;
3346 
3347   TrackCallback got_loading_state_changed_start_;
3348   TrackCallback got_before_browse_;
3349   TrackCallback got_get_resource_handler_;
3350   TrackCallback got_load_start_;
3351   TrackCallback got_cancel_load_;
3352   TrackCallback got_load_error_;
3353   TrackCallback got_load_end_;
3354   TrackCallback got_loading_state_changed_end_;
3355 
3356   IMPLEMENT_REFCOUNTING(CancelAfterNavTestHandler);
3357 };
3358 
3359 }  // namespace
3360 
3361 // Test that navigation canceled after commit calls everything.
TEST(NavigationTest,CancelAfterCommit)3362 TEST(NavigationTest, CancelAfterCommit) {
3363   CefRefPtr<CancelAfterNavTestHandler> handler =
3364       new CancelAfterNavTestHandler();
3365   handler->ExecuteTest();
3366   ReleaseAndWaitForDestructor(handler);
3367 }
3368 
3369 namespace {
3370 
3371 const char kExtraInfoUrl[] = "http://tests-extrainfonav.com/extra.html";
3372 const char kExtraInfoPopupUrl[] =
3373     "http://tests-extrainfonav.com/extra_popup.html";
3374 const char kExtraInfoNavMsg[] = "NavigationTest.ExtraInfoNav";
3375 const char kExtraInfoTestCmdKey[] = "nav-extra-info-test";
3376 
SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info)3377 void SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info) {
3378   // Necessary for identifying the test case.
3379   extra_info->SetBool(kExtraInfoTestCmdKey, true);
3380 
3381   // Arbitrary data for testing.
3382   extra_info->SetBool("bool", true);
3383   CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
3384   dict->SetInt("key1", 5);
3385   dict->SetString("key2", "test string");
3386   extra_info->SetDictionary("dictionary", dict);
3387   extra_info->SetDouble("double", 5.43322);
3388   extra_info->SetString("string", "some string");
3389 }
3390 
3391 // Renderer side
3392 class ExtraInfoNavRendererTest : public ClientAppRenderer::Delegate {
3393  public:
ExtraInfoNavRendererTest()3394   ExtraInfoNavRendererTest() : run_test_(false) {}
3395 
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)3396   void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
3397                         CefRefPtr<CefBrowser> browser,
3398                         CefRefPtr<CefDictionaryValue> extra_info) override {
3399     run_test_ = extra_info && extra_info->HasKey(kExtraInfoTestCmdKey);
3400     if (!run_test_)
3401       return;
3402 
3403     CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
3404     SetBrowserExtraInfo(expected);
3405     TestDictionaryEqual(expected, extra_info);
3406 
3407     SendTestResults(browser, browser->GetMainFrame());
3408   }
3409 
3410  protected:
3411   // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)3412   void SendTestResults(CefRefPtr<CefBrowser> browser,
3413                        CefRefPtr<CefFrame> frame) {
3414     // Check if the test has failed.
3415     bool result = !TestFailed();
3416 
3417     CefRefPtr<CefProcessMessage> return_msg =
3418         CefProcessMessage::Create(kExtraInfoNavMsg);
3419     CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
3420     EXPECT_TRUE(args.get());
3421     EXPECT_TRUE(args->SetBool(0, result));
3422     EXPECT_TRUE(args->SetBool(1, browser->IsPopup()));
3423     frame->SendProcessMessage(PID_BROWSER, return_msg);
3424   }
3425 
3426   bool run_test_;
3427 
3428   IMPLEMENT_REFCOUNTING(ExtraInfoNavRendererTest);
3429 };
3430 
3431 class ExtraInfoNavTestHandler : public TestHandler {
3432  public:
ExtraInfoNavTestHandler()3433   ExtraInfoNavTestHandler() : popup_opened_(false) {}
3434 
RunTest()3435   void RunTest() override {
3436     AddResource(kExtraInfoUrl,
3437                 "<html><head></head><body>ExtraInfo</body></html>",
3438                 "text/html");
3439     AddResource(kExtraInfoPopupUrl, "<html>ExtraInfoPopup</html>", "text/html");
3440 
3441     CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
3442     SetBrowserExtraInfo(extra_info);
3443 
3444     // Create the browser.
3445     CreateBrowser(kExtraInfoUrl, nullptr, extra_info);
3446 
3447     // Time out the test after a reasonable period of time.
3448     SetTestTimeout();
3449   }
3450 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3451   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3452                  CefRefPtr<CefFrame> frame,
3453                  int httpStatusCode) override {
3454     if (popup_opened_) {
3455       DestroyTest();
3456     } else {
3457       browser->GetMainFrame()->ExecuteJavaScript(
3458           "window.open('" + std::string(kExtraInfoPopupUrl) + "');",
3459           CefString(), 0);
3460     }
3461   }
3462 
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,const CefString & target_frame_name,cef_window_open_disposition_t target_disposition,bool user_gesture,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)3463   bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
3464                      CefRefPtr<CefFrame> frame,
3465                      const CefString& target_url,
3466                      const CefString& target_frame_name,
3467                      cef_window_open_disposition_t target_disposition,
3468                      bool user_gesture,
3469                      const CefPopupFeatures& popupFeatures,
3470                      CefWindowInfo& windowInfo,
3471                      CefRefPtr<CefClient>& client,
3472                      CefBrowserSettings& settings,
3473                      CefRefPtr<CefDictionaryValue>& extra_info,
3474                      bool* no_javascript_access) override {
3475     const std::string& url = target_url;
3476     EXPECT_FALSE(popup_opened_);
3477     EXPECT_STREQ(kExtraInfoPopupUrl, url.c_str());
3478 
3479     CefRefPtr<CefDictionaryValue> extra = CefDictionaryValue::Create();
3480     SetBrowserExtraInfo(extra);
3481 
3482     extra_info = extra;
3483 
3484     popup_opened_ = true;
3485     return false;
3486   }
3487 
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)3488   bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
3489                                 CefRefPtr<CefFrame> frame,
3490                                 CefProcessId source_process,
3491                                 CefRefPtr<CefProcessMessage> message) override {
3492     if (message->GetName().ToString() == kExtraInfoNavMsg) {
3493       // Test that the renderer side succeeded.
3494       CefRefPtr<CefListValue> args = message->GetArgumentList();
3495       EXPECT_TRUE(args.get());
3496       EXPECT_TRUE(args->GetBool(0));
3497       if (popup_opened_) {
3498         EXPECT_TRUE(args->GetBool(1));
3499         got_process_message_popup_.yes();
3500       } else {
3501         EXPECT_FALSE(args->GetBool(1));
3502         got_process_message_main_.yes();
3503       }
3504       return true;
3505     }
3506 
3507     // Message not handled.
3508     return false;
3509   }
3510 
3511  protected:
3512   bool popup_opened_;
3513   TrackCallback got_process_message_main_;
3514   TrackCallback got_process_message_popup_;
3515 
DestroyTest()3516   void DestroyTest() override {
3517     // Verify test expectations.
3518     EXPECT_TRUE(got_process_message_main_);
3519     EXPECT_TRUE(got_process_message_popup_);
3520 
3521     TestHandler::DestroyTest();
3522   }
3523 
3524   IMPLEMENT_REFCOUNTING(ExtraInfoNavTestHandler);
3525 };
3526 
3527 }  // namespace
3528 
TEST(NavigationTest,ExtraInfo)3529 TEST(NavigationTest, ExtraInfo) {
3530   CefRefPtr<ExtraInfoNavTestHandler> handler = new ExtraInfoNavTestHandler();
3531   handler->ExecuteTest();
3532   ReleaseAndWaitForDestructor(handler);
3533 }
3534 
3535 // Entry point for creating navigation renderer test objects.
3536 // Called from client_app_delegates.cc.
CreateNavigationRendererTests(ClientAppRenderer::DelegateSet & delegates)3537 void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet& delegates) {
3538   delegates.insert(new HistoryNavRendererTest);
3539   delegates.insert(new OrderNavRendererTest);
3540   delegates.insert(new LoadNavRendererTest);
3541   delegates.insert(new ExtraInfoNavRendererTest);
3542 }
3543