| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // This file tests that Service Workers (a Content feature) work in the Chromium | 5 // This file tests that Service Workers (a Content feature) work in the Chromium |
| 6 // embedder. | 6 // embedder. |
| 7 | 7 |
| 8 #include <tuple> |
| 9 |
| 8 #include "base/bind.h" | 10 #include "base/bind.h" |
| 9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 10 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
| 11 #include "base/numerics/safe_conversions.h" | 13 #include "base/numerics/safe_conversions.h" |
| 12 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
| 13 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 15 #include "base/test/histogram_tester.h" | 17 #include "base/test/histogram_tester.h" |
| 16 #include "base/threading/thread_restrictions.h" | 18 #include "base/threading/thread_restrictions.h" |
| 17 #include "build/build_config.h" | 19 #include "build/build_config.h" |
| 18 #include "chrome/browser/chrome_notification_types.h" | 20 #include "chrome/browser/chrome_notification_types.h" |
| 19 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 21 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 20 #include "chrome/browser/content_settings/tab_specific_content_settings.h" | 22 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| 23 #include "chrome/browser/net/prediction_options.h" |
| 24 #include "chrome/browser/net/predictor.h" |
| 21 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/ui/browser.h" | 26 #include "chrome/browser/ui/browser.h" |
| 23 #include "chrome/browser/ui/browser_window.h" | 27 #include "chrome/browser/ui/browser_window.h" |
| 24 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 28 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 25 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
| 26 #include "chrome/test/base/in_process_browser_test.h" | 30 #include "chrome/test/base/in_process_browser_test.h" |
| 27 #include "chrome/test/base/ui_test_utils.h" | 31 #include "chrome/test/base/ui_test_utils.h" |
| 28 #include "components/content_settings/core/browser/host_content_settings_map.h" | 32 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 29 #include "content/public/browser/browser_context.h" | 33 #include "content/public/browser/browser_context.h" |
| 30 #include "content/public/browser/render_frame_host.h" | 34 #include "content/public/browser/render_frame_host.h" |
| 31 #include "content/public/browser/service_worker_context.h" | 35 #include "content/public/browser/service_worker_context.h" |
| 32 #include "content/public/browser/storage_partition.h" | 36 #include "content/public/browser/storage_partition.h" |
| 33 #include "content/public/browser/web_contents.h" | 37 #include "content/public/browser/web_contents.h" |
| 38 #include "content/public/common/content_switches.h" |
| 34 #include "content/public/test/browser_test_utils.h" | 39 #include "content/public/test/browser_test_utils.h" |
| 35 #include "net/test/embedded_test_server/embedded_test_server.h" | 40 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 41 #include "net/test/embedded_test_server/embedded_test_server_connection_listener
.h" |
| 36 #include "ppapi/shared_impl/ppapi_switches.h" | 42 #include "ppapi/shared_impl/ppapi_switches.h" |
| 37 | 43 |
| 38 namespace { | 44 namespace { |
| 39 | 45 |
| 40 const std::string kInstallAndWaitForActivatedPage = | 46 const std::string kInstallAndWaitForActivatedPage = |
| 41 "<script>" | 47 "<script>" |
| 42 "navigator.serviceWorker.register('./sw.js', {scope: './scope/'})" | 48 "navigator.serviceWorker.register('./sw.js', {scope: './scope/'})" |
| 43 " .then(function(reg) {" | 49 " .then(function(reg) {" |
| 44 " reg.addEventListener('updatefound', function() {" | 50 " reg.addEventListener('updatefound', function() {" |
| 45 " var worker = reg.installing;" | 51 " var worker = reg.installing;" |
| (...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 InitializeServer(); | 699 InitializeServer(); |
| 694 NavigateToPageAndWaitForReadyTitle("/test.html"); | 700 NavigateToPageAndWaitForReadyTitle("/test.html"); |
| 695 GetServiceWorkerContext()->StopAllServiceWorkersForOrigin( | 701 GetServiceWorkerContext()->StopAllServiceWorkersForOrigin( |
| 696 embedded_test_server()->base_url()); | 702 embedded_test_server()->base_url()); |
| 697 RunNavigationHintTest( | 703 RunNavigationHintTest( |
| 698 "/scope/", | 704 "/scope/", |
| 699 content::StartServiceWorkerForNavigationHintResult::NO_FETCH_HANDLER, | 705 content::StartServiceWorkerForNavigationHintResult::NO_FETCH_HANDLER, |
| 700 false); | 706 false); |
| 701 } | 707 } |
| 702 | 708 |
| 709 class ConnectionListener |
| 710 : public net::test_server::EmbeddedTestServerConnectionListener { |
| 711 public: |
| 712 ConnectionListener() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
| 713 ~ConnectionListener() override {} |
| 714 |
| 715 void AcceptedSocket(const net::StreamSocket& connection) override { |
| 716 base::AutoLock lock(lock_); |
| 717 socket_accepted_ = true; |
| 718 if (wait_accept_loop_) |
| 719 task_runner_->PostTask(FROM_HERE, wait_accept_loop_->QuitClosure()); |
| 720 } |
| 721 void ReadFromSocket(const net::StreamSocket& socket, int rv) override {} |
| 722 |
| 723 void ResetSocketAcceptedFlag() { |
| 724 base::AutoLock lock(lock_); |
| 725 socket_accepted_ = false; |
| 726 } |
| 727 |
| 728 bool GetSocketAcceptedFlag() const { |
| 729 base::AutoLock lock(lock_); |
| 730 return socket_accepted_; |
| 731 } |
| 732 |
| 733 void WaitForSocketAcceptedOnUI() { |
| 734 { |
| 735 base::AutoLock lock(lock_); |
| 736 if (socket_accepted_) |
| 737 return; |
| 738 wait_accept_loop_.reset(new base::RunLoop()); |
| 739 } |
| 740 wait_accept_loop_->Run(); |
| 741 } |
| 742 |
| 743 private: |
| 744 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 745 |
| 746 // This lock protects the members below, which each are used on both the |
| 747 // IO and UI thread. Members declared after the lock are protected by it. |
| 748 mutable base::Lock lock_; |
| 749 bool socket_accepted_ = false; |
| 750 std::unique_ptr<base::RunLoop> wait_accept_loop_; |
| 751 |
| 752 DISALLOW_COPY_AND_ASSIGN(ConnectionListener); |
| 753 }; |
| 754 |
| 755 class ChromeServiceWorkerPredictionOptionsTest |
| 756 : public ChromeServiceWorkerTest, |
| 757 public ::testing::WithParamInterface<std::tuple< |
| 758 bool, |
| 759 chrome_browser_net::NetworkPredictionOptionsForServiceWorker>> { |
| 760 protected: |
| 761 ChromeServiceWorkerPredictionOptionsTest() |
| 762 : cross_site_test_server_(new net::EmbeddedTestServer()) {} |
| 763 ~ChromeServiceWorkerPredictionOptionsTest() override {} |
| 764 |
| 765 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 766 ChromeServiceWorkerTest::SetUpCommandLine(command_line); |
| 767 if (std::get<0>(GetParam())) |
| 768 command_line->AppendSwitch(switches::kEnableBrowserSideNavigation); |
| 769 switch (Options()) { |
| 770 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 771 PRECONNECT_ONLY: |
| 772 command_line->AppendSwitchASCII( |
| 773 switches::kNetworkPredictionOptionsForServiceWorker, |
| 774 chrome_browser_net::kPreconnectOnly); |
| 775 break; |
| 776 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 777 START_SERVICE_WORKER_AND_PRECONNECT: |
| 778 command_line->AppendSwitchASCII( |
| 779 switches::kNetworkPredictionOptionsForServiceWorker, |
| 780 chrome_browser_net::kStartServiceWorkerAndPreconnect); |
| 781 break; |
| 782 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 783 START_SERVICE_WORKER_AND_DEFER_PRECONNECT: |
| 784 command_line->AppendSwitchASCII( |
| 785 switches::kNetworkPredictionOptionsForServiceWorker, |
| 786 chrome_browser_net::kStartServiceWorkerAndDeferPreconnect); |
| 787 break; |
| 788 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 789 START_SERVICE_WORKER_ONLY: |
| 790 command_line->AppendSwitchASCII( |
| 791 switches::kNetworkPredictionOptionsForServiceWorker, |
| 792 chrome_browser_net::kStartServiceWorkerOnly); |
| 793 break; |
| 794 } |
| 795 } |
| 796 |
| 797 void SetUpOnMainThread() override { |
| 798 WriteServiceWorkerPredictionOptionsTestFiles(); |
| 799 |
| 800 embedded_test_server()->ServeFilesFromDirectory( |
| 801 service_worker_dir_.GetPath()); |
| 802 ASSERT_TRUE(embedded_test_server()->Start()); |
| 803 |
| 804 cross_site_test_server()->ServeFilesFromDirectory( |
| 805 service_worker_dir_.GetPath()); |
| 806 cross_site_connection_listener_.reset(new ConnectionListener()); |
| 807 cross_site_test_server()->SetConnectionListener( |
| 808 cross_site_connection_listener_.get()); |
| 809 ASSERT_TRUE(cross_site_test_server()->Start()); |
| 810 |
| 811 browser()->profile()->GetNetworkPredictor()->SetPredictorEnabledForTest( |
| 812 true); |
| 813 } |
| 814 |
| 815 void InitializeServiceWorkerTest() { |
| 816 base::HistogramTester histogram_tester; |
| 817 const base::string16 expected_title = base::ASCIIToUTF16("READY"); |
| 818 content::TitleWatcher title_watcher( |
| 819 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); |
| 820 ui_test_utils::NavigateToURL( |
| 821 browser(), embedded_test_server()->GetURL( |
| 822 "/sw_test_page.html?" + |
| 823 cross_site_test_server()->GetURL("/test.js").spec())); |
| 824 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 825 histogram_tester.ExpectTotalCount("ServiceWorker.StartNewWorker.Status", 1); |
| 826 histogram_tester.ExpectBucketCount("ServiceWorker.StartNewWorker.Status", |
| 827 0 /* SERVICE_WORKER_OK */, 1); |
| 828 |
| 829 // Stop the service worker. |
| 830 content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) |
| 831 ->GetServiceWorkerContext() |
| 832 ->StopAllServiceWorkersForOrigin(embedded_test_server()->base_url()); |
| 833 |
| 834 // Disconnect the connection. |
| 835 cross_site_test_server()->FlushAllSocketsAndConnectionsOnUIThread(); |
| 836 EXPECT_TRUE(cross_site_connection_listener()->GetSocketAcceptedFlag()); |
| 837 cross_site_connection_listener()->ResetSocketAcceptedFlag(); |
| 838 } |
| 839 |
| 840 void NavigateToServiceWorkerTestPage() { |
| 841 const base::string16 expected_title = base::ASCIIToUTF16("SW"); |
| 842 content::TitleWatcher title_watcher( |
| 843 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); |
| 844 ui_test_utils::NavigateToURL(browser(), |
| 845 embedded_test_server()->GetURL("/dummy.html")); |
| 846 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 847 } |
| 848 |
| 849 void InitializeNoServiceWorkerTest() { |
| 850 const base::string16 expected_title = base::ASCIIToUTF16("READY"); |
| 851 content::TitleWatcher title_watcher( |
| 852 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); |
| 853 ui_test_utils::NavigateToURL( |
| 854 browser(), embedded_test_server()->GetURL( |
| 855 "/no_sw_test_page.html?" + |
| 856 cross_site_test_server()->GetURL("/test.js").spec())); |
| 857 |
| 858 // Disconnect the connection. |
| 859 cross_site_test_server()->FlushAllSocketsAndConnectionsOnUIThread(); |
| 860 EXPECT_TRUE(cross_site_connection_listener()->GetSocketAcceptedFlag()); |
| 861 cross_site_connection_listener()->ResetSocketAcceptedFlag(); |
| 862 } |
| 863 |
| 864 void NavigateToNoServiceWorkerTestPage() { |
| 865 const base::string16 expected_title = base::ASCIIToUTF16("READY"); |
| 866 content::TitleWatcher title_watcher( |
| 867 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); |
| 868 ui_test_utils::NavigateToURL( |
| 869 browser(), embedded_test_server()->GetURL("/no_sw_test_page.html")); |
| 870 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 871 } |
| 872 |
| 873 chrome_browser_net::NetworkPredictionOptionsForServiceWorker Options() const { |
| 874 return std::get<1>(GetParam()); |
| 875 } |
| 876 |
| 877 net::EmbeddedTestServer* cross_site_test_server() { |
| 878 return cross_site_test_server_.get(); |
| 879 } |
| 880 |
| 881 ConnectionListener* cross_site_connection_listener() { |
| 882 return cross_site_connection_listener_.get(); |
| 883 } |
| 884 |
| 885 private: |
| 886 void WriteServiceWorkerPredictionOptionsTestFiles() { |
| 887 WriteFile(FILE_PATH_LITERAL("test.js"), "document.title = 'READY';"); |
| 888 WriteFile(FILE_PATH_LITERAL("sw.js"), |
| 889 "this.onfetch = function(event) {" |
| 890 " event.respondWith(new Response(" |
| 891 " '<title>SW</title>', " |
| 892 " {headers: {'Content-Type': 'text/html'}}));" |
| 893 "};"); |
| 894 WriteFile(FILE_PATH_LITERAL("sw_test_page.html"), |
| 895 "<body><script>" |
| 896 "navigator.serviceWorker.register('./sw.js', {scope: './'})" |
| 897 " .then(reg => {" |
| 898 " reg.addEventListener('updatefound', _ => {" |
| 899 " var worker = reg.installing;" |
| 900 " worker.addEventListener('statechange', _ => {" |
| 901 " if (worker.state != 'activated')" |
| 902 " return;" |
| 903 " var script = document.createElement('script');" |
| 904 " script.src = window.location.search.substring(1);" |
| 905 " document.body.appendChild(script);" |
| 906 " });" |
| 907 " });" |
| 908 " });" |
| 909 "</script></body>"); |
| 910 WriteFile(FILE_PATH_LITERAL("no_sw_test_page.html"), |
| 911 "<body><script>" |
| 912 "if (window.location.search != '') {" |
| 913 " var script = document.createElement('script');" |
| 914 " script.src = window.location.search.substring(1);" |
| 915 " document.body.appendChild(script);" |
| 916 "} else {" |
| 917 " document.title = 'READY';" |
| 918 "}" |
| 919 "</script></body>"); |
| 920 } |
| 921 |
| 922 std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_; |
| 923 std::unique_ptr<ConnectionListener> cross_site_connection_listener_; |
| 924 |
| 925 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerPredictionOptionsTest); |
| 926 }; |
| 927 |
| 928 IN_PROC_BROWSER_TEST_P(ChromeServiceWorkerPredictionOptionsTest, |
| 929 ServiceWorkerTest) { |
| 930 InitializeServiceWorkerTest(); |
| 931 base::HistogramTester histogram_tester; |
| 932 NavigateToServiceWorkerTestPage(); |
| 933 histogram_tester.ExpectTotalCount("ServiceWorker.StartWorker.Purpose", 1); |
| 934 |
| 935 switch (Options()) { |
| 936 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 937 PRECONNECT_ONLY: |
| 938 histogram_tester.ExpectBucketCount( |
| 939 "ServiceWorker.StartWorker.Purpose", |
| 940 10 /* ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME */, 1); |
| 941 break; |
| 942 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 943 START_SERVICE_WORKER_AND_PRECONNECT: |
| 944 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 945 START_SERVICE_WORKER_AND_DEFER_PRECONNECT: |
| 946 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 947 START_SERVICE_WORKER_ONLY: |
| 948 histogram_tester.ExpectBucketCount( |
| 949 "ServiceWorker.StartWorker.Purpose", |
| 950 27 /* ServiceWorkerMetrics::EventType::NAVIGATION_HINT */, 1); |
| 951 break; |
| 952 } |
| 953 |
| 954 // Note: Wrting a chrome browset test which checks that the preconnection is |
| 955 // defered until the service worker startup is too complex. So we only check |
| 956 // that the preconnection is accutualy executed. |
| 957 switch (Options()) { |
| 958 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 959 PRECONNECT_ONLY: |
| 960 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 961 START_SERVICE_WORKER_AND_PRECONNECT: |
| 962 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 963 START_SERVICE_WORKER_AND_DEFER_PRECONNECT: |
| 964 cross_site_connection_listener()->WaitForSocketAcceptedOnUI(); |
| 965 break; |
| 966 case chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 967 START_SERVICE_WORKER_ONLY: |
| 968 EXPECT_FALSE(cross_site_connection_listener()->GetSocketAcceptedFlag()); |
| 969 break; |
| 970 } |
| 971 } |
| 972 |
| 973 IN_PROC_BROWSER_TEST_P(ChromeServiceWorkerPredictionOptionsTest, |
| 974 NoServiceWorkerTest) { |
| 975 InitializeNoServiceWorkerTest(); |
| 976 base::HistogramTester histogram_tester; |
| 977 NavigateToNoServiceWorkerTestPage(); |
| 978 // If there is no service workers, the preconnection must be executed |
| 979 // regardless of the options. |
| 980 cross_site_connection_listener()->WaitForSocketAcceptedOnUI(); |
| 981 } |
| 982 |
| 983 INSTANTIATE_TEST_CASE_P( |
| 984 /* no prefix */, |
| 985 ChromeServiceWorkerPredictionOptionsTest, |
| 986 ::testing::Combine( |
| 987 ::testing::Values(false, true), |
| 988 |
| 989 ::testing::Values( |
| 990 chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 991 PRECONNECT_ONLY, |
| 992 chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 993 START_SERVICE_WORKER_AND_PRECONNECT, |
| 994 chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 995 START_SERVICE_WORKER_AND_DEFER_PRECONNECT, |
| 996 chrome_browser_net::NetworkPredictionOptionsForServiceWorker:: |
| 997 START_SERVICE_WORKER_ONLY))); |
| 998 |
| 703 } // namespace | 999 } // namespace |
| OLD | NEW |