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