blob: c63e5055a4cecd534cd7db9590d6a449c5c13d37 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/vpn_provider.h"
#include <chromeos/dbus/service_constants.h>
#include <gtest/gtest.h>
#include "shill/error.h"
#include "shill/nice_mock_control.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_device_info.h"
#include "shill/mock_manager.h"
#include "shill/mock_metrics.h"
#include "shill/mock_profile.h"
#include "shill/mock_store.h"
#include "shill/mock_vpn_driver.h"
#include "shill/mock_vpn_service.h"
using std::string;
using testing::_;
using testing::DoAll;
using testing::NiceMock;
using testing::Return;
using testing::SetArgumentPointee;
namespace shill {
class VPNProviderTest : public testing::Test {
public:
VPNProviderTest()
: metrics_(NULL),
manager_(&control_, NULL, &metrics_, NULL),
device_info_(&control_, NULL, &metrics_, &manager_),
provider_(&control_, NULL, &metrics_, &manager_) {}
virtual ~VPNProviderTest() {}
protected:
static const char kHost[];
static const char kName[];
string GetServiceFriendlyName(const ServiceRefPtr &service) {
return service->friendly_name();
}
void SetConnectState(const ServiceRefPtr &service,
Service::ConnectState state) {
service->state_ = state;
}
void AddService(const VPNServiceRefPtr &service) {
provider_.services_.push_back(service);
}
VPNServiceRefPtr GetServiceAt(int idx) {
return provider_.services_[idx];
}
size_t GetServiceCount() const {
return provider_.services_.size();
}
NiceMockControl control_;
MockMetrics metrics_;
MockManager manager_;
MockDeviceInfo device_info_;
VPNProvider provider_;
};
const char VPNProviderTest::kHost[] = "10.8.0.1";
const char VPNProviderTest::kName[] = "vpn-name";
TEST_F(VPNProviderTest, GetServiceNoType) {
KeyValueStore args;
Error e;
args.SetString(kTypeProperty, kTypeVPN);
ServiceRefPtr service = provider_.GetService(args, &e);
EXPECT_EQ(Error::kNotSupported, e.type());
EXPECT_FALSE(service);
}
TEST_F(VPNProviderTest, GetServiceUnsupportedType) {
KeyValueStore args;
Error e;
args.SetString(kTypeProperty, kTypeVPN);
args.SetString(kProviderTypeProperty, "unknown-vpn-type");
args.SetString(kProviderHostProperty, kHost);
args.SetString(kNameProperty, kName);
ServiceRefPtr service = provider_.GetService(args, &e);
EXPECT_EQ(Error::kNotSupported, e.type());
EXPECT_FALSE(service);
}
TEST_F(VPNProviderTest, GetService) {
KeyValueStore args;
args.SetString(kTypeProperty, kTypeVPN);
args.SetString(kProviderTypeProperty, kProviderOpenVpn);
args.SetString(kProviderHostProperty, kHost);
args.SetString(kNameProperty, kName);
{
Error error;
ServiceRefPtr service = provider_.FindSimilarService(args, &error);
EXPECT_EQ(Error::kNotFound, error.type());
EXPECT_EQ(NULL, service.get());
}
EXPECT_EQ(0, GetServiceCount());
ServiceRefPtr service;
{
Error error;
EXPECT_CALL(manager_, device_info()).WillOnce(Return(&device_info_));
EXPECT_CALL(manager_, RegisterService(_));
service = provider_.GetService(args, &error);
EXPECT_TRUE(error.IsSuccess());
ASSERT_TRUE(service);
testing::Mock::VerifyAndClearExpectations(&manager_);
}
EXPECT_EQ("vpn_10_8_0_1_vpn_name", service->GetStorageIdentifier());
EXPECT_EQ(kName, GetServiceFriendlyName(service));
EXPECT_EQ(1, GetServiceCount());
// Configure the service to set its properties (including Provider.Host).
{
Error error;
service->Configure(args, &error);
EXPECT_TRUE(error.IsSuccess());
}
// None of the calls below should cause a new service to be registered.
EXPECT_CALL(manager_, RegisterService(_)).Times(0);
// A second call should return the same service.
{
Error error;
ServiceRefPtr get_service = provider_.GetService(args, &error);
EXPECT_TRUE(error.IsSuccess());
ASSERT_EQ(service, get_service);
}
EXPECT_EQ(1, GetServiceCount());
// FindSimilarService should also return this service.
{
Error error;
ServiceRefPtr similar_service = provider_.FindSimilarService(args, &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_EQ(service, similar_service);
}
EXPECT_EQ(1, GetServiceCount());
// However, CreateTemporaryService should create a different service.
{
Error error;
ServiceRefPtr temporary_service =
provider_.CreateTemporaryService(args, &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_NE(service, temporary_service);
// However this service will not be part of the provider.
EXPECT_EQ(1, GetServiceCount());
}
}
TEST_F(VPNProviderTest, OnDeviceInfoAvailable) {
const string kInterfaceName("tun0");
const int kInterfaceIndex = 1;
scoped_ptr<MockVPNDriver> bad_driver(new MockVPNDriver());
EXPECT_CALL(*bad_driver.get(), ClaimInterface(_, _))
.Times(2)
.WillRepeatedly(Return(false));
provider_.services_.push_back(
new VPNService(&control_, NULL, &metrics_, NULL, bad_driver.release()));
EXPECT_FALSE(provider_.OnDeviceInfoAvailable(kInterfaceName,
kInterfaceIndex));
scoped_ptr<MockVPNDriver> good_driver(new MockVPNDriver());
EXPECT_CALL(*good_driver.get(), ClaimInterface(_, _))
.WillOnce(Return(true));
provider_.services_.push_back(
new VPNService(&control_, NULL, &metrics_, NULL, good_driver.release()));
scoped_ptr<MockVPNDriver> dup_driver(new MockVPNDriver());
EXPECT_CALL(*dup_driver.get(), ClaimInterface(_, _))
.Times(0);
provider_.services_.push_back(
new VPNService(&control_, NULL, &metrics_, NULL, dup_driver.release()));
EXPECT_TRUE(provider_.OnDeviceInfoAvailable(kInterfaceName, kInterfaceIndex));
provider_.services_.clear();
}
TEST_F(VPNProviderTest, RemoveService) {
scoped_refptr<MockVPNService> service0(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
scoped_refptr<MockVPNService> service1(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
scoped_refptr<MockVPNService> service2(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
provider_.services_.push_back(service0.get());
provider_.services_.push_back(service1.get());
provider_.services_.push_back(service2.get());
ASSERT_EQ(3, provider_.services_.size());
provider_.RemoveService(service1);
EXPECT_EQ(2, provider_.services_.size());
EXPECT_EQ(service0, provider_.services_[0]);
EXPECT_EQ(service2, provider_.services_[1]);
provider_.RemoveService(service2);
EXPECT_EQ(1, provider_.services_.size());
EXPECT_EQ(service0, provider_.services_[0]);
provider_.RemoveService(service0);
EXPECT_EQ(0, provider_.services_.size());
}
MATCHER_P(ServiceWithStorageId, storage_id, "") {
return arg->GetStorageIdentifier() == storage_id;
}
TEST_F(VPNProviderTest, CreateServicesFromProfile) {
scoped_refptr<MockProfile> profile(
new NiceMock<MockProfile>(&control_, &metrics_, &manager_, ""));
NiceMock<MockStore> storage;
EXPECT_CALL(*profile, GetConstStorage()).WillRepeatedly(Return(&storage));
EXPECT_CALL(storage, GetString(_, _, _)).WillRepeatedly(Return(false));
std::set<string> groups;
const string kNonVPNIdentifier("foo_1");
groups.insert(kNonVPNIdentifier);
const string kVPNIdentifierNoProvider("vpn_no_provider");
groups.insert(kVPNIdentifierNoProvider);
const string kVPNIdentifierNoName("vpn_no_name");
groups.insert(kVPNIdentifierNoName);
const string kOpenVPNProvider(kProviderOpenVpn);
EXPECT_CALL(storage,
GetString(kVPNIdentifierNoName, kProviderTypeProperty, _))
.WillRepeatedly(
DoAll(SetArgumentPointee<2>(kOpenVPNProvider), Return(true)));
const string kVPNIdentifierNoHost("vpn_no_host");
groups.insert(kVPNIdentifierNoHost);
EXPECT_CALL(storage,
GetString(kVPNIdentifierNoHost, kProviderTypeProperty, _))
.WillRepeatedly(
DoAll(SetArgumentPointee<2>(kOpenVPNProvider), Return(true)));
const string kName("name");
EXPECT_CALL(storage, GetString(kVPNIdentifierNoHost, kNameProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kName), Return(true)));
const string kVPNIdentifierValid("vpn_valid");
groups.insert(kVPNIdentifierValid);
EXPECT_CALL(storage, GetString(kVPNIdentifierValid, kProviderTypeProperty, _))
.WillRepeatedly(
DoAll(SetArgumentPointee<2>(kOpenVPNProvider), Return(true)));
EXPECT_CALL(storage, GetString(kVPNIdentifierValid, kNameProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kName), Return(true)));
const string kHost("1.2.3.4");
EXPECT_CALL(storage, GetString(kVPNIdentifierValid, kProviderHostProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kHost), Return(true)));
EXPECT_CALL(storage, GetGroupsWithKey(kProviderTypeProperty))
.WillRepeatedly(Return(groups));
EXPECT_CALL(manager_, device_info())
.WillRepeatedly(Return(reinterpret_cast<DeviceInfo *>(NULL)));
EXPECT_CALL(manager_,
RegisterService(ServiceWithStorageId(kVPNIdentifierValid)));
EXPECT_CALL(*profile,
ConfigureService(ServiceWithStorageId(kVPNIdentifierValid)))
.WillOnce(Return(true));
provider_.CreateServicesFromProfile(profile);
GetServiceAt(0)->driver()->args()->SetString(kProviderHostProperty, kHost);
// Calling this again should not create any more services (checked by the
// Times(1) above).
provider_.CreateServicesFromProfile(profile);
}
TEST_F(VPNProviderTest, CreateService) {
static const char kName[] = "test-vpn-service";
static const char kStorageID[] = "test_vpn_storage_id";
static const char *kTypes[] = {
kProviderOpenVpn,
kProviderL2tpIpsec,
};
const size_t kTypesCount = arraysize(kTypes);
EXPECT_CALL(manager_, device_info())
.Times(kTypesCount)
.WillRepeatedly(Return(&device_info_));
EXPECT_CALL(manager_, RegisterService(_)).Times(kTypesCount);
for (size_t i = 0; i < kTypesCount; i++) {
Error error;
VPNServiceRefPtr service =
provider_.CreateService(kTypes[i], kName, kStorageID, &error);
ASSERT_TRUE(service) << kTypes[i];
ASSERT_TRUE(service->driver()) << kTypes[i];
EXPECT_EQ(kTypes[i], service->driver()->GetProviderType());
EXPECT_EQ(kName, GetServiceFriendlyName(service)) << kTypes[i];
EXPECT_EQ(kStorageID, service->GetStorageIdentifier()) << kTypes[i];
EXPECT_TRUE(error.IsSuccess()) << kTypes[i];
}
Error error;
VPNServiceRefPtr unknown_service =
provider_.CreateService("unknown-vpn-type", kName, kStorageID, &error);
EXPECT_FALSE(unknown_service);
EXPECT_EQ(Error::kNotSupported, error.type());
}
TEST_F(VPNProviderTest, HasActiveService) {
EXPECT_FALSE(provider_.HasActiveService());
scoped_refptr<MockVPNService> service0(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
scoped_refptr<MockVPNService> service1(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
scoped_refptr<MockVPNService> service2(
new MockVPNService(&control_, NULL, &metrics_, NULL, NULL));
AddService(service0);
AddService(service1);
AddService(service2);
EXPECT_FALSE(provider_.HasActiveService());
SetConnectState(service1, Service::kStateAssociating);
EXPECT_TRUE(provider_.HasActiveService());
SetConnectState(service1, Service::kStateOnline);
EXPECT_TRUE(provider_.HasActiveService());
}
} // namespace shill