// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/geolocation/wifi_data_provider_linux.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "dbus/message.h" #include "dbus/mock_bus.h" #include "dbus/mock_object_proxy.h" #include "dbus/object_path.h" #include "dbus/object_proxy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::_; using ::testing::Invoke; using ::testing::Return; using ::testing::Unused; namespace content { class GeolocationWifiDataProviderLinuxTest : public testing::Test { virtual void SetUp() { // Create a mock bus. dbus::Bus::Options options; options.bus_type = dbus::Bus::SYSTEM; mock_bus_ = new dbus::MockBus(options); // Create a mock proxy that behaves as NetworkManager. mock_network_manager_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), "org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager")); // Set an expectation so mock_network_manager_proxy_'s // CallMethodAndBlock() will use CreateNetworkManagerProxyResponse() // to return responses. EXPECT_CALL(*mock_network_manager_proxy_.get(), MockCallMethodAndBlock(_, _)) .WillRepeatedly(Invoke(this, &GeolocationWifiDataProviderLinuxTest:: CreateNetworkManagerProxyResponse)); // Create a mock proxy that behaves as NetworkManager/Devices/0. mock_device_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), "org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0")); EXPECT_CALL(*mock_device_proxy_.get(), MockCallMethodAndBlock(_, _)) .WillRepeatedly(Invoke( this, &GeolocationWifiDataProviderLinuxTest::CreateDeviceProxyResponse)); // Create a mock proxy that behaves as NetworkManager/AccessPoint/0. mock_access_point_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), "org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0")); EXPECT_CALL(*mock_access_point_proxy_.get(), MockCallMethodAndBlock(_, _)) .WillRepeatedly(Invoke(this, &GeolocationWifiDataProviderLinuxTest:: CreateAccessPointProxyResponse)); // Set an expectation so mock_bus_'s GetObjectProxy() for the given // service name and the object path will return // mock_network_manager_proxy_. EXPECT_CALL( *mock_bus_.get(), GetObjectProxy("org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager"))) .WillOnce(Return(mock_network_manager_proxy_.get())); // Likewise, set an expectation for mock_device_proxy_. EXPECT_CALL( *mock_bus_.get(), GetObjectProxy( "org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0"))) .WillOnce(Return(mock_device_proxy_.get())) .WillOnce(Return(mock_device_proxy_.get())); // Likewise, set an expectation for mock_access_point_proxy_. EXPECT_CALL( *mock_bus_.get(), GetObjectProxy( "org.freedesktop.NetworkManager", dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0"))) .WillOnce(Return(mock_access_point_proxy_.get())); // ShutdownAndBlock() should be called. EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); // Create the wlan API with the mock bus object injected. wifi_provider_linux_ = new WifiDataProviderLinux; wlan_api_.reset( wifi_provider_linux_->NewWlanApiForTesting(mock_bus_.get())); ASSERT_TRUE(wlan_api_.get()); } protected: // DeviceDataProviderImplBase, a super class of WifiDataProviderLinux, // requires a message loop to be present. message_loop_ is defined here, // as it should outlive wifi_provider_linux_. base::MessageLoop message_loop_; scoped_refptr mock_bus_; scoped_refptr mock_network_manager_proxy_; scoped_refptr mock_access_point_proxy_; scoped_refptr mock_device_proxy_; scoped_refptr wifi_provider_linux_; scoped_ptr wlan_api_; private: // Creates a response for |mock_network_manager_proxy_|. dbus::Response* CreateNetworkManagerProxyResponse( dbus::MethodCall* method_call, Unused) { if (method_call->GetInterface() == "org.freedesktop.NetworkManager" && method_call->GetMember() == "GetDevices") { // The list of devices is asked. Return the object path. std::vector object_paths; object_paths.push_back( dbus::ObjectPath("/org/freedesktop/NetworkManager/Devices/0")); scoped_ptr response = dbus::Response::CreateEmpty(); dbus::MessageWriter writer(response.get()); writer.AppendArrayOfObjectPaths(object_paths); return response.release(); } LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); return NULL; } // Creates a response for |mock_device_proxy_|. dbus::Response* CreateDeviceProxyResponse(dbus::MethodCall* method_call, Unused) { if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && method_call->GetMember() == "Get") { dbus::MessageReader reader(method_call); std::string interface_name; std::string property_name; if (reader.PopString(&interface_name) && reader.PopString(&property_name)) { // The device type is asked. Respond that the device type is wifi. scoped_ptr response = dbus::Response::CreateEmpty(); dbus::MessageWriter writer(response.get()); // This matches NM_DEVICE_TYPE_WIFI in wifi_data_provider_linux.cc. const int kDeviceTypeWifi = 2; writer.AppendVariantOfUint32(kDeviceTypeWifi); return response.release(); } } else if (method_call->GetInterface() == "org.freedesktop.NetworkManager.Device.Wireless" && method_call->GetMember() == "GetAccessPoints") { // The list of access points is asked. Return the object path. scoped_ptr response = dbus::Response::CreateEmpty(); dbus::MessageWriter writer(response.get()); std::vector object_paths; object_paths.push_back( dbus::ObjectPath("/org/freedesktop/NetworkManager/AccessPoint/0")); writer.AppendArrayOfObjectPaths(object_paths); return response.release(); } LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); return NULL; } // Creates a response for |mock_access_point_proxy_|. dbus::Response* CreateAccessPointProxyResponse(dbus::MethodCall* method_call, Unused) { if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && method_call->GetMember() == "Get") { dbus::MessageReader reader(method_call); std::string interface_name; std::string property_name; if (reader.PopString(&interface_name) && reader.PopString(&property_name)) { scoped_ptr response = dbus::Response::CreateEmpty(); dbus::MessageWriter writer(response.get()); if (property_name == "Ssid") { const uint8 kSsid[] = {0x74, 0x65, 0x73, 0x74}; // "test" dbus::MessageWriter variant_writer(response.get()); writer.OpenVariant("ay", &variant_writer); variant_writer.AppendArrayOfBytes(kSsid, arraysize(kSsid)); writer.CloseContainer(&variant_writer); } else if (property_name == "HwAddress") { // This will be converted to "00-11-22-33-44-55". const std::string kMacAddress = "00:11:22:33:44:55"; writer.AppendVariantOfString(kMacAddress); } else if (property_name == "Strength") { // This will be converted to -50. const uint8 kStrength = 100; writer.AppendVariantOfByte(kStrength); } else if (property_name == "Frequency") { // This will be converted to channel 4. const uint32 kFrequency = 2427; writer.AppendVariantOfUint32(kFrequency); } return response.release(); } } LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); return NULL; } }; TEST_F(GeolocationWifiDataProviderLinuxTest, GetAccessPointData) { WifiData::AccessPointDataSet access_point_data_set; ASSERT_TRUE(wlan_api_->GetAccessPointData(&access_point_data_set)); ASSERT_EQ(1U, access_point_data_set.size()); AccessPointData access_point_data = *access_point_data_set.begin(); // Check the contents of the access point data. // The expected values come from CreateAccessPointProxyResponse() above. EXPECT_EQ("test", base::UTF16ToUTF8(access_point_data.ssid)); EXPECT_EQ("00-11-22-33-44-55", base::UTF16ToUTF8(access_point_data.mac_address)); EXPECT_EQ(-50, access_point_data.radio_signal_strength); EXPECT_EQ(4, access_point_data.channel); } } // namespace content