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