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