1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/geolocation/wifi_data_provider_linux.h" 6 7 #include "base/memory/ref_counted.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "dbus/message.h" 12 #include "dbus/mock_bus.h" 13 #include "dbus/mock_object_proxy.h" 14 #include "dbus/object_path.h" 15 #include "dbus/object_proxy.h" 16 #include "testing/gmock/include/gmock/gmock.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 using ::testing::_; 20 using ::testing::Invoke; 21 using ::testing::Return; 22 using ::testing::Unused; 23 24 namespace content { 25 26 class GeolocationWifiDataProviderLinuxTest : public testing::Test { 27 virtual void SetUp() { 28 // Create a mock bus. 29 dbus::Bus::Options options; 30 options.bus_type = dbus::Bus::SYSTEM; 31 mock_bus_ = new dbus::MockBus(options); 32 33 // Create a mock proxy that behaves as NetworkManager. 34 mock_network_manager_proxy_ = 35 new dbus::MockObjectProxy( 36 mock_bus_.get(), 37 "org.freedesktop.NetworkManager", 38 dbus::ObjectPath("/org/freedesktop/NetworkManager")); 39 // Set an expectation so mock_network_manager_proxy_'s 40 // CallMethodAndBlock() will use CreateNetworkManagerProxyResponse() 41 // to return responses. 42 EXPECT_CALL(*mock_network_manager_proxy_.get(), 43 MockCallMethodAndBlock(_, _)) 44 .WillRepeatedly(Invoke(this, 45 &GeolocationWifiDataProviderLinuxTest:: 46 CreateNetworkManagerProxyResponse)); 47 48 // Create a mock proxy that behaves as NetworkManager/Devices/0. 49 mock_device_proxy_ = 50 new dbus::MockObjectProxy( 51 mock_bus_.get(), 52 "org.freedesktop.NetworkManager", 53 dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0")); 54 EXPECT_CALL(*mock_device_proxy_.get(), MockCallMethodAndBlock(_, _)) 55 .WillRepeatedly(Invoke( 56 this, 57 &GeolocationWifiDataProviderLinuxTest::CreateDeviceProxyResponse)); 58 59 // Create a mock proxy that behaves as NetworkManager/AccessPoint/0. 60 mock_access_point_proxy_ = 61 new dbus::MockObjectProxy( 62 mock_bus_.get(), 63 "org.freedesktop.NetworkManager", 64 dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0")); 65 EXPECT_CALL(*mock_access_point_proxy_.get(), MockCallMethodAndBlock(_, _)) 66 .WillRepeatedly(Invoke(this, 67 &GeolocationWifiDataProviderLinuxTest:: 68 CreateAccessPointProxyResponse)); 69 70 // Set an expectation so mock_bus_'s GetObjectProxy() for the given 71 // service name and the object path will return 72 // mock_network_manager_proxy_. 73 EXPECT_CALL( 74 *mock_bus_.get(), 75 GetObjectProxy("org.freedesktop.NetworkManager", 76 dbus::ObjectPath("/org/freedesktop/NetworkManager"))) 77 .WillOnce(Return(mock_network_manager_proxy_.get())); 78 // Likewise, set an expectation for mock_device_proxy_. 79 EXPECT_CALL( 80 *mock_bus_.get(), 81 GetObjectProxy( 82 "org.freedesktop.NetworkManager", 83 dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0"))) 84 .WillOnce(Return(mock_device_proxy_.get())) 85 .WillOnce(Return(mock_device_proxy_.get())); 86 // Likewise, set an expectation for mock_access_point_proxy_. 87 EXPECT_CALL( 88 *mock_bus_.get(), 89 GetObjectProxy( 90 "org.freedesktop.NetworkManager", 91 dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0"))) 92 .WillOnce(Return(mock_access_point_proxy_.get())); 93 94 // ShutdownAndBlock() should be called. 95 EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); 96 97 // Create the wlan API with the mock bus object injected. 98 wifi_provider_linux_ = new WifiDataProviderLinux; 99 wlan_api_.reset( 100 wifi_provider_linux_->NewWlanApiForTesting(mock_bus_.get())); 101 ASSERT_TRUE(wlan_api_.get()); 102 } 103 104 protected: 105 // DeviceDataProviderImplBase, a super class of WifiDataProviderLinux, 106 // requires a message loop to be present. message_loop_ is defined here, 107 // as it should outlive wifi_provider_linux_. 108 base::MessageLoop message_loop_; 109 scoped_refptr<dbus::MockBus> mock_bus_; 110 scoped_refptr<dbus::MockObjectProxy> mock_network_manager_proxy_; 111 scoped_refptr<dbus::MockObjectProxy> mock_access_point_proxy_; 112 scoped_refptr<dbus::MockObjectProxy> mock_device_proxy_; 113 scoped_refptr<WifiDataProviderLinux> wifi_provider_linux_; 114 scoped_ptr<WifiDataProviderCommon::WlanApiInterface> wlan_api_; 115 116 private: 117 // Creates a response for |mock_network_manager_proxy_|. 118 dbus::Response* CreateNetworkManagerProxyResponse( 119 dbus::MethodCall* method_call, 120 Unused) { 121 if (method_call->GetInterface() == "org.freedesktop.NetworkManager" && 122 method_call->GetMember() == "GetDevices") { 123 // The list of devices is asked. Return the object path. 124 std::vector<dbus::ObjectPath> object_paths; 125 object_paths.push_back( 126 dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0")); 127 128 scoped_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); 129 dbus::MessageWriter writer(response.get()); 130 writer.AppendArrayOfObjectPaths(object_paths); 131 return response.release(); 132 } 133 134 LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); 135 return NULL; 136 } 137 138 // Creates a response for |mock_device_proxy_|. 139 dbus::Response* CreateDeviceProxyResponse(dbus::MethodCall* method_call, 140 Unused) { 141 if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && 142 method_call->GetMember() == "Get") { 143 dbus::MessageReader reader(method_call); 144 std::string interface_name; 145 std::string property_name; 146 if (reader.PopString(&interface_name) && 147 reader.PopString(&property_name)) { 148 // The device type is asked. Respond that the device type is wifi. 149 scoped_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); 150 dbus::MessageWriter writer(response.get()); 151 // This matches NM_DEVICE_TYPE_WIFI in wifi_data_provider_linux.cc. 152 const int kDeviceTypeWifi = 2; 153 writer.AppendVariantOfUint32(kDeviceTypeWifi); 154 return response.release(); 155 } 156 } else if (method_call->GetInterface() == 157 "org.freedesktop.NetworkManager.Device.Wireless" && 158 method_call->GetMember() == "GetAccessPoints") { 159 // The list of access points is asked. Return the object path. 160 scoped_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); 161 dbus::MessageWriter writer(response.get()); 162 std::vector<dbus::ObjectPath> object_paths; 163 object_paths.push_back( 164 dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0")); 165 writer.AppendArrayOfObjectPaths(object_paths); 166 return response.release(); 167 } 168 169 LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); 170 return NULL; 171 } 172 173 174 // Creates a response for |mock_access_point_proxy_|. 175 dbus::Response* CreateAccessPointProxyResponse(dbus::MethodCall* method_call, 176 Unused) { 177 if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && 178 method_call->GetMember() == "Get") { 179 dbus::MessageReader reader(method_call); 180 181 std::string interface_name; 182 std::string property_name; 183 if (reader.PopString(&interface_name) && 184 reader.PopString(&property_name)) { 185 scoped_ptr<dbus::Response> response = dbus::Response::CreateEmpty(); 186 dbus::MessageWriter writer(response.get()); 187 188 if (property_name == "Ssid") { 189 const uint8 kSsid[] = {0x74, 0x65, 0x73, 0x74}; // "test" 190 dbus::MessageWriter variant_writer(response.get()); 191 writer.OpenVariant("ay", &variant_writer); 192 variant_writer.AppendArrayOfBytes(kSsid, arraysize(kSsid)); 193 writer.CloseContainer(&variant_writer); 194 } else if (property_name == "HwAddress") { 195 // This will be converted to "00-11-22-33-44-55". 196 const std::string kMacAddress = "00:11:22:33:44:55"; 197 writer.AppendVariantOfString(kMacAddress); 198 } else if (property_name == "Strength") { 199 // This will be converted to -50. 200 const uint8 kStrength = 100; 201 writer.AppendVariantOfByte(kStrength); 202 } else if (property_name == "Frequency") { 203 // This will be converted to channel 4. 204 const uint32 kFrequency = 2427; 205 writer.AppendVariantOfUint32(kFrequency); 206 } 207 return response.release(); 208 } 209 } 210 211 LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); 212 return NULL; 213 } 214 }; 215 216 TEST_F(GeolocationWifiDataProviderLinuxTest, GetAccessPointData) { 217 WifiData::AccessPointDataSet access_point_data_set; 218 ASSERT_TRUE(wlan_api_->GetAccessPointData(&access_point_data_set)); 219 220 ASSERT_EQ(1U, access_point_data_set.size()); 221 AccessPointData access_point_data = *access_point_data_set.begin(); 222 223 // Check the contents of the access point data. 224 // The expected values come from CreateAccessPointProxyResponse() above. 225 EXPECT_EQ("test", UTF16ToUTF8(access_point_data.ssid)); 226 EXPECT_EQ("00-11-22-33-44-55", UTF16ToUTF8(access_point_data.mac_address)); 227 EXPECT_EQ(-50, access_point_data.radio_signal_strength); 228 EXPECT_EQ(4, access_point_data.channel); 229 } 230 231 } // namespace content 232