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 "base/bind.h"
6 #include "base/callback_forward.h"
7 #include "base/check_op.h"
8 #include "base/feature_list.h"
9 #include "base/macros.h"
10 #include "base/run_loop.h"
11 #include "base/sequence_checker.h"
12 #include "base/test/bind.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/network_service_instance.h"
19 #include "content/public/browser/storage_partition.h"
20 #include "content/public/common/network_service_util.h"
21 #include "content/public/test/browser_test.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "mojo/public/cpp/bindings/remote.h"
24 #include "net/base/network_change_notifier.h"
25 #include "services/network/public/cpp/features.h"
26 #include "services/network/public/cpp/network_connection_tracker.h"
27 #include "services/network/public/mojom/network_service_test.mojom.h"
28 
29 namespace {
30 
31 class TestNetworkConnectionObserver
32     : public network::NetworkConnectionTracker::NetworkConnectionObserver {
33  public:
TestNetworkConnectionObserver(network::NetworkConnectionTracker * tracker)34   explicit TestNetworkConnectionObserver(
35       network::NetworkConnectionTracker* tracker)
36       : num_notifications_(0),
37         tracker_(tracker),
38         run_loop_(std::make_unique<base::RunLoop>()),
39         connection_type_(network::mojom::ConnectionType::CONNECTION_UNKNOWN) {
40     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
41     tracker_->AddNetworkConnectionObserver(this);
42   }
43 
~TestNetworkConnectionObserver()44   ~TestNetworkConnectionObserver() override {
45     tracker_->RemoveNetworkConnectionObserver(this);
46   }
47 
48   // NetworkConnectionObserver implementation:
OnConnectionChanged(network::mojom::ConnectionType type)49   void OnConnectionChanged(network::mojom::ConnectionType type) override {
50     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
51     network::mojom::ConnectionType queried_type;
52     bool sync = tracker_->GetConnectionType(
53         &queried_type,
54         base::BindOnce([](network::mojom::ConnectionType type) {}));
55     EXPECT_TRUE(sync);
56     EXPECT_EQ(type, queried_type);
57 
58     num_notifications_++;
59     connection_type_ = type;
60     run_loop_->Quit();
61   }
62 
WaitForNotification()63   void WaitForNotification() {
64     run_loop_->Run();
65     run_loop_ = std::make_unique<base::RunLoop>();
66   }
67 
num_notifications() const68   size_t num_notifications() const { return num_notifications_; }
connection_type() const69   network::mojom::ConnectionType connection_type() const {
70     return connection_type_;
71   }
72 
73  private:
74   size_t num_notifications_;
75   network::NetworkConnectionTracker* tracker_;
76   std::unique_ptr<base::RunLoop> run_loop_;
77   network::mojom::ConnectionType connection_type_;
78 
79   SEQUENCE_CHECKER(sequence_checker_);
80 
81   DISALLOW_COPY_AND_ASSIGN(TestNetworkConnectionObserver);
82 };
83 
84 }  // namespace
85 
86 class NetworkConnectionTrackerBrowserTest : public InProcessBrowserTest {
87  public:
NetworkConnectionTrackerBrowserTest()88   NetworkConnectionTrackerBrowserTest() {}
~NetworkConnectionTrackerBrowserTest()89   ~NetworkConnectionTrackerBrowserTest() override {}
90 
91   // Simulates a network connection change.
SimulateNetworkChange(network::mojom::ConnectionType type)92   void SimulateNetworkChange(network::mojom::ConnectionType type) {
93     if (!content::IsInProcessNetworkService()) {
94       mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
95       content::GetNetworkService()->BindTestInterface(
96           network_service_test.BindNewPipeAndPassReceiver());
97       base::RunLoop run_loop;
98       network_service_test->SimulateNetworkChange(
99           type,
100           base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
101                          base::Unretained(&run_loop)));
102       run_loop.Run();
103       return;
104     }
105     net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
106         net::NetworkChangeNotifier::ConnectionType(type));
107   }
108 
109  private:
110 };
111 
112 // Basic test to make sure NetworkConnectionTracker is set up.
IN_PROC_BROWSER_TEST_F(NetworkConnectionTrackerBrowserTest,NetworkConnectionTracker)113 IN_PROC_BROWSER_TEST_F(NetworkConnectionTrackerBrowserTest,
114                        NetworkConnectionTracker) {
115   // NetworkService on ChromeOS doesn't yet have a NetworkChangeManager
116   // implementation. OSX uses a separate binary for service processes and
117   // browser test fixture doesn't have NetworkServiceTest mojo code.
118 #if !defined(OS_CHROMEOS) && !defined(OS_MAC)
119   network::NetworkConnectionTracker* tracker =
120       content::GetNetworkConnectionTracker();
121   EXPECT_NE(nullptr, tracker);
122   // Issue a GetConnectionType() request to make sure NetworkService has been
123   // started up. This way, NetworkService will receive the broadcast when
124   // SimulateNetworkChange() is called.
125   base::RunLoop run_loop;
126   network::mojom::ConnectionType ignored_type;
127   bool sync = tracker->GetConnectionType(
128       &ignored_type,
129       base::BindOnce(
130           [](base::RunLoop* run_loop, network::mojom::ConnectionType type) {
131             run_loop->Quit();
132           },
133           base::Unretained(&run_loop)));
134   if (!sync)
135     run_loop.Run();
136   TestNetworkConnectionObserver network_connection_observer(tracker);
137   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
138   network_connection_observer.WaitForNotification();
139   EXPECT_EQ(network::mojom::ConnectionType::CONNECTION_3G,
140             network_connection_observer.connection_type());
141   base::RunLoop().RunUntilIdle();
142   EXPECT_EQ(1u, network_connection_observer.num_notifications());
143 #endif
144 }
145 
146 // Simulates a network service crash, and ensures that network change manager
147 // binds to the restarted network service.
IN_PROC_BROWSER_TEST_F(NetworkConnectionTrackerBrowserTest,SimulateNetworkServiceCrash)148 IN_PROC_BROWSER_TEST_F(NetworkConnectionTrackerBrowserTest,
149                        SimulateNetworkServiceCrash) {
150   // Out-of-process network service is not enabled, so network service's crash
151   // and restart aren't applicable.
152   if (!content::IsOutOfProcessNetworkService())
153     return;
154 
155   network::NetworkConnectionTracker* tracker =
156       content::GetNetworkConnectionTracker();
157   EXPECT_NE(nullptr, tracker);
158 
159   // Issue a GetConnectionType() request to make sure NetworkService has been
160   // started up. This way, NetworkService will receive the broadcast when
161   // SimulateNetworkChange() is called.
162   {
163     base::RunLoop run_loop;
164     network::mojom::ConnectionType ignored_type;
165     bool sync = tracker->GetConnectionType(
166         &ignored_type,
167         base::BindOnce(
168             [](base::RunLoop* run_loop, network::mojom::ConnectionType type) {
169               run_loop->Quit();
170             },
171             base::Unretained(&run_loop)));
172     if (!sync)
173       run_loop.Run();
174   }
175 
176   TestNetworkConnectionObserver network_connection_observer(tracker);
177   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
178 
179   network_connection_observer.WaitForNotification();
180   EXPECT_EQ(network::mojom::ConnectionType::CONNECTION_3G,
181             network_connection_observer.connection_type());
182   // Wait a bit longer to make sure only 1 notification is received and that
183   // there is no duplicate notification.
184   base::RunLoop().RunUntilIdle();
185   EXPECT_EQ(1u, network_connection_observer.num_notifications());
186 
187   SimulateNetworkServiceCrash();
188 
189   // Issue a GetConnectionType() request to make sure NetworkService has been
190   // started up. This way, NetworkService will receive the broadcast when
191   // SimulateNetworkChange() is called.
192   {
193     base::RunLoop run_loop;
194     network::mojom::ConnectionType ignored_type;
195     bool sync = tracker->GetConnectionType(
196         &ignored_type,
197         base::BindOnce(
198             [](base::RunLoop* run_loop, network::mojom::ConnectionType type) {
199               run_loop->Quit();
200             },
201             base::Unretained(&run_loop)));
202     if (!sync)
203       run_loop.Run();
204   }
205 
206   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
207   network_connection_observer.WaitForNotification();
208   EXPECT_EQ(network::mojom::ConnectionType::CONNECTION_2G,
209             network_connection_observer.connection_type());
210 
211   // Wait a bit longer to make sure only 2 notifications are received.
212   base::RunLoop().RunUntilIdle();
213 
214   EXPECT_EQ(2u, network_connection_observer.num_notifications());
215 }
216