1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <map>
6 #include <memory>
7 
8 #include "base/command_line.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/run_loop.h"
11 #include "base/values.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/net/system_network_context_manager.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 #include "components/variations/variations_associated_data.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/test/browser_test.h"
19 #include "net/base/features.h"
20 #include "net/nqe/network_quality_estimator.h"
21 #include "net/test/embedded_test_server/embedded_test_server.h"
22 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
23 #include "services/network/public/cpp/network_quality_tracker.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "url/gurl.h"
26 
27 namespace {
28 
29 class TestNetworkQualityObserver
30     : public network::NetworkQualityTracker::EffectiveConnectionTypeObserver {
31  public:
TestNetworkQualityObserver(network::NetworkQualityTracker * tracker)32   explicit TestNetworkQualityObserver(network::NetworkQualityTracker* tracker)
33       : run_loop_wait_effective_connection_type_(
34             net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
35         tracker_(tracker),
36         effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
37     tracker_->AddEffectiveConnectionTypeObserver(this);
38   }
39 
~TestNetworkQualityObserver()40   ~TestNetworkQualityObserver() override {
41     tracker_->RemoveEffectiveConnectionTypeObserver(this);
42   }
43 
44   // NetworkQualityTracker::EffectiveConnectionTypeObserver implementation:
OnEffectiveConnectionTypeChanged(net::EffectiveConnectionType type)45   void OnEffectiveConnectionTypeChanged(
46       net::EffectiveConnectionType type) override {
47     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
48 
49     net::EffectiveConnectionType queried_type =
50         tracker_->GetEffectiveConnectionType();
51     EXPECT_EQ(type, queried_type);
52 
53     effective_connection_type_ = type;
54     if (effective_connection_type_ != run_loop_wait_effective_connection_type_)
55       return;
56     if (run_loop_)
57       run_loop_->Quit();
58   }
59 
WaitForNotification(net::EffectiveConnectionType run_loop_wait_effective_connection_type)60   void WaitForNotification(
61       net::EffectiveConnectionType run_loop_wait_effective_connection_type) {
62     if (effective_connection_type_ == run_loop_wait_effective_connection_type)
63       return;
64     ASSERT_NE(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
65               run_loop_wait_effective_connection_type);
66     run_loop_.reset(new base::RunLoop());
67     run_loop_wait_effective_connection_type_ =
68         run_loop_wait_effective_connection_type;
69     run_loop_->Run();
70     run_loop_.reset();
71   }
72 
73  private:
74   net::EffectiveConnectionType run_loop_wait_effective_connection_type_;
75   std::unique_ptr<base::RunLoop> run_loop_;
76   network::NetworkQualityTracker* tracker_;
77   net::EffectiveConnectionType effective_connection_type_;
78 
79   DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityObserver);
80 };
81 
CheckEffectiveConnectionType(net::EffectiveConnectionType expected)82 void CheckEffectiveConnectionType(net::EffectiveConnectionType expected) {
83   TestNetworkQualityObserver network_quality_observer(
84       g_browser_process->network_quality_tracker());
85   network_quality_observer.WaitForNotification(expected);
86 }
87 
88 class NetworkQualityEstimatorBrowserTest : public InProcessBrowserTest {
89  public:
NetworkQualityEstimatorBrowserTest()90   NetworkQualityEstimatorBrowserTest() {}
~NetworkQualityEstimatorBrowserTest()91   ~NetworkQualityEstimatorBrowserTest() override {}
92 
SetUp()93   void SetUp() override {
94     // Must start listening (And get a port for the proxy) before calling
95     // SetUp(). Use two phase EmbeddedTestServer setup for proxy tests.
96     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
97     InProcessBrowserTest::SetUp();
98   }
99 
SetUpOnMainThread()100   void SetUpOnMainThread() override {
101     embedded_test_server()->StartAcceptingConnections();
102   }
103 
TearDown()104   void TearDown() override {
105     // Need to stop this before |connection_listener_| is destroyed.
106     EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
107     InProcessBrowserTest::TearDown();
108   }
109 };
110 
111 class NetworkQualityEstimatorEctCommandLineBrowserTest
112     : public NetworkQualityEstimatorBrowserTest {
113  public:
NetworkQualityEstimatorEctCommandLineBrowserTest()114   NetworkQualityEstimatorEctCommandLineBrowserTest() {}
~NetworkQualityEstimatorEctCommandLineBrowserTest()115   ~NetworkQualityEstimatorEctCommandLineBrowserTest() override {}
116 
SetUpCommandLine(base::CommandLine * command_line)117   void SetUpCommandLine(base::CommandLine* command_line) override {
118     command_line->AppendSwitchASCII("--force-effective-connection-type",
119                                     "Slow-2G");
120   }
121 };
122 
IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorEctCommandLineBrowserTest,ForceECTFromCommandLine)123 IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorEctCommandLineBrowserTest,
124                        ForceECTFromCommandLine) {
125   CheckEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
126 }
127 
128 class NetworkQualityEstimatorEctFieldTrialBrowserTest
129     : public NetworkQualityEstimatorBrowserTest {
130  public:
NetworkQualityEstimatorEctFieldTrialBrowserTest()131   NetworkQualityEstimatorEctFieldTrialBrowserTest() {}
~NetworkQualityEstimatorEctFieldTrialBrowserTest()132   ~NetworkQualityEstimatorEctFieldTrialBrowserTest() override {}
133 
SetUpCommandLine(base::CommandLine * command_line)134   void SetUpCommandLine(base::CommandLine* command_line) override {
135     variations::testing::ClearAllVariationParams();
136     std::map<std::string, std::string> variation_params;
137     variation_params["force_effective_connection_type"] = "2G";
138     scoped_feature_list_.InitAndEnableFeatureWithParameters(
139         net::features::kNetworkQualityEstimator, variation_params);
140   }
141 
142  private:
143   base::test::ScopedFeatureList scoped_feature_list_;
144 };
145 
IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorEctFieldTrialBrowserTest,ForceECTUsingFieldTrial)146 IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorEctFieldTrialBrowserTest,
147                        ForceECTUsingFieldTrial) {
148   CheckEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
149 }
150 
151 class NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest
152     : public NetworkQualityEstimatorEctFieldTrialBrowserTest {
153  public:
NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest()154   NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest() {}
~NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest()155   ~NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest() override {}
156 
SetUpCommandLine(base::CommandLine * command_line)157   void SetUpCommandLine(base::CommandLine* command_line) override {
158     NetworkQualityEstimatorEctFieldTrialBrowserTest::SetUpCommandLine(
159         command_line);
160     command_line->AppendSwitchASCII("--force-effective-connection-type",
161                                     "Slow-2G");
162   }
163 };
164 
IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest,ECTFromCommandLineOverridesFieldTrial)165 IN_PROC_BROWSER_TEST_F(
166     NetworkQualityEstimatorEctFieldTrialAndCommandLineBrowserTest,
167     ECTFromCommandLineOverridesFieldTrial) {
168   CheckEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
169 }
170 
171 }  // namespace
172