Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: content/browser/devtools/protocol/devtools_protocol_browsertest.cc

Issue 2132673002: Adding Navigation Throttles to DevTools (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reduce number of delta lines in DevToolsProtocolTest Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 #include <utility> 6 #include <utility>
7 7
8 #include "base/base64.h" 8 #include "base/base64.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h" 11 #include "base/json/json_writer.h"
12 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h" 13 #include "base/run_loop.h"
13 #include "base/values.h" 14 #include "base/values.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
15 #include "content/public/browser/devtools_agent_host.h" 16 #include "content/public/browser/devtools_agent_host.h"
16 #include "content/public/browser/javascript_dialog_manager.h" 17 #include "content/public/browser/javascript_dialog_manager.h"
17 #include "content/public/browser/render_view_host.h" 18 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h" 19 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/url_constants.h" 20 #include "content/public/common/url_constants.h"
20 #include "content/public/test/browser_test_utils.h" 21 #include "content/public/test/browser_test_utils.h"
21 #include "content/public/test/content_browser_test.h" 22 #include "content/public/test/content_browser_test.h"
22 #include "content/public/test/content_browser_test_utils.h" 23 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h" 24 #include "content/public/test/test_navigation_observer.h"
24 #include "content/shell/browser/shell.h" 25 #include "content/shell/browser/shell.h"
25 #include "net/dns/mock_host_resolver.h" 26 #include "net/dns/mock_host_resolver.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h" 27 #include "net/test/embedded_test_server/embedded_test_server.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "third_party/re2/src/re2/re2.h"
27 #include "third_party/skia/include/core/SkBitmap.h" 30 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "ui/compositor/compositor_switches.h" 31 #include "ui/compositor/compositor_switches.h"
29 #include "ui/gfx/codec/png_codec.h" 32 #include "ui/gfx/codec/png_codec.h"
30 33
34 using testing::MatchesRegex;
35
31 namespace content { 36 namespace content {
32 37
33 namespace { 38 namespace {
34 39
35 const char kIdParam[] = "id"; 40 const char kIdParam[] = "id";
36 const char kMethodParam[] = "method"; 41 const char kMethodParam[] = "method";
37 const char kParamsParam[] = "params"; 42 const char kParamsParam[] = "params";
38 43
39 class TestJavaScriptDialogManager : public JavaScriptDialogManager, 44 class TestJavaScriptDialogManager : public JavaScriptDialogManager,
40 public WebContentsDelegate { 45 public WebContentsDelegate {
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 agent_host_->AttachClient(this); 168 agent_host_->AttachClient(this);
164 } 169 }
165 170
166 void TearDownOnMainThread() override { 171 void TearDownOnMainThread() override {
167 if (agent_host_) { 172 if (agent_host_) {
168 agent_host_->DetachClient(this); 173 agent_host_->DetachClient(this);
169 agent_host_ = nullptr; 174 agent_host_ = nullptr;
170 } 175 }
171 } 176 }
172 177
173 void WaitForNotification(const std::string& notification) { 178 // Waits for an event of type |notification_name| to be sent.
174 waiting_for_notification_ = notification; 179 void WaitForNotification(const std::string& notification_name) {
180 waiting_for_notification_ = notification_name;
181 waiting_for_notification_count_ =
182 notification_count_[notification_name] + 1;
175 RunMessageLoop(); 183 RunMessageLoop();
176 } 184 }
177 185
186 // Waits until the count of events of type |notification_name| is >= count.
187 void WaitForNotificationCount(const std::string& notification_name,
188 int count) {
189 if (notification_count_[notification_name] < count) {
190 waiting_for_notification_ = notification_name;
191 waiting_for_notification_count_ = count;
192 RunMessageLoop();
193 }
194 }
195
196 struct ExpectedNavigation {
197 std::string url_regex;
198 bool renderer_initiated;
199 bool is_in_main_frame;
200 bool is_redirect;
201 std::string navigation_response;
202 };
203
204 // Waits for the expected navigations to occur in any order. If an expected
205 // navigation occurs, Page.processNavigation is called with the specified
206 // navigation_response to either allow it to proceed or to cancel it.
207 void WaitForNavigationsInAnyOrder(
208 std::vector<ExpectedNavigation> expected_navigations) {
209 while (!expected_navigations.empty()) {
210 WaitForNotification("Page.navigationRequested");
211 ASSERT_TRUE(requested_notification_params_.get());
212
213 std::string url;
214 ASSERT_TRUE(requested_notification_params_->GetString("url", &url));
215 int navigation_id;
216 ASSERT_TRUE(requested_notification_params_->GetInteger("navigationId",
217 &navigation_id));
218 bool renderer_initiated;
219 ASSERT_TRUE(requested_notification_params_->GetBoolean(
220 "rendererInitiated", &renderer_initiated));
221 bool is_in_main_frame;
222 ASSERT_TRUE(requested_notification_params_->GetBoolean(
223 "isInMainFrame", &is_in_main_frame));
224 bool is_redirect;
225 ASSERT_TRUE(requested_notification_params_->GetBoolean("isRedirect",
226 &is_redirect));
227
228 bool navigation_was_expected;
229 for (auto it = expected_navigations.begin();
230 it != expected_navigations.end(); it++) {
231 if (!RE2::FullMatch(url, it->url_regex) ||
232 renderer_initiated != it->renderer_initiated ||
233 is_in_main_frame != it->is_in_main_frame ||
234 is_redirect != it->is_redirect) {
235 continue;
236 }
237
238 std::unique_ptr<base::DictionaryValue> params(
239 new base::DictionaryValue());
240 params->SetString("response", it->navigation_response);
241 params->SetInteger("navigationId", navigation_id);
242 SendCommand("Page.processNavigation", std::move(params), false);
243
244 navigation_was_expected = true;
245 expected_navigations.erase(it);
246 break;
247 }
248 EXPECT_TRUE(navigation_was_expected)
249 << "url = " << url << "renderer_initiated = " << renderer_initiated
250 << "is_in_main_frame = " << is_in_main_frame
251 << "is_redirect = " << is_redirect;
252 }
253 }
254
178 std::unique_ptr<base::DictionaryValue> result_; 255 std::unique_ptr<base::DictionaryValue> result_;
179 scoped_refptr<DevToolsAgentHost> agent_host_; 256 scoped_refptr<DevToolsAgentHost> agent_host_;
180 int last_sent_id_; 257 int last_sent_id_;
181 std::vector<int> result_ids_; 258 std::vector<int> result_ids_;
182 std::vector<std::string> notifications_; 259 std::unique_ptr<base::DictionaryValue> requested_notification_params_;
260
261 bool NoEventsReceived() const { return notification_count_.empty(); }
183 262
184 private: 263 private:
185 void DispatchProtocolMessage(DevToolsAgentHost* agent_host, 264 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
186 const std::string& message) override { 265 const std::string& message) override {
187 std::unique_ptr<base::DictionaryValue> root( 266 std::unique_ptr<base::DictionaryValue> root(
188 static_cast<base::DictionaryValue*>( 267 static_cast<base::DictionaryValue*>(
189 base::JSONReader::Read(message).release())); 268 base::JSONReader::Read(message).release()));
190 int id; 269 int id;
191 if (root->GetInteger("id", &id)) { 270 if (root->GetInteger("id", &id)) {
192 result_ids_.push_back(id); 271 result_ids_.push_back(id);
193 base::DictionaryValue* result; 272 base::DictionaryValue* result;
194 ASSERT_TRUE(root->GetDictionary("result", &result)); 273 ASSERT_TRUE(root->GetDictionary("result", &result));
195 result_.reset(result->DeepCopy()); 274 result_.reset(result->DeepCopy());
196 in_dispatch_ = false; 275 in_dispatch_ = false;
197 if (id && id == waiting_for_command_result_id_) { 276 if (id && id == waiting_for_command_result_id_) {
198 waiting_for_command_result_id_ = 0; 277 waiting_for_command_result_id_ = 0;
199 base::MessageLoop::current()->QuitNow(); 278 base::MessageLoop::current()->QuitNow();
200 } 279 }
201 } else { 280 } else {
202 std::string notification; 281 std::string notification;
203 EXPECT_TRUE(root->GetString("method", &notification)); 282 EXPECT_TRUE(root->GetString("method", &notification));
204 notifications_.push_back(notification); 283 int count = ++notification_count_[notification];
205 if (waiting_for_notification_ == notification) { 284 if (waiting_for_notification_ == notification &&
285 count >= waiting_for_notification_count_) {
286 base::DictionaryValue* params;
287 if (root->GetDictionary("params", &params)) {
288 requested_notification_params_ = params->CreateDeepCopy();
289 } else {
290 requested_notification_params_.reset();
291 }
206 waiting_for_notification_ = std::string(); 292 waiting_for_notification_ = std::string();
207 base::MessageLoop::current()->QuitNow(); 293 base::MessageLoop::current()->QuitNow();
208 } 294 }
209 } 295 }
210 } 296 }
211 297
212 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override { 298 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
213 EXPECT_TRUE(false); 299 EXPECT_TRUE(false);
214 } 300 }
215 301
302 std::map<std::string, int> notification_count_;
216 std::string waiting_for_notification_; 303 std::string waiting_for_notification_;
304 int waiting_for_notification_count_;
217 int waiting_for_command_result_id_; 305 int waiting_for_command_result_id_;
218 bool in_dispatch_; 306 bool in_dispatch_;
219 }; 307 };
220 308
221 class SyntheticKeyEventTest : public DevToolsProtocolTest { 309 class SyntheticKeyEventTest : public DevToolsProtocolTest {
222 protected: 310 protected:
223 void SendKeyEvent(const std::string& type, 311 void SendKeyEvent(const std::string& type,
224 int modifier, 312 int modifier,
225 int windowsKeyCode, 313 int windowsKeyCode,
226 int nativeKeyCode, 314 int nativeKeyCode,
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 SendCommand("Page.navigate", std::move(params), true); 497 SendCommand("Page.navigate", std::move(params), true);
410 navigation_observer.Wait(); 498 navigation_observer.Wait();
411 499
412 bool enough_results = result_ids_.size() >= 2u; 500 bool enough_results = result_ids_.size() >= 2u;
413 EXPECT_TRUE(enough_results); 501 EXPECT_TRUE(enough_results);
414 if (enough_results) { 502 if (enough_results) {
415 EXPECT_EQ(1, result_ids_[0]); // Page.enable 503 EXPECT_EQ(1, result_ids_[0]); // Page.enable
416 EXPECT_EQ(2, result_ids_[1]); // Page.navigate 504 EXPECT_EQ(2, result_ids_[1]); // Page.navigate
417 } 505 }
418 506
419 enough_results = notifications_.size() >= 1u; 507 WaitForNotificationCount("Page.frameStartedLoading", 1);
420 EXPECT_TRUE(enough_results);
421 bool found_frame_notification = false;
422 for (const std::string& notification : notifications_) {
423 if (notification == "Page.frameStartedLoading")
424 found_frame_notification = true;
425 }
426 EXPECT_TRUE(found_frame_notification);
427 } 508 }
428 509
429 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) { 510 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) {
430 host_resolver()->AddRule("*", "127.0.0.1"); 511 host_resolver()->AddRule("*", "127.0.0.1");
431 ASSERT_TRUE(embedded_test_server()->Start()); 512 ASSERT_TRUE(embedded_test_server()->Start());
432 content::SetupCrossSiteRedirector(embedded_test_server()); 513 content::SetupCrossSiteRedirector(embedded_test_server());
433 514
434 GURL test_url1 = embedded_test_server()->GetURL( 515 GURL test_url1 = embedded_test_server()->GetURL(
435 "A.com", "/devtools/navigation.html"); 516 "A.com", "/devtools/navigation.html");
436 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1); 517 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1);
437 Attach(); 518 Attach();
438 519
439 GURL test_url2 = embedded_test_server()->GetURL( 520 GURL test_url2 = embedded_test_server()->GetURL(
440 "B.com", "/devtools/navigation.html"); 521 "B.com", "/devtools/navigation.html");
441 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1); 522 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1);
442 523
443 EXPECT_EQ(0u, notifications_.size()); 524 EXPECT_TRUE(NoEventsReceived());
444 } 525 }
445 526
446 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) { 527 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) {
447 ASSERT_TRUE(embedded_test_server()->Start()); 528 ASSERT_TRUE(embedded_test_server()->Start());
448 GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html"); 529 GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
449 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1); 530 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
450 531
451 Shell* second = CreateBrowser(); 532 Shell* second = CreateBrowser();
452 NavigateToURLBlockUntilNavigationsComplete(second, test_url, 1); 533 NavigateToURLBlockUntilNavigationsComplete(second, test_url, 1);
453 534
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, BrowserNewPage) { 671 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, BrowserNewPage) {
591 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); 672 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
592 Attach(); 673 Attach();
593 EXPECT_EQ(1u, shell()->windows().size()); 674 EXPECT_EQ(1u, shell()->windows().size());
594 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); 675 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
595 params->SetString("initialUrl", "about:blank"); 676 params->SetString("initialUrl", "about:blank");
596 SendCommand("Browser.newPage", std::move(params), true); 677 SendCommand("Browser.newPage", std::move(params), true);
597 EXPECT_EQ(2u, shell()->windows().size()); 678 EXPECT_EQ(2u, shell()->windows().size());
598 } 679 }
599 680
681 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ControlNavigations_MainFrame) {
nasko 2016/07/14 16:47:19 No underscores, just CamelCase.
alex clarke (OOO till 29th) 2016/07/14 17:38:34 Done.
682 ASSERT_TRUE(embedded_test_server()->Start());
683
684 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
685 Attach();
686 SendCommand("Page.enable", nullptr);
687
688 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
689 params->SetBoolean("enabled", true);
690 SendCommand("Page.setControlNavigations", std::move(params), true);
691
692 GURL test_url = embedded_test_server()->GetURL(
693 "/devtools/control_navigations/meta_tag.html");
694 shell()->LoadURL(test_url);
695
696 std::vector<ExpectedNavigation> expected_navigations = {
697 {"http://127.0.0.1:\\d+/devtools/control_navigations/meta_tag.html",
698 false /* expected_renderer_initiated */,
699 true /* expected_is_in_main_frame */, false /* expected_is_redirect */,
700 "Proceed"},
701 {"http://127.0.0.1:\\d+/devtools/navigation.html",
702 true /* expected_renderer_initiated */,
703 true /* expected_is_in_main_frame */, false /* expected_is_redirect */,
704 "Cancel"}};
705
706 WaitForNavigationsInAnyOrder(std::move(expected_navigations));
707
708 WaitForNotificationCount("Page.frameStoppedLoading", 2);
709
710 // Check main frame has the expected url.
711 SendCommand("Page.getResourceTree", nullptr);
712
713 const base::DictionaryValue* frame_tree;
714 ASSERT_TRUE(result_->GetDictionary("frameTree", &frame_tree));
715 const base::DictionaryValue* frame;
716 ASSERT_TRUE(frame_tree->GetDictionary("frame", &frame));
717
718 std::string frame_url;
719 ASSERT_TRUE(frame->GetString("url", &frame_url));
720 EXPECT_THAT(
721 frame_url,
722 MatchesRegex(
723 "http://127.0.0.1:\\d+/devtools/control_navigations/meta_tag.html"));
nasko 2016/07/14 16:47:19 very minor nit: You could just strip the port numb
alex clarke (OOO till 29th) 2016/07/14 17:38:34 Seems like a good idea, are there any utilities fo
nasko 2016/07/14 17:55:51 You can use a GURL::Replacements. There are some e
alex clarke (OOO till 29th) 2016/07/15 13:21:21 Done.
724 }
725
726 // TODO(alexclarke): Make this work with IsolateAllSitesForTesting.
727 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ControlNavigations_ChildFrames) {
nasko 2016/07/14 16:47:20 Thanks for adding this test!
728 host_resolver()->AddRule("*", "127.0.0.1");
729 ASSERT_TRUE(embedded_test_server()->Start());
730 content::SetupCrossSiteRedirector(embedded_test_server());
731
732 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
nasko 2016/07/14 16:47:19 Why do you need to navigate to about:blank first?
alex clarke (OOO till 29th) 2016/07/14 17:38:34 For two reasons: 1. To make sure there's a page we
nasko 2016/07/14 17:55:51 In general, each frame starts with an initial blan
733 Attach();
734 SendCommand("Page.enable", nullptr);
735
736 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
737 params->SetBoolean("enabled", true);
738 SendCommand("Page.setControlNavigations", std::move(params), true);
739
740 GURL test_url = embedded_test_server()->GetURL(
741 "/devtools/control_navigations/iframe_navigation.html");
742 shell()->LoadURL(test_url);
743
744 // Allow main frame navigation, and all iframe navigations to http://a.com
745 // Allow initial iframe navigation to http://b.com but dissallow it to
746 // navigate to /devtools/navigation.html.
747 std::vector<ExpectedNavigation> expected_navigations = {
748 {"http://127.0.0.1:\\d+/devtools/control_navigations/"
749 "iframe_navigation.html",
750 /* expected_renderer_initiated */ false,
751 /* expected_is_in_main_frame */ true,
752 /* expected_is_redirect */ false, "Proceed"},
753 {"http://127.0.0.1:\\d+/cross-site/a.com/devtools/control_navigations/"
754 "meta_tag.html",
755 /* expected_renderer_initiated */ true,
756 /* expected_is_in_main_frame */ false,
757 /* expected_is_redirect */ false, "Proceed"},
758 {"http://127.0.0.1:\\d+/cross-site/b.com/devtools/control_navigations/"
759 "meta_tag.html",
760 /* expected_renderer_initiated */ true,
761 /* expected_is_in_main_frame */ false,
762 /* expected_is_redirect */ false, "Proceed"},
763 {"http://a.com:\\d+/devtools/control_navigations/meta_tag.html",
764 /* expected_renderer_initiated */ true,
765 /* expected_is_in_main_frame */ false,
766 /* expected_is_redirect */ true, "Proceed"},
767 {"http://b.com:\\d+/devtools/control_navigations/meta_tag.html",
768 /* expected_renderer_initiated */ true,
769 /* expected_is_in_main_frame */ false,
770 /* expected_is_redirect */ true, "Proceed"},
771 {"http://a.com:\\d+/devtools/navigation.html",
772 /* expected_renderer_initiated */ true,
773 /* expected_is_in_main_frame */ false,
774 /* expected_is_redirect */ false, "Proceed"},
775 {"http://b.com:\\d+/devtools/navigation.html",
776 /* expected_renderer_initiated */ true,
777 /* expected_is_in_main_frame */ false,
778 /* expected_is_redirect */ false, "Cancel"}};
779
780 WaitForNavigationsInAnyOrder(std::move(expected_navigations));
781
782 WaitForNotificationCount("Page.frameStoppedLoading", 5);
783
784 // Check that the a.com iframe navigated to /devtools/navigation.html and that
785 // the b.com iframe was stuck at /devtools/control_navigations/meta_tag.html.
786 SendCommand("Page.getResourceTree", nullptr);
787
788 const base::DictionaryValue* frame_tree;
789 ASSERT_TRUE(result_->GetDictionary("frameTree", &frame_tree));
790
791 const base::ListValue* child_frames;
792 ASSERT_TRUE(frame_tree->GetList("childFrames", &child_frames));
793 EXPECT_EQ(2u, child_frames->GetSize());
794
795 const base::DictionaryValue* child_frame0;
796 ASSERT_TRUE(child_frames->GetDictionary(0, &child_frame0));
797 ASSERT_TRUE(child_frame0->GetDictionary("frame", &child_frame0));
798
799 std::string frame0_url;
800 ASSERT_TRUE(child_frame0->GetString("url", &frame0_url));
801 EXPECT_THAT(frame0_url,
802 MatchesRegex("http://a.com:\\d+/devtools/navigation.html"));
803
804 const base::DictionaryValue* child_frame1;
805 ASSERT_TRUE(child_frames->GetDictionary(1, &child_frame1));
806 ASSERT_TRUE(child_frame1->GetDictionary("frame", &child_frame1));
807 std::string frame1_url;
808 ASSERT_TRUE(child_frame1->GetString("url", &frame1_url));
809 EXPECT_THAT(
810 frame1_url,
811 MatchesRegex(
812 "http://b.com:\\d+/devtools/control_navigations/meta_tag.html"));
813 }
814
600 } // namespace content 815 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698