1 // Copyright 2018 The Chromium Authors
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 "net/base/network_change_notifier_fuchsia.h"
6
7 #include <fuchsia/net/interfaces/cpp/fidl_test_base.h>
8 #include <lib/fidl/cpp/binding.h>
9
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/auto_reset.h"
16 #include "base/functional/bind.h"
17 #include "base/logging.h"
18 #include "base/run_loop.h"
19 #include "base/test/task_environment.h"
20 #include "base/threading/sequence_bound.h"
21 #include "base/threading/thread.h"
22 #include "net/base/ip_address.h"
23 #include "net/base/network_change_notifier.h"
24 #include "net/dns/dns_config_service.h"
25 #include "net/dns/system_dns_config_change_notifier.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace net {
30 namespace {
31
32 enum : uint32_t { kDefaultInterfaceId = 1, kSecondaryInterfaceId = 2 };
33
34 using IPv4Octets = std::array<uint8_t, 4>;
35 using IPv6Octets = std::array<uint8_t, 16>;
36
37 constexpr IPv4Octets kDefaultIPv4Address = {192, 168, 0, 2};
38 constexpr uint8_t kDefaultIPv4Prefix = 16;
39 constexpr IPv4Octets kSecondaryIPv4Address = {10, 0, 0, 1};
40 constexpr uint8_t kSecondaryIPv4Prefix = 8;
41
42 constexpr IPv6Octets kDefaultIPv6Address = {0x20, 0x01, 0x01};
43 constexpr uint8_t kDefaultIPv6Prefix = 16;
44 constexpr IPv6Octets kSecondaryIPv6Address = {0x20, 0x01, 0x02};
45 constexpr uint8_t kSecondaryIPv6Prefix = 16;
46
47 constexpr const char kDefaultInterfaceName[] = "net1";
48 constexpr const char kSecondaryInterfaceName[] = "net2";
49
IpAddressFrom(IPv4Octets octets)50 fuchsia::net::IpAddress IpAddressFrom(IPv4Octets octets) {
51 fuchsia::net::IpAddress output;
52 output.ipv4().addr = octets;
53 return output;
54 }
55
IpAddressFrom(IPv6Octets octets)56 fuchsia::net::IpAddress IpAddressFrom(IPv6Octets octets) {
57 fuchsia::net::IpAddress output;
58 output.ipv6().addr = octets;
59 return output;
60 }
61
62 template <typename T>
SubnetFrom(T octets,uint8_t prefix)63 fuchsia::net::Subnet SubnetFrom(T octets, uint8_t prefix) {
64 fuchsia::net::Subnet output;
65 output.addr = IpAddressFrom(octets);
66 output.prefix_len = prefix;
67 return output;
68 }
69
70 template <typename T>
InterfaceAddressFrom(T octets,uint8_t prefix)71 fuchsia::net::interfaces::Address InterfaceAddressFrom(T octets,
72 uint8_t prefix) {
73 fuchsia::net::interfaces::Address addr;
74 addr.set_addr(SubnetFrom(octets, prefix));
75 return addr;
76 }
77
78 template <typename T>
MakeSingleItemVec(T item)79 std::vector<T> MakeSingleItemVec(T item) {
80 std::vector<T> vec;
81 vec.push_back(std::move(item));
82 return vec;
83 }
84
DefaultInterfaceProperties(fuchsia::hardware::network::DeviceClass device_class=fuchsia::hardware::network::DeviceClass::ETHERNET)85 fuchsia::net::interfaces::Properties DefaultInterfaceProperties(
86 fuchsia::hardware::network::DeviceClass device_class =
87 fuchsia::hardware::network::DeviceClass::ETHERNET) {
88 // For most tests a live interface with an IPv4 address and ethernet class is
89 // sufficient.
90 fuchsia::net::interfaces::Properties interface;
91 interface.set_id(kDefaultInterfaceId);
92 interface.set_name(kDefaultInterfaceName);
93 interface.set_online(true);
94 interface.set_has_default_ipv4_route(true);
95 interface.set_has_default_ipv6_route(true);
96 interface.set_device_class(fuchsia::net::interfaces::DeviceClass::WithDevice(
97 std::move(device_class)));
98 interface.set_addresses(MakeSingleItemVec(
99 InterfaceAddressFrom(kDefaultIPv4Address, kDefaultIPv4Prefix)));
100 return interface;
101 }
102
SecondaryInterfaceProperties()103 fuchsia::net::interfaces::Properties SecondaryInterfaceProperties() {
104 // For most tests a live interface with an IPv4 address and ethernet class is
105 // sufficient.
106 fuchsia::net::interfaces::Properties interface;
107 interface.set_id(kSecondaryInterfaceId);
108 interface.set_name(kSecondaryInterfaceName);
109 interface.set_online(true);
110 interface.set_has_default_ipv4_route(false);
111 interface.set_has_default_ipv6_route(false);
112 interface.set_device_class(fuchsia::net::interfaces::DeviceClass::WithDevice(
113 fuchsia::hardware::network::DeviceClass::ETHERNET));
114 interface.set_addresses(MakeSingleItemVec(
115 InterfaceAddressFrom(kSecondaryIPv4Address, kSecondaryIPv4Prefix)));
116 return interface;
117 }
118
119 template <typename F>
MakeChangeEvent(uint64_t interface_id,F fn)120 fuchsia::net::interfaces::Event MakeChangeEvent(uint64_t interface_id, F fn) {
121 fuchsia::net::interfaces::Properties props;
122 props.set_id(interface_id);
123 fn(&props);
124 return fuchsia::net::interfaces::Event::WithChanged(std::move(props));
125 }
126
127 // Partial fake implementation of a fuchsia.net.interfaces/Watcher.
128 class FakeWatcher : public fuchsia::net::interfaces::testing::Watcher_TestBase {
129 public:
FakeWatcher()130 FakeWatcher() : binding_(this) {
131 // Always create the watcher with an empty set of interfaces.
132 // Callers can override the initial set of events with SetInitial.
133 pending_.push(fuchsia::net::interfaces::Event::WithIdle(
134 fuchsia::net::interfaces::Empty{}));
135 }
136 FakeWatcher(const FakeWatcher&) = delete;
137 FakeWatcher& operator=(const FakeWatcher&) = delete;
138 ~FakeWatcher() override = default;
139
Bind(fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> request)140 void Bind(fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> request) {
141 CHECK_EQ(ZX_OK, binding_.Bind(std::move(request)));
142 }
143
Unbind()144 void Unbind() { binding_.Unbind(); }
145
PushEvent(fuchsia::net::interfaces::Event event)146 void PushEvent(fuchsia::net::interfaces::Event event) {
147 if (pending_callback_) {
148 pending_callback_(std::move(event));
149 pending_callback_ = nullptr;
150 } else {
151 pending_.push(std::move(event));
152 }
153 }
154
SetInitial(std::vector<fuchsia::net::interfaces::Properties> props)155 void SetInitial(std::vector<fuchsia::net::interfaces::Properties> props) {
156 // Discard any pending events.
157 pending_ = std::queue<fuchsia::net::interfaces::Event>();
158 for (auto& prop : props) {
159 pending_.push(
160 fuchsia::net::interfaces::Event::WithExisting(std::move(prop)));
161 }
162 pending_.push(fuchsia::net::interfaces::Event::WithIdle(
163 fuchsia::net::interfaces::Empty{}));
164 // We should not have a pending callback already when setting initial state.
165 CHECK(!pending_callback_);
166 }
167
168 private:
Watch(WatchCallback callback)169 void Watch(WatchCallback callback) override {
170 ASSERT_FALSE(pending_callback_);
171 if (pending_.empty()) {
172 pending_callback_ = std::move(callback);
173 } else {
174 callback(std::move(pending_.front()));
175 pending_.pop();
176 }
177 }
178
NotImplemented_(const std::string & name)179 void NotImplemented_(const std::string& name) override {
180 LOG(FATAL) << "Unimplemented function called: " << name;
181 }
182
183 std::queue<fuchsia::net::interfaces::Event> pending_;
184 fidl::Binding<fuchsia::net::interfaces::Watcher> binding_;
185 WatchCallback pending_callback_ = nullptr;
186 };
187
188 class FakeWatcherAsync {
189 public:
FakeWatcherAsync()190 FakeWatcherAsync() {
191 base::Thread::Options options(base::MessagePumpType::IO, 0);
192 CHECK(thread_.StartWithOptions(std::move(options)));
193 watcher_ = base::SequenceBound<FakeWatcher>(thread_.task_runner());
194 }
195 FakeWatcherAsync(const FakeWatcherAsync&) = delete;
196 FakeWatcherAsync& operator=(const FakeWatcherAsync&) = delete;
197 ~FakeWatcherAsync() = default;
198
Bind(fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> request)199 void Bind(fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> request) {
200 watcher_.AsyncCall(&FakeWatcher::Bind).WithArgs(std::move(request));
201 }
202
Unbind()203 void Unbind() { watcher_.AsyncCall(&FakeWatcher::Unbind); }
204
205 // Asynchronously push an event to the watcher.
PushEvent(fuchsia::net::interfaces::Event event)206 void PushEvent(fuchsia::net::interfaces::Event event) {
207 watcher_.AsyncCall(&FakeWatcher::PushEvent).WithArgs(std::move(event));
208 }
209
210 // Asynchronously push an initial set of interfaces to the watcher.
SetInitial(std::vector<fuchsia::net::interfaces::Properties> props)211 void SetInitial(std::vector<fuchsia::net::interfaces::Properties> props) {
212 watcher_.AsyncCall(&FakeWatcher::SetInitial).WithArgs(std::move(props));
213 }
214
215 // Asynchronously push an initial single intface to the watcher.
SetInitial(fuchsia::net::interfaces::Properties prop)216 void SetInitial(fuchsia::net::interfaces::Properties prop) {
217 SetInitial(MakeSingleItemVec(std::move(prop)));
218 }
219
220 // Ensures that any PushEvent() or SetInitial() calls have
221 // been processed.
FlushThread()222 void FlushThread() { thread_.FlushForTesting(); }
223
224 private:
225 base::Thread thread_{"Watcher Thread"};
226 base::SequenceBound<FakeWatcher> watcher_;
227 };
228
229 template <class T>
230 class ResultReceiver {
231 public:
~ResultReceiver()232 ~ResultReceiver() { EXPECT_EQ(entries_.size(), 0u); }
RunAndExpectEntries(std::vector<T> expected_entries)233 bool RunAndExpectEntries(std::vector<T> expected_entries) {
234 if (entries_.size() < expected_entries.size()) {
235 base::RunLoop loop;
236 base::AutoReset<size_t> size(&expected_count_, expected_entries.size());
237 base::AutoReset<base::OnceClosure> quit(&quit_loop_, loop.QuitClosure());
238 loop.Run();
239 }
240 return expected_entries == std::exchange(entries_, {});
241 }
AddEntry(T entry)242 void AddEntry(T entry) {
243 entries_.push_back(entry);
244 if (quit_loop_ && entries_.size() >= expected_count_)
245 std::move(quit_loop_).Run();
246 }
247
248 protected:
249 size_t expected_count_ = 0u;
250 std::vector<T> entries_;
251 base::OnceClosure quit_loop_;
252 };
253
254 // Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
255 class FakeConnectionTypeObserver final
256 : public NetworkChangeNotifier::ConnectionTypeObserver {
257 public:
FakeConnectionTypeObserver()258 FakeConnectionTypeObserver() {
259 NetworkChangeNotifier::AddConnectionTypeObserver(this);
260 }
~FakeConnectionTypeObserver()261 ~FakeConnectionTypeObserver() override {
262 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
263 }
264
RunAndExpectConnectionTypes(std::vector<NetworkChangeNotifier::ConnectionType> sequence)265 bool RunAndExpectConnectionTypes(
266 std::vector<NetworkChangeNotifier::ConnectionType> sequence) {
267 return receiver_.RunAndExpectEntries(sequence);
268 }
269
270 // ConnectionTypeObserver implementation.
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)271 void OnConnectionTypeChanged(
272 NetworkChangeNotifier::ConnectionType type) override {
273 receiver_.AddEntry(type);
274 }
275
276 protected:
277 ResultReceiver<NetworkChangeNotifier::ConnectionType> receiver_;
278 };
279
280 // Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
281 class FakeNetworkChangeObserver final
282 : public NetworkChangeNotifier::NetworkChangeObserver {
283 public:
FakeNetworkChangeObserver()284 FakeNetworkChangeObserver() {
285 NetworkChangeNotifier::AddNetworkChangeObserver(this);
286 }
~FakeNetworkChangeObserver()287 ~FakeNetworkChangeObserver() override {
288 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
289 }
290
RunAndExpectNetworkChanges(std::vector<NetworkChangeNotifier::ConnectionType> sequence)291 bool RunAndExpectNetworkChanges(
292 std::vector<NetworkChangeNotifier::ConnectionType> sequence) {
293 return receiver_.RunAndExpectEntries(sequence);
294 }
295
296 // NetworkChangeObserver implementation.
OnNetworkChanged(NetworkChangeNotifier::ConnectionType type)297 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
298 receiver_.AddEntry(type);
299 }
300
301 protected:
302 ResultReceiver<NetworkChangeNotifier::ConnectionType> receiver_;
303 };
304
305 // Accumulates the list of ConnectionTypes notified via OnConnectionTypeChanged.
306 class FakeIPAddressObserver final
307 : public NetworkChangeNotifier::IPAddressObserver {
308 public:
FakeIPAddressObserver()309 FakeIPAddressObserver() { NetworkChangeNotifier::AddIPAddressObserver(this); }
~FakeIPAddressObserver()310 ~FakeIPAddressObserver() override {
311 NetworkChangeNotifier::RemoveIPAddressObserver(this);
312 EXPECT_EQ(ip_change_count_, 0u);
313 }
314
ip_change_count() const315 size_t ip_change_count() const { return ip_change_count_; }
316
RunAndExpectCallCount(size_t expected_count)317 bool RunAndExpectCallCount(size_t expected_count) {
318 if (ip_change_count_ < expected_count) {
319 base::RunLoop loop;
320 base::AutoReset<size_t> expectation(&expected_count_, expected_count);
321 base::AutoReset<base::OnceClosure> quit(&quit_loop_, loop.QuitClosure());
322 loop.Run();
323 }
324 return std::exchange(ip_change_count_, 0u) == expected_count;
325 }
326
327 // IPAddressObserver implementation.
OnIPAddressChanged()328 void OnIPAddressChanged() override {
329 ip_change_count_++;
330 if (quit_loop_ && ip_change_count_ >= expected_count_)
331 std::move(quit_loop_).Run();
332 }
333
334 protected:
335 size_t expected_count_ = 0u;
336 size_t ip_change_count_ = 0u;
337 base::OnceClosure quit_loop_;
338 };
339
340 } // namespace
341
342 class NetworkChangeNotifierFuchsiaTest : public testing::Test {
343 public:
344 NetworkChangeNotifierFuchsiaTest() = default;
345 NetworkChangeNotifierFuchsiaTest(const NetworkChangeNotifierFuchsiaTest&) =
346 delete;
347 NetworkChangeNotifierFuchsiaTest& operator=(
348 const NetworkChangeNotifierFuchsiaTest&) = delete;
349 ~NetworkChangeNotifierFuchsiaTest() override = default;
350
351 // Creates a NetworkChangeNotifier that binds to |watcher_|.
352 // |observer_| is registered last, so that tests need only express
353 // expectations on changes they make themselves.
CreateNotifier(bool require_wlan=false,bool disconnect_watcher=false)354 void CreateNotifier(bool require_wlan = false,
355 bool disconnect_watcher = false) {
356 // Ensure that internal state is up-to-date before the
357 // notifier queries it.
358 watcher_.FlushThread();
359
360 fidl::InterfaceHandle<fuchsia::net::interfaces::Watcher> watcher;
361 fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> watcher_request =
362 watcher.NewRequest();
363 if (disconnect_watcher) {
364 // Reset the InterfaceRequest to close the `watcher` channel.
365 watcher_request = {};
366 } else {
367 watcher_.Bind(std::move(watcher_request));
368 }
369
370 // Use a noop DNS notifier.
371 dns_config_notifier_ = std::make_unique<SystemDnsConfigChangeNotifier>(
372 nullptr /* task_runner */, nullptr /* dns_config_service */);
373 notifier_ = base::WrapUnique(new NetworkChangeNotifierFuchsia(
374 std::move(watcher), require_wlan, dns_config_notifier_.get()));
375
376 type_observer_ = std::make_unique<FakeConnectionTypeObserver>();
377 ip_observer_ = std::make_unique<FakeIPAddressObserver>();
378 }
379
TearDown()380 void TearDown() override {
381 // Spin the loops to catch any unintended notifications.
382 watcher_.FlushThread();
383 base::RunLoop().RunUntilIdle();
384 }
385
386 protected:
387 base::test::SingleThreadTaskEnvironment task_environment_{
388 base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
389
390 FakeWatcherAsync watcher_;
391
392 // Allows us to allocate our own NetworkChangeNotifier for unit testing.
393 NetworkChangeNotifier::DisableForTest disable_for_test_;
394 std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier_;
395 std::unique_ptr<NetworkChangeNotifierFuchsia> notifier_;
396
397 std::unique_ptr<FakeConnectionTypeObserver> type_observer_;
398 std::unique_ptr<FakeIPAddressObserver> ip_observer_;
399 };
400
TEST_F(NetworkChangeNotifierFuchsiaTest,ConnectFail_BeforeGetWatcher)401 TEST_F(NetworkChangeNotifierFuchsiaTest, ConnectFail_BeforeGetWatcher) {
402 // CreateNotifier will pass an already-disconnected Watcher handle to the
403 // new NetworkChangeNotifier, which will cause the process to exit during
404 // construction.
405 EXPECT_EXIT(
406 CreateNotifier(/*require_wlan=*/false, /*disconnect_watcher=*/true),
407 testing::ExitedWithCode(1), "");
408 }
409
TEST_F(NetworkChangeNotifierFuchsiaTest,ConnectFail_AfterGetWatcher)410 TEST_F(NetworkChangeNotifierFuchsiaTest, ConnectFail_AfterGetWatcher) {
411 CreateNotifier();
412
413 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
414 notifier_->GetCurrentConnectionType());
415
416 // Disconnect the Watcher protocol in-use by the NetworkChangeNotifier.
417 watcher_.Unbind();
418 watcher_.FlushThread();
419
420 // Spin the loop to process the disconnection, which should terminate the
421 // test process.
422 EXPECT_EXIT(base::RunLoop().RunUntilIdle(), testing::ExitedWithCode(1), "");
423
424 // Teardown the notifier here to ensure it doesn't observe further events.
425 notifier_ = nullptr;
426 }
427
TEST_F(NetworkChangeNotifierFuchsiaTest,InitialState)428 TEST_F(NetworkChangeNotifierFuchsiaTest, InitialState) {
429 CreateNotifier();
430 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
431 notifier_->GetCurrentConnectionType());
432 }
433
TEST_F(NetworkChangeNotifierFuchsiaTest,InterfacesChangeDuringConstruction)434 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfacesChangeDuringConstruction) {
435 // Set a live interface with an IP address.
436 watcher_.SetInitial(DefaultInterfaceProperties(
437 fuchsia::hardware::network::DeviceClass::WLAN));
438
439 // Inject an interfaces change event so that the notifier will receive it
440 // immediately after the initial state.
441 watcher_.PushEvent(MakeChangeEvent(
442 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
443 props->set_addresses(MakeSingleItemVec(
444 InterfaceAddressFrom(kSecondaryIPv4Address, kSecondaryIPv4Prefix)));
445 }));
446
447 // Create the Notifier, which should process the initial network state before
448 // returning, but not the change event, yet.
449 CreateNotifier();
450 EXPECT_EQ(ip_observer_->ip_change_count(), 0u);
451
452 // Now spin the loop to allow the change event to be processed, triggering a
453 // call to the |ip_observer_|.
454 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
455 }
456
TEST_F(NetworkChangeNotifierFuchsiaTest,NotifyNetworkChangeOnInitialIPChange)457 TEST_F(NetworkChangeNotifierFuchsiaTest, NotifyNetworkChangeOnInitialIPChange) {
458 // Set a live interface with an IP address and create the notifier.
459 watcher_.SetInitial(DefaultInterfaceProperties(
460 fuchsia::hardware::network::DeviceClass::WLAN));
461 CreateNotifier();
462
463 // Add the NetworkChangeNotifier, and change the IP address. This should
464 // trigger a network change notification.
465 FakeNetworkChangeObserver network_change_observer;
466
467 watcher_.PushEvent(MakeChangeEvent(
468 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
469 props->set_addresses(MakeSingleItemVec(
470 InterfaceAddressFrom(kSecondaryIPv4Address, kSecondaryIPv4Prefix)));
471 }));
472
473 EXPECT_TRUE(network_change_observer.RunAndExpectNetworkChanges(
474 {NetworkChangeNotifier::CONNECTION_NONE,
475 NetworkChangeNotifier::CONNECTION_WIFI}));
476 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
477 }
478
TEST_F(NetworkChangeNotifierFuchsiaTest,NoChange)479 TEST_F(NetworkChangeNotifierFuchsiaTest, NoChange) {
480 // Set a live interface with an IP address and create the notifier.
481 watcher_.SetInitial(DefaultInterfaceProperties());
482 CreateNotifier();
483 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
484 notifier_->GetCurrentConnectionType());
485 // Push an event with no side-effects.
486 watcher_.PushEvent(MakeChangeEvent(kDefaultInterfaceId, [](auto*) {}));
487 }
488
TEST_F(NetworkChangeNotifierFuchsiaTest,NoChangeV6)489 TEST_F(NetworkChangeNotifierFuchsiaTest, NoChangeV6) {
490 auto initial = DefaultInterfaceProperties();
491 initial.set_addresses(MakeSingleItemVec(
492 InterfaceAddressFrom(kDefaultIPv6Address, kDefaultIPv6Prefix)));
493 watcher_.SetInitial(std::move(initial));
494 CreateNotifier();
495 // Push an event with no side-effects.
496 watcher_.PushEvent(MakeChangeEvent(kDefaultInterfaceId, [](auto*) {}));
497 }
498
TEST_F(NetworkChangeNotifierFuchsiaTest,MultiInterfaceNoChange)499 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiInterfaceNoChange) {
500 std::vector<fuchsia::net::interfaces::Properties> props;
501 props.push_back(DefaultInterfaceProperties());
502 props.push_back(SecondaryInterfaceProperties());
503 watcher_.SetInitial(std::move(props));
504 CreateNotifier();
505 // Push an event with no side-effects.
506 watcher_.PushEvent(MakeChangeEvent(kDefaultInterfaceId, [](auto*) {}));
507 }
508
TEST_F(NetworkChangeNotifierFuchsiaTest,MultiV6IPNoChange)509 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPNoChange) {
510 auto props = DefaultInterfaceProperties();
511 props.mutable_addresses()->push_back(
512 InterfaceAddressFrom(kDefaultIPv6Address, kDefaultIPv6Prefix));
513 props.mutable_addresses()->push_back(
514 InterfaceAddressFrom(kSecondaryIPv6Address, kSecondaryIPv6Prefix));
515
516 watcher_.SetInitial(std::move(props));
517 CreateNotifier();
518
519 // Push an event with no side-effects.
520 watcher_.PushEvent(MakeChangeEvent(kDefaultInterfaceId, [](auto*) {}));
521 }
522
TEST_F(NetworkChangeNotifierFuchsiaTest,IpChange)523 TEST_F(NetworkChangeNotifierFuchsiaTest, IpChange) {
524 watcher_.SetInitial(DefaultInterfaceProperties());
525 CreateNotifier();
526 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
527 notifier_->GetCurrentConnectionType());
528
529 watcher_.PushEvent(MakeChangeEvent(
530 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
531 props->set_addresses(MakeSingleItemVec(
532 InterfaceAddressFrom(kSecondaryIPv4Address, kSecondaryIPv4Prefix)));
533 }));
534
535 // Expect a single OnIPAddressChanged() notification.
536 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
537 }
538
TEST_F(NetworkChangeNotifierFuchsiaTest,IpChangeV6)539 TEST_F(NetworkChangeNotifierFuchsiaTest, IpChangeV6) {
540 auto props = DefaultInterfaceProperties();
541 props.set_addresses(MakeSingleItemVec(
542 InterfaceAddressFrom(kDefaultIPv6Address, kDefaultIPv6Prefix)));
543 watcher_.SetInitial(std::move(props));
544 CreateNotifier();
545 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
546 notifier_->GetCurrentConnectionType());
547
548 watcher_.PushEvent(MakeChangeEvent(
549 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
550 props->set_addresses(MakeSingleItemVec(
551 InterfaceAddressFrom(kSecondaryIPv6Address, kSecondaryIPv6Prefix)));
552 }));
553
554 // Expect a single OnIPAddressChanged() notification.
555 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
556 }
557
TEST_F(NetworkChangeNotifierFuchsiaTest,MultiV6IPChanged)558 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPChanged) {
559 auto props = DefaultInterfaceProperties();
560 props.mutable_addresses()->push_back(
561 InterfaceAddressFrom(kDefaultIPv6Address, kDefaultIPv6Prefix));
562
563 watcher_.SetInitial(std::move(props));
564 CreateNotifier();
565 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
566 notifier_->GetCurrentConnectionType());
567
568 watcher_.PushEvent(MakeChangeEvent(
569 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
570 std::vector<fuchsia::net::interfaces::Address> addrs;
571 addrs.push_back(
572 InterfaceAddressFrom(kSecondaryIPv4Address, kSecondaryIPv4Prefix));
573 addrs.push_back(
574 InterfaceAddressFrom(kSecondaryIPv6Address, kSecondaryIPv6Prefix));
575 props->set_addresses(std::move(addrs));
576 }));
577
578 // Expect a single OnIPAddressChanged() notification.
579 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
580 }
581
TEST_F(NetworkChangeNotifierFuchsiaTest,Ipv6AdditionalIpChange)582 TEST_F(NetworkChangeNotifierFuchsiaTest, Ipv6AdditionalIpChange) {
583 watcher_.SetInitial(DefaultInterfaceProperties());
584 CreateNotifier();
585 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
586 notifier_->GetCurrentConnectionType());
587
588 watcher_.PushEvent(MakeChangeEvent(
589 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
590 // Add the initial default address + a new IPv6 one. Address changes are
591 // always sent as the entire new list of addresses.
592 props->mutable_addresses()->push_back(
593 InterfaceAddressFrom(kDefaultIPv4Address, kDefaultIPv4Prefix));
594 props->mutable_addresses()->push_back(
595 InterfaceAddressFrom(kDefaultIPv6Address, kDefaultIPv6Prefix));
596 }));
597
598 // Expect a single OnIPAddressChanged() notification.
599 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
600 }
601
TEST_F(NetworkChangeNotifierFuchsiaTest,InterfaceDown)602 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDown) {
603 watcher_.SetInitial(DefaultInterfaceProperties());
604 CreateNotifier();
605 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
606 notifier_->GetCurrentConnectionType());
607
608 watcher_.PushEvent(MakeChangeEvent(
609 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
610 props->set_online(false);
611 }));
612
613 EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
614 {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE}));
615 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
616 }
617
TEST_F(NetworkChangeNotifierFuchsiaTest,InterfaceUp)618 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceUp) {
619 auto props = DefaultInterfaceProperties();
620 props.set_online(false);
621 watcher_.SetInitial(std::move(props));
622 CreateNotifier();
623 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
624 notifier_->GetCurrentConnectionType());
625
626 watcher_.PushEvent(MakeChangeEvent(
627 kDefaultInterfaceId, [](fuchsia::net::interfaces::Properties* props) {
628 props->set_online(true);
629 }));
630
631 EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
632 {NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET}));
633 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
634 }
635
TEST_F(NetworkChangeNotifierFuchsiaTest,InterfaceDeleted)636 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDeleted) {
637 watcher_.SetInitial(DefaultInterfaceProperties());
638 CreateNotifier();
639 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET,
640 notifier_->GetCurrentConnectionType());
641
642 watcher_.PushEvent(
643 fuchsia::net::interfaces::Event::WithRemoved(kDefaultInterfaceId));
644
645 EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
646 {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE}));
647 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
648 }
649
TEST_F(NetworkChangeNotifierFuchsiaTest,InterfaceAdded)650 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceAdded) {
651 // Initial interface list is intentionally left empty.
652 CreateNotifier();
653 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
654 notifier_->GetCurrentConnectionType());
655
656 watcher_.PushEvent(
657 fuchsia::net::interfaces::Event::WithAdded(DefaultInterfaceProperties(
658 fuchsia::hardware::network::DeviceClass::WLAN)));
659
660 EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
661 {NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI}));
662 EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
663 }
664
TEST_F(NetworkChangeNotifierFuchsiaTest,SecondaryInterfaceAddedNoop)665 TEST_F(NetworkChangeNotifierFuchsiaTest, SecondaryInterfaceAddedNoop) {
666 watcher_.SetInitial(DefaultInterfaceProperties());
667 CreateNotifier();
668
669 watcher_.PushEvent(fuchsia::net::interfaces::Event::WithAdded(
670 SecondaryInterfaceProperties()));
671 }
672
TEST_F(NetworkChangeNotifierFuchsiaTest,SecondaryInterfaceDeletedNoop)673 TEST_F(NetworkChangeNotifierFuchsiaTest, SecondaryInterfaceDeletedNoop) {
674 std::vector<fuchsia::net::interfaces::Properties> interfaces;
675 interfaces.push_back(DefaultInterfaceProperties());
676 interfaces.push_back(SecondaryInterfaceProperties());
677
678 watcher_.SetInitial(std::move(interfaces));
679 CreateNotifier();
680
681 watcher_.PushEvent(
682 fuchsia::net::interfaces::Event::WithRemoved(kSecondaryInterfaceId));
683 }
684
TEST_F(NetworkChangeNotifierFuchsiaTest,FoundWiFi)685 TEST_F(NetworkChangeNotifierFuchsiaTest, FoundWiFi) {
686 watcher_.SetInitial(DefaultInterfaceProperties(
687 fuchsia::hardware::network::DeviceClass::WLAN));
688 CreateNotifier();
689 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
690 notifier_->GetCurrentConnectionType());
691 }
692
TEST_F(NetworkChangeNotifierFuchsiaTest,FindsInterfaceWithRequiredWlan)693 TEST_F(NetworkChangeNotifierFuchsiaTest, FindsInterfaceWithRequiredWlan) {
694 watcher_.SetInitial(DefaultInterfaceProperties(
695 fuchsia::hardware::network::DeviceClass::WLAN));
696 CreateNotifier(/*require_wlan=*/true);
697 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
698 notifier_->GetCurrentConnectionType());
699 }
700
TEST_F(NetworkChangeNotifierFuchsiaTest,IgnoresNonWlanInterface)701 TEST_F(NetworkChangeNotifierFuchsiaTest, IgnoresNonWlanInterface) {
702 watcher_.SetInitial(DefaultInterfaceProperties());
703 CreateNotifier(/*require_wlan=*/true);
704 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE,
705 notifier_->GetCurrentConnectionType());
706 }
707
708 } // namespace net
709