xref: /aosp_15_r20/external/cronet/net/base/network_change_notifier_fuchsia_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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