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