| // Copyright 2022 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "base/barrier_closure.h" | 
 | #include "base/containers/contains.h" | 
 | #include "base/functional/bind.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/test/metrics/histogram_tester.h" | 
 | #include "build/build_config.h" | 
 | #include "chrome/browser/browser_process.h" | 
 | #include "chrome/browser/profiles/profile.h" | 
 | #include "chrome/browser/ui/browser.h" | 
 | #include "chrome/browser/ui/browser_commands.h" | 
 | #include "chrome/browser/ui/tabs/tab_strip_model.h" | 
 | #include "chrome/test/base/chrome_test_utils.h" | 
 | #include "chrome/test/base/in_process_browser_test.h" | 
 | #include "chrome/test/base/ui_test_utils.h" | 
 | #include "components/prefs/pref_service.h" | 
 | #include "content/public/test/browser_test.h" | 
 | #include "content/public/test/browser_test_base.h" | 
 | #include "content/public/test/browser_test_utils.h" | 
 | #include "content/public/test/prerender_test_util.h" | 
 | #include "data_saver.h" | 
 | #include "net/test/embedded_test_server/embedded_test_server.h" | 
 | #include "net/test/embedded_test_server/http_request.h" | 
 | #include "net/test/embedded_test_server/http_response.h" | 
 | #include "services/network/public/cpp/network_quality_tracker.h" | 
 | #include "third_party/blink/public/common/features.h" | 
 |  | 
 | namespace { | 
 |  | 
 | std::unique_ptr<net::test_server::HttpResponse> CaptureHeaderHandlerWithContent( | 
 |     const std::string& path, | 
 |     net::test_server::HttpRequest::HeaderMap* header_map, | 
 |     const std::string& mime_type, | 
 |     const std::string& content, | 
 |     base::OnceClosure done_callback, | 
 |     const net::test_server::HttpRequest& request) { | 
 |   GURL request_url = request.GetURL(); | 
 |   if (request_url.path() != path) | 
 |     return nullptr; | 
 |  | 
 |   *header_map = request.headers; | 
 |   auto response = std::make_unique<net::test_server::BasicHttpResponse>(); | 
 |   if (!mime_type.empty()) { | 
 |     response->set_content_type(mime_type); | 
 |   } | 
 |   response->set_content(content); | 
 |   std::move(done_callback).Run(); | 
 |   return response; | 
 | } | 
 |  | 
 | // Test version of the observer. Used to wait for the event when the network | 
 | // quality tracker sends the network quality change notification. | 
 | class TestEffectiveConnectionTypeObserver | 
 |     : public network::NetworkQualityTracker::EffectiveConnectionTypeObserver { | 
 |  public: | 
 |   explicit TestEffectiveConnectionTypeObserver( | 
 |       network::NetworkQualityTracker* tracker) | 
 |       : run_loop_wait_effective_connection_type_( | 
 |             net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 
 |         run_loop_(std::make_unique<base::RunLoop>()), | 
 |         tracker_(tracker), | 
 |         effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { | 
 |     tracker_->AddEffectiveConnectionTypeObserver(this); | 
 |   } | 
 |  | 
 |   TestEffectiveConnectionTypeObserver( | 
 |       const TestEffectiveConnectionTypeObserver&) = delete; | 
 |   TestEffectiveConnectionTypeObserver& operator=( | 
 |       const TestEffectiveConnectionTypeObserver&) = delete; | 
 |  | 
 |   ~TestEffectiveConnectionTypeObserver() override { | 
 |     tracker_->RemoveEffectiveConnectionTypeObserver(this); | 
 |   } | 
 |  | 
 |   void WaitForNotification( | 
 |       net::EffectiveConnectionType run_loop_wait_effective_connection_type) { | 
 |     if (effective_connection_type_ == run_loop_wait_effective_connection_type) | 
 |       return; | 
 |     ASSERT_NE(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, | 
 |               run_loop_wait_effective_connection_type); | 
 |     run_loop_wait_effective_connection_type_ = | 
 |         run_loop_wait_effective_connection_type; | 
 |     run_loop_->Run(); | 
 |     run_loop_ = std::make_unique<base::RunLoop>(); | 
 |   } | 
 |  | 
 |  private: | 
 |   // NetworkQualityTracker::EffectiveConnectionTypeObserver implementation: | 
 |   void OnEffectiveConnectionTypeChanged( | 
 |       net::EffectiveConnectionType type) override { | 
 |     DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 
 |  | 
 |     net::EffectiveConnectionType queried_type = | 
 |         tracker_->GetEffectiveConnectionType(); | 
 |     EXPECT_EQ(type, queried_type); | 
 |  | 
 |     effective_connection_type_ = type; | 
 |     if (effective_connection_type_ != run_loop_wait_effective_connection_type_) | 
 |       return; | 
 |     run_loop_->Quit(); | 
 |   } | 
 |  | 
 |   net::EffectiveConnectionType run_loop_wait_effective_connection_type_; | 
 |   std::unique_ptr<base::RunLoop> run_loop_; | 
 |   raw_ptr<network::NetworkQualityTracker> tracker_; | 
 |   net::EffectiveConnectionType effective_connection_type_; | 
 | }; | 
 |  | 
 | // Test version of the observer. Used to wait for the event when the network | 
 | // quality tracker sends the network quality change notification. | 
 | class TestRTTAndThroughputEstimatesObserver | 
 |     : public network::NetworkQualityTracker::RTTAndThroughputEstimatesObserver { | 
 |  public: | 
 |   explicit TestRTTAndThroughputEstimatesObserver( | 
 |       network::NetworkQualityTracker* tracker) | 
 |       : tracker_(tracker), | 
 |         downstream_throughput_kbps_(std::numeric_limits<int32_t>::max()) { | 
 |     tracker_->AddRTTAndThroughputEstimatesObserver(this); | 
 |   } | 
 |  | 
 |   TestRTTAndThroughputEstimatesObserver( | 
 |       const TestRTTAndThroughputEstimatesObserver&) = delete; | 
 |   TestRTTAndThroughputEstimatesObserver& operator=( | 
 |       const TestRTTAndThroughputEstimatesObserver&) = delete; | 
 |  | 
 |   ~TestRTTAndThroughputEstimatesObserver() override { | 
 |     tracker_->RemoveRTTAndThroughputEstimatesObserver(this); | 
 |   } | 
 |  | 
 |   void WaitForNotification(base::TimeDelta expected_http_rtt) { | 
 |     // It's not meaningful to wait for notification with RTT set to | 
 |     // base::TimeDelta() since that value implies that the network quality | 
 |     // estimate was unavailable. | 
 |     EXPECT_NE(base::TimeDelta(), expected_http_rtt); | 
 |     http_rtt_notification_wait_ = expected_http_rtt; | 
 |     if (http_rtt_notification_wait_ == http_rtt_) | 
 |       return; | 
 |  | 
 |     // WaitForNotification should not be called twice. | 
 |     EXPECT_EQ(nullptr, run_loop_); | 
 |     run_loop_ = std::make_unique<base::RunLoop>(); | 
 |     run_loop_->Run(); | 
 |     EXPECT_EQ(expected_http_rtt, http_rtt_); | 
 |     run_loop_.reset(); | 
 |   } | 
 |  | 
 |  private: | 
 |   // RTTAndThroughputEstimatesObserver implementation: | 
 |   void OnRTTOrThroughputEstimatesComputed( | 
 |       base::TimeDelta http_rtt, | 
 |       base::TimeDelta transport_rtt, | 
 |       int32_t downstream_throughput_kbps) override { | 
 |     EXPECT_EQ(http_rtt, tracker_->GetHttpRTT()); | 
 |     EXPECT_EQ(downstream_throughput_kbps, | 
 |               tracker_->GetDownstreamThroughputKbps()); | 
 |  | 
 |     http_rtt_ = http_rtt; | 
 |     downstream_throughput_kbps_ = downstream_throughput_kbps; | 
 |  | 
 |     if (run_loop_ && http_rtt == http_rtt_notification_wait_) | 
 |       run_loop_->Quit(); | 
 |   } | 
 |  | 
 |   raw_ptr<network::NetworkQualityTracker> tracker_; | 
 |   // May be null. | 
 |   std::unique_ptr<base::RunLoop> run_loop_; | 
 |   base::TimeDelta http_rtt_; | 
 |   int32_t downstream_throughput_kbps_; | 
 |   base::TimeDelta http_rtt_notification_wait_; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | class DataSaverBrowserTest : public InProcessBrowserTest { | 
 |  public: | 
 |   DataSaverBrowserTest() | 
 |       : prerender_helper_( | 
 |             base::BindRepeating(&DataSaverBrowserTest::GetActiveWebContents, | 
 |                                 base::Unretained(this))) {} | 
 |  | 
 |   void SetUp() override { | 
 |     prerender_helper_.SetUp(embedded_test_server()); | 
 |     InProcessBrowserTest::SetUp(); | 
 |   } | 
 |  | 
 |   content::test::PrerenderTestHelper* prerender_helper() { | 
 |     return &prerender_helper_; | 
 |   } | 
 |  | 
 |  protected: | 
 |   void VerifySaveDataHeader(const std::string& expected_header_value, | 
 |                             Browser* browser = nullptr) { | 
 |     if (!browser) | 
 |       browser = InProcessBrowserTest::browser(); | 
 |     ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |         browser, embedded_test_server()->GetURL("/echoheader?Save-Data"))); | 
 |     EXPECT_EQ( | 
 |         expected_header_value, | 
 |         content::EvalJs(browser->tab_strip_model()->GetActiveWebContents(), | 
 |                         "document.body.textContent;")); | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     data_saver::ResetIsDataSaverEnabledForTesting(); | 
 |     InProcessBrowserTest::TearDown(); | 
 |   } | 
 |  | 
 |   content::WebContents* GetActiveWebContents() { | 
 |     return chrome_test_utils::GetActiveWebContents(this); | 
 |   } | 
 |  | 
 |  private: | 
 |   content::test::PrerenderTestHelper prerender_helper_; | 
 | }; | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverBrowserTest, DataSaverEnabled) { | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(true); | 
 |   VerifySaveDataHeader("on"); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverBrowserTest, DataSaverDisabled) { | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(false); | 
 |   VerifySaveDataHeader("None"); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverBrowserTest, DataSaverDisabledInIncognito) { | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(true); | 
 |   VerifySaveDataHeader("None", CreateIncognitoBrowser()); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverBrowserTest, | 
 |                        DataSaverEnabledDisablesPrerendering) { | 
 |   base::HistogramTester histogram_tester; | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(true); | 
 |  | 
 |   const GURL initial_url = embedded_test_server()->GetURL("/empty.html"); | 
 |   const GURL prerendering_url = | 
 |       embedded_test_server()->GetURL("/empty.html?prerender"); | 
 |  | 
 |   content::test::PrerenderHostRegistryObserver observer( | 
 |       *GetActiveWebContents()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url)); | 
 |   prerender_helper()->AddPrerenderAsync(prerendering_url); | 
 |   observer.WaitForTrigger(prerendering_url); | 
 |  | 
 |   int host_id = prerender_helper()->GetHostForUrl(prerendering_url); | 
 |   EXPECT_EQ(host_id, content::RenderFrameHost::kNoFrameTreeNodeId); | 
 |  | 
 |   histogram_tester.ExpectUniqueSample( | 
 |       "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule", | 
 |       /*PrerenderFinalStatus::kDataSaverEnabled=*/38, 1); | 
 | } | 
 |  | 
 | class DataSaverWithServerBrowserTest : public InProcessBrowserTest { | 
 |  protected: | 
 |   void Init() { | 
 |     test_server_ = std::make_unique<net::EmbeddedTestServer>(); | 
 |     test_server_->RegisterRequestHandler(base::BindRepeating( | 
 |         &DataSaverWithServerBrowserTest::VerifySaveDataHeader, | 
 |         base::Unretained(this))); | 
 |     test_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir()); | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     data_saver::ResetIsDataSaverEnabledForTesting(); | 
 |     InProcessBrowserTest::TearDown(); | 
 |   } | 
 |  | 
 |   std::unique_ptr<net::test_server::HttpResponse> VerifySaveDataHeader( | 
 |       const net::test_server::HttpRequest& request) { | 
 |     auto save_data_header_it = request.headers.find("save-data"); | 
 |  | 
 |     if (request.relative_url == "/favicon.ico") { | 
 |       // Favicon request could be received for the previous page load. | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     if (!expected_save_data_header_.empty()) { | 
 |       EXPECT_TRUE(save_data_header_it != request.headers.end()) | 
 |           << request.relative_url; | 
 |       EXPECT_EQ(expected_save_data_header_, save_data_header_it->second) | 
 |           << request.relative_url; | 
 |     } else { | 
 |       EXPECT_TRUE(save_data_header_it == request.headers.end()) | 
 |           << request.relative_url; | 
 |     } | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   std::unique_ptr<net::EmbeddedTestServer> test_server_; | 
 |   std::string expected_save_data_header_; | 
 | }; | 
 |  | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_F(DataSaverWithServerBrowserTest, DISABLED_ReloadPage) { | 
 |   Init(); | 
 |   ASSERT_TRUE(test_server_->Start()); | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(true); | 
 |  | 
 |   expected_save_data_header_ = "on"; | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), test_server_->GetURL("/google/google.html"))); | 
 |  | 
 |   // Reload the webpage and expect the main and the subresources will get the | 
 |   // correct save-data header. | 
 |   expected_save_data_header_ = "on"; | 
 |   chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); | 
 |   EXPECT_TRUE(content::WaitForLoadStop( | 
 |       browser()->tab_strip_model()->GetActiveWebContents())); | 
 |  | 
 |   // Reload the webpage with data saver disabled, and expect all the resources | 
 |   // will get no save-data header. | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(false); | 
 |   expected_save_data_header_ = ""; | 
 |   chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); | 
 |   EXPECT_TRUE(content::WaitForLoadStop( | 
 |       browser()->tab_strip_model()->GetActiveWebContents())); | 
 | } | 
 |  | 
 | class DataSaverForWorkerBrowserTest : public InProcessBrowserTest, | 
 |                                       public testing::WithParamInterface<bool> { | 
 |  protected: | 
 |   // Sends a request to |url| and returns its headers via |header_map|. |script| | 
 |   // is provided as the response body. | 
 |   void RequestAndGetHeaders( | 
 |       const std::string& url, | 
 |       const std::string& script, | 
 |       net::test_server::HttpRequest::HeaderMap* header_map) { | 
 |     base::RunLoop loop; | 
 |     embedded_test_server()->RegisterRequestHandler(base::BindRepeating( | 
 |         &CaptureHeaderHandlerWithContent, "/capture", header_map, | 
 |         "text/javascript", script, loop.QuitClosure())); | 
 |     ASSERT_TRUE(embedded_test_server()->Start()); | 
 |  | 
 |     ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |         browser(), embedded_test_server()->GetURL(url))); | 
 |     loop.Run(); | 
 |   } | 
 |  | 
 |   content::WebContents* GetActiveWebContents() { | 
 |     return browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   } | 
 |  | 
 |   static bool IsEnabledDataSaver() { return GetParam(); } | 
 |  | 
 |   void TearDown() override { | 
 |     data_saver::ResetIsDataSaverEnabledForTesting(); | 
 |     InProcessBrowserTest::TearDown(); | 
 |   } | 
 | }; | 
 |  | 
 | INSTANTIATE_TEST_SUITE_P(/* no prefix */, | 
 |                          DataSaverForWorkerBrowserTest, | 
 |                          testing::Bool()); | 
 |  | 
 | // Checks that the Save-Data header is sent in a request for dedicated worker | 
 | // script when the data saver is enabled. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, | 
 |                        DISABLED_DedicatedWorker) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |  | 
 |   const std::string kWorkerScript = R"(postMessage('DONE');)"; | 
 |   net::test_server::HttpRequest::HeaderMap header_map; | 
 |   RequestAndGetHeaders( | 
 |       "/workers/create_dedicated_worker.html?worker_url=/capture", | 
 |       kWorkerScript, &header_map); | 
 |  | 
 |   if (IsEnabledDataSaver()) { | 
 |     EXPECT_TRUE(base::Contains(header_map, "Save-Data")); | 
 |     EXPECT_EQ("on", header_map["Save-Data"]); | 
 |   } else { | 
 |     EXPECT_FALSE(base::Contains(header_map, "Save-Data")); | 
 |   } | 
 |  | 
 |   // Wait until the worker script is loaded to stop the test from crashing | 
 |   // during destruction. | 
 |   EXPECT_EQ("DONE", content::EvalJs( | 
 |                         browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                         "waitForMessage();")); | 
 | } | 
 |  | 
 | // Checks that the Save-Data header is sent in a request for shared worker | 
 | // script when the data saver is enabled. Disabled on Android since a shared | 
 | // worker is not available on Android. | 
 | #if BUILDFLAG(IS_ANDROID) | 
 | #define MAYBE_SharedWorker DISABLED_SharedWorker | 
 | #else | 
 | #define MAYBE_SharedWorker SharedWorker | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, MAYBE_SharedWorker) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |  | 
 |   const std::string kWorkerScript = | 
 |       R"(self.onconnect = e => { e.ports[0].postMessage('DONE'); };)"; | 
 |   net::test_server::HttpRequest::HeaderMap header_map; | 
 |   RequestAndGetHeaders("/workers/create_shared_worker.html?worker_url=/capture", | 
 |                        kWorkerScript, &header_map); | 
 |  | 
 |   if (IsEnabledDataSaver()) { | 
 |     EXPECT_TRUE(base::Contains(header_map, "Save-Data")); | 
 |     EXPECT_EQ("on", header_map["Save-Data"]); | 
 |   } else { | 
 |     EXPECT_FALSE(base::Contains(header_map, "Save-Data")); | 
 |   } | 
 |  | 
 |   // Wait until the worker script is loaded to stop the test from crashing | 
 |   // during destruction. | 
 |   EXPECT_EQ("DONE", content::EvalJs( | 
 |                         browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                         "waitForMessage();")); | 
 | } | 
 |  | 
 | // Checks that the Save-Data header is not sent in a request for a service | 
 | // worker script when it's disabled. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, ServiceWorker_Register) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   net::test_server::HttpRequest::HeaderMap header_map; | 
 |   base::RunLoop loop; | 
 |   embedded_test_server()->RegisterRequestHandler(base::BindRepeating( | 
 |       &CaptureHeaderHandlerWithContent, "/capture", &header_map, | 
 |       "text/javascript", "// empty", loop.QuitClosure())); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/create_service_worker.html"))); | 
 |  | 
 |   EXPECT_EQ("DONE", | 
 |             content::EvalJs(GetActiveWebContents(), "register('/capture');")); | 
 |   loop.Run(); | 
 |  | 
 |   if (IsEnabledDataSaver()) { | 
 |     EXPECT_TRUE(base::Contains(header_map, "Save-Data")); | 
 |     EXPECT_EQ("on", header_map["Save-Data"]); | 
 |   } else { | 
 |     EXPECT_FALSE(base::Contains(header_map, "Save-Data")); | 
 |   } | 
 |  | 
 |   // Service worker doesn't have to wait for onmessage event because | 
 |   // navigator.serviceWorker.ready can ensure that the script load has | 
 |   // been completed. | 
 | } | 
 |  | 
 | // Checks that the Save-Data header is not sent in a request for a service | 
 | // worker script when it's disabled. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, ServiceWorker_Update) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   net::test_server::HttpRequest::HeaderMap header_map; | 
 |   base::RunLoop loop; | 
 |   // Wait for two requests to capture the request header for updating. | 
 |   embedded_test_server()->RegisterRequestHandler( | 
 |       base::BindRepeating(&CaptureHeaderHandlerWithContent, "/capture", | 
 |                           &header_map, "text/javascript", "// empty", | 
 |                           base::BarrierClosure(2, loop.QuitClosure()))); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/create_service_worker.html"))); | 
 |  | 
 |   EXPECT_EQ("DONE", | 
 |             content::EvalJs(GetActiveWebContents(), "register('/capture');")); | 
 |   EXPECT_EQ("DONE", content::EvalJs(GetActiveWebContents(), "update();")); | 
 |   loop.Run(); | 
 |  | 
 |   if (IsEnabledDataSaver()) { | 
 |     EXPECT_TRUE(base::Contains(header_map, "Save-Data")); | 
 |     EXPECT_EQ("on", header_map["Save-Data"]); | 
 |   } else { | 
 |     EXPECT_FALSE(base::Contains(header_map, "Save-Data")); | 
 |   } | 
 |  | 
 |   // Service worker doesn't have to wait for onmessage event because | 
 |   // navigator.serviceWorker.ready can ensure that the script load has | 
 |   // been completed. | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a dedicated worker. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, | 
 |                        DISABLED_FetchFromWorker) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), | 
 |       embedded_test_server()->GetURL("/workers/fetch_from_worker.html"))); | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ(expected, | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "fetch_from_worker('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a shared worker. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, | 
 |                        DISABLED_FetchFromSharedWorker) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/workers/fetch_from_shared_worker.html"))); | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ( | 
 |       expected, | 
 |       content::EvalJs(GetActiveWebContents(), | 
 |                       "fetch_from_shared_worker('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a service worker. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P(DataSaverForWorkerBrowserTest, | 
 |                        DISABLED_FetchFromServiceWorker) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/fetch_from_service_worker.html"))); | 
 |   EXPECT_EQ("ready", content::EvalJs(GetActiveWebContents(), "setup();")); | 
 |  | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ( | 
 |       expected, | 
 |       content::EvalJs(GetActiveWebContents(), | 
 |                       "fetch_from_service_worker('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a page controlled by a service worker without fetch handler. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     DataSaverForWorkerBrowserTest, | 
 |     DISABLED_FetchFromServiceWorkerControlledPage_NoFetchHandler) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/create_service_worker.html"))); | 
 |   EXPECT_EQ("DONE", | 
 |             content::EvalJs(GetActiveWebContents(), "register('empty.js');")); | 
 |  | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), | 
 |       embedded_test_server()->GetURL("/service_worker/fetch_from_page.html"))); | 
 |  | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ(expected, | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "fetch_from_page('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a page controlled by a service worker with fetch handler but no respondWith. | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     DataSaverForWorkerBrowserTest, | 
 |     DISABLED_FetchFromServiceWorkerControlledPage_PassThrough) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/create_service_worker.html"))); | 
 |   EXPECT_EQ("DONE", | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "register('fetch_event_pass_through.js');")); | 
 |  | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), | 
 |       embedded_test_server()->GetURL("/service_worker/fetch_from_page.html"))); | 
 |  | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ(expected, | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "fetch_from_page('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | // Checks that Save-Data header is appropriately set to requests from fetch() in | 
 | // a page controlled by a service worker with fetch handler and responds with | 
 | // fetch(). | 
 | // TODO(crbug.com/1401238): Fix and enable test. | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     DataSaverForWorkerBrowserTest, | 
 |     DISABLED_FetchFromServiceWorkerControlledPage_RespondWithFetch) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(IsEnabledDataSaver()); | 
 |   ASSERT_TRUE(embedded_test_server()->Start()); | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), embedded_test_server()->GetURL( | 
 |                      "/service_worker/create_service_worker.html"))); | 
 |   EXPECT_EQ("DONE", | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "register('fetch_event_respond_with_fetch.js');")); | 
 |  | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), | 
 |       embedded_test_server()->GetURL("/service_worker/fetch_from_page.html"))); | 
 |  | 
 |   const char* expected = IsEnabledDataSaver() ? "on" : "None"; | 
 |   EXPECT_EQ(expected, | 
 |             content::EvalJs(GetActiveWebContents(), | 
 |                             "fetch_from_page('/echoheader?Save-Data');")); | 
 | } | 
 |  | 
 | class DataSaverWithImageServerBrowserTest : public InProcessBrowserTest { | 
 |  public: | 
 |   DataSaverWithImageServerBrowserTest() { | 
 |     scoped_feature_list_.InitWithFeatures({blink::features::kSaveDataImgSrcset}, | 
 |                                           {}); | 
 |   } | 
 |   void SetUp() override { | 
 |     test_server_ = std::make_unique<net::EmbeddedTestServer>(); | 
 |     test_server_->RegisterRequestMonitor(base::BindRepeating( | 
 |         &DataSaverWithImageServerBrowserTest::MonitorImageRequest, | 
 |         base::Unretained(this))); | 
 |     test_server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir()); | 
 |     ASSERT_TRUE(test_server_->Start()); | 
 |  | 
 |     InProcessBrowserTest::SetUp(); | 
 |   } | 
 |  | 
 |   void SetImagesNotToLoad(const std::vector<std::string>& imgs_not_to_load) { | 
 |     imgs_not_to_load_ = std::vector<std::string>(imgs_not_to_load); | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     data_saver::ResetIsDataSaverEnabledForTesting(); | 
 |     InProcessBrowserTest::TearDown(); | 
 |   } | 
 |  | 
 |   std::unique_ptr<net::EmbeddedTestServer> test_server_; | 
 |  | 
 |  private: | 
 |   // Called by |test_server_|. | 
 |   void MonitorImageRequest(const net::test_server::HttpRequest& request) { | 
 |     for (const auto& img : imgs_not_to_load_) | 
 |       EXPECT_FALSE(request.GetURL().path() == img); | 
 |   } | 
 |  | 
 |   base::test::ScopedFeatureList scoped_feature_list_; | 
 |   std::vector<std::string> imgs_not_to_load_; | 
 | }; | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverWithImageServerBrowserTest, | 
 |                        ImgSrcset_DataSaverEnabled) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(true); | 
 |   SetImagesNotToLoad({"/data_saver/red.jpg"}); | 
 |  | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), test_server_->GetURL("/data_saver/image_srcset.html"))); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(DataSaverWithImageServerBrowserTest, | 
 |                        ImgSrcset_DataSaverDisabled) { | 
 |   data_saver::OverrideIsDataSaverEnabledForTesting(false); | 
 |   SetImagesNotToLoad({"/data_saver/green.jpg"}); | 
 |  | 
 |   ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
 |       browser(), test_server_->GetURL("/data_saver/image_srcset.html"))); | 
 | } |