blob: c88b5e55db7fca9e9bd47fe061d65747332a8895 [file] [log] [blame]
//
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "shill/wifi/wifi_service.h"
#include <limits>
#include <set>
#include <string>
#include <vector>
#include <base/strings/stringprintf.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <chromeos/dbus/service_constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "shill/event_dispatcher.h"
#include "shill/manager.h"
#include "shill/metrics.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_certificate_file.h"
#include "shill/mock_control.h"
#include "shill/mock_eap_credentials.h"
#include "shill/mock_log.h"
#include "shill/mock_manager.h"
#include "shill/mock_profile.h"
#include "shill/mock_service.h"
#include "shill/mock_store.h"
#include "shill/net/mock_netlink_manager.h"
#include "shill/property_store_test.h"
#include "shill/refptr_types.h"
#include "shill/service_property_change_test.h"
#include "shill/supplicant/wpa_supplicant.h"
#include "shill/technology.h"
#include "shill/tethering.h"
#include "shill/wifi/mock_wake_on_wifi.h"
#include "shill/wifi/mock_wifi.h"
#include "shill/wifi/mock_wifi_provider.h"
#include "shill/wifi/wifi_endpoint.h"
using std::set;
using std::string;
using std::vector;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::EndsWith;
using ::testing::HasSubstr;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SetArgPointee;
using ::testing::StrEq;
using ::testing::StrNe;
using ::testing::StrictMock;
namespace shill {
class WiFiServiceTest : public PropertyStoreTest {
public:
WiFiServiceTest()
: mock_manager_(control_interface(), dispatcher(), metrics()),
wifi_(new NiceMock<MockWiFi>(
control_interface(),
dispatcher(),
metrics(),
manager(),
"wifi",
fake_mac,
0,
new MockWakeOnWiFi())),
simple_ssid_(1, 'a'),
simple_ssid_string_("a") {}
virtual ~WiFiServiceTest() {}
protected:
static const char fake_mac[];
MockEapCredentials* SetMockEap(
const WiFiServiceRefPtr& service) {
MockEapCredentials* eap = new MockEapCredentials();
service->eap_.reset(eap); // Passes ownership.
return eap;
}
bool CheckConnectable(const string& security, const char* passphrase,
bool is_1x_connectable) {
Error error;
WiFiServiceRefPtr service = MakeSimpleService(security);
if (passphrase)
service->SetPassphrase(passphrase, &error);
MockEapCredentials* eap = SetMockEap(service);
EXPECT_CALL(*eap, IsConnectable())
.WillRepeatedly(Return(is_1x_connectable));
const string kKeyManagement8021x(WPASupplicant::kKeyManagementIeee8021X);
if (security == kSecurityWep && is_1x_connectable) {
EXPECT_CALL(*eap, key_management())
.WillRepeatedly(ReturnRef(kKeyManagement8021x));
}
service->OnEapCredentialsChanged(Service::kReasonCredentialsLoaded);
return service->connectable();
}
WiFiEndpoint* MakeEndpoint(const string& ssid, const string& bssid,
uint16_t frequency, int16_t signal_dbm,
bool has_wpa_property, bool has_rsn_property) {
return WiFiEndpoint::MakeEndpoint(
nullptr, wifi(), ssid, bssid, WPASupplicant::kNetworkModeInfrastructure,
frequency, signal_dbm, has_wpa_property, has_rsn_property);
}
WiFiEndpoint* MakeOpenEndpoint(const string& ssid, const string& bssid,
uint16_t frequency, int16_t signal_dbm) {
return WiFiEndpoint::MakeOpenEndpoint(
nullptr, wifi(), ssid, bssid, WPASupplicant::kNetworkModeInfrastructure,
frequency, signal_dbm);
}
WiFiEndpoint* MakeOpenEndpointWithWiFi(WiFiRefPtr wifi,
const string& ssid,
const string& bssid,
uint16_t frequency,
int16_t signal_dbm) {
return WiFiEndpoint::MakeOpenEndpoint(
nullptr, wifi, ssid, bssid, WPASupplicant::kNetworkModeInfrastructure,
frequency, signal_dbm);
}
WiFiServiceRefPtr MakeSimpleService(const string& security) {
return new WiFiService(control_interface(),
dispatcher(),
metrics(),
manager(),
&provider_,
simple_ssid_,
kModeManaged,
security,
false);
}
WiFiServiceRefPtr MakeGenericService() {
return MakeSimpleService(kSecurityWep);
}
void SetWiFi(WiFiServiceRefPtr service, WiFiRefPtr wifi) {
service->SetWiFi(wifi); // Has side-effects.
}
void SetWiFiForService(WiFiServiceRefPtr service, WiFiRefPtr wifi) {
service->wifi_ = wifi;
}
WiFiServiceRefPtr MakeServiceWithWiFi(const string& security) {
WiFiServiceRefPtr service = MakeSimpleService(security);
SetWiFiForService(service, wifi_);
return service;
}
WiFiServiceRefPtr MakeServiceWithMockManager() {
return new WiFiService(control_interface(),
dispatcher(),
metrics(),
&mock_manager_,
&provider_,
simple_ssid_,
kModeManaged,
kSecurityNone,
false);
}
scoped_refptr<MockWiFi> MakeSimpleWiFi(const string& link_name) {
return new NiceMock<MockWiFi>(control_interface(),
dispatcher(),
metrics(),
manager(),
link_name,
fake_mac,
0,
new MockWakeOnWiFi());
}
ServiceMockAdaptor* GetAdaptor(WiFiService* service) {
return static_cast<ServiceMockAdaptor*>(service->adaptor());
}
Error::Type TestConfigurePassphrase(const string& security,
const char* passphrase) {
WiFiServiceRefPtr service = MakeSimpleService(security);
KeyValueStore args;
if (passphrase) {
args.SetString(kPassphraseProperty, passphrase);
}
Error error;
service->Configure(args, &error);
return error.type();
}
bool SetRoamThreshold(WiFiServiceRefPtr service, uint16_t threshold) {
return service->SetRoamThreshold(threshold, nullptr);
}
uint16_t GetRoamThreshold(WiFiServiceRefPtr service) const {
return service->GetRoamThreshold(nullptr);
}
scoped_refptr<MockWiFi> wifi() { return wifi_; }
MockManager* mock_manager() { return &mock_manager_; }
MockWiFiProvider* provider() { return &provider_; }
string GetAnyDeviceAddress() { return WiFiService::kAnyDeviceAddress; }
const vector<uint8_t>& simple_ssid() { return simple_ssid_; }
const string& simple_ssid_string() { return simple_ssid_string_; }
private:
MockManager mock_manager_;
MockNetlinkManager netlink_manager_;
scoped_refptr<MockWiFi> wifi_;
MockWiFiProvider provider_;
const vector<uint8_t> simple_ssid_;
const string simple_ssid_string_;
};
// static
const char WiFiServiceTest::fake_mac[] = "AaBBcCDDeeFF";
MATCHER_P3(ContainsWiFiProperties, ssid, mode, security, "") {
string hex_ssid = base::HexEncode(ssid.data(), ssid.size());
return
arg.ContainsString(WiFiService::kStorageType) &&
arg.GetString(WiFiService::kStorageType) == kTypeWifi &&
arg.ContainsString(WiFiService::kStorageSSID) &&
arg.GetString(WiFiService::kStorageSSID) == hex_ssid &&
arg.ContainsString(WiFiService::kStorageMode) &&
arg.GetString(WiFiService::kStorageMode) == mode &&
arg.ContainsString(WiFiService::kStorageSecurityClass) &&
arg.GetString(WiFiService::kStorageSecurityClass) == security;
}
class WiFiServiceSecurityTest : public WiFiServiceTest {
public:
bool TestStorageSecurityIs(WiFiServiceRefPtr wifi_service,
const string& security) {
string id = wifi_service->GetStorageIdentifier();
size_t mac_pos = id.find(base::ToLowerASCII(GetAnyDeviceAddress()));
EXPECT_NE(mac_pos, string::npos);
size_t mode_pos = id.find(string(kModeManaged), mac_pos);
EXPECT_NE(mode_pos, string::npos);
return id.find(string(security), mode_pos) != string::npos;
}
// Test that a service that is created with security |from_security|
// gets by default a storage identifier with |to_security| as its
// security component, and that when saved, it sets the Security
// property in to |to_security| as well.
bool TestStorageMapping(const string& from_security,
const string& to_security) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(from_security);
NiceMock<MockStore> mock_store;
EXPECT_CALL(mock_store, SetString(_, _, _)).WillRepeatedly(Return(true));
EXPECT_CALL(mock_store,
SetString(_, WiFiService::kStorageSecurity, from_security))
.Times(1);
EXPECT_CALL(mock_store,
SetString(_, WiFiService::kStorageSecurityClass, to_security))
.Times(1);
wifi_service->Save(&mock_store);
return TestStorageSecurityIs(wifi_service, to_security);
}
// Test whether a service of type |service_security| can load from a
// storage interface containing an entry for |storage_security|.
// Make sure the result meets |expectation|. If |expectation| is
// true, also make sure the service storage identifier changes to
// match |storage_security|.
bool TestLoadMapping(const string& service_security,
const string& storage_security,
bool expectation) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(service_security);
NiceMock<MockStore> mock_store;
EXPECT_CALL(mock_store, GetGroupsWithProperties(_))
.WillRepeatedly(Return(set<string>()));
const string kStorageId = "storage_id";
EXPECT_CALL(mock_store, ContainsGroup(kStorageId))
.WillRepeatedly(Return(true));
set<string> groups;
groups.insert(kStorageId);
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(wifi_service->ssid(),
kModeManaged,
storage_security)))
.WillRepeatedly(Return(groups));
bool is_loadable = wifi_service->IsLoadableFrom(mock_store);
EXPECT_EQ(expectation, is_loadable);
bool is_loaded = wifi_service->Load(&mock_store);
EXPECT_EQ(expectation, is_loaded);
const string expected_identifier(expectation ? kStorageId : "");
EXPECT_EQ(expected_identifier,
wifi_service->GetLoadableStorageIdentifier(mock_store));
if (expectation != is_loadable || expectation != is_loaded) {
return false;
} else if (!expectation) {
return true;
} else {
return wifi_service->GetStorageIdentifier() == kStorageId;
}
}
};
class WiFiServiceUpdateFromEndpointsTest : public WiFiServiceTest {
public:
WiFiServiceUpdateFromEndpointsTest()
: kOkEndpointStrength(WiFiService::SignalToStrength(kOkEndpointSignal)),
kBadEndpointStrength(WiFiService::SignalToStrength(kBadEndpointSignal)),
kGoodEndpointStrength(
WiFiService::SignalToStrength(kGoodEndpointSignal)),
service(MakeGenericService()),
adaptor(*GetAdaptor(service.get())) {
ok_endpoint = MakeOpenEndpoint(
simple_ssid_string(), kOkEndpointBssId, kOkEndpointFrequency,
kOkEndpointSignal);
good_endpoint = MakeOpenEndpoint(
simple_ssid_string(), kGoodEndpointBssId, kGoodEndpointFrequency,
kGoodEndpointSignal);
bad_endpoint = MakeOpenEndpoint(
simple_ssid_string(), kBadEndpointBssId, kBadEndpointFrequency,
kBadEndpointSignal);
}
protected:
static const uint16_t kOkEndpointFrequency = 2422;
static const uint16_t kBadEndpointFrequency = 2417;
static const uint16_t kGoodEndpointFrequency = 2412;
static const int16_t kOkEndpointSignal = -50;
static const int16_t kBadEndpointSignal = -75;
static const int16_t kGoodEndpointSignal = -25;
static const char kOkEndpointBssId[];
static const char kGoodEndpointBssId[];
static const char kBadEndpointBssId[];
// Can't be both static and const (because initialization requires a
// function call). So choose to be just const.
const uint8_t kOkEndpointStrength;
const uint8_t kBadEndpointStrength;
const uint8_t kGoodEndpointStrength;
WiFiEndpointRefPtr ok_endpoint;
WiFiEndpointRefPtr bad_endpoint;
WiFiEndpointRefPtr good_endpoint;
WiFiServiceRefPtr service;
ServiceMockAdaptor& adaptor;
};
const char WiFiServiceUpdateFromEndpointsTest::kOkEndpointBssId[] =
"00:00:00:00:00:01";
const char WiFiServiceUpdateFromEndpointsTest::kGoodEndpointBssId[] =
"00:00:00:00:00:02";
const char WiFiServiceUpdateFromEndpointsTest::kBadEndpointBssId[] =
"00:00:00:00:00:03";
class WiFiServiceFixupStorageTest : public WiFiServiceTest {
protected:
void AddGroup(string group_name) {
groups_.insert(group_name);
}
void AddServiceEntry(bool has_type, bool has_mode, bool has_security,
bool has_security_class) {
int index = groups_.size();
string id = base::StringPrintf("%s_%d_%d_%s_%s", kTypeWifi,
index, index, kModeManaged,
kSecurityWpa);
AddGroup(id);
EXPECT_CALL(store_, GetString(id, WiFiService::kStorageType, _))
.WillOnce(Return(has_type));
if (!has_type) {
EXPECT_CALL(store_, SetString(id, WiFiService::kStorageType,
kTypeWifi));
}
EXPECT_CALL(store_, GetString(id, WiFiService::kStorageMode, _))
.WillOnce(Return(has_mode));
if (!has_mode) {
EXPECT_CALL(store_, SetString(id, WiFiService::kStorageMode,
kModeManaged));
}
EXPECT_CALL(store_, GetString(id, WiFiService::kStorageSecurity, _))
.WillOnce(Return(has_security));
if (!has_security) {
EXPECT_CALL(store_, SetString(id, WiFiService::kStorageSecurity,
kSecurityWpa));
}
EXPECT_CALL(store_, GetString(id, WiFiService::kStorageSecurityClass, _))
.WillOnce(Return(has_security_class));
if (!has_security_class) {
EXPECT_CALL(store_, SetString(id, WiFiService::kStorageSecurityClass,
kSecurityPsk));
}
}
bool FixupServiceEntries() {
EXPECT_CALL(store_, GetGroups()).WillOnce(Return(groups_));
return WiFiService::FixupServiceEntries(&store_);
}
private:
StrictMock<MockStore> store_;
set<string> groups_;
};
TEST_F(WiFiServiceTest, Constructor) {
string histogram = metrics()->GetFullMetricName(
Metrics::kMetricTimeToJoinMillisecondsSuffix, Technology::kWifi);
EXPECT_CALL(*metrics(), AddServiceStateTransitionTimer(_, _, _, _))
.Times(AnyNumber());
EXPECT_CALL(*metrics(), AddServiceStateTransitionTimer(
_, histogram, Service::kStateAssociating, Service::kStateConfiguring));
MakeSimpleService(kSecurityNone);
}
TEST_F(WiFiServiceTest, StorageId) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(kSecurityNone);
string id = wifi_service->GetStorageIdentifier();
for (char c : id) {
EXPECT_TRUE(c == '_' || isxdigit(c) || (isalpha(c) && islower(c)));
}
size_t mac_pos = id.find(base::ToLowerASCII(GetAnyDeviceAddress()));
EXPECT_NE(mac_pos, string::npos);
EXPECT_NE(id.find(string(kModeManaged), mac_pos), string::npos);
}
// Make sure the passphrase is registered as a write only property
// by reading and comparing all string properties returned on the store.
TEST_F(WiFiServiceTest, PassphraseWriteOnly) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(kSecurityWpa);
ReadablePropertyConstIterator<string> it =
(wifi_service->store()).GetStringPropertiesIter();
for ( ; !it.AtEnd(); it.Advance())
EXPECT_NE(it.Key(), kPassphraseProperty);
}
// Make sure setting the passphrase via D-Bus Service.SetProperty validates
// the passphrase.
TEST_F(WiFiServiceTest, PassphraseSetPropertyValidation) {
// We only spot check two password cases here to make sure the
// SetProperty code path does validation. We're not going to exhaustively
// test for all types of passwords.
WiFiServiceRefPtr wifi_service = MakeSimpleService(kSecurityWep);
Error error;
EXPECT_TRUE(wifi_service->mutable_store()->SetStringProperty(
kPassphraseProperty, "0:abcde", &error));
EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
kPassphraseProperty, "invalid", &error));
EXPECT_EQ(Error::kInvalidPassphrase, error.type());
}
TEST_F(WiFiServiceTest, PassphraseSetPropertyOpenNetwork) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(kSecurityNone);
Error error;
EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
kPassphraseProperty, "invalid", &error));
EXPECT_EQ(Error::kNotSupported, error.type());
}
TEST_F(WiFiServiceTest, NonUTF8SSID) {
vector<uint8_t> ssid;
ssid.push_back(0xff); // not a valid UTF-8 byte-sequence
WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
dispatcher(),
metrics(),
manager(),
provider(),
ssid,
kModeManaged,
kSecurityNone,
false);
brillo::VariantDictionary properties;
// if service doesn't propertly sanitize SSID, this will generate SIGABRT.
EXPECT_TRUE(wifi_service->store().GetProperties(&properties, nullptr));
}
MATCHER(PSKSecurityArgs, "") {
return arg.ContainsString(WPASupplicant::kPropertySecurityProtocol) &&
arg.GetString(WPASupplicant::kPropertySecurityProtocol) ==
string("WPA RSN") &&
arg.ContainsString(WPASupplicant::kPropertyPreSharedKey);
}
MATCHER_P(FrequencyArg, has_arg, "") {
return has_arg ==
arg.ContainsInt(WPASupplicant::kNetworkPropertyFrequency);
}
TEST_F(WiFiServiceTest, ConnectReportBSSes) {
WiFiEndpointRefPtr endpoint1 =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
WiFiEndpointRefPtr endpoint2 =
MakeOpenEndpoint("a", "00:00:00:00:00:02", 0, 0);
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityNone);
wifi_service->AddEndpoint(endpoint1);
wifi_service->AddEndpoint(endpoint2);
EXPECT_CALL(*metrics(), NotifyWifiAvailableBSSes(2));
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
}
TEST_F(WiFiServiceTest, ConnectWithPreferredDevice) {
// Setup service, device, and endpoints.
WiFiServiceRefPtr wifi_service = MakeServiceWithMockManager();
const string kDeviceName1 = "test_device1";
const string kDeviceName2 = "test_device2";
scoped_refptr<MockWiFi> wifi1 = MakeSimpleWiFi(kDeviceName1);
scoped_refptr<MockWiFi> wifi2 = MakeSimpleWiFi(kDeviceName2);
WiFiEndpointRefPtr endpoint1 =
MakeOpenEndpointWithWiFi(wifi1, "a", "00:00:00:00:00:01", 0, 0);
WiFiEndpointRefPtr endpoint2 =
MakeOpenEndpointWithWiFi(wifi2, "a", "00:00:00:00:00:01", 0, 0);
wifi_service->SetPreferredDevice(kDeviceName1, nullptr);
wifi_service->AddEndpoint(endpoint1);
wifi_service->AddEndpoint(endpoint2);
EXPECT_EQ(wifi1, wifi_service->wifi_);
EXPECT_CALL(*wifi1, ConnectTo(wifi_service.get()));
EXPECT_CALL(*wifi2, ConnectTo(_)).Times(0);
wifi_service->Connect(nullptr, "in test");
}
TEST_F(WiFiServiceTest, ConnectTaskWPA) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityWpa);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
Error error;
wifi_service->SetPassphrase("0:mumblemumblem", &error);
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
PSKSecurityArgs());
}
TEST_F(WiFiServiceTest, ConnectTaskRSN) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityRsn);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
Error error;
wifi_service->SetPassphrase("0:mumblemumblem", &error);
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
PSKSecurityArgs());
}
TEST_F(WiFiServiceTest, ConnectConditions) {
Error error;
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityNone);
scoped_refptr<MockProfile> mock_profile(
new NiceMock<MockProfile>(control_interface(), metrics(), manager()));
wifi_service->set_profile(mock_profile);
// With nothing else going on, the service should attempt to connect.
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(&error, "in test");
Mock::VerifyAndClearExpectations(wifi().get());
// But if we're already "connecting" or "connected" then we shouldn't attempt
// again.
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get())).Times(0);
wifi_service->SetState(Service::kStateAssociating);
wifi_service->Connect(&error, "in test");
wifi_service->SetState(Service::kStateConfiguring);
wifi_service->Connect(&error, "in test");
wifi_service->SetState(Service::kStateConnected);
wifi_service->Connect(&error, "in test");
wifi_service->SetState(Service::kStatePortal);
wifi_service->Connect(&error, "in test");
wifi_service->SetState(Service::kStateOnline);
wifi_service->Connect(&error, "in test");
Mock::VerifyAndClearExpectations(wifi().get());
}
TEST_F(WiFiServiceTest, ConnectTaskPSK) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityPsk);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
Error error;
wifi_service->SetPassphrase("0:mumblemumblem", &error);
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
PSKSecurityArgs());
}
TEST_F(WiFiServiceTest, ConnectTask8021x) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurity8021x);
service->mutable_eap()->set_identity("identity");
service->mutable_eap()->set_password("mumble");
service->OnEapCredentialsChanged(Service::kReasonCredentialsLoaded);
EXPECT_CALL(*wifi(), ConnectTo(service.get()));
service->Connect(nullptr, "in test");
KeyValueStore params = service->GetSupplicantConfigurationParameters();
EXPECT_TRUE(
params.ContainsString(WPASupplicant::kNetworkPropertyEapIdentity));
EXPECT_TRUE(params.ContainsString(WPASupplicant::kNetworkPropertyCaPath));
}
TEST_F(WiFiServiceTest, ConnectTask8021xWithMockEap) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurity8021x);
MockEapCredentials* eap = SetMockEap(service);
EXPECT_CALL(*eap, IsConnectable()).WillOnce(Return(true));
EXPECT_CALL(*wifi(), ConnectTo(service.get()));
service->OnEapCredentialsChanged(Service::kReasonCredentialsLoaded);
service->Connect(nullptr, "in test");
EXPECT_CALL(*eap, PopulateSupplicantProperties(_, _));
// The mocked function does not actually set EAP parameters so we cannot
// expect them to be set.
service->GetSupplicantConfigurationParameters();
}
TEST_F(WiFiServiceTest, ConnectTaskAdHocFrequency) {
vector<uint8_t> ssid(1, 'a');
WiFiEndpointRefPtr endpoint_nofreq =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
WiFiEndpointRefPtr endpoint_freq =
MakeOpenEndpoint("a", "00:00:00:00:00:02", 2412, 0);
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityNone);
wifi_service->AddEndpoint(endpoint_freq);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
FrequencyArg(false));
wifi_service = new WiFiService(control_interface(),
dispatcher(),
metrics(),
manager(),
provider(),
ssid,
kModeAdhoc,
kSecurityNone,
false);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
SetWiFiForService(wifi_service, wifi());
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
FrequencyArg(false));
wifi_service = new WiFiService(control_interface(),
dispatcher(),
metrics(),
manager(),
provider(),
ssid,
kModeAdhoc,
kSecurityNone,
false);
wifi_service->AddEndpoint(endpoint_nofreq);
SetWiFiForService(wifi_service, wifi());
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
FrequencyArg(false));
wifi_service = new WiFiService(control_interface(),
dispatcher(),
metrics(),
manager(),
provider(),
ssid,
kModeAdhoc,
kSecurityNone,
false);
wifi_service->AddEndpoint(endpoint_freq);
SetWiFiForService(wifi_service, wifi());
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
FrequencyArg(true));
}
TEST_F(WiFiServiceTest, ConnectTaskWPA80211w) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityPsk);
WiFiEndpointRefPtr endpoint =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
endpoint->ieee80211w_required_ = true;
wifi_service->AddEndpoint(endpoint);
Error error;
wifi_service->SetPassphrase("0:mumblemumblem", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
KeyValueStore params =
wifi_service->GetSupplicantConfigurationParameters();
EXPECT_TRUE(params.ContainsString(WPASupplicant::kPropertySecurityProtocol));
EXPECT_TRUE(params.ContainsString(WPASupplicant::kPropertyPreSharedKey));
EXPECT_TRUE(params.ContainsUint(WPASupplicant::kNetworkPropertyIeee80211w));
}
MATCHER_P(WEPSecurityArgsKeyIndex, index, "") {
uint32_t index_u32 = index;
return arg.ContainsString(WPASupplicant::kPropertyAuthAlg) &&
arg.ContainsUint8s(
WPASupplicant::kPropertyWEPKey + base::IntToString(index)) &&
arg.ContainsUint(WPASupplicant::kPropertyWEPTxKeyIndex) &&
(arg.GetUint(WPASupplicant::kPropertyWEPTxKeyIndex) == index_u32);
}
TEST_F(WiFiServiceTest, ConnectTaskWEP) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityWep);
Error error;
wifi_service->SetPassphrase("0:abcdefghijklm", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
WEPSecurityArgsKeyIndex(0));
wifi_service->SetPassphrase("abcdefghijklm", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
WEPSecurityArgsKeyIndex(0));
wifi_service->SetPassphrase("1:abcdefghijklm", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
WEPSecurityArgsKeyIndex(1));
wifi_service->SetPassphrase("2:abcdefghijklm", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
WEPSecurityArgsKeyIndex(2));
wifi_service->SetPassphrase("3:abcdefghijklm", &error);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
EXPECT_THAT(wifi_service->GetSupplicantConfigurationParameters(),
WEPSecurityArgsKeyIndex(3));
}
// Dynamic WEP + 802.1x.
TEST_F(WiFiServiceTest, ConnectTaskDynamicWEP) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityWep);
wifi_service->mutable_eap()->SetKeyManagement("IEEE8021X", nullptr);
wifi_service->mutable_eap()->set_identity("something");
wifi_service->mutable_eap()->set_password("mumble");
wifi_service->OnEapCredentialsChanged(Service::kReasonCredentialsLoaded);
EXPECT_CALL(*wifi(), ConnectTo(wifi_service.get()));
wifi_service->Connect(nullptr, "in test");
KeyValueStore params =
wifi_service->GetSupplicantConfigurationParameters();
EXPECT_TRUE(
params.ContainsString(WPASupplicant::kNetworkPropertyEapIdentity));
EXPECT_TRUE(params.ContainsString(WPASupplicant::kNetworkPropertyCaPath));
EXPECT_FALSE(
params.ContainsString(WPASupplicant::kPropertySecurityProtocol));
}
TEST_F(WiFiServiceTest, ConnectTaskFT) {
{
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityWpa);
wifi_service->ft_enabled_ = false;
wifi_service->Connect(nullptr, "in test");
KeyValueStore params = wifi_service->GetSupplicantConfigurationParameters();
EXPECT_EQ(
"WPA-PSK",
params.GetString(WPASupplicant::kNetworkPropertyEapKeyManagement));
wifi_service->ft_enabled_ = true;
wifi_service->Connect(nullptr, "in test");
params = wifi_service->GetSupplicantConfigurationParameters();
EXPECT_EQ(
"WPA-PSK FT-PSK",
params.GetString(WPASupplicant::kNetworkPropertyEapKeyManagement));
}
{
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurity8021x);
wifi_service->mutable_eap()->set_identity("identity");
wifi_service->mutable_eap()->set_password("mumble");
wifi_service->OnEapCredentialsChanged(Service::kReasonCredentialsLoaded);
wifi_service->ft_enabled_ = false;
wifi_service->Connect(nullptr, "in test");
KeyValueStore params = wifi_service->GetSupplicantConfigurationParameters();
EXPECT_EQ(
"WPA-EAP",
params.GetString(WPASupplicant::kNetworkPropertyEapKeyManagement));
wifi_service->ft_enabled_ = true;
wifi_service->Connect(nullptr, "in test");
params = wifi_service->GetSupplicantConfigurationParameters();
EXPECT_EQ(
"WPA-EAP FT-EAP",
params.GetString(WPASupplicant::kNetworkPropertyEapKeyManagement));
}
}
TEST_F(WiFiServiceTest, SetPassphraseResetHasEverConnected) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityRsn);
const string kPassphrase = "abcdefgh";
Error error;
// A changed passphrase should reset has_ever_connected_ field.
wifi_service->has_ever_connected_ = true;
EXPECT_TRUE(wifi_service->has_ever_connected());
wifi_service->SetPassphrase(kPassphrase, &error);
EXPECT_FALSE(wifi_service->has_ever_connected());
}
TEST_F(WiFiServiceTest, SetPassphraseRemovesCachedCredentials) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityRsn);
const string kPassphrase = "abcdefgh";
{
Error error;
// A changed passphrase should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
wifi_service->SetPassphrase(kPassphrase, &error);
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// An unchanged passphrase should not trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(0);
wifi_service->SetPassphrase(kPassphrase, &error);
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// A modified passphrase should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
wifi_service->SetPassphrase(kPassphrase + "X", &error);
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// A cleared passphrase should also trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
wifi_service->ClearPassphrase(&error);
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// An invalid passphrase should not trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(0);
wifi_service->SetPassphrase("", &error);
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_FALSE(error.IsSuccess());
}
{
// A change to EAP parameters in a PSK (non 802.1x) service will not
// trigger cache removal.
wifi_service->has_ever_connected_ = true;
EXPECT_TRUE(wifi_service->has_ever_connected());
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get())).Times(0);
wifi_service->OnEapCredentialsChanged(Service::kReasonPropertyUpdate);
EXPECT_TRUE(wifi_service->has_ever_connected());
Mock::VerifyAndClearExpectations(wifi().get());
}
WiFiServiceRefPtr eap_wifi_service = MakeServiceWithWiFi(kSecurity8021x);
{
// Any change to EAP parameters (including a null one) will trigger cache
// removal in an 802.1x service. This is a lot less granular than the
// passphrase checks above.
// Changes in EAP parameters should also clear has_ever_connected_.
eap_wifi_service->has_ever_connected_ = true;
EXPECT_TRUE(eap_wifi_service->has_ever_connected());
EXPECT_CALL(*wifi(), ClearCachedCredentials(eap_wifi_service.get()));
eap_wifi_service->OnEapCredentialsChanged(Service::kReasonPropertyUpdate);
EXPECT_FALSE(eap_wifi_service->has_ever_connected());
Mock::VerifyAndClearExpectations(wifi().get());
}
}
// This test is somewhat redundant, since:
//
// a) we test that generic property setters return false on a null
// change (e.g. in PropertyAccessorTest.SignedIntCorrectness)
// b) we test that custom EAP property setters return false on a null
// change in EapCredentialsTest.CustomSetterNoopChange
// c) we test that the various custom accessors pass through the
// return value of custom setters
// (e.g. PropertyAccessorTest.CustomAccessorCorrectness)
// d) we test that PropertyStore skips the change callback when a
// property setter return false (PropertyStoreTypedTest.SetProperty)
//
// Nonetheless, I think it's worth testing the WiFi+EAP case directly.
TEST_F(WiFiServiceTest, EapAuthPropertyChangeClearsCachedCredentials) {
WiFiServiceRefPtr wifi_service =
MakeServiceWithWiFi(kSecurity8021x);
PropertyStore& property_store(*wifi_service->mutable_store());
// Property with custom accessor.
const string kPassword = "abcdefgh";
{
Error error;
// A changed passphrase should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
EXPECT_TRUE(property_store.SetStringProperty(
kEapPasswordProperty, kPassword, &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// An unchanged passphrase should not trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(0);
EXPECT_FALSE(property_store.SetStringProperty(
kEapPasswordProperty, kPassword, &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// A modified passphrase should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
EXPECT_TRUE(property_store.SetStringProperty(
kEapPasswordProperty, kPassword + "X", &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
// Property with generic accessor.
const string kCertId = "abcdefgh";
{
Error error;
// A changed cert id should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
EXPECT_TRUE(property_store.SetStringProperty(
kEapCertIdProperty, kCertId, &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// An unchanged cert id should not trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(0);
EXPECT_FALSE(property_store.SetStringProperty(
kEapCertIdProperty, kCertId, &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
{
Error error;
// A modified cert id should trigger cache removal.
EXPECT_CALL(*wifi(), ClearCachedCredentials(wifi_service.get()));
EXPECT_TRUE(property_store.SetStringProperty(
kEapCertIdProperty, kCertId + "X", &error));
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_TRUE(error.IsSuccess());
}
}
TEST_F(WiFiServiceTest, LoadHidden) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
ASSERT_FALSE(service->hidden_ssid_);
NiceMock<MockStore> mock_store;
const string storage_id = service->GetStorageIdentifier();
set<string> groups;
groups.insert(storage_id);
EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityNone)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, GetBool(_, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_store,
GetBool(StrEq(storage_id), WiFiService::kStorageHiddenSSID, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_TRUE(service->hidden_ssid_);
}
TEST_F(WiFiServiceTest, SetPassphraseForNonPassphraseService) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
NiceMock<MockStore> mock_store;
const string storage_id = service->GetStorageIdentifier();
set<string> groups;
groups.insert(storage_id);
EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityNone)))
.WillRepeatedly(Return(groups));
EXPECT_TRUE(service->Load(&mock_store));
Error error;
EXPECT_FALSE(service->SetPassphrase("password", &error));
EXPECT_TRUE(error.type() == Error::kNotSupported);
}
TEST_F(WiFiServiceTest, LoadMultipleMatchingGroups) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityNone);
set<string> groups;
groups.insert("id0");
groups.insert("id1");
// Make sure we retain the first matched group in the same way that
// WiFiService::Load() will.
string first_group = *groups.begin();
NiceMock<MockStore> mock_store;
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityNone)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, ContainsGroup(first_group))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_store, ContainsGroup(StrNe(first_group))).Times(0);
EXPECT_CALL(mock_store, GetBool(first_group, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_store, GetBool(StrNe(first_group), _, _)).Times(0);
ScopedMockLog log;
EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
EXPECT_CALL(log, Log(logging::LOG_WARNING, _,
EndsWith("choosing the first.")));
EXPECT_TRUE(service->Load(&mock_store));
}
TEST_F(WiFiServiceSecurityTest, WPAMapping) {
EXPECT_TRUE(TestStorageMapping(kSecurityRsn, kSecurityPsk));
EXPECT_TRUE(TestStorageMapping(kSecurityWpa, kSecurityPsk));
EXPECT_TRUE(TestStorageMapping(kSecurityPsk, kSecurityPsk));
EXPECT_TRUE(TestStorageMapping(kSecurityWep, kSecurityWep));
EXPECT_TRUE(TestStorageMapping(kSecurityNone, kSecurityNone));
EXPECT_TRUE(TestStorageMapping(kSecurity8021x, kSecurity8021x));
}
TEST_F(WiFiServiceSecurityTest, LoadMapping) {
EXPECT_TRUE(TestLoadMapping(kSecurityRsn, kSecurityPsk, true));
EXPECT_TRUE(TestLoadMapping(kSecurityRsn, kSecurityRsn, false));
EXPECT_TRUE(TestLoadMapping(kSecurityRsn, kSecurityWpa, false));
EXPECT_TRUE(TestLoadMapping(kSecurityWpa, kSecurityPsk, true));
EXPECT_TRUE(TestLoadMapping(kSecurityWpa, kSecurityWpa, false));
EXPECT_TRUE(TestLoadMapping(kSecurityWpa, kSecurityRsn, false));
EXPECT_TRUE(TestLoadMapping(kSecurityWep, kSecurityWep, true));
EXPECT_TRUE(TestLoadMapping(kSecurityWep, kSecurityPsk, false));
}
TEST_F(WiFiServiceTest, LoadAndUnloadPassphrase) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityPsk);
NiceMock<MockStore> mock_store;
const string kStorageId = service->GetStorageIdentifier();
EXPECT_CALL(mock_store, ContainsGroup(StrEq(kStorageId)))
.WillRepeatedly(Return(true));
set<string> groups;
groups.insert(kStorageId);
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityPsk)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, GetBool(_, _, _))
.WillRepeatedly(Return(false));
const string kPassphrase = "passphrase";
EXPECT_CALL(mock_store,
GetCryptedString(StrEq(kStorageId),
WiFiService::kStoragePassphrase, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(kPassphrase), Return(true)));
EXPECT_CALL(mock_store,
GetCryptedString(StrEq(kStorageId),
StrNe(WiFiService::kStoragePassphrase), _))
.WillRepeatedly(Return(false));
EXPECT_TRUE(service->need_passphrase_);
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(kPassphrase, service->passphrase_);
EXPECT_TRUE(service->connectable());
EXPECT_FALSE(service->need_passphrase_);
service->Unload();
EXPECT_EQ(string(""), service->passphrase_);
EXPECT_FALSE(service->connectable());
EXPECT_TRUE(service->need_passphrase_);
}
TEST_F(WiFiServiceTest, LoadPassphraseClearCredentials) {
const string kOldPassphrase = "oldpassphrase";
const string kPassphrase = "passphrase";
const bool kHasEverConnected = true;
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityPsk);
NiceMock<MockStore> mock_store;
const string kStorageId = service->GetStorageIdentifier();
EXPECT_CALL(mock_store, ContainsGroup(StrEq(kStorageId)))
.WillRepeatedly(Return(true));
set<string> groups;
groups.insert(kStorageId);
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityPsk)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, GetBool(_, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_store,
GetCryptedString(StrEq(kStorageId),
WiFiService::kStoragePassphrase, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(kPassphrase), Return(true)));
EXPECT_CALL(mock_store,
GetCryptedString(StrEq(kStorageId),
StrNe(WiFiService::kStoragePassphrase), _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_store,
GetBool(kStorageId, Service::kStorageHasEverConnected, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(kHasEverConnected),
Return(true)));
// Set old passphrase for service
EXPECT_TRUE(service->need_passphrase_);
service->passphrase_ = kOldPassphrase;
service->has_ever_connected_ = true;
scoped_refptr<MockProfile> mock_profile(
new NiceMock<MockProfile>(control_interface(), metrics(), manager()));
service->set_profile(mock_profile);
// Detect if the service is going to attempt to update the stored profile.
EXPECT_CALL(*mock_profile, GetConstStorage()).Times(0);
// The kOldPassphrase is different than the newly loaded passhprase,
// so the credentials should be cleared.
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(1);
EXPECT_CALL(*mock_profile, UpdateService(_)).Times(0);
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(kPassphrase, service->passphrase_);
EXPECT_TRUE(service->has_ever_connected_);
Mock::VerifyAndClearExpectations(wifi().get());
Mock::VerifyAndClearExpectations(mock_profile.get());
// Repeat Service::Load with same old and new passphrase. Since the old
// and new passphrase match, verify the cache is not cleared during
// profile load.
service->set_profile(mock_profile);
EXPECT_CALL(*mock_profile, GetConstStorage()).Times(0);
EXPECT_CALL(*wifi(), ClearCachedCredentials(_)).Times(0);
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(kPassphrase, service->passphrase_);
EXPECT_TRUE(service->has_ever_connected_);
}
TEST_F(WiFiServiceTest, ConfigureMakesConnectable) {
string guid("legit_guid");
KeyValueStore args;
args.SetString(kEapIdentityProperty, "legit_identity");
args.SetString(kEapPasswordProperty, "legit_password");
args.SetString(kEapMethodProperty, "PEAP");
args.SetString(kGuidProperty, guid);
Error error;
WiFiServiceRefPtr service = MakeSimpleService(kSecurity8021x);
// Hack the GUID in so that we don't have to mess about with WiFi to regsiter
// our service. This way, Manager will handle the lookup itself.
service->SetGuid(guid, nullptr);
manager()->RegisterService(service);
EXPECT_FALSE(service->connectable());
EXPECT_EQ(service.get(), manager()->GetService(args, &error).get());
EXPECT_TRUE(error.IsSuccess());
EXPECT_TRUE(service->connectable());
}
TEST_F(WiFiServiceTest, ConfigurePassphrase) {
EXPECT_EQ(Error::kNotSupported,
TestConfigurePassphrase(kSecurityNone, ""));
EXPECT_EQ(Error::kNotSupported,
TestConfigurePassphrase(kSecurityNone, "foo"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep, nullptr));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, ""));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "abcd"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep, "abcde"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep, "abcdefghijklm"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep, "0:abcdefghijklm"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep, "0102030405"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "0x0102030405"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "O102030405"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "1:O102030405"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "1:0xO102030405"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWep, "0xO102030405"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep,
"0102030405060708090a0b0c0d"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep,
"0102030405060708090A0B0C0D"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep,
"0:0102030405060708090a0b0c0d"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWep,
"0:0x0102030405060708090a0b0c0d"));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWpa, nullptr));
EXPECT_EQ(Error::kSuccess,
TestConfigurePassphrase(kSecurityWpa, "secure password"));
EXPECT_EQ(Error::kInvalidPassphrase,
TestConfigurePassphrase(kSecurityWpa, ""));
EXPECT_EQ(Error::kSuccess, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAAsciiMinLen, 'Z').c_str()));
EXPECT_EQ(Error::kSuccess, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAAsciiMaxLen, 'Z').c_str()));
// subtle: invalid length for hex key, but valid as ascii passphrase
EXPECT_EQ(Error::kSuccess, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAHexLen-1, '1').c_str()));
EXPECT_EQ(Error::kSuccess, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAHexLen, '1').c_str()));
EXPECT_EQ(Error::kInvalidPassphrase, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAAsciiMinLen-1, 'Z').c_str()));
EXPECT_EQ(Error::kInvalidPassphrase, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAAsciiMaxLen+1, 'Z').c_str()));
EXPECT_EQ(Error::kInvalidPassphrase, TestConfigurePassphrase(
kSecurityWpa,
string(IEEE_80211::kWPAHexLen+1, '1').c_str()));
}
TEST_F(WiFiServiceTest, ConfigureRedundantProperties) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
KeyValueStore args;
args.SetString(kTypeProperty, kTypeWifi);
args.SetString(kSSIDProperty, simple_ssid_string());
args.SetString(kSecurityProperty, kSecurityNone);
args.SetString(kWifiHexSsid, "This is ignored even if it is invalid hex.");
const string kGUID = "aguid";
args.SetString(kGuidProperty, kGUID);
EXPECT_EQ("", service->guid());
Error error;
service->Configure(args, &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_EQ(kGUID, service->guid());
}
TEST_F(WiFiServiceTest, DisconnectWithWiFi) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityWep);
EXPECT_CALL(*wifi(), DisconnectFromIfActive(service.get())).Times(1);
Error error;
service->Disconnect(&error, "in test");
}
TEST_F(WiFiServiceTest, DisconnectWithoutWiFi) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWep);
EXPECT_CALL(*wifi(), DisconnectFrom(_)).Times(0);
Error error;
service->Disconnect(&error, "in test");
EXPECT_EQ(Error::kOperationFailed, error.type());
}
TEST_F(WiFiServiceTest, DisconnectWithoutWiFiWhileAssociating) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWep);
EXPECT_CALL(*wifi(), DisconnectFrom(_)).Times(0);
service->SetState(Service::kStateAssociating);
ScopedMockLog log;
EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
EXPECT_CALL(log, Log(logging::LOG_ERROR, _,
HasSubstr("WiFi endpoints do not (yet) exist.")));
Error error;
service->Disconnect(&error, "in test");
EXPECT_EQ(Error::kOperationFailed, error.type());
}
TEST_F(WiFiServiceTest, UnloadAndClearCacheWEP) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityWep);
EXPECT_CALL(*wifi(), ClearCachedCredentials(service.get())).Times(1);
EXPECT_CALL(*wifi(), DisconnectFromIfActive(service.get())).Times(1);
service->Unload();
}
TEST_F(WiFiServiceTest, UnloadAndClearCache8021x) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurity8021x);
EXPECT_CALL(*wifi(), ClearCachedCredentials(service.get())).Times(1);
EXPECT_CALL(*wifi(), DisconnectFromIfActive(service.get())).Times(1);
service->Unload();
}
TEST_F(WiFiServiceTest, ParseStorageIdentifierNone) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
const string storage_id = service->GetStorageIdentifier();
string address;
string mode;
string security;
EXPECT_TRUE(service->ParseStorageIdentifier(storage_id, &address, &mode,
&security));
EXPECT_EQ(base::ToLowerASCII(GetAnyDeviceAddress()), address);
EXPECT_EQ(kModeManaged, mode);
EXPECT_EQ(kSecurityNone, security);
}
TEST_F(WiFiServiceTest, ParseStorageIdentifier8021x) {
// Do a separate test for 802.1x, since kSecurity8021x contains a "_",
// which needs to be dealt with specially in the parser.
WiFiServiceRefPtr service = MakeSimpleService(kSecurity8021x);
const string storage_id = service->GetStorageIdentifier();
string address;
string mode;
string security;
EXPECT_TRUE(service->ParseStorageIdentifier(storage_id, &address, &mode,
&security));
EXPECT_EQ(base::ToLowerASCII(GetAnyDeviceAddress()), address);
EXPECT_EQ(kModeManaged, mode);
EXPECT_EQ(kSecurity8021x, security);
}
TEST_F(WiFiServiceFixupStorageTest, FixedEntries) {
const string kNonWiFiId = "vpn_foo";
const string kUnparsableWiFiId = "wifi_foo";
AddGroup(kNonWiFiId);
AddGroup(kUnparsableWiFiId);
AddServiceEntry(true, true, true, true);
AddServiceEntry(false, false, false, false);
AddServiceEntry(true, true, true, true);
AddServiceEntry(false, false, false, false);
EXPECT_TRUE(FixupServiceEntries());
}
TEST_F(WiFiServiceFixupStorageTest, NoFixedEntries) {
const string kNonWiFiId = "vpn_foo";
const string kUnparsableWiFiId = "wifi_foo";
AddGroup(kNonWiFiId);
AddGroup(kUnparsableWiFiId);
AddServiceEntry(true, true, true, true);
EXPECT_FALSE(FixupServiceEntries());
}
TEST_F(WiFiServiceFixupStorageTest, MissingTypeProperty) {
AddServiceEntry(false, true, true, true);
EXPECT_TRUE(FixupServiceEntries());
}
TEST_F(WiFiServiceFixupStorageTest, MissingModeProperty) {
AddServiceEntry(true, false, true, true);
EXPECT_TRUE(FixupServiceEntries());
}
TEST_F(WiFiServiceFixupStorageTest, MissingSecurityProperty) {
AddServiceEntry(true, true, false, true);
EXPECT_TRUE(FixupServiceEntries());
}
TEST_F(WiFiServiceFixupStorageTest, MissingSecurityClassProperty) {
AddServiceEntry(true, true, true, false);
EXPECT_TRUE(FixupServiceEntries());
}
TEST_F(WiFiServiceTest, Connectable) {
// Open network should be connectable.
EXPECT_TRUE(CheckConnectable(kSecurityNone, nullptr, false));
// Open network should remain connectable if we try to set a password on it.
EXPECT_TRUE(CheckConnectable(kSecurityNone, "abcde", false));
// WEP network with passphrase set should be connectable.
EXPECT_TRUE(CheckConnectable(kSecurityWep, "abcde", false));
// WEP network without passphrase set should NOT be connectable.
EXPECT_FALSE(CheckConnectable(kSecurityWep, nullptr, false));
// A bad passphrase should not make a WEP network connectable.
EXPECT_FALSE(CheckConnectable(kSecurityWep, "a", false));
// Similar to WEP, for WPA.
EXPECT_TRUE(CheckConnectable(kSecurityWpa, "abcdefgh", false));
EXPECT_FALSE(CheckConnectable(kSecurityWpa, nullptr, false));
EXPECT_FALSE(CheckConnectable(kSecurityWpa, "a", false));
// 802.1x without connectable EAP credentials should NOT be connectable.
EXPECT_FALSE(CheckConnectable(kSecurity8021x, nullptr, false));
// 802.1x with connectable EAP credentials should be connectable.
EXPECT_TRUE(CheckConnectable(kSecurity8021x, nullptr, true));
// Dynamic WEP + 802.1X should be connectable under the same conditions.
EXPECT_TRUE(CheckConnectable(kSecurityWep, nullptr, true));
}
TEST_F(WiFiServiceTest, IsAutoConnectable) {
const char* reason;
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
EXPECT_CALL(*wifi(), IsIdle())
.WillRepeatedly(Return(true));
EXPECT_FALSE(service->HasEndpoints());
EXPECT_FALSE(service->IsAutoConnectable(&reason));
EXPECT_STREQ(WiFiService::kAutoConnNoEndpoint, reason);
reason = "";
WiFiEndpointRefPtr endpoint =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
service->AddEndpoint(endpoint);
EXPECT_CALL(*wifi(), IsIdle())
.WillRepeatedly(Return(true));
EXPECT_TRUE(service->HasEndpoints());
EXPECT_TRUE(service->IsAutoConnectable(&reason));
EXPECT_STREQ("", reason);
// WiFi only supports connecting to one Service at a time. So, to
// avoid disrupting connectivity, we only allow auto-connection to
// a WiFiService when the corresponding WiFi is idle.
EXPECT_CALL(*wifi(), IsIdle())
.WillRepeatedly(Return(false));
EXPECT_TRUE(service->HasEndpoints());
EXPECT_FALSE(service->IsAutoConnectable(&reason));
EXPECT_STREQ(WiFiService::kAutoConnBusy, reason);
}
TEST_F(WiFiServiceTest, AutoConnect) {
const char* reason;
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
EXPECT_FALSE(service->IsAutoConnectable(&reason));
EXPECT_CALL(*wifi(), ConnectTo(_)).Times(0);
service->AutoConnect();
dispatcher()->DispatchPendingEvents();
WiFiEndpointRefPtr endpoint =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
service->AddEndpoint(endpoint);
EXPECT_CALL(*wifi(), IsIdle())
.WillRepeatedly(Return(true));
EXPECT_TRUE(service->IsAutoConnectable(&reason));
EXPECT_CALL(*wifi(), ConnectTo(_));
service->AutoConnect();
dispatcher()->DispatchPendingEvents();
Error error;
service->UserInitiatedDisconnect("RPC", &error);
dispatcher()->DispatchPendingEvents();
EXPECT_FALSE(service->IsAutoConnectable(&reason));
}
TEST_F(WiFiServiceTest, ClearWriteOnlyDerivedProperty) {
WiFiServiceRefPtr wifi_service = MakeSimpleService(kSecurityWep);
EXPECT_EQ("", wifi_service->passphrase_);
Error error;
const string kPassphrase = "0:abcde";
EXPECT_TRUE(
wifi_service->mutable_store()->SetAnyProperty(kPassphraseProperty,
brillo::Any(kPassphrase),
&error));
EXPECT_EQ(kPassphrase, wifi_service->passphrase_);
EXPECT_TRUE(wifi_service->mutable_store()->ClearProperty(kPassphraseProperty,
&error));
EXPECT_EQ("", wifi_service->passphrase_);
}
TEST_F(WiFiServiceTest, SignalToStrength) {
// Verify that our mapping is sane, in the sense that it preserves ordering.
// We break the test into two domains, because we assume that positive
// values aren't actually in dBm.
for (int16_t i = std::numeric_limits<int16_t>::min(); i < 0; ++i) {
int16_t current_mapped = WiFiService::SignalToStrength(i);
int16_t next_mapped = WiFiService::SignalToStrength(i+1);
EXPECT_LE(current_mapped, next_mapped)
<< "(original values " << i << " " << i+1 << ")";
EXPECT_GE(current_mapped, Service::kStrengthMin);
EXPECT_LE(current_mapped, Service::kStrengthMax);
}
for (int16_t i = 1; i < std::numeric_limits<int16_t>::max(); ++i) {
int16_t current_mapped = WiFiService::SignalToStrength(i);
int16_t next_mapped = WiFiService::SignalToStrength(i+1);
EXPECT_LE(current_mapped, next_mapped)
<< "(original values " << i << " " << i+1 << ")";
EXPECT_GE(current_mapped, Service::kStrengthMin);
EXPECT_LE(current_mapped, Service::kStrengthMax);
}
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, Strengths) {
// If the chosen signal values don't map to distinct strength
// values, then we can't expect our other tests to pass. So verify
// their distinctness.
EXPECT_TRUE(kOkEndpointStrength != kBadEndpointStrength);
EXPECT_TRUE(kOkEndpointStrength != kGoodEndpointStrength);
EXPECT_TRUE(kGoodEndpointStrength != kBadEndpointStrength);
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, Floating) {
// Initial endpoint updates values.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, kOkEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kOkEndpointBssId));
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, kOkEndpointStrength));
EXPECT_CALL(adaptor,
EmitUint16Changed(kWifiPhyMode, Metrics::kWiFiNetworkPhyMode11b));
service->AddEndpoint(ok_endpoint);
EXPECT_EQ(1, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Endpoint with stronger signal updates values.
EXPECT_CALL(adaptor,
EmitUint16Changed(kWifiFrequency, kGoodEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kGoodEndpointBssId));
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, kGoodEndpointStrength));
// However, both endpoints are 11b.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiPhyMode, _)).Times(0);
service->AddEndpoint(good_endpoint);
EXPECT_EQ(2, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Endpoint with lower signal does not change values.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiPhyMode, _)).Times(0);
service->AddEndpoint(bad_endpoint);
EXPECT_EQ(3, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Removing non-optimal endpoint does not change values.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiPhyMode, _)).Times(0);
service->RemoveEndpoint(bad_endpoint);
EXPECT_EQ(2, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Removing optimal endpoint updates values.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, kOkEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kOkEndpointBssId));
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, kOkEndpointStrength));
// However, both endpoints are 11b.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiPhyMode, _)).Times(0);
service->RemoveEndpoint(good_endpoint);
EXPECT_EQ(1, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Removing last endpoint updates values (and doesn't crash).
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _));
EXPECT_CALL(adaptor, EmitUint8Changed(kSignalStrengthProperty, _));
EXPECT_CALL(adaptor, EmitUint16Changed(
kWifiPhyMode, Metrics::kWiFiNetworkPhyModeUndef));
service->RemoveEndpoint(ok_endpoint);
EXPECT_EQ(0, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, Connected) {
EXPECT_CALL(adaptor, EmitUint16Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitStringChanged(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitUint8Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitBoolChanged(_, _)).Times(AnyNumber());
service->AddEndpoint(bad_endpoint);
service->AddEndpoint(ok_endpoint);
EXPECT_EQ(2, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Setting current endpoint forces adoption of its values, even if it
// doesn't have the highest signal.
EXPECT_CALL(adaptor,
EmitUint16Changed(kWifiFrequency, kBadEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kBadEndpointBssId));
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, kBadEndpointStrength));
service->NotifyCurrentEndpoint(bad_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Adding a better endpoint doesn't matter, when current endpoint is set.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
service->AddEndpoint(good_endpoint);
EXPECT_EQ(3, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Removing a better endpoint doesn't matter, when current endpoint is set.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
service->RemoveEndpoint(good_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Removing the current endpoint is safe and sane.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, kOkEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kOkEndpointBssId));
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, kOkEndpointStrength));
service->RemoveEndpoint(bad_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Clearing the current endpoint (without removing it) is also safe and sane.
service->NotifyCurrentEndpoint(ok_endpoint);
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
service->NotifyCurrentEndpoint(nullptr);
Mock::VerifyAndClearExpectations(&adaptor);
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, EndpointModified) {
EXPECT_CALL(adaptor, EmitUint16Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitStringChanged(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitUint8Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitBoolChanged(_, _)).Times(AnyNumber());
service->AddEndpoint(ok_endpoint);
service->AddEndpoint(good_endpoint);
EXPECT_EQ(2, service->GetEndpointCount());
Mock::VerifyAndClearExpectations(&adaptor);
// Updating sub-optimal Endpoint doesn't update Service.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor,
EmitUint8Changed(kSignalStrengthProperty, _)).Times(0);
ok_endpoint->signal_strength_ = (kOkEndpointSignal + kGoodEndpointSignal) / 2;
service->NotifyEndpointUpdated(ok_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Updating optimal Endpoint updates appropriate Service property.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, _)).Times(0);
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, _)).Times(0);
EXPECT_CALL(adaptor, EmitUint8Changed(kSignalStrengthProperty, _));
good_endpoint->signal_strength_ = kGoodEndpointSignal + 1;
service->NotifyEndpointUpdated(good_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Change in optimal Endpoint updates Service properties.
EXPECT_CALL(adaptor, EmitUint16Changed(kWifiFrequency, kOkEndpointFrequency));
EXPECT_CALL(adaptor, EmitStringChanged(kWifiBSsid, kOkEndpointBssId));
EXPECT_CALL(adaptor, EmitUint8Changed(kSignalStrengthProperty, _));
ok_endpoint->signal_strength_ = kGoodEndpointSignal + 2;
service->NotifyEndpointUpdated(ok_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, Ieee80211w) {
EXPECT_CALL(adaptor, EmitUint16Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitStringChanged(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitUint8Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitBoolChanged(_, _)).Times(AnyNumber());
service->AddEndpoint(ok_endpoint);
EXPECT_FALSE(service->ieee80211w_required());
good_endpoint->ieee80211w_required_ = true;
service->AddEndpoint(good_endpoint);
EXPECT_TRUE(service->ieee80211w_required());
service->RemoveEndpoint(good_endpoint);
EXPECT_TRUE(service->ieee80211w_required());
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, PhysicalMode) {
EXPECT_CALL(adaptor, EmitUint16Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitStringChanged(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitUint8Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitBoolChanged(_, _)).Times(AnyNumber());
// No endpoints -> undef.
EXPECT_EQ(Metrics::kWiFiNetworkPhyModeUndef, service->physical_mode());
// Endpoint has unknown physical mode -> undef.
ok_endpoint->physical_mode_ = Metrics::kWiFiNetworkPhyModeUndef;
service->AddEndpoint(ok_endpoint);
EXPECT_EQ(Metrics::kWiFiNetworkPhyModeUndef, service->physical_mode());
// New endpoint with 802.11a -> 802.11a.
good_endpoint->physical_mode_ = Metrics::kWiFiNetworkPhyMode11a;
service->AddEndpoint(good_endpoint);
EXPECT_EQ(Metrics::kWiFiNetworkPhyMode11a, service->physical_mode());
// Remove 802.11a endpoint -> undef.
service->RemoveEndpoint(good_endpoint);
EXPECT_EQ(Metrics::kWiFiNetworkPhyModeUndef, service->physical_mode());
// Change endpoint -> take endpoint's new value.
ok_endpoint->physical_mode_ = Metrics::kWiFiNetworkPhyMode11n;
service->NotifyEndpointUpdated(ok_endpoint);
EXPECT_EQ(Metrics::kWiFiNetworkPhyMode11n, service->physical_mode());
// No endpoints -> undef.
service->RemoveEndpoint(ok_endpoint);
EXPECT_EQ(Metrics::kWiFiNetworkPhyModeUndef, service->physical_mode());
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, WarningOnDisconnect) {
service->AddEndpoint(ok_endpoint);
service->SetState(Service::kStateAssociating);
ScopedMockLog log;
EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
EXPECT_CALL(log, Log(logging::LOG_WARNING, _,
EndsWith("disconnect due to no remaining endpoints.")));
service->RemoveEndpoint(ok_endpoint);
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, AddEndpointWithPreferredDevice) {
// Setup service, device, and endpoints.
WiFiServiceRefPtr wifi_service = MakeServiceWithMockManager();
const string kDeviceName1 = "test_device1";
const string kDeviceName2 = "test_device2";
scoped_refptr<MockWiFi> wifi1 = MakeSimpleWiFi(kDeviceName1);
scoped_refptr<MockWiFi> wifi2 = MakeSimpleWiFi(kDeviceName2);
// Best signal for endpoint associated with the preferred device.
const int16_t kPreferredDeviceBestSignal = -40;
WiFiEndpointRefPtr endpoint0 =
MakeOpenEndpointWithWiFi(wifi2, "a", "00:00:00:00:00:01", 0,
kPreferredDeviceBestSignal + 10);
WiFiEndpointRefPtr endpoint1 =
MakeOpenEndpointWithWiFi(wifi1, "a", "00:00:00:00:00:01", 0,
kPreferredDeviceBestSignal - 10);
WiFiEndpointRefPtr endpoint2 =
MakeOpenEndpointWithWiFi(wifi1, "a", "00:00:00:00:00:01", 0,
kPreferredDeviceBestSignal);
WiFiEndpointRefPtr endpoint3 =
MakeOpenEndpointWithWiFi(wifi2, "a", "00:00:00:00:00:01", 0,
kPreferredDeviceBestSignal + 10);
wifi_service->SetPreferredDevice(kDeviceName1, nullptr);
wifi_service->AddEndpoint(endpoint0);
wifi_service->AddEndpoint(endpoint1);
wifi_service->AddEndpoint(endpoint2);
wifi_service->AddEndpoint(endpoint3);
EXPECT_EQ(wifi1, wifi_service->wifi_);
// Service should display the signal strength of the best signal endpoint
// that's associated with the preferred device.
EXPECT_EQ(WiFiService::SignalToStrength(kPreferredDeviceBestSignal),
wifi_service->strength());
}
MATCHER_P(IsSetwiseEqual, expected_set, "") {
set<uint16_t> arg_set(arg.begin(), arg.end());
return arg_set == expected_set;
}
TEST_F(WiFiServiceUpdateFromEndpointsTest, FrequencyList) {
EXPECT_CALL(adaptor, EmitUint16Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitStringChanged(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitUint8Changed(_, _)).Times(AnyNumber());
EXPECT_CALL(adaptor, EmitBoolChanged(_, _)).Times(AnyNumber());
// No endpoints -> empty list.
EXPECT_EQ(vector<uint16_t>(), service->frequency_list());
// Add endpoint -> endpoint's frequency in list.
EXPECT_CALL(adaptor, EmitUint16sChanged(
kWifiFrequencyListProperty, vector<uint16_t>{kGoodEndpointFrequency}));
service->AddEndpoint(good_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Add another endpoint -> both frequencies in list.
// Order doesn't matter.
set<uint16_t> expected_frequencies{kGoodEndpointFrequency,
kOkEndpointFrequency};
EXPECT_CALL(adaptor, EmitUint16sChanged(
kWifiFrequencyListProperty, IsSetwiseEqual(expected_frequencies)));
service->AddEndpoint(ok_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Remove endpoint -> other endpoint's frequency remains.
EXPECT_CALL(adaptor, EmitUint16sChanged(
kWifiFrequencyListProperty, vector<uint16_t>{kOkEndpointFrequency}));
service->RemoveEndpoint(good_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
// Endpoint with same frequency -> frequency remains.
// Notification may or may not occur -- don't care.
// Frequency may or may not be repeated in list -- don't care.
WiFiEndpointRefPtr same_freq_as_ok_endpoint = MakeOpenEndpoint(
simple_ssid_string(), "aa:bb:cc:dd:ee:ff", ok_endpoint->frequency(), 0);
service->AddEndpoint(same_freq_as_ok_endpoint);
EXPECT_THAT(service->frequency_list(),
IsSetwiseEqual(set<uint16_t>{kOkEndpointFrequency}));
Mock::VerifyAndClearExpectations(&adaptor);
// Remove endpoint with same frequency -> frequency remains.
// Notification may or may not occur -- don't care.
service->RemoveEndpoint(ok_endpoint);
EXPECT_EQ(vector<uint16_t>{same_freq_as_ok_endpoint->frequency()},
service->frequency_list());
Mock::VerifyAndClearExpectations(&adaptor);
// Remove last endpoint. Frequency list goes empty.
EXPECT_CALL(adaptor, EmitUint16sChanged(
kWifiFrequencyListProperty, vector<uint16_t>{}));
service->RemoveEndpoint(same_freq_as_ok_endpoint);
Mock::VerifyAndClearExpectations(&adaptor);
}
TEST_F(WiFiServiceTest, SecurityFromCurrentEndpoint) {
WiFiServiceRefPtr service(MakeSimpleService(kSecurityPsk));
EXPECT_EQ(kSecurityPsk, service->GetSecurity(nullptr));
WiFiEndpoint* endpoint = MakeOpenEndpoint(
simple_ssid_string(), "00:00:00:00:00:00", 0, 0);
service->AddEndpoint(endpoint);
EXPECT_EQ(kSecurityPsk, service->GetSecurity(nullptr));
service->NotifyCurrentEndpoint(endpoint);
EXPECT_EQ(kSecurityNone, service->GetSecurity(nullptr));
service->NotifyCurrentEndpoint(nullptr);
EXPECT_EQ(kSecurityPsk, service->GetSecurity(nullptr));
}
TEST_F(WiFiServiceTest, UpdateSecurity) {
// Cleartext and pre-shared-key crypto.
{
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
EXPECT_EQ(Service::kCryptoNone, service->crypto_algorithm());
EXPECT_FALSE(service->key_rotation());
EXPECT_FALSE(service->endpoint_auth());
}
{
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWep);
EXPECT_EQ(Service::kCryptoRc4, service->crypto_algorithm());
EXPECT_FALSE(service->key_rotation());
EXPECT_FALSE(service->endpoint_auth());
}
{
WiFiServiceRefPtr service = MakeSimpleService(kSecurityPsk);
EXPECT_EQ(Service::kCryptoRc4, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_FALSE(service->endpoint_auth());
}
{
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWpa);
EXPECT_EQ(Service::kCryptoRc4, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_FALSE(service->endpoint_auth());
}
{
WiFiServiceRefPtr service = MakeSimpleService(kSecurityRsn);
EXPECT_EQ(Service::kCryptoAes, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_FALSE(service->endpoint_auth());
}
// Crypto with 802.1X key management.
{
// WEP
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWep);
service->SetEAPKeyManagement("IEEE8021X");
EXPECT_EQ(Service::kCryptoRc4, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_TRUE(service->endpoint_auth());
}
{
// WPA
WiFiServiceRefPtr service = MakeSimpleService(kSecurity8021x);
WiFiEndpointRefPtr endpoint =
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, false);
service->AddEndpoint(endpoint);
EXPECT_EQ(Service::kCryptoRc4, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_TRUE(service->endpoint_auth());
}
{
// RSN
WiFiServiceRefPtr service = MakeSimpleService(kSecurity8021x);
WiFiEndpointRefPtr endpoint =
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, true);
service->AddEndpoint(endpoint);
EXPECT_EQ(Service::kCryptoAes, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_TRUE(service->endpoint_auth());
}
{
// AP supports both WPA and RSN.
WiFiServiceRefPtr service = MakeSimpleService(kSecurity8021x);
WiFiEndpointRefPtr endpoint =
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, true);
service->AddEndpoint(endpoint);
EXPECT_EQ(Service::kCryptoAes, service->crypto_algorithm());
EXPECT_TRUE(service->key_rotation());
EXPECT_TRUE(service->endpoint_auth());
}
}
TEST_F(WiFiServiceTest, ComputeCipher8021x) {
// No endpoints.
{
const set<WiFiEndpointConstRefPtr> endpoints;
EXPECT_EQ(Service::kCryptoNone,
WiFiService::ComputeCipher8021x(endpoints));
}
// Single endpoint, various configs.
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, false));
EXPECT_EQ(Service::kCryptoNone,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, false));
EXPECT_EQ(Service::kCryptoRc4,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, true));
EXPECT_EQ(Service::kCryptoAes,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, true));
EXPECT_EQ(Service::kCryptoAes,
WiFiService::ComputeCipher8021x(endpoints));
}
// Multiple endpoints.
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, false));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, false, false));
EXPECT_EQ(Service::kCryptoNone,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, false));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, true, false));
EXPECT_EQ(Service::kCryptoNone,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, false));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, true, false));
EXPECT_EQ(Service::kCryptoRc4,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, false));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, false, true));
EXPECT_EQ(Service::kCryptoRc4,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, false, true));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, false, true));
EXPECT_EQ(Service::kCryptoAes,
WiFiService::ComputeCipher8021x(endpoints));
}
{
set<WiFiEndpointConstRefPtr> endpoints;
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:01", 0, 0, true, true));
endpoints.insert(
MakeEndpoint("a", "00:00:00:00:00:02", 0, 0, true, true));
EXPECT_EQ(Service::kCryptoAes,
WiFiService::ComputeCipher8021x(endpoints));
}
}
TEST_F(WiFiServiceTest, Unload) {
WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityNone);
EXPECT_CALL(*wifi(), DestroyIPConfigLease(service->GetStorageIdentifier())).
Times(1);
service->Unload();
}
TEST_F(WiFiServiceTest, PropertyChanges) {
WiFiServiceRefPtr service = MakeServiceWithMockManager();
ServiceMockAdaptor* adaptor = GetAdaptor(service.get());
TestCommonPropertyChanges(service, adaptor);
TestAutoConnectPropertyChange(service, adaptor);
EXPECT_CALL(*adaptor,
EmitRpcIdentifierChanged(kDeviceProperty, _));
SetWiFi(service, wifi());
Mock::VerifyAndClearExpectations(adaptor);
EXPECT_CALL(*adaptor,
EmitRpcIdentifierChanged(kDeviceProperty, _));
service->ResetWiFi();
Mock::VerifyAndClearExpectations(adaptor);
}
// Custom property setters should return false, and make no changes, if
// the new value is the same as the old value.
TEST_F(WiFiServiceTest, CustomSetterNoopChange) {
WiFiServiceRefPtr service = MakeServiceWithMockManager();
TestCustomSetterNoopChange(service, mock_manager());
}
TEST_F(WiFiServiceTest, SuspectedCredentialFailure) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityWpa);
EXPECT_FALSE(service->has_ever_connected());
EXPECT_EQ(0, service->suspected_credential_failures_);
EXPECT_TRUE(service->AddSuspectedCredentialFailure());
EXPECT_EQ(0, service->suspected_credential_failures_);
service->has_ever_connected_ = true;
for (int i = 0; i < WiFiService::kSuspectedCredentialFailureThreshold - 1;
++i) {
EXPECT_FALSE(service->AddSuspectedCredentialFailure());
EXPECT_EQ(i + 1, service->suspected_credential_failures_);
}
EXPECT_TRUE(service->AddSuspectedCredentialFailure());
// Make sure the failure state does not reset just because we ask again.
EXPECT_TRUE(service->AddSuspectedCredentialFailure());
// Make sure the failure state resets because of a credential change.
// A credential change changes the has_ever_connected to false and
// immediately returns true when attempting to add the failure.
Error error;
service->SetPassphrase("Panchromatic Resonance", &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_TRUE(service->AddSuspectedCredentialFailure());
EXPECT_EQ(0, service->suspected_credential_failures_);
// Make sure that we still return true after resetting the failure
// count.
service->suspected_credential_failures_ = 3;
EXPECT_EQ(3, service->suspected_credential_failures_);
service->ResetSuspectedCredentialFailures();
EXPECT_EQ(0, service->suspected_credential_failures_);
EXPECT_TRUE(service->AddSuspectedCredentialFailure());
}
TEST_F(WiFiServiceTest, GetTethering) {
WiFiServiceRefPtr service = MakeSimpleService(kSecurityNone);
EXPECT_EQ(kTetheringNotDetectedState, service->GetTethering(nullptr));
// Since the device isn't connected, we shouldn't even query the WiFi device.
EXPECT_CALL(*wifi(), IsConnectedViaTether()).Times(0);
SetWiFiForService(service, wifi());
EXPECT_EQ(kTetheringNotDetectedState, service->GetTethering(nullptr));
Mock::VerifyAndClearExpectations(wifi().get());
scoped_refptr<MockProfile> mock_profile(
new NiceMock<MockProfile>(control_interface(), metrics(), manager()));
service->set_profile(mock_profile);
service->SetState(Service::kStateConnected);
// A connected service should return "confirmed" iff the underlying device
// reports it is tethered.
EXPECT_CALL(*wifi(), IsConnectedViaTether())
.WillOnce(Return(true))
.WillOnce(Return(false));
EXPECT_EQ(kTetheringConfirmedState, service->GetTethering(nullptr));
EXPECT_EQ(kTetheringNotDetectedState, service->GetTethering(nullptr));
Mock::VerifyAndClearExpectations(wifi().get());
// Add two endpoints that have a BSSID associated with some Android devices
// in tethering mode.
WiFiEndpointRefPtr endpoint_android1 =
MakeOpenEndpoint("a", "02:1a:11:00:00:01", 2412, 0);
service->AddEndpoint(endpoint_android1);
WiFiEndpointRefPtr endpoint_android2 =
MakeOpenEndpoint("a", "02:1a:11:00:00:02", 2412, 0);
service->AddEndpoint(endpoint_android2);
// Since there are two endpoints, we should not detect tethering mode.
EXPECT_CALL(*wifi(), IsConnectedViaTether()).WillOnce(Return(false));
EXPECT_EQ(kTetheringNotDetectedState, service->GetTethering(nullptr));
// If the device reports that it is tethered, this should override any
// findings gained from examining the endpoints.
EXPECT_CALL(*wifi(), IsConnectedViaTether()).WillOnce(Return(true));
EXPECT_EQ(kTetheringConfirmedState, service->GetTethering(nullptr));
// Continue in the un-tethered device case for a few more tests below.
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_CALL(*wifi(), IsConnectedViaTether())
.WillRepeatedly(Return(false));
// Removing an endpoint so we only have one should put us in the "Suspected"
// state.
service->RemoveEndpoint(endpoint_android1);
EXPECT_EQ(kTetheringSuspectedState, service->GetTethering(nullptr));
// Add a different endpoint which has a locally administered MAC address
// but not one used by Android.
service->RemoveEndpoint(endpoint_android2);
WiFiEndpointRefPtr endpoint_ios =
MakeOpenEndpoint("a", "02:00:00:00:00:01", 2412, 0);
service->AddEndpoint(endpoint_ios);
EXPECT_EQ(kTetheringNotDetectedState, service->GetTethering(nullptr));
// If this endpoint reports the right vendor OUI, we should suspect
// it to be tethered. However since this evaluation normally only
// happens in the endpoint constructor, we must force it to recalculate.
endpoint_ios->vendor_information_.oui_set.insert(Tethering::kIosOui);
endpoint_ios->CheckForTetheringSignature();
EXPECT_EQ(kTetheringSuspectedState, service->GetTethering(nullptr));
// If the device reports that it is tethered, this should override any
// findings gained from examining the endpoints.
Mock::VerifyAndClearExpectations(wifi().get());
EXPECT_CALL(*wifi(), IsConnectedViaTether()).WillOnce(Return(true));
EXPECT_EQ(kTetheringConfirmedState, service->GetTethering(nullptr));
}
TEST_F(WiFiServiceTest, IsVisible) {
WiFiServiceRefPtr wifi_service = MakeServiceWithWiFi(kSecurityNone);
ServiceMockAdaptor* adaptor = GetAdaptor(wifi_service.get());
// Adding the first endpoint emits a change: Visible = true.
EXPECT_CALL(*adaptor, EmitBoolChanged(kVisibleProperty, true));
WiFiEndpointRefPtr endpoint =
MakeOpenEndpoint("a", "00:00:00:00:00:01", 0, 0);
wifi_service->AddEndpoint(endpoint);
EXPECT_TRUE(wifi_service->IsVisible());
Mock::VerifyAndClearExpectations(adaptor);
// Removing the last endpoint emits a change: Visible = false.
EXPECT_CALL(*adaptor, EmitBoolChanged(kVisibleProperty, false));
wifi_service->RemoveEndpoint(endpoint);
EXPECT_FALSE(wifi_service->IsVisible());
Mock::VerifyAndClearExpectations(adaptor);
// Entering the a connecting state emits a change: Visible = true
// although the service has no endpoints.
EXPECT_CALL(*adaptor, EmitBoolChanged(kVisibleProperty, true));
wifi_service->SetState(Service::kStateAssociating);
EXPECT_TRUE(wifi_service->IsVisible());
Mock::VerifyAndClearExpectations(adaptor);
// Moving between connecting / connected states does not trigger an Emit.
EXPECT_CALL(*adaptor, EmitBoolChanged(kVisibleProperty, _)).Times(0);
wifi_service->SetState(Service::kStateConfiguring);
EXPECT_TRUE(wifi_service->IsVisible());
Mock::VerifyAndClearExpectations(adaptor);
// Entering the Idle state emits a change: Visible = false.
EXPECT_CALL(*adaptor, EmitBoolChanged(kVisibleProperty, false));
wifi_service->SetState(Service::kStateIdle);
EXPECT_FALSE(wifi_service->IsVisible());
Mock::VerifyAndClearExpectations(adaptor);
}
TEST_F(WiFiServiceTest, ConfigurePreferredDevice) {
const string kDeviceName = "test_device";
WiFiServiceRefPtr service = MakeGenericService();
KeyValueStore args;
args.SetString(kWifiPreferredDeviceProperty, kDeviceName);
// With no wifi device.
Error error;
service->Configure(args, &error);
EXPECT_EQ(Error::kSuccess, error.type());
EXPECT_EQ(kDeviceName, service->preferred_device_);
// With non-preferred wifi device.
SetWiFiForService(service, wifi());
service->Configure(args, &error);
EXPECT_EQ(Error::kSuccess, error.type());
EXPECT_EQ(nullptr, service->wifi_);
EXPECT_EQ(kDeviceName, service->preferred_device_);
// With preferred wifi device.
scoped_refptr<MockWiFi> preferred_wifi = MakeSimpleWiFi(kDeviceName);
SetWiFiForService(service, preferred_wifi);
service->Configure(args, &error);
EXPECT_EQ(Error::kSuccess, error.type());
EXPECT_EQ(preferred_wifi, service->wifi_);
EXPECT_EQ(kDeviceName, service->preferred_device_);
}
TEST_F(WiFiServiceTest, LoadAndUnloadPreferredDevice) {
WiFiServiceRefPtr service = MakeGenericService();
NiceMock<MockStore> mock_store;
const string kStorageId = service->GetStorageIdentifier();
EXPECT_CALL(mock_store, ContainsGroup(StrEq(kStorageId)))
.WillRepeatedly(Return(true));
set<string> groups;
groups.insert(kStorageId);
EXPECT_CALL(mock_store, GetGroupsWithProperties(
ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityWep)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, GetBool(_, _, _))
.WillRepeatedly(Return(false));
const string kDeviceName = "test_device";
EXPECT_CALL(mock_store,
GetString(StrEq(kStorageId),
WiFiService::kStoragePreferredDevice, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(kDeviceName), Return(true)));
EXPECT_CALL(mock_store,
GetString(StrEq(kStorageId),
StrNe(WiFiService::kStoragePreferredDevice), _))
.WillRepeatedly(Return(false));
// With no wifi device.
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(kDeviceName, service->preferred_device_);
service->Unload();
EXPECT_EQ("", service->preferred_device_);
// With non-preferred wifi device.
SetWiFiForService(service, wifi());
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(nullptr, service->wifi_);
EXPECT_EQ(kDeviceName, service->preferred_device_);
service->Unload();
EXPECT_EQ("", service->preferred_device_);
// With preferred wifi device.
scoped_refptr<MockWiFi> preferred_wifi = MakeSimpleWiFi(kDeviceName);
SetWiFiForService(service, preferred_wifi);
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(preferred_wifi, service->wifi_);
EXPECT_EQ(kDeviceName, service->preferred_device_);
service->Unload();
EXPECT_EQ("", service->preferred_device_);
}
TEST_F(WiFiServiceTest, ChooseDevice) {
const string kDeviceName1 = "test_device1";
const string kDeviceName2 = "test_device2";
scoped_refptr<MockWiFi> wifi1 = MakeSimpleWiFi(kDeviceName1);
scoped_refptr<MockWiFi> wifi2 = MakeSimpleWiFi(kDeviceName2);
WiFiServiceRefPtr service = MakeServiceWithMockManager();
// No preferred device.
EXPECT_CALL(*mock_manager(), GetEnabledDeviceByLinkName(_)).Times(0);
EXPECT_CALL(*mock_manager(),
GetEnabledDeviceWithTechnology(Technology::kWifi))
.WillOnce(Return(wifi1));
EXPECT_EQ(wifi1, service->ChooseDevice());
Mock::VerifyAndClearExpectations(mock_manager());
// With preferred device.
service->SetPreferredDevice(kDeviceName2, nullptr);
EXPECT_CALL(*mock_manager(), GetEnabledDeviceByLinkName(kDeviceName2))
.WillOnce(Return(wifi2));
EXPECT_CALL(*mock_manager(), GetEnabledDeviceWithTechnology(_)).Times(0);
EXPECT_EQ(wifi2, service->ChooseDevice());
Mock::VerifyAndClearExpectations(mock_manager());
}
TEST_F(WiFiServiceTest, RoamThresholdProperty) {
WiFiServiceRefPtr service = MakeGenericService();
static const uint16_t kRoamThreshold16 = 16;
static const uint16_t kRoamThreshold32 = 32;
EXPECT_TRUE(SetRoamThreshold(service, kRoamThreshold16));
EXPECT_EQ(GetRoamThreshold(service), kRoamThreshold16);
// Try a different number
EXPECT_TRUE(SetRoamThreshold(service, kRoamThreshold32));
EXPECT_EQ(GetRoamThreshold(service), kRoamThreshold32);
}
TEST_F(WiFiServiceTest, SaveLoadRoamThreshold) {
WiFiServiceRefPtr service = MakeGenericService();
NiceMock<MockStore> mock_store;
const uint16_t kRoamThreshold = 10;
const string kStorageId = service->GetStorageIdentifier();
EXPECT_CALL(mock_store, ContainsGroup(StrEq(kStorageId)))
.WillRepeatedly(Return(true));
set<string> groups;
groups.insert(kStorageId);
EXPECT_CALL(mock_store, GetGroupsWithProperties(ContainsWiFiProperties(
simple_ssid(), kModeManaged, kSecurityWep)))
.WillRepeatedly(Return(groups));
EXPECT_CALL(mock_store, GetBool(_, _, _)).Times(AnyNumber());
EXPECT_CALL(mock_store, SetBool(_, _, _)).Times(AnyNumber());
// First, save these values.
service->roam_threshold_db_ = kRoamThreshold;
service->roam_threshold_db_set_ = true;
EXPECT_CALL(mock_store,
SetUint64(StrEq(kStorageId), WiFiService::kStorageRoamThreshold,
kRoamThreshold));
EXPECT_CALL(mock_store, SetBool(StrEq(kStorageId),
WiFiService::kStorageRoamThresholdSet, true));
EXPECT_TRUE(service->Save(&mock_store));
// Then, load these values into the WiFiService members.
service->roam_threshold_db_ = 0;
service->roam_threshold_db_set_ = false;
EXPECT_CALL(mock_store, GetUint64(StrEq(kStorageId),
WiFiService::kStorageRoamThreshold, _))
.WillOnce(DoAll(SetArgPointee<2>(kRoamThreshold), Return(true)));
EXPECT_CALL(mock_store, GetBool(StrEq(kStorageId),
WiFiService::kStorageRoamThresholdSet, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_TRUE(service->Load(&mock_store));
EXPECT_EQ(kRoamThreshold, service->roam_threshold_db_);
EXPECT_TRUE(service->roam_threshold_db_set_);
}
} // namespace shill