• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be found
3 // in the LICENSE file.
4 
5 #include <limits>
6 #include <map>
7 #include <memory>
8 #include <queue>
9 #include <sstream>
10 #include <string>
11 
12 #include "include/base/cef_callback.h"
13 #include "include/wrapper/cef_closure_task.h"
14 #include "tests/ceftests/routing_test_handler.h"
15 #include "tests/ceftests/test_handler.h"
16 #include "tests/gtest/include/gtest/gtest.h"
17 
18 // Set to 1 to enable verbose debugging info logging.
19 #define VERBOSE_DEBUGGING 0
20 
21 namespace {
22 
23 // Must match CefFrameHostImpl::kInvalidFrameId.
24 const int kInvalidFrameId = -4;
25 
26 // Tracks callback status for a single frame object.
27 struct FrameStatus {
28   // Callbacks in expected order. Not all callbacks are executed in all cases
29   // (see IsExpectedCallback).
30   enum CallbackType {
31     FRAME_CREATED,
32     MAIN_FRAME_INITIAL_ASSIGNED,
33     AFTER_CREATED,
34     FRAME_ATTACHED,
35     MAIN_FRAME_CHANGED_ASSIGNED,
36     LOAD_START,
37     LOAD_END,
38     BEFORE_CLOSE,
39     FRAME_DETACHED,
40     MAIN_FRAME_CHANGED_REMOVED,
41     MAIN_FRAME_FINAL_REMOVED,
42 
43     CALLBACK_LAST = MAIN_FRAME_FINAL_REMOVED,
44   };
45 
GetCallbackName__anon37f9906d0111::FrameStatus46   static const char* GetCallbackName(int type) {
47     switch (type) {
48       case FRAME_CREATED:
49         return "OnFrameCreated";
50       case MAIN_FRAME_INITIAL_ASSIGNED:
51         return "OnMainFrameChanged(initial_assigned)";
52       case AFTER_CREATED:
53         return "OnAfterCreated";
54       case FRAME_ATTACHED:
55         return "OnFrameAttached";
56       case MAIN_FRAME_CHANGED_ASSIGNED:
57         return "OnMainFrameChanged(changed_assigned)";
58       case LOAD_START:
59         return "OnLoadStart";
60       case LOAD_END:
61         return "OnLoadEnd";
62       case BEFORE_CLOSE:
63         return "OnBeforeClose";
64       case FRAME_DETACHED:
65         return "OnFrameDetached";
66       case MAIN_FRAME_CHANGED_REMOVED:
67         return "OnMainFrameChanged(changed_removed)";
68       case MAIN_FRAME_FINAL_REMOVED:
69         return "OnMainFrameChanged(final_removed)";
70     }
71     NOTREACHED();
72     return "Unknown";
73   }
74 
75   // Returns true for callbacks that should only execute for main frames.
IsMainFrameOnlyCallback__anon37f9906d0111::FrameStatus76   static bool IsMainFrameOnlyCallback(int type) {
77     return (type == MAIN_FRAME_INITIAL_ASSIGNED || type == AFTER_CREATED ||
78             type == MAIN_FRAME_CHANGED_ASSIGNED || type == BEFORE_CLOSE ||
79             type == MAIN_FRAME_CHANGED_REMOVED ||
80             type == MAIN_FRAME_FINAL_REMOVED);
81   }
82 
GetFrameDebugString__anon37f9906d0111::FrameStatus83   static std::string GetFrameDebugString(CefRefPtr<CefFrame> frame) {
84     // Match the logic in frame_util::GetFrameDebugString.
85     // Specific formulation of the frame ID is an implementation detail that
86     // should generally not be relied upon, but this decomposed format makes the
87     // debug logging easier to follow.
88     uint64 frame_id = frame->GetIdentifier();
89     uint32_t process_id = frame_id >> 32;
90     uint32_t routing_id = std::numeric_limits<uint32_t>::max() & frame_id;
91     std::stringstream ss;
92     ss << (frame->IsMain() ? "main" : " sub") << "[" << process_id << ","
93        << routing_id << "]";
94     return ss.str();
95   }
96 
FrameStatus__anon37f9906d0111::FrameStatus97   FrameStatus(CefRefPtr<CefFrame> frame)
98       : frame_id_(frame->GetIdentifier()),
99         is_main_(frame->IsMain()),
100         ident_str_(GetFrameDebugString(frame)) {}
101 
frame_id__anon37f9906d0111::FrameStatus102   int64 frame_id() const { return frame_id_; }
is_main__anon37f9906d0111::FrameStatus103   bool is_main() const { return is_main_; }
104 
AllQueriesDelivered__anon37f9906d0111::FrameStatus105   bool AllQueriesDelivered(std::string* msg = nullptr) const {
106     EXPECT_UI_THREAD();
107     const int expected_ct = is_temporary_ ? 0 : expected_query_ct_;
108 #if VERBOSE_DEBUGGING
109     if (msg) {
110       std::stringstream ss;
111       ss << ident_str_ << "(expected=" << expected_ct
112          << " delivered=" << delivered_query_ct_ << ")";
113       *msg += ss.str();
114     }
115 #endif
116     return delivered_query_ct_ == expected_ct;
117   }
QueriesDeliveredCount__anon37f9906d0111::FrameStatus118   int QueriesDeliveredCount() const {
119     EXPECT_UI_THREAD();
120     return delivered_query_ct_;
121   }
122 
IsSame__anon37f9906d0111::FrameStatus123   bool IsSame(CefRefPtr<CefFrame> frame) const {
124     return frame->GetIdentifier() == frame_id();
125   }
126 
IsLoaded__anon37f9906d0111::FrameStatus127   bool IsLoaded(std::string* msg = nullptr) const {
128 #if VERBOSE_DEBUGGING
129     if (msg) {
130       std::stringstream ss;
131       ss << ident_str_ << "(";
132       for (int i = 0; i <= LOAD_END; ++i) {
133         ss << GetCallbackName(i) << "=" << got_callback_[i];
134         if (i < LOAD_END)
135           ss << " ";
136       }
137       ss << ")";
138       *msg += ss.str();
139     }
140 #endif
141     return got_callback_[LOAD_END];
142   }
IsDetached__anon37f9906d0111::FrameStatus143   bool IsDetached() const { return got_callback_[FRAME_DETACHED]; }
144 
SetIsFirstMain__anon37f9906d0111::FrameStatus145   void SetIsFirstMain(bool val) {
146     EXPECT_TRUE(is_main_);
147     is_first_main_ = val;
148     if (is_first_main_) {
149       // Also expect OnAfterCreated
150       expected_query_ct_++;
151     }
152   }
SetIsLastMain__anon37f9906d0111::FrameStatus153   void SetIsLastMain(bool val) {
154     EXPECT_TRUE(is_main_);
155     is_last_main_ = val;
156   }
157 
SetIsTemporary__anon37f9906d0111::FrameStatus158   void SetIsTemporary(bool val) {
159     EXPECT_FALSE(is_main_);
160     is_temporary_ = val;
161   }
IsTemporary__anon37f9906d0111::FrameStatus162   bool IsTemporary() const { return is_temporary_; }
163 
SetAdditionalDebugInfo__anon37f9906d0111::FrameStatus164   void SetAdditionalDebugInfo(const std::string& debug_info) {
165     debug_info_ = debug_info;
166   }
167 
GetDebugString__anon37f9906d0111::FrameStatus168   std::string GetDebugString() const { return debug_info_ + ident_str_; }
169 
170   // The main frame will be reused for same-origin navigations.
ResetMainLoadStatus__anon37f9906d0111::FrameStatus171   void ResetMainLoadStatus() {
172     EXPECT_TRUE(is_main_);
173 
174     ResetCallbackStatus(LOAD_START, /*expect_query=*/true);
175     ResetCallbackStatus(LOAD_END, /*expect_query=*/true);
176   }
177 
OnFrameCreated__anon37f9906d0111::FrameStatus178   void OnFrameCreated(CefRefPtr<CefBrowser> browser,
179                       CefRefPtr<CefFrame> frame) {
180     EXPECT_UI_THREAD();
181     VerifyBrowser(__FUNCTION__, browser);
182     VerifyFrame(__FUNCTION__, frame);
183 
184     GotCallback(__FUNCTION__, FRAME_CREATED);
185 
186     // Test delivery of messages using a frame that isn't connected yet.
187     // This tests queuing of messages in the browser process and possibly the
188     // renderer process.
189     ExecuteQuery(frame, FRAME_CREATED);
190   }
191 
OnFrameAttached__anon37f9906d0111::FrameStatus192   void OnFrameAttached(CefRefPtr<CefBrowser> browser,
193                        CefRefPtr<CefFrame> frame) {
194     EXPECT_UI_THREAD();
195     VerifyBrowser(__FUNCTION__, browser);
196     VerifyFrame(__FUNCTION__, frame);
197 
198     GotCallback(__FUNCTION__, FRAME_ATTACHED);
199 
200     // Test delivery of messages using a frame that just connected.
201     // This tests queuing of messages in the browser process and possibly the
202     // renderer process.
203     ExecuteQuery(frame, FRAME_ATTACHED);
204   }
205 
OnFrameDetached__anon37f9906d0111::FrameStatus206   void OnFrameDetached(CefRefPtr<CefBrowser> browser,
207                        CefRefPtr<CefFrame> frame) {
208     EXPECT_UI_THREAD();
209     VerifyBrowser(__FUNCTION__, browser);
210     // A frame is never valid after it's detached.
211     VerifyFrame(__FUNCTION__, frame, /*expect_valid=*/false);
212 
213     GotCallback(__FUNCTION__, FRAME_DETACHED);
214   }
215 
OnMainFrameChanged__anon37f9906d0111::FrameStatus216   void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
217                           CefRefPtr<CefFrame> old_frame,
218                           CefRefPtr<CefFrame> new_frame) {
219     EXPECT_UI_THREAD();
220     EXPECT_TRUE(is_main_);
221     VerifyBrowser(__FUNCTION__, browser);
222 
223     bool got_match = false;
224 
225     if (old_frame && new_frame) {
226       EXPECT_NE(old_frame->GetIdentifier(), new_frame->GetIdentifier());
227     }
228 
229     if (old_frame && IsSame(old_frame)) {
230       got_match = true;
231       // A frame is never valid after it's detached.
232       VerifyFrame(__FUNCTION__, old_frame, /*expect_valid=*/false);
233       GotCallback(__FUNCTION__, new_frame ? MAIN_FRAME_CHANGED_REMOVED
234                                           : MAIN_FRAME_FINAL_REMOVED);
235       if (is_last_main_) {
236         EXPECT_FALSE(new_frame);
237       }
238     }
239 
240     if (new_frame && IsSame(new_frame)) {
241       got_match = true;
242       VerifyFrame(__FUNCTION__, new_frame);
243       GotCallback(__FUNCTION__, old_frame ? MAIN_FRAME_CHANGED_ASSIGNED
244                                           : MAIN_FRAME_INITIAL_ASSIGNED);
245       if (is_first_main_) {
246         EXPECT_FALSE(old_frame);
247       }
248     }
249 
250     EXPECT_TRUE(got_match);
251   }
252 
OnAfterCreated__anon37f9906d0111::FrameStatus253   void OnAfterCreated(CefRefPtr<CefBrowser> browser) {
254     EXPECT_UI_THREAD();
255     VerifyBrowser(__FUNCTION__, browser);
256 
257     auto frame = browser->GetMainFrame();
258     VerifyFrame(__FUNCTION__, frame);
259 
260     GotCallback(__FUNCTION__, AFTER_CREATED);
261     ExecuteQuery(frame, AFTER_CREATED);
262   }
263 
264   // Called for all existing frames, not just the target frame.
265   // We need to track this status to know if the browser should be valid in
266   // following calls to OnFrameDetached.
OnBeforeClose__anon37f9906d0111::FrameStatus267   void OnBeforeClose(CefRefPtr<CefBrowser> browser) {
268     EXPECT_UI_THREAD();
269     VerifyBrowser(__FUNCTION__, browser);
270 
271     auto frame = browser->GetMainFrame();
272     EXPECT_TRUE(frame->IsValid());
273 
274     got_before_close_ = true;
275     if (IsSame(frame)) {
276       VerifyFrame(__FUNCTION__, frame);
277       GotCallback(__FUNCTION__, BEFORE_CLOSE);
278     }
279   }
280 
OnLoadStart__anon37f9906d0111::FrameStatus281   void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
282     EXPECT_UI_THREAD();
283     VerifyBrowser(__FUNCTION__, browser);
284     VerifyFrame(__FUNCTION__, frame);
285 
286     GotCallback(__FUNCTION__, LOAD_START);
287     ExecuteQuery(frame, LOAD_START);
288   }
289 
OnLoadEnd__anon37f9906d0111::FrameStatus290   void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
291     EXPECT_UI_THREAD();
292     VerifyBrowser(__FUNCTION__, browser);
293     VerifyFrame(__FUNCTION__, frame);
294 
295     GotCallback(__FUNCTION__, LOAD_END);
296     ExecuteQuery(frame, LOAD_END);
297   }
298 
OnQuery__anon37f9906d0111::FrameStatus299   void OnQuery(CefRefPtr<CefBrowser> browser,
300                CefRefPtr<CefFrame> frame,
301                const CefString& request) {
302     EXPECT_UI_THREAD();
303 
304     const std::string& received_query = request;
305 
306 #if VERBOSE_DEBUGGING
307     LOG(INFO) << GetDebugString() << " recv query " << received_query << " ("
308               << (delivered_query_ct_ + 1) << " of " << expected_query_ct_
309               << ")";
310 #endif
311 
312     VerifyBrowser(__FUNCTION__, browser);
313     VerifyFrame(__FUNCTION__, frame);
314 
315     EXPECT_GE(pending_queries_.size(), 1U);
316     const std::string& expected_query = pending_queries_.front();
317     EXPECT_STREQ(expected_query.c_str(), received_query.c_str());
318     if (expected_query == received_query)
319       pending_queries_.pop();
320 
321     EXPECT_LT(delivered_query_ct_, expected_query_ct_);
322     delivered_query_ct_++;
323   }
324 
VerifyTestResults__anon37f9906d0111::FrameStatus325   void VerifyTestResults() {
326     EXPECT_UI_THREAD();
327 
328     // Verify that all expected callbacks have executed.
329     VerifyCallbackStatus(__FUNCTION__, CALLBACK_LAST + 1);
330 
331     if (is_temporary_) {
332       // Should not receive any queries.
333       EXPECT_FALSE(is_main_);
334       EXPECT_EQ(0, delivered_query_ct_);
335     } else {
336       // Verify that all expected messages have been sent and received.
337       EXPECT_EQ(expected_query_ct_, delivered_query_ct_);
338       EXPECT_EQ(0U, pending_queries_.size());
339       while (!pending_queries_.empty()) {
340         ADD_FAILURE() << "Query sent but not received: "
341                       << pending_queries_.front();
342         pending_queries_.pop();
343       }
344     }
345   }
346 
DidGetCallback__anon37f9906d0111::FrameStatus347   bool DidGetCallback(int callback) const { return got_callback_[callback]; }
348 
349  private:
GotCallback__anon37f9906d0111::FrameStatus350   void GotCallback(const std::string& func, int callback) {
351 #if VERBOSE_DEBUGGING
352     LOG(INFO) << GetDebugString() << " callback " << GetCallbackName(callback);
353 #endif
354 
355     EXPECT_TRUE(IsExpectedCallback(callback)) << func;
356     VerifyCallbackStatus(func, callback);
357     got_callback_[callback].yes();
358   }
359 
IsExpectedCallback__anon37f9906d0111::FrameStatus360   bool IsExpectedCallback(int callback) const {
361     if (!is_main_ && IsMainFrameOnlyCallback(callback))
362       return false;
363 
364     if (is_main_) {
365       if ((callback == MAIN_FRAME_INITIAL_ASSIGNED ||
366            callback == AFTER_CREATED) &&
367           !is_first_main_) {
368         return false;
369       }
370       if ((callback == BEFORE_CLOSE || callback == MAIN_FRAME_FINAL_REMOVED) &&
371           !is_last_main_) {
372         return false;
373       }
374       if (callback == MAIN_FRAME_CHANGED_ASSIGNED && is_first_main_) {
375         return false;
376       }
377       if (callback == MAIN_FRAME_CHANGED_REMOVED && is_last_main_) {
378         return false;
379       }
380     } else if (is_temporary_) {
381       // For cross-process sub-frame navigation a sub-frame is first created in
382       // the parent's renderer process. That sub-frame is then discarded after
383       // the real cross-origin sub-frame is created in a different renderer
384       // process. These discarded sub-frames will get OnFrameCreated/
385       // OnFrameAttached immediately followed by OnFrameDetached.
386       return callback == FRAME_CREATED || callback == FRAME_ATTACHED ||
387              callback == FRAME_DETACHED;
388     }
389 
390     return true;
391   }
392 
VerifyCallbackStatus__anon37f9906d0111::FrameStatus393   void VerifyCallbackStatus(const std::string& func,
394                             int current_callback) const {
395     EXPECT_UI_THREAD();
396 
397     for (int i = 0; i <= CALLBACK_LAST; ++i) {
398       if (i < current_callback && IsExpectedCallback(i)) {
399         EXPECT_TRUE(got_callback_[i])
400             << "inside " << func << " should already have gotten "
401             << GetCallbackName(i);
402       } else {
403         EXPECT_FALSE(got_callback_[i])
404             << "inside " << func << " should not already have gotten "
405             << GetCallbackName(i);
406       }
407     }
408   }
409 
VerifyBrowser__anon37f9906d0111::FrameStatus410   void VerifyBrowser(const std::string& func,
411                      CefRefPtr<CefBrowser> browser) const {
412     const bool expect_valid = !got_before_close_;
413     if (expect_valid) {
414       EXPECT_TRUE(browser->IsValid()) << func;
415     } else {
416       EXPECT_FALSE(browser->IsValid()) << func;
417     }
418 
419     // Note that this might not be the same main frame as us when navigating
420     // cross-origin, because the new main frame object is assigned to the
421     // browser before the CefFrameHandler callbacks related to main frame change
422     // have executed. This started out as an implementation detail but it fits
423     // nicely with the concept that "GetMainFrame() always returns a frame that
424     // can be used", which wouldn't be the case if we returned the old frame
425     // when calling GetMainFrame() from inside OnFrameCreated (for the new
426     // frame), OnFrameDetached (for the old frame) or OnMainFrameChanged.
427     auto main_frame = browser->GetMainFrame();
428     if (expect_valid) {
429       EXPECT_TRUE(main_frame) << func;
430       EXPECT_TRUE(main_frame->IsValid()) << func;
431       EXPECT_TRUE(main_frame->IsMain()) << func;
432     } else {
433       // GetMainFrame() returns nullptr after OnBeforeClose.
434       EXPECT_FALSE(main_frame) << func;
435     }
436   }
437 
VerifyFrame__anon37f9906d0111::FrameStatus438   void VerifyFrame(const std::string& func,
439                    CefRefPtr<CefFrame> frame,
440                    bool expect_valid = true) const {
441     if (expect_valid) {
442       EXPECT_TRUE(frame->IsValid()) << func;
443     } else {
444       EXPECT_FALSE(frame->IsValid()) << func;
445     }
446 
447     // |frame| should be us. This checks the frame type and ID.
448     EXPECT_STREQ(ident_str_.c_str(), GetFrameDebugString(frame).c_str())
449         << func;
450   }
451 
ExecuteQuery__anon37f9906d0111::FrameStatus452   void ExecuteQuery(CefRefPtr<CefFrame> frame, int callback) {
453     EXPECT_UI_THREAD();
454     const std::string& value = GetCallbackName(callback);
455 
456     std::string js_string;
457 
458 #if VERBOSE_DEBUGGING
459     LOG(INFO) << GetDebugString() << " sent query " << value;
460     js_string +=
461         "console.log('" + GetDebugString() + " exec query " + value + "');";
462 #endif
463 
464     js_string += "window.testQuery({request:'" + value + "'});";
465 
466     pending_queries_.push(value);
467 
468     // GetURL() will return an empty string for early callbacks, but that
469     // doesn't appear to cause any issues.
470     frame->ExecuteJavaScript(js_string, frame->GetURL(), 0);
471   }
472 
473   // Reset state so we can get the same callback again.
ResetCallbackStatus__anon37f9906d0111::FrameStatus474   void ResetCallbackStatus(int callback, bool expect_query) {
475     EXPECT_UI_THREAD();
476 
477     EXPECT_TRUE(got_callback_[callback]) << GetCallbackName(callback);
478     got_callback_[callback].reset();
479 
480     if (expect_query)
481       delivered_query_ct_--;
482   }
483 
484   const int64 frame_id_;
485   const bool is_main_;
486   const std::string ident_str_;
487 
488   bool is_first_main_ = false;
489   bool is_last_main_ = false;
490   bool is_temporary_ = false;
491   std::string debug_info_;
492 
493   bool got_before_close_ = false;
494 
495   TrackCallback got_callback_[CALLBACK_LAST + 1];
496 
497   std::queue<std::string> pending_queries_;
498 
499   // Expect OnCreated, OnAttached, OnLoadStart, OnLoadEnd.
500   int expected_query_ct_ = 4;
501   int delivered_query_ct_ = 0;
502 };
503 
504 const char kOrderMainUrl[] = "http://tests-frame-handler/main-order.html";
505 
506 class OrderMainTestHandler : public RoutingTestHandler, public CefFrameHandler {
507  public:
OrderMainTestHandler(CompletionState * completion_state=nullptr)508   OrderMainTestHandler(CompletionState* completion_state = nullptr)
509       : RoutingTestHandler(completion_state) {}
510 
GetFrameHandler()511   CefRefPtr<CefFrameHandler> GetFrameHandler() override {
512     get_frame_handler_ct_++;
513     return this;
514   }
515 
RunTest()516   void RunTest() override {
517     // Add the main resource that we will navigate to/from.
518     AddResource(GetMainURL(), GetMainHtml(), "text/html");
519 
520     // Create the browser.
521     CreateBrowser(GetMainURL());
522 
523     // Time out the test after a reasonable period of time.
524     SetTestTimeout();
525   }
526 
OnAfterCreated(CefRefPtr<CefBrowser> browser)527   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
528     EXPECT_UI_THREAD();
529     RoutingTestHandler::OnAfterCreated(browser);
530 
531     EXPECT_FALSE(got_after_created_);
532     got_after_created_ = true;
533 
534     EXPECT_TRUE(current_main_frame_);
535     current_main_frame_->OnAfterCreated(browser);
536   }
537 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)538   void OnLoadStart(CefRefPtr<CefBrowser> browser,
539                    CefRefPtr<CefFrame> frame,
540                    TransitionType transition_type) override {
541     EXPECT_UI_THREAD();
542     RoutingTestHandler::OnLoadStart(browser, frame, transition_type);
543 
544     EXPECT_TRUE(current_main_frame_);
545     current_main_frame_->OnLoadStart(browser, frame);
546   }
547 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)548   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
549                  CefRefPtr<CefFrame> frame,
550                  int httpStatusCode) override {
551     EXPECT_UI_THREAD();
552     RoutingTestHandler::OnLoadEnd(browser, frame, httpStatusCode);
553 
554     EXPECT_TRUE(current_main_frame_);
555     current_main_frame_->OnLoadEnd(browser, frame);
556 
557     MaybeDestroyTest();
558   }
559 
OnBeforeClose(CefRefPtr<CefBrowser> browser)560   void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
561     EXPECT_UI_THREAD();
562 
563     EXPECT_FALSE(got_before_close_);
564     got_before_close_ = true;
565 
566     EXPECT_TRUE(current_main_frame_);
567     current_main_frame_->OnBeforeClose(browser);
568 
569     RoutingTestHandler::OnBeforeClose(browser);
570   }
571 
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)572   bool OnQuery(CefRefPtr<CefBrowser> browser,
573                CefRefPtr<CefFrame> frame,
574                int64 query_id,
575                const CefString& request,
576                bool persistent,
577                CefRefPtr<Callback> callback) override {
578     EXPECT_UI_THREAD();
579 
580     // Messages for the old and new frames are interleaved during cross-origin
581     // navigation.
582     if (pending_main_frame_) {
583       EXPECT_TRUE(IsCrossOrigin());
584       pending_main_frame_->OnQuery(browser, frame, request);
585     } else {
586       EXPECT_TRUE(current_main_frame_);
587       current_main_frame_->OnQuery(browser, frame, request);
588     }
589 
590     MaybeDestroyTest();
591     return true;
592   }
593 
OnFrameCreated(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)594   void OnFrameCreated(CefRefPtr<CefBrowser> browser,
595                       CefRefPtr<CefFrame> frame) override {
596     EXPECT_UI_THREAD();
597 
598     EXPECT_TRUE(frame->IsMain());
599     EXPECT_FALSE(pending_main_frame_);
600 
601     // First callback referencing the new frame.
602     pending_main_frame_ = new FrameStatus(frame);
603     pending_main_frame_->SetAdditionalDebugInfo(GetAdditionalDebugInfo());
604     pending_main_frame_->SetIsFirstMain(!got_after_created_);
605     pending_main_frame_->SetIsLastMain(!IsCrossOrigin() || IsLastNavigation());
606     pending_main_frame_->OnFrameCreated(browser, frame);
607   }
608 
OnFrameAttached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,bool reattached)609   void OnFrameAttached(CefRefPtr<CefBrowser> browser,
610                        CefRefPtr<CefFrame> frame,
611                        bool reattached) override {
612     EXPECT_UI_THREAD();
613 
614     // May arrive before or after OnMainFrameChanged switches the frame (after
615     // on initial browser creation, before on cross-origin navigation).
616     if (pending_main_frame_) {
617       EXPECT_TRUE(IsCrossOrigin());
618       pending_main_frame_->OnFrameAttached(browser, frame);
619     } else {
620       EXPECT_TRUE(current_main_frame_);
621       current_main_frame_->OnFrameAttached(browser, frame);
622     }
623   }
624 
OnFrameDetached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)625   void OnFrameDetached(CefRefPtr<CefBrowser> browser,
626                        CefRefPtr<CefFrame> frame) override {
627     EXPECT_UI_THREAD();
628     EXPECT_TRUE(current_main_frame_);
629     current_main_frame_->OnFrameDetached(browser, frame);
630   }
631 
OnMainFrameChanged(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> old_frame,CefRefPtr<CefFrame> new_frame)632   void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
633                           CefRefPtr<CefFrame> old_frame,
634                           CefRefPtr<CefFrame> new_frame) override {
635     EXPECT_UI_THREAD();
636     EXPECT_TRUE(old_frame || new_frame);
637     if (old_frame) {
638       EXPECT_FALSE(old_frame->IsValid());
639       EXPECT_TRUE(old_frame->IsMain());
640 
641       // May be nullptr with PopupOrderMainTestHandler.
642       if (current_main_frame_) {
643         // Last callback referencing the old frame.
644         EXPECT_TRUE(current_main_frame_);
645         current_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
646         current_main_frame_->VerifyTestResults();
647         delete current_main_frame_;
648         current_main_frame_ = nullptr;
649       }
650     }
651     if (new_frame) {
652       EXPECT_TRUE(new_frame->IsValid());
653       EXPECT_TRUE(new_frame->IsMain());
654 
655       // Always called after OnFrameCreated. See also comments in
656       // OnFrameAttached.
657       EXPECT_TRUE(pending_main_frame_);
658       pending_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
659 
660       // The pending frame becomes the current frame.
661       EXPECT_FALSE(current_main_frame_);
662       current_main_frame_ = pending_main_frame_;
663       pending_main_frame_ = nullptr;
664     }
665 
666     if (old_frame && new_frame) {
667       // Main frame changed due to cross-origin navigation.
668       EXPECT_TRUE(IsCrossOrigin());
669       main_frame_changed_ct_++;
670     }
671 
672     if (old_frame && !new_frame) {
673       // Very last callback.
674       VerifyTestResults();
675     }
676   }
677 
678  protected:
GetMainURL() const679   virtual std::string GetMainURL() const { return kOrderMainUrl; }
680 
GetMainHtml() const681   virtual std::string GetMainHtml() const {
682     return "<html><body>TEST</body></html>";
683   }
684 
GetNextMainURL()685   virtual std::string GetNextMainURL() { return std::string(); }
IsFirstNavigation() const686   virtual bool IsFirstNavigation() const { return true; }
IsLastNavigation() const687   virtual bool IsLastNavigation() const { return true; }
IsCrossOrigin() const688   virtual bool IsCrossOrigin() const { return false; }
689 
GetAdditionalDebugInfo() const690   virtual std::string GetAdditionalDebugInfo() const { return std::string(); }
691 
AllQueriesDelivered(std::string * msg=nullptr) const692   virtual bool AllQueriesDelivered(std::string* msg = nullptr) const {
693     EXPECT_UI_THREAD();
694     if (pending_main_frame_)
695       return false;
696     return current_main_frame_->AllQueriesDelivered(msg);
697   }
698 
AllFramesLoaded(std::string * msg=nullptr) const699   virtual bool AllFramesLoaded(std::string* msg = nullptr) const {
700     EXPECT_UI_THREAD();
701     if (pending_main_frame_)
702       return false;
703     return current_main_frame_->IsLoaded(msg);
704   }
705 
MaybeDestroyTest()706   void MaybeDestroyTest() {
707 #if VERBOSE_DEBUGGING
708     std::string delivered_msg, loaded_msg;
709     const bool all_queries_delivered = AllQueriesDelivered(&delivered_msg);
710     const bool all_frames_loaded = AllFramesLoaded(&loaded_msg);
711     LOG(INFO) << (current_main_frame_ ? current_main_frame_->GetDebugString()
712                                       : "")
713               << " AllQueriesDelivered=" << all_queries_delivered << " {"
714               << delivered_msg << "}"
715               << " AllFramesLoaded=" << all_frames_loaded << " {" << loaded_msg
716               << "}";
717     if (all_queries_delivered && all_frames_loaded) {
718 #else
719     if (AllQueriesDelivered() && AllFramesLoaded()) {
720 #endif
721       const std::string& next_url = GetNextMainURL();
722       if (!next_url.empty()) {
723         if (!IsCrossOrigin()) {
724           // Reusing the same main frame for same origin nav.
725           current_main_frame_->ResetMainLoadStatus();
726         }
727 
728 #if VERBOSE_DEBUGGING
729         LOG(INFO) << current_main_frame_->GetDebugString()
730                   << "--> Navigating to " << next_url;
731 #endif
732         GetBrowser()->GetMainFrame()->LoadURL(next_url);
733       } else {
734 #if VERBOSE_DEBUGGING
735         LOG(INFO) << "--> Destroy test";
736 #endif
737         DestroyTest();
738       }
739     }
740   }
741 
742   virtual void VerifyTestResults() {
743     EXPECT_UI_THREAD();
744 
745     // OnMainFrameChanged should have cleaned up.
746     EXPECT_FALSE(pending_main_frame_);
747     EXPECT_FALSE(current_main_frame_);
748 
749     EXPECT_TRUE(got_after_created_);
750     EXPECT_TRUE(got_before_close_);
751 
752     // We document GetFrameHandler() as only being called a single time.
753     EXPECT_EQ(1, get_frame_handler_ct_);
754 
755     // Make sure we get the expected number OnMainFrameChanged callbacks for the
756     // main frame.
757     EXPECT_EQ(expected_main_frame_changed_ct_, main_frame_changed_ct_);
758   }
759 
760   // Number of times we expect the main frame to change (e.g. once per
761   // cross-origin navigation).
762   int expected_main_frame_changed_ct_ = 0;
763 
764   bool got_after_created_ = false;
765   bool got_before_close_ = false;
766 
767  private:
768   int get_frame_handler_ct_ = 0;
769   int main_frame_changed_ct_ = 0;
770 
771   FrameStatus* current_main_frame_ = nullptr;
772   FrameStatus* pending_main_frame_ = nullptr;
773 
774   IMPLEMENT_REFCOUNTING(OrderMainTestHandler);
775 };
776 
777 }  // namespace
778 
779 // Test the ordering and behavior of main frame callbacks.
TEST(FrameHandlerTest,OrderMain)780 TEST(FrameHandlerTest, OrderMain) {
781   CefRefPtr<OrderMainTestHandler> handler = new OrderMainTestHandler();
782   handler->ExecuteTest();
783   ReleaseAndWaitForDestructor(handler);
784 }
785 
786 namespace {
787 
788 const char kOrderMainUrlPrefix[] = "http://tests-frame-handler";
789 
790 class NavigateOrderMainTestHandler : public OrderMainTestHandler {
791  public:
NavigateOrderMainTestHandler(bool cross_origin,int additional_nav_ct=2)792   NavigateOrderMainTestHandler(bool cross_origin, int additional_nav_ct = 2)
793       : cross_origin_(cross_origin), additional_nav_ct_(additional_nav_ct) {
794     // Once for each cross-origin LoadURL call.
795     expected_main_frame_changed_ct_ = cross_origin ? additional_nav_ct_ : 0;
796   }
797 
RunTest()798   void RunTest() override {
799     // Resources for the 2nd+ navigation.
800     for (int i = 1; i <= additional_nav_ct_; i++) {
801       AddResource(GetURLForNav(i), GetMainHtmlForNav(i), "text/html");
802     }
803 
804     OrderMainTestHandler::RunTest();
805   }
806 
807  protected:
808   // Loaded when the browser is created.
GetMainURL() const809   std::string GetMainURL() const override { return GetURLForNav(0); }
GetMainHtml() const810   std::string GetMainHtml() const override { return GetMainHtmlForNav(0); }
811 
GetNextMainURL()812   std::string GetNextMainURL() override {
813     if (current_nav_ct_ == additional_nav_ct_) {
814       // No more navigations.
815       return std::string();
816     }
817     return GetURLForNav(++current_nav_ct_);
818   }
819 
IsFirstNavigation() const820   bool IsFirstNavigation() const override { return current_nav_ct_ == 0U; }
IsLastNavigation() const821   bool IsLastNavigation() const override {
822     return current_nav_ct_ == additional_nav_ct_;
823   }
IsCrossOrigin() const824   bool IsCrossOrigin() const override { return cross_origin_; }
additional_nav_ct() const825   int additional_nav_ct() const { return additional_nav_ct_; }
826 
VerifyTestResults()827   void VerifyTestResults() override {
828     OrderMainTestHandler::VerifyTestResults();
829     EXPECT_TRUE(IsLastNavigation());
830   }
831 
GetMainHtmlForNav(int nav) const832   virtual std::string GetMainHtmlForNav(int nav) const {
833     return "<html><body>TEST " + std::to_string(nav) + "</body></html>";
834   }
835 
GetURLForNav(int nav,const std::string & suffix="") const836   std::string GetURLForNav(int nav, const std::string& suffix = "") const {
837     std::stringstream ss;
838     if (cross_origin_) {
839       ss << kOrderMainUrlPrefix << nav << "/cross-origin" << suffix << ".html";
840     } else {
841       ss << kOrderMainUrlPrefix << "/" << nav << "same-origin" << suffix
842          << ".html";
843     }
844     return ss.str();
845   }
846 
847  private:
848   const bool cross_origin_;
849   const int additional_nav_ct_;
850 
851   int current_nav_ct_ = 0;
852 };
853 
854 }  // namespace
855 
856 // Main frame navigating to different URLs with the same origin.
TEST(FrameHandlerTest,OrderMainNavSameOrigin)857 TEST(FrameHandlerTest, OrderMainNavSameOrigin) {
858   CefRefPtr<NavigateOrderMainTestHandler> handler =
859       new NavigateOrderMainTestHandler(/*cross_origin=*/false);
860   handler->ExecuteTest();
861   ReleaseAndWaitForDestructor(handler);
862 }
863 
864 // Main frame navigating cross-origin.
TEST(FrameHandlerTest,OrderMainNavCrossOrigin)865 TEST(FrameHandlerTest, OrderMainNavCrossOrigin) {
866   CefRefPtr<NavigateOrderMainTestHandler> handler =
867       new NavigateOrderMainTestHandler(/*cross_origin=*/true);
868   handler->ExecuteTest();
869   ReleaseAndWaitForDestructor(handler);
870 }
871 
872 namespace {
873 
874 // Tracks sub-frames for a single main frame load.
875 class FrameStatusMap {
876  public:
FrameStatusMap(size_t expected_frame_ct)877   explicit FrameStatusMap(size_t expected_frame_ct)
878       : expected_frame_ct_(expected_frame_ct) {}
~FrameStatusMap()879   ~FrameStatusMap() { EXPECT_TRUE(frame_map_.empty()); }
880 
Contains(CefRefPtr<CefFrame> frame) const881   bool Contains(CefRefPtr<CefFrame> frame) const {
882     return frame_map_.find(frame->GetIdentifier()) != frame_map_.end();
883   }
884 
CreateFrameStatus(CefRefPtr<CefFrame> frame)885   FrameStatus* CreateFrameStatus(CefRefPtr<CefFrame> frame) {
886     EXPECT_UI_THREAD();
887 
888     EXPECT_LT(size(), expected_frame_ct_);
889 
890     const int64 id = frame->GetIdentifier();
891     EXPECT_NE(kInvalidFrameId, id);
892     EXPECT_EQ(frame_map_.find(id), frame_map_.end());
893 
894     FrameStatus* status = new FrameStatus(frame);
895     frame_map_.insert(std::make_pair(id, status));
896     return status;
897   }
898 
GetFrameStatus(CefRefPtr<CefFrame> frame) const899   FrameStatus* GetFrameStatus(CefRefPtr<CefFrame> frame) const {
900     EXPECT_UI_THREAD();
901 
902     const int64 id = frame->GetIdentifier();
903     EXPECT_NE(kInvalidFrameId, id);
904     Map::const_iterator it = frame_map_.find(id);
905     EXPECT_NE(it, frame_map_.end());
906     return it->second;
907   }
908 
RemoveFrameStatus(CefRefPtr<CefFrame> frame)909   void RemoveFrameStatus(CefRefPtr<CefFrame> frame) {
910     const int64 id = frame->GetIdentifier();
911     Map::iterator it = frame_map_.find(id);
912     EXPECT_NE(it, frame_map_.end());
913     frame_map_.erase(it);
914   }
915 
OnBeforeClose(CefRefPtr<CefBrowser> browser)916   void OnBeforeClose(CefRefPtr<CefBrowser> browser) {
917     Map::const_iterator it = frame_map_.begin();
918     for (; it != frame_map_.end(); ++it) {
919       it->second->OnBeforeClose(browser);
920     }
921   }
922 
AllQueriesDelivered(std::string * msg=nullptr) const923   bool AllQueriesDelivered(std::string* msg = nullptr) const {
924     if (size() != expected_frame_ct_) {
925 #if VERBOSE_DEBUGGING
926       if (msg) {
927         std::stringstream ss;
928         ss << " SUB COUNT MISMATCH! size=" << size()
929            << " expected=" << expected_frame_ct_;
930         *msg += ss.str();
931       }
932 #endif
933       return false;
934     }
935 
936     Map::const_iterator it = frame_map_.begin();
937     for (; it != frame_map_.end(); ++it) {
938       if (!it->second->AllQueriesDelivered(msg)) {
939 #if VERBOSE_DEBUGGING
940         if (msg) {
941           *msg += " " + it->second->GetDebugString() + " PENDING";
942         }
943 #endif
944         return false;
945       }
946     }
947 
948     return true;
949   }
950 
AllFramesLoaded(std::string * msg=nullptr) const951   bool AllFramesLoaded(std::string* msg = nullptr) const {
952     if (size() != expected_frame_ct_) {
953 #if VERBOSE_DEBUGGING
954       if (msg) {
955         std::stringstream ss;
956         ss << " SUB COUNT MISMATCH! size=" << size()
957            << " expected=" << expected_frame_ct_;
958         *msg += ss.str();
959       }
960 #endif
961       return false;
962     }
963 
964     Map::const_iterator it = frame_map_.begin();
965     for (; it != frame_map_.end(); ++it) {
966       if (!it->second->IsTemporary() && !it->second->IsLoaded(msg)) {
967 #if VERBOSE_DEBUGGING
968         if (msg) {
969           *msg += " " + it->second->GetDebugString() + " PENDING";
970         }
971 #endif
972         return false;
973       }
974     }
975 
976     return true;
977   }
978 
AllFramesDetached() const979   bool AllFramesDetached() const {
980     if (size() != expected_frame_ct_)
981       return false;
982 
983     Map::const_iterator it = frame_map_.begin();
984     for (; it != frame_map_.end(); ++it) {
985       if (!it->second->IsDetached())
986         return false;
987     }
988 
989     return true;
990   }
991 
VerifyAndClearTestResults()992   void VerifyAndClearTestResults() {
993     EXPECT_EQ(expected_frame_ct_, size());
994     Map::const_iterator it = frame_map_.begin();
995     for (; it != frame_map_.end(); ++it) {
996       it->second->VerifyTestResults();
997       delete it->second;
998     }
999     frame_map_.clear();
1000   }
1001 
size() const1002   size_t size() const { return frame_map_.size(); }
1003 
1004  private:
1005   using Map = std::map<int64, FrameStatus*>;
1006   Map frame_map_;
1007 
1008   // The expected number of sub-frames.
1009   const size_t expected_frame_ct_;
1010 };
1011 
1012 class OrderSubTestHandler : public NavigateOrderMainTestHandler {
1013  public:
1014   enum TestMode {
1015     // Two sub-frames at the same level.
1016     SUBFRAME_PEERS,
1017 
1018     // One sub-frame inside the other.
1019     SUBFRAME_CHILDREN,
1020   };
1021 
OrderSubTestHandler(bool cross_origin,int additional_nav_ct,TestMode mode,size_t expected_frame_ct=2U)1022   OrderSubTestHandler(bool cross_origin,
1023                       int additional_nav_ct,
1024                       TestMode mode,
1025                       size_t expected_frame_ct = 2U)
1026       : NavigateOrderMainTestHandler(cross_origin, additional_nav_ct),
1027         test_mode_(mode),
1028         expected_frame_ct_(expected_frame_ct) {}
~OrderSubTestHandler()1029   ~OrderSubTestHandler() override { EXPECT_TRUE(frame_maps_.empty()); }
1030 
RunTest()1031   void RunTest() override {
1032     for (int i = 0; i <= additional_nav_ct(); i++) {
1033       AddResource(GetSubURL1ForNav(i), GetSubFrameHtml1ForNav(i), "text/html");
1034       AddResource(GetSubURL2ForNav(i), GetSubFrameHtml2ForNav(i), "text/html");
1035     }
1036 
1037     NavigateOrderMainTestHandler::RunTest();
1038   }
1039 
OnBeforeClose(CefRefPtr<CefBrowser> browser)1040   void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
1041     NavigateOrderMainTestHandler::OnBeforeClose(browser);
1042 
1043     for (auto& map : frame_maps_) {
1044       // Also need to notify any sub-frames.
1045       map->OnBeforeClose(browser);
1046     }
1047   }
1048 
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)1049   bool OnQuery(CefRefPtr<CefBrowser> browser,
1050                CefRefPtr<CefFrame> frame,
1051                int64 query_id,
1052                const CefString& request,
1053                bool persistent,
1054                CefRefPtr<Callback> callback) override {
1055     if (!frame->IsMain()) {
1056       auto map = GetFrameMap(frame);
1057       auto status = map->GetFrameStatus(frame);
1058       status->OnQuery(browser, frame, request);
1059       if (status->AllQueriesDelivered()) {
1060         MaybeDestroyTest();
1061       }
1062       return true;
1063     }
1064 
1065     return NavigateOrderMainTestHandler::OnQuery(browser, frame, query_id,
1066                                                  request, persistent, callback);
1067   }
1068 
OnFrameCreated(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1069   void OnFrameCreated(CefRefPtr<CefBrowser> browser,
1070                       CefRefPtr<CefFrame> frame) override {
1071     if (!frame->IsMain()) {
1072       // Potentially the first notification of a new sub-frame after navigation.
1073       auto map = GetOrCreateFrameMap(frame);
1074       auto status = map->CreateFrameStatus(frame);
1075       status->SetAdditionalDebugInfo(GetAdditionalDebugInfo());
1076       status->OnFrameCreated(browser, frame);
1077       return;
1078     }
1079 
1080     NavigateOrderMainTestHandler::OnFrameCreated(browser, frame);
1081   }
1082 
OnFrameAttached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,bool reattached)1083   void OnFrameAttached(CefRefPtr<CefBrowser> browser,
1084                        CefRefPtr<CefFrame> frame,
1085                        bool reattached) override {
1086     if (!frame->IsMain()) {
1087       auto map = GetFrameMap(frame);
1088       auto status = map->GetFrameStatus(frame);
1089       status->OnFrameAttached(browser, frame);
1090       return;
1091     }
1092 
1093     NavigateOrderMainTestHandler::OnFrameAttached(browser, frame, reattached);
1094   }
1095 
OnFrameDetached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1096   void OnFrameDetached(CefRefPtr<CefBrowser> browser,
1097                        CefRefPtr<CefFrame> frame) override {
1098     if (!frame->IsMain()) {
1099       // Potentially the last notification for an old sub-frame after
1100       // navigation.
1101       auto map = GetFrameMap(frame);
1102       auto status = map->GetFrameStatus(frame);
1103       status->OnFrameDetached(browser, frame);
1104 
1105       if (map->AllFramesDetached()) {
1106         // Verify results from the previous navigation.
1107         VerifyAndClearSubFrameTestResults(map);
1108       }
1109       return;
1110     }
1111 
1112     NavigateOrderMainTestHandler::OnFrameDetached(browser, frame);
1113   }
1114 
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1115   void OnLoadStart(CefRefPtr<CefBrowser> browser,
1116                    CefRefPtr<CefFrame> frame,
1117                    TransitionType transition_type) override {
1118     if (!frame->IsMain()) {
1119       auto map = GetFrameMap(frame);
1120       auto status = map->GetFrameStatus(frame);
1121       status->OnLoadStart(browser, frame);
1122       return;
1123     }
1124 
1125     NavigateOrderMainTestHandler::OnLoadStart(browser, frame, transition_type);
1126   }
1127 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1128   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1129                  CefRefPtr<CefFrame> frame,
1130                  int httpStatusCode) override {
1131     if (!frame->IsMain()) {
1132       auto map = GetFrameMap(frame);
1133       auto status = map->GetFrameStatus(frame);
1134       status->OnLoadEnd(browser, frame);
1135       return;
1136     }
1137 
1138     NavigateOrderMainTestHandler::OnLoadEnd(browser, frame, httpStatusCode);
1139   }
1140 
1141  protected:
GetSubURL1ForNav(int nav) const1142   virtual std::string GetSubURL1ForNav(int nav) const {
1143     return GetURLForNav(nav, "sub1");
1144   }
1145 
GetSubFrameHtml1ForNav(int nav) const1146   std::string GetSubFrameHtml1ForNav(int nav) const {
1147     if (test_mode_ == SUBFRAME_CHILDREN) {
1148       return "<iframe src=\"" + GetSubURL2ForNav(nav) + "\">";
1149     }
1150     return "<html><body>Sub1</body></html>";
1151   }
1152 
GetSubURL2ForNav(int nav) const1153   virtual std::string GetSubURL2ForNav(int nav) const {
1154     return GetURLForNav(nav, "sub2");
1155   }
1156 
GetSubFrameHtml2ForNav(int nav) const1157   std::string GetSubFrameHtml2ForNav(int nav) const {
1158     return "<html><body>Sub2</body></html>";
1159   }
1160 
GetMainHtmlForNav(int nav) const1161   std::string GetMainHtmlForNav(int nav) const override {
1162     if (test_mode_ == SUBFRAME_PEERS) {
1163       return "<html><body><iframe src=\"" + GetSubURL1ForNav(nav) +
1164              "\"></iframe><iframe src=\"" + GetSubURL2ForNav(nav) +
1165              "\"></iframe></body></html>";
1166     } else if (test_mode_ == SUBFRAME_CHILDREN) {
1167       return "<html><body><iframe src=\"" + GetSubURL1ForNav(nav) +
1168              "\"></iframe></iframe></body></html>";
1169     }
1170     NOTREACHED();
1171     return std::string();
1172   }
1173 
AllQueriesDelivered(std::string * msg=nullptr) const1174   bool AllQueriesDelivered(std::string* msg = nullptr) const override {
1175     if (!NavigateOrderMainTestHandler::AllQueriesDelivered(msg)) {
1176 #if VERBOSE_DEBUGGING
1177       if (msg)
1178         *msg += " MAIN PENDING";
1179 #endif
1180       return false;
1181     }
1182 
1183     if (frame_maps_.empty()) {
1184 #if VERBOSE_DEBUGGING
1185       if (msg)
1186         *msg += " NO SUBS";
1187 #endif
1188       return false;
1189     }
1190 
1191     if (!frame_maps_.back()->AllQueriesDelivered(msg)) {
1192 #if VERBOSE_DEBUGGING
1193       if (msg)
1194         *msg += " SUBS PENDING";
1195 #endif
1196       return false;
1197     }
1198     return true;
1199   }
1200 
AllFramesLoaded(std::string * msg=nullptr) const1201   bool AllFramesLoaded(std::string* msg = nullptr) const override {
1202     if (!NavigateOrderMainTestHandler::AllFramesLoaded(msg)) {
1203 #if VERBOSE_DEBUGGING
1204       if (msg)
1205         *msg += " MAIN PENDING";
1206 #endif
1207       return false;
1208     }
1209 
1210     if (frame_maps_.empty()) {
1211 #if VERBOSE_DEBUGGING
1212       if (msg)
1213         *msg += " NO SUBS";
1214 #endif
1215       return false;
1216     }
1217 
1218     if (!frame_maps_.back()->AllFramesLoaded(msg)) {
1219 #if VERBOSE_DEBUGGING
1220       if (msg)
1221         *msg += " SUBS PENDING";
1222 #endif
1223       return false;
1224     }
1225     return true;
1226   }
1227 
VerifyTestResults()1228   void VerifyTestResults() override {
1229     NavigateOrderMainTestHandler::VerifyTestResults();
1230     EXPECT_TRUE(frame_maps_.empty());
1231   }
1232 
expected_frame_ct() const1233   size_t expected_frame_ct() const { return expected_frame_ct_; }
1234 
GetFrameMap(CefRefPtr<CefFrame> frame) const1235   FrameStatusMap* GetFrameMap(CefRefPtr<CefFrame> frame) const {
1236     for (auto& map : frame_maps_) {
1237       if (map->Contains(frame))
1238         return map.get();
1239     }
1240     return nullptr;
1241   }
1242 
1243  private:
1244   // All sub-frame objects should already have received all callbacks.
VerifyAndClearSubFrameTestResults(FrameStatusMap * map)1245   void VerifyAndClearSubFrameTestResults(FrameStatusMap* map) {
1246     map->VerifyAndClearTestResults();
1247 
1248     bool found = false;
1249     FrameStatusMapVector::iterator it = frame_maps_.begin();
1250     for (; it != frame_maps_.end(); ++it) {
1251       if ((*it).get() == map) {
1252         frame_maps_.erase(it);
1253         found = true;
1254         break;
1255       }
1256     }
1257 
1258     EXPECT_TRUE(found);
1259   }
1260 
GetOrCreateFrameMap(CefRefPtr<CefFrame> frame)1261   FrameStatusMap* GetOrCreateFrameMap(CefRefPtr<CefFrame> frame) {
1262     if (auto map = GetFrameMap(frame))
1263       return map;
1264 
1265     if (frame_maps_.empty() ||
1266         frame_maps_.back()->size() >= expected_frame_ct_) {
1267       // Start a new frame map.
1268       auto map = std::make_unique<FrameStatusMap>(expected_frame_ct_);
1269       frame_maps_.push_back(std::move(map));
1270     }
1271 
1272     return frame_maps_.back().get();
1273   }
1274 
1275   const TestMode test_mode_;
1276 
1277   // The expected number of sub-frames.
1278   const size_t expected_frame_ct_;
1279 
1280   using FrameStatusMapVector = std::vector<std::unique_ptr<FrameStatusMap>>;
1281   FrameStatusMapVector frame_maps_;
1282 };
1283 
1284 }  // namespace
1285 
1286 // Main frame loads two sub-frames that are peers in the same origin.
TEST(FrameHandlerTest,OrderSubSameOriginPeers)1287 TEST(FrameHandlerTest, OrderSubSameOriginPeers) {
1288   CefRefPtr<OrderSubTestHandler> handler =
1289       new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/0,
1290                               OrderSubTestHandler::SUBFRAME_PEERS);
1291   handler->ExecuteTest();
1292   ReleaseAndWaitForDestructor(handler);
1293 }
1294 
1295 // Main frame loads two sub-frames that are peers in the same origin, then
1296 // navigates in the same origin and does it again twice.
TEST(FrameHandlerTest,OrderSubSameOriginPeersNavSameOrigin)1297 TEST(FrameHandlerTest, OrderSubSameOriginPeersNavSameOrigin) {
1298   CefRefPtr<OrderSubTestHandler> handler =
1299       new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/2,
1300                               OrderSubTestHandler::SUBFRAME_PEERS);
1301   handler->ExecuteTest();
1302   ReleaseAndWaitForDestructor(handler);
1303 }
1304 
1305 // Main frame loads two sub-frames that are peers in the same origin, then
1306 // navigates cross-origin and does it again twice.
TEST(FrameHandlerTest,OrderSubSameOriginPeersNavCrossOrigin)1307 TEST(FrameHandlerTest, OrderSubSameOriginPeersNavCrossOrigin) {
1308   CefRefPtr<OrderSubTestHandler> handler =
1309       new OrderSubTestHandler(/*cross_origin=*/true, /*additional_nav_ct=*/2,
1310                               OrderSubTestHandler::SUBFRAME_PEERS);
1311   handler->ExecuteTest();
1312   ReleaseAndWaitForDestructor(handler);
1313 }
1314 
1315 // Main frame loads a sub-frame that then has it's own sub-frame.
TEST(FrameHandlerTest,OrderSubSameOriginChildren)1316 TEST(FrameHandlerTest, OrderSubSameOriginChildren) {
1317   CefRefPtr<OrderSubTestHandler> handler =
1318       new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/0,
1319                               OrderSubTestHandler::SUBFRAME_CHILDREN);
1320   handler->ExecuteTest();
1321   ReleaseAndWaitForDestructor(handler);
1322 }
1323 
1324 // Main frame loads a sub-frame that then has it's own sub-frame, then navigates
1325 // in the same origin and does it again twice.
TEST(FrameHandlerTest,OrderSubSameOriginChildrenNavSameOrigin)1326 TEST(FrameHandlerTest, OrderSubSameOriginChildrenNavSameOrigin) {
1327   CefRefPtr<OrderSubTestHandler> handler =
1328       new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/2,
1329                               OrderSubTestHandler::SUBFRAME_CHILDREN);
1330   handler->ExecuteTest();
1331   ReleaseAndWaitForDestructor(handler);
1332 }
1333 
1334 // Main frame loads a sub-frame that then has it's own sub-frame, then navigates
1335 // cross-origin and does it again twice.
TEST(FrameHandlerTest,OrderSubSameOriginChildrenNavCrossOrigin)1336 TEST(FrameHandlerTest, OrderSubSameOriginChildrenNavCrossOrigin) {
1337   CefRefPtr<OrderSubTestHandler> handler =
1338       new OrderSubTestHandler(/*cross_origin=*/true, /*additional_nav_ct=*/2,
1339                               OrderSubTestHandler::SUBFRAME_CHILDREN);
1340   handler->ExecuteTest();
1341   ReleaseAndWaitForDestructor(handler);
1342 }
1343 
1344 namespace {
1345 
1346 // Like above, but also navigating the sub-frames cross-origin.
1347 class CrossOriginOrderSubTestHandler : public OrderSubTestHandler {
1348  public:
CrossOriginOrderSubTestHandler(int additional_nav_ct,TestMode mode)1349   CrossOriginOrderSubTestHandler(int additional_nav_ct, TestMode mode)
1350       : OrderSubTestHandler(/*cross_origin=*/true,
1351                             additional_nav_ct,
1352                             mode,
1353                             /*expected_frame_ct=*/4U) {}
1354 
OnFrameDetached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1355   void OnFrameDetached(CefRefPtr<CefBrowser> browser,
1356                        CefRefPtr<CefFrame> frame) override {
1357     // A sub-frame is first created in the parent's renderer process. That
1358     // sub-frame is then discarded after the real cross-origin sub-frame is
1359     // created in a different renderer process. These discarded sub-frames will
1360     // get OnFrameCreated/OnFrameAttached immediately followed by
1361     // OnFrameDetached.
1362     if (!frame->IsMain()) {
1363       auto map = GetFrameMap(frame);
1364       auto status = map->GetFrameStatus(frame);
1365       if (status && !status->DidGetCallback(FrameStatus::LOAD_START)) {
1366         status->SetIsTemporary(true);
1367         temp_frame_detached_ct_++;
1368       }
1369     }
1370 
1371     OrderSubTestHandler::OnFrameDetached(browser, frame);
1372   }
1373 
1374  protected:
GetSubURL1ForNav(int nav) const1375   std::string GetSubURL1ForNav(int nav) const override {
1376     std::stringstream ss;
1377     ss << kOrderMainUrlPrefix << nav << "-sub1/sub-cross-origin.html";
1378     return ss.str();
1379   }
1380 
GetSubURL2ForNav(int nav) const1381   std::string GetSubURL2ForNav(int nav) const override {
1382     std::stringstream ss;
1383     ss << kOrderMainUrlPrefix << nav << "-sub2/sub-cross-origin.html";
1384     return ss.str();
1385   }
1386 
VerifyTestResults()1387   void VerifyTestResults() override {
1388     OrderSubTestHandler::VerifyTestResults();
1389 
1390     const size_t expected_temp_ct =
1391         (expected_frame_ct() / 2U) * (1U + additional_nav_ct());
1392     EXPECT_EQ(expected_temp_ct, temp_frame_detached_ct_);
1393   }
1394 
1395  private:
1396   size_t temp_frame_detached_ct_ = 0U;
1397 };
1398 
1399 }  // namespace
1400 
1401 // Main frame loads two sub-frames that are peers in a different origin.
TEST(FrameHandlerTest,OrderSubCrossOriginPeers)1402 TEST(FrameHandlerTest, OrderSubCrossOriginPeers) {
1403   CefRefPtr<CrossOriginOrderSubTestHandler> handler =
1404       new CrossOriginOrderSubTestHandler(
1405           /*additional_nav_ct=*/0,
1406           CrossOriginOrderSubTestHandler::SUBFRAME_PEERS);
1407   handler->ExecuteTest();
1408   ReleaseAndWaitForDestructor(handler);
1409 }
1410 
1411 // Main frame loads two sub-frames that are peers in a different origin, then
1412 // navigates cross-origin and does it again twice.
TEST(FrameHandlerTest,OrderSubCrossOriginPeersNavCrossOrigin)1413 TEST(FrameHandlerTest, OrderSubCrossOriginPeersNavCrossOrigin) {
1414   CefRefPtr<CrossOriginOrderSubTestHandler> handler =
1415       new CrossOriginOrderSubTestHandler(
1416           /*additional_nav_ct=*/2,
1417           CrossOriginOrderSubTestHandler::SUBFRAME_PEERS);
1418   handler->ExecuteTest();
1419   ReleaseAndWaitForDestructor(handler);
1420 }
1421 
1422 // Main frame loads a sub-frame in a different origin that then has it's own
1423 // sub-frame in a different origin.
TEST(FrameHandlerTest,OrderSubCrossOriginChildren)1424 TEST(FrameHandlerTest, OrderSubCrossOriginChildren) {
1425   CefRefPtr<CrossOriginOrderSubTestHandler> handler =
1426       new CrossOriginOrderSubTestHandler(
1427           /*additional_nav_ct=*/0,
1428           CrossOriginOrderSubTestHandler::SUBFRAME_CHILDREN);
1429   handler->ExecuteTest();
1430   ReleaseAndWaitForDestructor(handler);
1431 }
1432 
1433 // Main frame loads a sub-frame in a different origin that then has it's own
1434 // sub-frame in a different origin, then navigates cross-origin and does it
1435 // again twice.
TEST(FrameHandlerTest,OrderSubCrossOriginChildrenNavCrossOrigin)1436 TEST(FrameHandlerTest, OrderSubCrossOriginChildrenNavCrossOrigin) {
1437   CefRefPtr<CrossOriginOrderSubTestHandler> handler =
1438       new CrossOriginOrderSubTestHandler(
1439           /*additional_nav_ct=*/2,
1440           CrossOriginOrderSubTestHandler::SUBFRAME_CHILDREN);
1441   handler->ExecuteTest();
1442   ReleaseAndWaitForDestructor(handler);
1443 }
1444 
1445 namespace {
1446 
1447 const char kOrderMainCrossUrl[] =
1448     "http://tests-frame-handler-cross/main-order.html";
1449 
1450 // Will be assigned as popup handler via
1451 // ParentOrderMainTestHandler::OnBeforePopup.
1452 class PopupOrderMainTestHandler : public OrderMainTestHandler {
1453  public:
PopupOrderMainTestHandler(CompletionState * completion_state,bool cross_origin)1454   PopupOrderMainTestHandler(CompletionState* completion_state,
1455                             bool cross_origin)
1456       : OrderMainTestHandler(completion_state), cross_origin_(cross_origin) {
1457     expected_main_frame_changed_ct_ = cross_origin_ ? 1 : 0;
1458   }
1459 
SetupTest()1460   void SetupTest() override {
1461     // Proceed to RunTest().
1462     SetupComplete();
1463   }
1464 
RunTest()1465   void RunTest() override {
1466     // Add the main resource that we will navigate to/from.
1467     AddResource(GetMainURL(), GetMainHtml(), "text/html");
1468 
1469     // Time out the test after a reasonable period of time.
1470     SetTestTimeout();
1471   }
1472 
OnFrameCreated(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1473   void OnFrameCreated(CefRefPtr<CefBrowser> browser,
1474                       CefRefPtr<CefFrame> frame) override {
1475     EXPECT_UI_THREAD();
1476 
1477     EXPECT_TRUE(frame->IsMain());
1478     if (cross_origin_ && !temp_main_frame_) {
1479       // The first main frame in the popup will be created in the parent
1480       // process.
1481       EXPECT_FALSE(got_temp_created_);
1482       got_temp_created_.yes();
1483 
1484       temp_main_frame_ = new FrameStatus(frame);
1485       temp_main_frame_->SetAdditionalDebugInfo(GetAdditionalDebugInfo() +
1486                                                "temp ");
1487       temp_main_frame_->SetIsFirstMain(true);
1488       temp_main_frame_->OnFrameCreated(browser, frame);
1489       return;
1490     }
1491 
1492     OrderMainTestHandler::OnFrameCreated(browser, frame);
1493   }
1494 
OnAfterCreated(CefRefPtr<CefBrowser> browser)1495   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1496     if (temp_main_frame_ && temp_main_frame_->IsSame(browser->GetMainFrame())) {
1497       EXPECT_FALSE(got_after_created_);
1498       got_after_created_ = true;
1499 
1500       EXPECT_TRUE(cross_origin_);
1501       temp_main_frame_->OnAfterCreated(browser);
1502 
1503       // Intentionally skipping the immediate parent class method.
1504       RoutingTestHandler::OnAfterCreated(browser);
1505       return;
1506     }
1507 
1508     OrderMainTestHandler::OnAfterCreated(browser);
1509   }
1510 
OnFrameAttached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,bool reattached)1511   void OnFrameAttached(CefRefPtr<CefBrowser> browser,
1512                        CefRefPtr<CefFrame> frame,
1513                        bool reattached) override {
1514     if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
1515       EXPECT_TRUE(cross_origin_);
1516       temp_main_frame_->OnFrameAttached(browser, frame);
1517       return;
1518     }
1519 
1520     OrderMainTestHandler::OnFrameAttached(browser, frame, reattached);
1521   }
1522 
OnMainFrameChanged(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> old_frame,CefRefPtr<CefFrame> new_frame)1523   void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
1524                           CefRefPtr<CefFrame> old_frame,
1525                           CefRefPtr<CefFrame> new_frame) override {
1526     if (temp_main_frame_ && temp_main_frame_->IsSame(new_frame)) {
1527       EXPECT_TRUE(cross_origin_);
1528       temp_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
1529       return;
1530     }
1531 
1532     OrderMainTestHandler::OnMainFrameChanged(browser, old_frame, new_frame);
1533   }
1534 
OnFrameDetached(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1535   void OnFrameDetached(CefRefPtr<CefBrowser> browser,
1536                        CefRefPtr<CefFrame> frame) override {
1537     if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
1538       EXPECT_TRUE(cross_origin_);
1539       EXPECT_FALSE(got_temp_destroyed_);
1540       got_temp_destroyed_.yes();
1541 
1542 #if VERBOSE_DEBUGGING
1543       LOG(INFO) << temp_main_frame_->GetDebugString()
1544                 << " callback OnFrameDetached(discarded)";
1545 #endif
1546 
1547       // All of the initial main frame callbacks go to the proxy.
1548       EXPECT_TRUE(temp_main_frame_->DidGetCallback(FrameStatus::AFTER_CREATED));
1549       EXPECT_TRUE(temp_main_frame_->DidGetCallback(
1550           FrameStatus::MAIN_FRAME_INITIAL_ASSIGNED));
1551       EXPECT_TRUE(!temp_main_frame_->DidGetCallback(FrameStatus::LOAD_START));
1552       EXPECT_TRUE(temp_main_frame_->DidGetCallback(FrameStatus::FRAME_CREATED));
1553       EXPECT_TRUE(
1554           temp_main_frame_->DidGetCallback(FrameStatus::FRAME_ATTACHED));
1555 
1556       // Should receive queries for OnFrameCreated, OnAfterCreated,
1557       // OnFrameAttached.
1558       EXPECT_EQ(temp_main_frame_->QueriesDeliveredCount(), 3);
1559 
1560       delete temp_main_frame_;
1561       temp_main_frame_ = nullptr;
1562       return;
1563     }
1564 
1565     OrderMainTestHandler::OnFrameDetached(browser, frame);
1566   }
1567 
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)1568   bool OnQuery(CefRefPtr<CefBrowser> browser,
1569                CefRefPtr<CefFrame> frame,
1570                int64 query_id,
1571                const CefString& request,
1572                bool persistent,
1573                CefRefPtr<Callback> callback) override {
1574     if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
1575       EXPECT_TRUE(cross_origin_);
1576       temp_main_frame_->OnQuery(browser, frame, request);
1577       return true;
1578     }
1579 
1580     return OrderMainTestHandler::OnQuery(browser, frame, query_id, request,
1581                                          persistent, callback);
1582   }
1583 
GetMainURL() const1584   std::string GetMainURL() const override {
1585     return cross_origin_ ? kOrderMainCrossUrl : kOrderMainUrl;
1586   }
1587 
1588  protected:
IsCrossOrigin() const1589   bool IsCrossOrigin() const override { return cross_origin_; }
1590 
VerifyTestResults()1591   void VerifyTestResults() override {
1592     OrderMainTestHandler::VerifyTestResults();
1593 
1594     if (cross_origin_) {
1595       EXPECT_TRUE(got_temp_created_);
1596       EXPECT_TRUE(got_temp_destroyed_);
1597     } else {
1598       EXPECT_FALSE(got_temp_created_);
1599       EXPECT_FALSE(got_temp_destroyed_);
1600     }
1601     EXPECT_FALSE(temp_main_frame_);
1602   }
1603 
1604  private:
GetAdditionalDebugInfo() const1605   std::string GetAdditionalDebugInfo() const override { return " popup: "; }
1606 
1607   const bool cross_origin_;
1608 
1609   TrackCallback got_temp_created_;
1610   TrackCallback got_temp_destroyed_;
1611   FrameStatus* temp_main_frame_ = nullptr;
1612 };
1613 
1614 class ParentOrderMainTestHandler : public OrderMainTestHandler {
1615  public:
ParentOrderMainTestHandler(CompletionState * completion_state,CefRefPtr<PopupOrderMainTestHandler> popup_handler)1616   ParentOrderMainTestHandler(CompletionState* completion_state,
1617                              CefRefPtr<PopupOrderMainTestHandler> popup_handler)
1618       : OrderMainTestHandler(completion_state), popup_handler_(popup_handler) {}
1619 
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)1620   bool OnBeforePopup(
1621       CefRefPtr<CefBrowser> browser,
1622       CefRefPtr<CefFrame> frame,
1623       const CefString& target_url,
1624       const CefString& target_frame_name,
1625       CefLifeSpanHandler::WindowOpenDisposition target_disposition,
1626       bool user_gesture,
1627       const CefPopupFeatures& popupFeatures,
1628       CefWindowInfo& windowInfo,
1629       CefRefPtr<CefClient>& client,
1630       CefBrowserSettings& settings,
1631       CefRefPtr<CefDictionaryValue>& extra_info,
1632       bool* no_javascript_access) override {
1633     // Intentionally not calling the parent class method.
1634     EXPECT_FALSE(got_on_before_popup_);
1635     got_on_before_popup_.yes();
1636 
1637     client = popup_handler_;
1638     popup_handler_ = nullptr;
1639 
1640     // Proceed with popup creation.
1641     return false;
1642   }
1643 
OnAfterCreated(CefRefPtr<CefBrowser> browser)1644   void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1645     OrderMainTestHandler::OnAfterCreated(browser);
1646 
1647     // Create the popup ASAP.
1648     browser->GetMainFrame()->ExecuteJavaScript(
1649         "window.open('" + popup_handler_->GetMainURL() + "');", CefString(), 0);
1650   }
1651 
SetupTest()1652   void SetupTest() override {
1653     // Proceed to RunTest().
1654     SetupComplete();
1655   }
1656 
DestroyTest()1657   void DestroyTest() override {
1658     EXPECT_TRUE(got_on_before_popup_);
1659     OrderMainTestHandler::DestroyTest();
1660   }
1661 
1662  private:
GetAdditionalDebugInfo() const1663   std::string GetAdditionalDebugInfo() const override { return "parent: "; }
1664 
1665   CefRefPtr<PopupOrderMainTestHandler> popup_handler_;
1666 
1667   TrackCallback got_on_before_popup_;
1668 };
1669 
RunOrderMainPopupTest(bool cross_origin)1670 void RunOrderMainPopupTest(bool cross_origin) {
1671   TestHandler::CompletionState completion_state(/*count=*/2);
1672   TestHandler::Collection collection(&completion_state);
1673 
1674   CefRefPtr<PopupOrderMainTestHandler> popup_handler =
1675       new PopupOrderMainTestHandler(&completion_state, cross_origin);
1676   CefRefPtr<ParentOrderMainTestHandler> parent_handler =
1677       new ParentOrderMainTestHandler(&completion_state, popup_handler);
1678 
1679   collection.AddTestHandler(popup_handler.get());
1680   collection.AddTestHandler(parent_handler.get());
1681   collection.ExecuteTests();
1682 
1683   ReleaseAndWaitForDestructor(parent_handler);
1684   ReleaseAndWaitForDestructor(popup_handler);
1685 }
1686 
1687 }  // namespace
1688 
1689 // Test the ordering and behavior of main frame callbacks in a popup with the
1690 // same origin.
TEST(FrameHandlerTest,OrderMainPopupSameOrigin)1691 TEST(FrameHandlerTest, OrderMainPopupSameOrigin) {
1692   RunOrderMainPopupTest(/*cross_origin=*/false);
1693 }
1694 
1695 // Test the ordering and behavior of main frame callbacks in a popup with a
1696 // different origin.
TEST(FrameHandlerTest,OrderMainPopupCrossOrigin)1697 TEST(FrameHandlerTest, OrderMainPopupCrossOrigin) {
1698   RunOrderMainPopupTest(/*cross_origin=*/true);
1699 }
1700