2288 lines
92 KiB
C++
2288 lines
92 KiB
C++
//
|
|
// 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 <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <base/strings/stringprintf.h>
|
|
#include <base/strings/string_number_conversions.h>
|
|
#include <base/strings/string_util.h>
|
|
#if defined(__ANDROID__)
|
|
#include <dbus/service_constants.h>
|
|
#else
|
|
#include <chromeos/dbus/service_constants.h>
|
|
#endif // __ANDROID__
|
|
#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/property_store_unittest.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_wifi.h"
|
|
#include "shill/wifi/mock_wifi_provider.h"
|
|
#include "shill/wifi/wifi_endpoint.h"
|
|
|
|
using base::FilePath;
|
|
using std::map;
|
|
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::SetArgumentPointee;
|
|
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)),
|
|
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);
|
|
}
|
|
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_;
|
|
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 (uint i = 0; i < id.length(); ++i) {
|
|
EXPECT_TRUE(id[i] == '_' ||
|
|
isxdigit(id[i]) ||
|
|
(isalpha(id[i]) && islower(id[i])));
|
|
}
|
|
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, 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(SetArgumentPointee<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(SetArgumentPointee<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(SetArgumentPointee<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(SetArgumentPointee<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(&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(SetArgumentPointee<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(SetArgumentPointee<2>(kRoamThreshold), Return(true)));
|
|
EXPECT_CALL(mock_store, GetBool(StrEq(kStorageId),
|
|
WiFiService::kStorageRoamThresholdSet, _))
|
|
.WillOnce(DoAll(SetArgumentPointee<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
|