1 //
2 // Copyright (C) 2014 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "update_engine/update_manager/real_shill_provider.h"
17
18 #include <memory>
19 #include <utility>
20
21 #include <base/time/time.h>
22 #include <brillo/make_unique_ptr.h>
23 #include <brillo/message_loops/fake_message_loop.h>
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 #include <shill/dbus-constants.h>
27 #include <shill/dbus-proxies.h>
28 #include <shill/dbus-proxy-mocks.h>
29
30 #include "update_engine/common/fake_clock.h"
31 #include "update_engine/common/test_utils.h"
32 #include "update_engine/dbus_test_utils.h"
33 #include "update_engine/fake_shill_proxy.h"
34 #include "update_engine/update_manager/umtest_utils.h"
35
36 using base::Time;
37 using base::TimeDelta;
38 using chromeos_update_engine::ConnectionTethering;
39 using chromeos_update_engine::ConnectionType;
40 using chromeos_update_engine::FakeClock;
41 using org::chromium::flimflam::ManagerProxyMock;
42 using org::chromium::flimflam::ServiceProxyMock;
43 using std::unique_ptr;
44 using testing::Mock;
45 using testing::Return;
46 using testing::SetArgPointee;
47 using testing::_;
48
49 namespace {
50
51 // Fake service paths.
52 const char* const kFakeEthernetServicePath = "/fake/ethernet/service";
53 const char* const kFakeWifiServicePath = "/fake/wifi/service";
54 const char* const kFakeWimaxServicePath = "/fake/wimax/service";
55 const char* const kFakeBluetoothServicePath = "/fake/bluetooth/service";
56 const char* const kFakeCellularServicePath = "/fake/cellular/service";
57 const char* const kFakeVpnServicePath = "/fake/vpn/service";
58 const char* const kFakeUnknownServicePath = "/fake/unknown/service";
59
60 } // namespace
61
62 namespace chromeos_update_manager {
63
64 class UmRealShillProviderTest : public ::testing::Test {
65 protected:
66 // Initialize the RealShillProvider under test.
SetUp()67 void SetUp() override {
68 fake_clock_.SetWallclockTime(InitTime());
69 loop_.SetAsCurrent();
70 fake_shill_proxy_ = new chromeos_update_engine::FakeShillProxy();
71 provider_.reset(new RealShillProvider(fake_shill_proxy_, &fake_clock_));
72
73 ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
74
75 // The PropertyChanged signal should be subscribed to.
76 MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER(
77 manager_property_changed_, *manager_proxy_mock, PropertyChanged);
78 }
79
TearDown()80 void TearDown() override {
81 provider_.reset();
82 // Check for leaked callbacks on the main loop.
83 EXPECT_FALSE(loop_.PendingTasks());
84 }
85
86 // These methods generate fixed timestamps for use in faking the current time.
InitTime()87 Time InitTime() {
88 Time::Exploded now_exp;
89 now_exp.year = 2014;
90 now_exp.month = 3;
91 now_exp.day_of_week = 2;
92 now_exp.day_of_month = 18;
93 now_exp.hour = 8;
94 now_exp.minute = 5;
95 now_exp.second = 33;
96 now_exp.millisecond = 675;
97 return Time::FromLocalExploded(now_exp);
98 }
99
ConnChangedTime()100 Time ConnChangedTime() {
101 return InitTime() + TimeDelta::FromSeconds(10);
102 }
103
104 // Sets the default_service object path in the response from the
105 // ManagerProxyMock instance.
106 void SetManagerReply(const char* default_service, bool reply_succeeds);
107
108 // Sets the |service_type|, |physical_technology| and |service_tethering|
109 // properties in the mocked service |service_path|. If any of the three
110 // const char* is a nullptr, the corresponding property will not be included
111 // in the response.
112 // Returns the mock object pointer, owned by the |fake_shill_proxy_|.
113 ServiceProxyMock* SetServiceReply(const std::string& service_path,
114 const char* service_type,
115 const char* physical_technology,
116 const char* service_tethering);
117
InitWithDefaultService(const char * default_service)118 void InitWithDefaultService(const char* default_service) {
119 SetManagerReply(default_service, true);
120 // Check that provider initializes correctly.
121 EXPECT_TRUE(provider_->Init());
122 // RunOnce to notify the signal handler was connected properly.
123 EXPECT_TRUE(loop_.RunOnce(false));
124 }
125
126 // Sends a signal informing the provider about a default connection
127 // |service_path|. Sets the fake connection change time in
128 // |conn_change_time_p| if provided.
SendDefaultServiceSignal(const std::string & service_path,Time * conn_change_time_p)129 void SendDefaultServiceSignal(const std::string& service_path,
130 Time* conn_change_time_p) {
131 const Time conn_change_time = ConnChangedTime();
132 fake_clock_.SetWallclockTime(conn_change_time);
133 ASSERT_TRUE(manager_property_changed_.IsHandlerRegistered());
134 manager_property_changed_.signal_callback().Run(
135 shill::kDefaultServiceProperty, dbus::ObjectPath(service_path));
136 fake_clock_.SetWallclockTime(conn_change_time + TimeDelta::FromSeconds(5));
137 if (conn_change_time_p)
138 *conn_change_time_p = conn_change_time;
139 }
140
141 // Sets up expectations for detection of a connection |service_path| with type
142 // |shill_type_str| and tethering mode |shill_tethering_str|. Ensures that the
143 // new connection status and change time are properly detected by the
144 // provider. Writes the fake connection change time to |conn_change_time_p|,
145 // if provided.
SetupConnectionAndAttrs(const std::string & service_path,const char * shill_type,const char * shill_tethering,Time * conn_change_time_p)146 void SetupConnectionAndAttrs(const std::string& service_path,
147 const char* shill_type,
148 const char* shill_tethering,
149 Time* conn_change_time_p) {
150 SetServiceReply(service_path, shill_type, nullptr, shill_tethering);
151 // Note: We don't setup this |service_path| as the default service path but
152 // we instead send a signal notifying the change since the code won't call
153 // GetProperties on the Manager object at this point.
154
155 // Send a signal about a new default service.
156 Time conn_change_time;
157 SendDefaultServiceSignal(service_path, &conn_change_time);
158
159 // Query the connection status, ensure last change time reported correctly.
160 UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
161 UmTestUtils::ExpectVariableHasValue(conn_change_time,
162 provider_->var_conn_last_changed());
163
164 // Write the connection change time to the output argument.
165 if (conn_change_time_p)
166 *conn_change_time_p = conn_change_time;
167 }
168
169 // Sets up a connection and tests that its type is being properly detected by
170 // the provider.
SetupConnectionAndTestType(const char * service_path,const char * shill_type,ConnectionType expected_conn_type)171 void SetupConnectionAndTestType(const char* service_path,
172 const char* shill_type,
173 ConnectionType expected_conn_type) {
174 // Set up and test the connection, record the change time.
175 Time conn_change_time;
176 SetupConnectionAndAttrs(service_path,
177 shill_type,
178 shill::kTetheringNotDetectedState,
179 &conn_change_time);
180
181 // Query the connection type, ensure last change time did not change.
182 UmTestUtils::ExpectVariableHasValue(expected_conn_type,
183 provider_->var_conn_type());
184 UmTestUtils::ExpectVariableHasValue(conn_change_time,
185 provider_->var_conn_last_changed());
186 }
187
188 // Sets up a connection and tests that its tethering mode is being properly
189 // detected by the provider.
SetupConnectionAndTestTethering(const char * service_path,const char * shill_tethering,ConnectionTethering expected_conn_tethering)190 void SetupConnectionAndTestTethering(
191 const char* service_path,
192 const char* shill_tethering,
193 ConnectionTethering expected_conn_tethering) {
194 // Set up and test the connection, record the change time.
195 Time conn_change_time;
196 SetupConnectionAndAttrs(
197 service_path, shill::kTypeEthernet, shill_tethering, &conn_change_time);
198
199 // Query the connection tethering, ensure last change time did not change.
200 UmTestUtils::ExpectVariableHasValue(expected_conn_tethering,
201 provider_->var_conn_tethering());
202 UmTestUtils::ExpectVariableHasValue(conn_change_time,
203 provider_->var_conn_last_changed());
204 }
205
206 brillo::FakeMessageLoop loop_{nullptr};
207 FakeClock fake_clock_;
208 chromeos_update_engine::FakeShillProxy* fake_shill_proxy_;
209
210 // The registered signal handler for the signal Manager.PropertyChanged.
211 chromeos_update_engine::dbus_test_utils::MockSignalHandler<
212 void(const std::string&, const brillo::Any&)> manager_property_changed_;
213
214 unique_ptr<RealShillProvider> provider_;
215 };
216
SetManagerReply(const char * default_service,bool reply_succeeds)217 void UmRealShillProviderTest::SetManagerReply(const char* default_service,
218 bool reply_succeeds) {
219 ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
220 if (!reply_succeeds) {
221 EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
222 .WillOnce(Return(false));
223 return;
224 }
225
226 // Create a dictionary of properties and optionally include the default
227 // service.
228 brillo::VariantDictionary reply_dict;
229 reply_dict["SomeOtherProperty"] = 0xC0FFEE;
230
231 if (default_service) {
232 reply_dict[shill::kDefaultServiceProperty] =
233 dbus::ObjectPath(default_service);
234 }
235 EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
236 .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
237 }
238
SetServiceReply(const std::string & service_path,const char * service_type,const char * physical_technology,const char * service_tethering)239 ServiceProxyMock* UmRealShillProviderTest::SetServiceReply(
240 const std::string& service_path,
241 const char* service_type,
242 const char* physical_technology,
243 const char* service_tethering) {
244 brillo::VariantDictionary reply_dict;
245 reply_dict["SomeOtherProperty"] = 0xC0FFEE;
246
247 if (service_type)
248 reply_dict[shill::kTypeProperty] = std::string(service_type);
249
250 if (physical_technology) {
251 reply_dict[shill::kPhysicalTechnologyProperty] =
252 std::string(physical_technology);
253 }
254
255 if (service_tethering)
256 reply_dict[shill::kTetheringProperty] = std::string(service_tethering);
257
258 ServiceProxyMock* service_proxy_mock = new ServiceProxyMock();
259
260 // Plumb return value into mock object.
261 EXPECT_CALL(*service_proxy_mock, GetProperties(_, _, _))
262 .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
263
264 fake_shill_proxy_->SetServiceForPath(
265 dbus::ObjectPath(service_path),
266 brillo::make_unique_ptr(service_proxy_mock));
267 return service_proxy_mock;
268 }
269
270
271 // Query the connection status, type and time last changed, as they were set
272 // during initialization (no signals).
TEST_F(UmRealShillProviderTest,ReadBaseValues)273 TEST_F(UmRealShillProviderTest, ReadBaseValues) {
274 InitWithDefaultService("/");
275 // Query the provider variables.
276 UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
277 UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
278 UmTestUtils::ExpectVariableHasValue(InitTime(),
279 provider_->var_conn_last_changed());
280 }
281
282 // Ensure that invalid DBus paths are ignored.
TEST_F(UmRealShillProviderTest,InvalidServicePath)283 TEST_F(UmRealShillProviderTest, InvalidServicePath) {
284 InitWithDefaultService("invalid");
285 UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
286 UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
287 UmTestUtils::ExpectVariableHasValue(InitTime(),
288 provider_->var_conn_last_changed());
289 }
290
291 // Ensure that a service path property including a different type is ignored.
TEST_F(UmRealShillProviderTest,InvalidServicePathType)292 TEST_F(UmRealShillProviderTest, InvalidServicePathType) {
293 ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
294 brillo::VariantDictionary reply_dict;
295 reply_dict[shill::kDefaultServiceProperty] = "/not/an/object/path";
296 EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
297 .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
298
299 EXPECT_TRUE(provider_->Init());
300 EXPECT_TRUE(loop_.RunOnce(false));
301
302 UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
303 }
304
305 // Test that Ethernet connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeEthernet)306 TEST_F(UmRealShillProviderTest, ReadConnTypeEthernet) {
307 InitWithDefaultService("/");
308 SetupConnectionAndTestType(kFakeEthernetServicePath,
309 shill::kTypeEthernet,
310 ConnectionType::kEthernet);
311 }
312
313 // Test that Wifi connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeWifi)314 TEST_F(UmRealShillProviderTest, ReadConnTypeWifi) {
315 InitWithDefaultService("/");
316 SetupConnectionAndTestType(kFakeWifiServicePath,
317 shill::kTypeWifi,
318 ConnectionType::kWifi);
319 }
320
321 // Test that Wimax connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeWimax)322 TEST_F(UmRealShillProviderTest, ReadConnTypeWimax) {
323 InitWithDefaultService("/");
324 SetupConnectionAndTestType(kFakeWimaxServicePath,
325 shill::kTypeWimax,
326 ConnectionType::kWimax);
327 }
328
329 // Test that Bluetooth connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeBluetooth)330 TEST_F(UmRealShillProviderTest, ReadConnTypeBluetooth) {
331 InitWithDefaultService("/");
332 SetupConnectionAndTestType(kFakeBluetoothServicePath,
333 shill::kTypeBluetooth,
334 ConnectionType::kBluetooth);
335 }
336
337 // Test that Cellular connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeCellular)338 TEST_F(UmRealShillProviderTest, ReadConnTypeCellular) {
339 InitWithDefaultService("/");
340 SetupConnectionAndTestType(kFakeCellularServicePath,
341 shill::kTypeCellular,
342 ConnectionType::kCellular);
343 }
344
345 // Test that an unknown connection is identified as such.
TEST_F(UmRealShillProviderTest,ReadConnTypeUnknown)346 TEST_F(UmRealShillProviderTest, ReadConnTypeUnknown) {
347 InitWithDefaultService("/");
348 SetupConnectionAndTestType(kFakeUnknownServicePath,
349 "FooConnectionType",
350 ConnectionType::kUnknown);
351 }
352
353 // Tests that VPN connection is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTypeVpn)354 TEST_F(UmRealShillProviderTest, ReadConnTypeVpn) {
355 InitWithDefaultService("/");
356 // Mock logic for returning a default service path and its type.
357 SetServiceReply(kFakeVpnServicePath,
358 shill::kTypeVPN,
359 shill::kTypeWifi,
360 shill::kTetheringNotDetectedState);
361
362 // Send a signal about a new default service.
363 Time conn_change_time;
364 SendDefaultServiceSignal(kFakeVpnServicePath, &conn_change_time);
365
366 // Query the connection type, ensure last change time reported correctly.
367 UmTestUtils::ExpectVariableHasValue(ConnectionType::kWifi,
368 provider_->var_conn_type());
369 UmTestUtils::ExpectVariableHasValue(conn_change_time,
370 provider_->var_conn_last_changed());
371 }
372
373 // Ensure that the connection type is properly cached in the provider through
374 // subsequent variable readings.
TEST_F(UmRealShillProviderTest,ConnTypeCacheUsed)375 TEST_F(UmRealShillProviderTest, ConnTypeCacheUsed) {
376 InitWithDefaultService("/");
377 SetupConnectionAndTestType(kFakeEthernetServicePath,
378 shill::kTypeEthernet,
379 ConnectionType::kEthernet);
380
381 UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
382 provider_->var_conn_type());
383 }
384
385 // Ensure that the cached connection type remains valid even when a default
386 // connection signal occurs but the connection is not changed.
TEST_F(UmRealShillProviderTest,ConnTypeCacheRemainsValid)387 TEST_F(UmRealShillProviderTest, ConnTypeCacheRemainsValid) {
388 InitWithDefaultService("/");
389 SetupConnectionAndTestType(kFakeEthernetServicePath,
390 shill::kTypeEthernet,
391 ConnectionType::kEthernet);
392
393 SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
394
395 UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
396 provider_->var_conn_type());
397 }
398
399 // Ensure that the cached connection type is invalidated and re-read when the
400 // default connection changes.
TEST_F(UmRealShillProviderTest,ConnTypeCacheInvalidated)401 TEST_F(UmRealShillProviderTest, ConnTypeCacheInvalidated) {
402 InitWithDefaultService("/");
403 SetupConnectionAndTestType(kFakeEthernetServicePath,
404 shill::kTypeEthernet,
405 ConnectionType::kEthernet);
406
407 SetupConnectionAndTestType(kFakeWifiServicePath,
408 shill::kTypeWifi,
409 ConnectionType::kWifi);
410 }
411
412 // Test that a non-tethering mode is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTetheringNotDetected)413 TEST_F(UmRealShillProviderTest, ReadConnTetheringNotDetected) {
414 InitWithDefaultService("/");
415 SetupConnectionAndTestTethering(kFakeWifiServicePath,
416 shill::kTetheringNotDetectedState,
417 ConnectionTethering::kNotDetected);
418 }
419
420 // Test that a suspected tethering mode is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTetheringSuspected)421 TEST_F(UmRealShillProviderTest, ReadConnTetheringSuspected) {
422 InitWithDefaultService("/");
423 SetupConnectionAndTestTethering(kFakeWifiServicePath,
424 shill::kTetheringSuspectedState,
425 ConnectionTethering::kSuspected);
426 }
427
428 // Test that a confirmed tethering mode is identified correctly.
TEST_F(UmRealShillProviderTest,ReadConnTetheringConfirmed)429 TEST_F(UmRealShillProviderTest, ReadConnTetheringConfirmed) {
430 InitWithDefaultService("/");
431 SetupConnectionAndTestTethering(kFakeWifiServicePath,
432 shill::kTetheringConfirmedState,
433 ConnectionTethering::kConfirmed);
434 }
435
436 // Test that an unknown tethering mode is identified as such.
TEST_F(UmRealShillProviderTest,ReadConnTetheringUnknown)437 TEST_F(UmRealShillProviderTest, ReadConnTetheringUnknown) {
438 InitWithDefaultService("/");
439 SetupConnectionAndTestTethering(kFakeWifiServicePath,
440 "FooConnTethering",
441 ConnectionTethering::kUnknown);
442 }
443
444 // Ensure that the connection tethering mode is properly cached in the provider.
TEST_F(UmRealShillProviderTest,ConnTetheringCacheUsed)445 TEST_F(UmRealShillProviderTest, ConnTetheringCacheUsed) {
446 InitWithDefaultService("/");
447 SetupConnectionAndTestTethering(kFakeEthernetServicePath,
448 shill::kTetheringNotDetectedState,
449 ConnectionTethering::kNotDetected);
450
451 UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
452 provider_->var_conn_tethering());
453 }
454
455 // Ensure that the cached connection tethering mode remains valid even when a
456 // default connection signal occurs but the connection is not changed.
TEST_F(UmRealShillProviderTest,ConnTetheringCacheRemainsValid)457 TEST_F(UmRealShillProviderTest, ConnTetheringCacheRemainsValid) {
458 InitWithDefaultService("/");
459 SetupConnectionAndTestTethering(kFakeEthernetServicePath,
460 shill::kTetheringNotDetectedState,
461 ConnectionTethering::kNotDetected);
462
463 SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
464
465 UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
466 provider_->var_conn_tethering());
467 }
468
469 // Ensure that the cached connection tethering mode is invalidated and re-read
470 // when the default connection changes.
TEST_F(UmRealShillProviderTest,ConnTetheringCacheInvalidated)471 TEST_F(UmRealShillProviderTest, ConnTetheringCacheInvalidated) {
472 InitWithDefaultService("/");
473 SetupConnectionAndTestTethering(kFakeEthernetServicePath,
474 shill::kTetheringNotDetectedState,
475 ConnectionTethering::kNotDetected);
476
477 SetupConnectionAndTestTethering(kFakeWifiServicePath,
478 shill::kTetheringConfirmedState,
479 ConnectionTethering::kConfirmed);
480 }
481
482 // Fake two DBus signals prompting a default connection change, but otherwise
483 // give the same service path. Check connection status and the time it was last
484 // changed, making sure that it is the time when the first signal was sent (and
485 // not the second).
TEST_F(UmRealShillProviderTest,ReadLastChangedTimeTwoSignals)486 TEST_F(UmRealShillProviderTest, ReadLastChangedTimeTwoSignals) {
487 InitWithDefaultService("/");
488 // Send a default service signal twice, advancing the clock in between.
489 Time conn_change_time;
490 SetupConnectionAndAttrs(kFakeEthernetServicePath,
491 shill::kTypeEthernet,
492 shill::kTetheringNotDetectedState,
493 &conn_change_time);
494 // This will set the service path to the same value, so it should not call
495 // GetProperties() again.
496 SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
497
498 // Query the connection status, ensure last change time reported as the first
499 // time the signal was sent.
500 UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
501 UmTestUtils::ExpectVariableHasValue(conn_change_time,
502 provider_->var_conn_last_changed());
503 }
504
505 // Make sure that the provider initializes correctly even if shill is not
506 // responding, that variables can be obtained, and that they all return a null
507 // value (indicating that the underlying values were not set).
TEST_F(UmRealShillProviderTest,NoInitConnStatusReadBaseValues)508 TEST_F(UmRealShillProviderTest, NoInitConnStatusReadBaseValues) {
509 // Initialize the provider, no initial connection status response.
510 SetManagerReply(nullptr, false);
511 EXPECT_TRUE(provider_->Init());
512 EXPECT_TRUE(loop_.RunOnce(false));
513 UmTestUtils::ExpectVariableNotSet(provider_->var_is_connected());
514 UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
515 UmTestUtils::ExpectVariableNotSet(provider_->var_conn_last_changed());
516 }
517
518 // Test that, once a signal is received, the connection status and other info
519 // can be read correctly.
TEST_F(UmRealShillProviderTest,NoInitConnStatusReadConnTypeEthernet)520 TEST_F(UmRealShillProviderTest, NoInitConnStatusReadConnTypeEthernet) {
521 // Initialize the provider with no initial connection status response.
522 SetManagerReply(nullptr, false);
523 EXPECT_TRUE(provider_->Init());
524 EXPECT_TRUE(loop_.RunOnce(false));
525
526 SetupConnectionAndAttrs(kFakeEthernetServicePath,
527 shill::kTypeEthernet,
528 shill::kTetheringNotDetectedState,
529 nullptr);
530 UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
531 }
532
533 } // namespace chromeos_update_manager
534