blob: aa23a2fa32a123498b0d1461cf857e5a6e7b0092 [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];
}
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(flimflam::kTypeProperty, flimflam::kTypeVPN);
VPNServiceRefPtr service = provider_.GetService(args, &e);
EXPECT_EQ(Error::kNotSupported, e.type());
EXPECT_FALSE(service);
}
TEST_F(VPNProviderTest, GetServiceUnsupportedType) {
KeyValueStore args;
Error e;
args.SetString(flimflam::kTypeProperty, flimflam::kTypeVPN);
args.SetString(flimflam::kProviderTypeProperty, "unknown-vpn-type");
args.SetString(flimflam::kProviderHostProperty, kHost);
args.SetString(flimflam::kNameProperty, kName);
VPNServiceRefPtr service = provider_.GetService(args, &e);
EXPECT_EQ(Error::kNotSupported, e.type());
EXPECT_FALSE(service);
}
TEST_F(VPNProviderTest, GetService) {
KeyValueStore args;
Error e;
args.SetString(flimflam::kTypeProperty, flimflam::kTypeVPN);
args.SetString(flimflam::kProviderTypeProperty, flimflam::kProviderOpenVpn);
args.SetString(flimflam::kProviderHostProperty, kHost);
args.SetString(flimflam::kNameProperty, kName);
EXPECT_CALL(manager_, device_info()).WillOnce(Return(&device_info_));
EXPECT_CALL(manager_, RegisterService(_));
VPNServiceRefPtr service0 = provider_.GetService(args, &e);
EXPECT_TRUE(e.IsSuccess());
ASSERT_TRUE(service0);
EXPECT_EQ("vpn_10_8_0_1_vpn_name", service0->GetStorageIdentifier());
EXPECT_EQ(kName, GetServiceFriendlyName(service0));
// Configure the service to set its properties (including Provider.Host).
service0->Configure(args, &e);
EXPECT_TRUE(e.IsSuccess());
// A second call should return the same service.
VPNServiceRefPtr service1 = provider_.GetService(args, &e);
EXPECT_TRUE(e.IsSuccess());
ASSERT_EQ(service0.get(), service1.get());
}
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(flimflam::kProviderOpenVpn);
EXPECT_CALL(storage, GetString(kVPNIdentifierNoName,
flimflam::kProviderTypeProperty,
_))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kOpenVPNProvider),
Return(true)));
const string kVPNIdentifierNoHost("vpn_no_host");
groups.insert(kVPNIdentifierNoHost);
EXPECT_CALL(storage, GetString(kVPNIdentifierNoHost,
flimflam::kProviderTypeProperty,
_))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kOpenVPNProvider),
Return(true)));
const string kName("name");
EXPECT_CALL(storage, GetString(kVPNIdentifierNoHost,
flimflam::kNameProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kName), Return(true)));
const string kVPNIdentifierValid("vpn_valid");
groups.insert(kVPNIdentifierValid);
EXPECT_CALL(storage, GetString(kVPNIdentifierValid,
flimflam::kProviderTypeProperty,
_))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kOpenVPNProvider),
Return(true)));
EXPECT_CALL(storage, GetString(kVPNIdentifierValid,
flimflam::kNameProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kName), Return(true)));
const string kHost("1.2.3.4");
EXPECT_CALL(storage, GetString(kVPNIdentifierValid,
flimflam::kProviderHostProperty, _))
.WillRepeatedly(DoAll(SetArgumentPointee<2>(kHost), Return(true)));
EXPECT_CALL(storage, GetGroupsWithKey(flimflam::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(flimflam::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[] = {
flimflam::kProviderOpenVpn,
flimflam::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