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