blob: d3b76b9ab57e58d91a52e05d75215946d999fb7f [file] [log] [blame]
//
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "shill/vpn/l2tp_ipsec_driver.h"
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/memory/weak_ptr.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <gtest/gtest.h>
#include <vpn-manager/service_error.h>
#include "shill/ipconfig.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_certificate_file.h"
#include "shill/mock_device_info.h"
#include "shill/mock_external_task.h"
#include "shill/mock_manager.h"
#include "shill/mock_metrics.h"
#include "shill/mock_ppp_device.h"
#include "shill/mock_ppp_device_factory.h"
#include "shill/mock_process_manager.h"
#include "shill/nice_mock_control.h"
#include "shill/test_event_dispatcher.h"
#include "shill/vpn/mock_vpn_provider.h"
#include "shill/vpn/mock_vpn_service.h"
using base::FilePath;
using std::find;
using std::map;
using std::string;
using std::vector;
using testing::_;
using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
namespace shill {
class L2TPIPSecDriverTest : public testing::Test,
public RPCTaskDelegate {
public:
L2TPIPSecDriverTest()
: device_info_(&control_, &dispatcher_, &metrics_, &manager_),
metrics_(&dispatcher_),
manager_(&control_, &dispatcher_, &metrics_),
driver_(new L2TPIPSecDriver(&control_, &dispatcher_, &metrics_,
&manager_, &device_info_,
&process_manager_)),
service_(new MockVPNService(&control_, &dispatcher_, &metrics_,
&manager_, driver_)),
device_(new MockPPPDevice(&control_, &dispatcher_, &metrics_, &manager_,
kInterfaceName, kInterfaceIndex)),
certificate_file_(new MockCertificateFile()),
weak_ptr_factory_(this) {
driver_->certificate_file_.reset(certificate_file_); // Passes ownership.
}
virtual ~L2TPIPSecDriverTest() {}
void SetUp() override {
manager_.vpn_provider_ = std::make_unique<MockVPNProvider>();
manager_.vpn_provider_->allowed_uids_.push_back(1000);
manager_.UpdateProviderMapping();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
void TearDown() override {
driver_->device_ = nullptr;
driver_->service_ = nullptr;
ASSERT_TRUE(temp_dir_.Delete());
// The ExternalTask instance initially held by |driver_->external_task_|
// could be scheduled to be destroyed after |driver_| is destroyed. To
// avoid leaking any ExternalTask instance when the test finishes, we
// explicitly destroy |service_| here, which indirectly destroys |driver_|
// and in turn schedules the destruction of |driver_->external_task_| in
// the message loop. Then we run until the message loop becomes idle to
// exercise the destruction task of ExternalTask.
service_ = nullptr;
dispatcher_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
dispatcher_.DispatchForever();
}
protected:
static const char kInterfaceName[];
static const int kInterfaceIndex;
void SetArg(const string& arg, const string& value) {
driver_->args()->SetString(arg, value);
}
void SetArgArray(const string& arg, const vector<string>& value) {
driver_->args()->SetStrings(arg, value);
}
KeyValueStore* GetArgs() {
return driver_->args();
}
string GetProviderType() {
return driver_->GetProviderType();
}
void SetDevice(const PPPDeviceRefPtr& device) {
driver_->device_ = device;
}
void SetService(const VPNServiceRefPtr& service) {
driver_->service_ = service;
}
VPNServiceRefPtr GetService() {
return driver_->service_;
}
void OnConnectTimeout() {
driver_->OnConnectTimeout();
}
void StartConnectTimeout(int timeout_seconds) {
driver_->StartConnectTimeout(timeout_seconds);
}
bool IsConnectTimeoutStarted() const {
return driver_->IsConnectTimeoutStarted();
}
bool IsPSKFileCleared(const FilePath& psk_file_path) const {
return !base::PathExists(psk_file_path) && GetPSKFile().empty();
}
bool IsXauthCredentialsFileCleared(
const FilePath& xauth_credentials_file_path) const {
return !base::PathExists(xauth_credentials_file_path) &&
GetXauthCredentialsFile().empty();
}
// Used to assert that a flag appears in the options.
void ExpectInFlags(const vector<string>& options, const string& flag,
const string& value);
FilePath SetupPSKFile();
FilePath SetupXauthCredentialsFile();
FilePath GetPSKFile() const { return driver_->psk_file_; }
FilePath GetXauthCredentialsFile() const {
return driver_->xauth_credentials_file_;
}
void InvokeNotify(const string& reason, const map<string, string>& dict) {
driver_->Notify(reason, dict);
}
void FakeUpConnect(FilePath* psk_file, FilePath* xauth_credentials_file) {
*psk_file = SetupPSKFile();
*xauth_credentials_file = SetupXauthCredentialsFile();
SetService(service_);
StartConnectTimeout(0);
}
void ExpectDeviceConnected(const map<string, string>& ppp_config) {
EXPECT_CALL(*device_, SetEnabled(true));
EXPECT_CALL(*device_, SelectService(static_cast<ServiceRefPtr>(service_)));
EXPECT_CALL(*device_, UpdateIPConfig(_));
}
void ExpectMetricsReported() {
Error unused_error;
PropertyStore store;
driver_->InitPropertyStore(&store);
store.SetStringProperty(kL2tpIpsecPskProperty, "x", &unused_error);
store.SetStringProperty(kL2tpIpsecPasswordProperty, "y", &unused_error);
EXPECT_CALL(metrics_, SendEnumToUMA(
Metrics::kMetricVpnDriver,
Metrics::kVpnDriverL2tpIpsec,
Metrics::kMetricVpnDriverMax));
EXPECT_CALL(metrics_, SendEnumToUMA(
Metrics::kMetricVpnRemoteAuthenticationType,
Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
Metrics::kVpnRemoteAuthenticationTypeMax));
EXPECT_CALL(metrics_, SendEnumToUMA(
Metrics::kMetricVpnUserAuthenticationType,
Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
Metrics::kVpnUserAuthenticationTypeMax));
}
// Inherited from RPCTaskDelegate.
void GetLogin(string* user, string* password) override;
void Notify(const string& reason, const map<string, string>& dict) override;
base::ScopedTempDir temp_dir_;
NiceMockControl control_;
NiceMock<MockDeviceInfo> device_info_;
EventDispatcherForTest dispatcher_;
MockMetrics metrics_;
MockProcessManager process_manager_;
MockManager manager_;
L2TPIPSecDriver* driver_; // Owned by |service_|.
scoped_refptr<MockVPNService> service_;
scoped_refptr<MockPPPDevice> device_;
MockCertificateFile* certificate_file_; // Owned by |driver_|.
base::WeakPtrFactory<L2TPIPSecDriverTest> weak_ptr_factory_;
};
const char L2TPIPSecDriverTest::kInterfaceName[] = "ppp0";
const int L2TPIPSecDriverTest::kInterfaceIndex = 123;
void L2TPIPSecDriverTest::GetLogin(string* /*user*/, string* /*password*/) {}
void L2TPIPSecDriverTest::Notify(
const string& /*reason*/, const map<string, string>& /*dict*/) {}
void L2TPIPSecDriverTest::ExpectInFlags(
const vector<string>& options, const string& flag, const string& value) {
string flagValue = base::StringPrintf("%s=%s", flag.c_str(), value.c_str());
vector<string>::const_iterator it =
find(options.begin(), options.end(), flagValue);
EXPECT_TRUE(it != options.end());
}
FilePath L2TPIPSecDriverTest::SetupPSKFile() {
FilePath psk_file;
EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &psk_file));
EXPECT_FALSE(psk_file.empty());
EXPECT_TRUE(base::PathExists(psk_file));
driver_->psk_file_ = psk_file;
return psk_file;
}
FilePath L2TPIPSecDriverTest::SetupXauthCredentialsFile() {
FilePath xauth_credentials_file;
EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(),
&xauth_credentials_file));
EXPECT_FALSE(xauth_credentials_file.empty());
EXPECT_TRUE(base::PathExists(xauth_credentials_file));
driver_->xauth_credentials_file_ = xauth_credentials_file;
return xauth_credentials_file;
}
TEST_F(L2TPIPSecDriverTest, GetProviderType) {
EXPECT_EQ(kProviderL2tpIpsec, GetProviderType());
}
TEST_F(L2TPIPSecDriverTest, Cleanup) {
driver_->IdleService(); // Ensure no crash.
FilePath psk_file;
FilePath xauth_credentials_file;
FakeUpConnect(&psk_file, &xauth_credentials_file);
driver_->device_ = device_;
driver_->external_task_.reset(
new MockExternalTask(&control_,
&process_manager_,
weak_ptr_factory_.GetWeakPtr(),
base::Callback<void(pid_t, int)>()));
EXPECT_CALL(*device_, DropConnection());
EXPECT_CALL(*device_, SetEnabled(false));
EXPECT_CALL(*service_, SetFailure(Service::kFailureBadPassphrase));
driver_->FailService(Service::kFailureBadPassphrase); // Trigger Cleanup.
EXPECT_TRUE(IsPSKFileCleared(psk_file));
EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
EXPECT_FALSE(driver_->device_);
EXPECT_FALSE(driver_->service_);
EXPECT_FALSE(driver_->IsConnectTimeoutStarted());
EXPECT_FALSE(driver_->external_task_);
driver_->service_ = service_;
EXPECT_CALL(*service_, SetState(Service::kStateIdle));
driver_->IdleService();
EXPECT_FALSE(driver_->service_);
}
TEST_F(L2TPIPSecDriverTest, DeleteTemporaryFiles) {
FilePath psk_file = SetupPSKFile();
FilePath xauth_credentials_file = SetupXauthCredentialsFile();
driver_->DeleteTemporaryFiles();
EXPECT_TRUE(IsPSKFileCleared(psk_file));
EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
}
TEST_F(L2TPIPSecDriverTest, InitOptionsNoHost) {
Error error;
vector<string> options;
EXPECT_FALSE(driver_->InitOptions(&options, &error));
EXPECT_EQ(Error::kInvalidArguments, error.type());
EXPECT_TRUE(options.empty());
}
TEST_F(L2TPIPSecDriverTest, InitOptions) {
static const char kHost[] = "192.168.2.254";
static const char kPSK[] = "foobar";
static const char kXauthUser[] = "silly";
static const char kXauthPassword[] = "rabbit";
const vector<string> kCaCertPEM{ "Insert PEM encoded data here" };
static const char kPEMCertfile[] = "/tmp/der-file-from-pem-cert";
FilePath pem_cert(kPEMCertfile);
SetArg(kProviderHostProperty, kHost);
SetArg(kL2tpIpsecPskProperty, kPSK);
SetArg(kL2tpIpsecXauthUserProperty, kXauthUser);
SetArg(kL2tpIpsecXauthPasswordProperty, kXauthPassword);
SetArgArray(kL2tpIpsecCaCertPemProperty, kCaCertPEM);
EXPECT_CALL(*certificate_file_, CreatePEMFromStrings(kCaCertPEM))
.WillOnce(Return(pem_cert));
const FilePath temp_dir(temp_dir_.GetPath());
// Once each for PSK and Xauth options.
EXPECT_CALL(manager_, run_path())
.WillOnce(ReturnRef(temp_dir))
.WillOnce(ReturnRef(temp_dir));
Error error;
vector<string> options;
EXPECT_TRUE(driver_->InitOptions(&options, &error));
EXPECT_TRUE(error.IsSuccess());
ExpectInFlags(options, "--remote_host", kHost);
ASSERT_FALSE(driver_->psk_file_.empty());
ExpectInFlags(options, "--psk_file", driver_->psk_file_.value());
ASSERT_FALSE(driver_->xauth_credentials_file_.empty());
ExpectInFlags(options, "--xauth_credentials_file",
driver_->xauth_credentials_file_.value());
ExpectInFlags(options, "--server_ca_file", kPEMCertfile);
}
TEST_F(L2TPIPSecDriverTest, InitPSKOptions) {
Error error;
vector<string> options;
static const char kPSK[] = "foobar";
const FilePath bad_dir("/non/existent/directory");
const FilePath temp_dir(temp_dir_.GetPath());
EXPECT_CALL(manager_, run_path())
.WillOnce(ReturnRef(bad_dir))
.WillOnce(ReturnRef(temp_dir));
EXPECT_TRUE(driver_->InitPSKOptions(&options, &error));
EXPECT_TRUE(options.empty());
EXPECT_TRUE(error.IsSuccess());
SetArg(kL2tpIpsecPskProperty, kPSK);
EXPECT_FALSE(driver_->InitPSKOptions(&options, &error));
EXPECT_TRUE(options.empty());
EXPECT_EQ(Error::kInternalError, error.type());
error.Reset();
EXPECT_TRUE(driver_->InitPSKOptions(&options, &error));
ASSERT_FALSE(driver_->psk_file_.empty());
ExpectInFlags(options, "--psk_file", driver_->psk_file_.value());
EXPECT_TRUE(error.IsSuccess());
string contents;
EXPECT_TRUE(base::ReadFileToString(driver_->psk_file_, &contents));
EXPECT_EQ(kPSK, contents);
struct stat buf;
ASSERT_EQ(0, stat(driver_->psk_file_.value().c_str(), &buf));
EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, buf.st_mode);
}
TEST_F(L2TPIPSecDriverTest, InitPEMOptions) {
const vector<string> kCaCertPEM{ "Insert PEM encoded data here" };
static const char kPEMCertfile[] = "/tmp/der-file-from-pem-cert";
FilePath empty_cert;
FilePath pem_cert(kPEMCertfile);
SetArgArray(kL2tpIpsecCaCertPemProperty, kCaCertPEM);
EXPECT_CALL(*certificate_file_, CreatePEMFromStrings(kCaCertPEM))
.WillOnce(Return(empty_cert))
.WillOnce(Return(pem_cert));
vector<string> options;
driver_->InitPEMOptions(&options);
EXPECT_TRUE(options.empty());
driver_->InitPEMOptions(&options);
ExpectInFlags(options, "--server_ca_file", kPEMCertfile);
}
TEST_F(L2TPIPSecDriverTest, InitXauthOptions) {
vector<string> options;
EXPECT_CALL(manager_, run_path()).Times(0);
{
Error error;
EXPECT_TRUE(driver_->InitXauthOptions(&options, &error));
EXPECT_TRUE(error.IsSuccess());
}
EXPECT_TRUE(options.empty());
static const char kUser[] = "foobar";
SetArg(kL2tpIpsecXauthUserProperty, kUser);
{
Error error;
EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
EXPECT_EQ(Error::kInvalidArguments, error.type());
}
EXPECT_TRUE(options.empty());
static const char kPassword[] = "foobar";
SetArg(kL2tpIpsecXauthUserProperty, "");
SetArg(kL2tpIpsecXauthPasswordProperty, kPassword);
{
Error error;
EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
EXPECT_EQ(Error::kInvalidArguments, error.type());
}
EXPECT_TRUE(options.empty());
Mock::VerifyAndClearExpectations(&manager_);
SetArg(kL2tpIpsecXauthUserProperty, kUser);
const FilePath bad_dir("/non/existent/directory");
const FilePath temp_dir(temp_dir_.GetPath());
EXPECT_CALL(manager_, run_path())
.WillOnce(ReturnRef(bad_dir))
.WillOnce(ReturnRef(temp_dir));
{
Error error;
EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
EXPECT_EQ(Error::kInternalError, error.type());
}
EXPECT_TRUE(options.empty());
{
Error error;
EXPECT_TRUE(driver_->InitXauthOptions(&options, &error));
EXPECT_TRUE(error.IsSuccess());
}
ASSERT_FALSE(driver_->xauth_credentials_file_.empty());
ExpectInFlags(options, "--xauth_credentials_file",
driver_->xauth_credentials_file_.value());
string contents;
EXPECT_TRUE(
base::ReadFileToString(driver_->xauth_credentials_file_, &contents));
string expected_contents(string(kUser) + "\n" + kPassword + "\n");
EXPECT_EQ(expected_contents, contents);
struct stat buf;
ASSERT_EQ(0, stat(driver_->xauth_credentials_file_.value().c_str(), &buf));
EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, buf.st_mode);
}
TEST_F(L2TPIPSecDriverTest, AppendValueOption) {
static const char kOption[] = "--l2tpipsec-option";
static const char kProperty[] = "L2TPIPSec.SomeProperty";
static const char kValue[] = "some-property-value";
static const char kOption2[] = "--l2tpipsec-option2";
static const char kProperty2[] = "L2TPIPSec.SomeProperty2";
static const char kValue2[] = "some-property-value2";
vector<string> options;
EXPECT_FALSE(
driver_->AppendValueOption(
"L2TPIPSec.UnknownProperty", kOption, &options));
EXPECT_TRUE(options.empty());
SetArg(kProperty, "");
EXPECT_FALSE(driver_->AppendValueOption(kProperty, kOption, &options));
EXPECT_TRUE(options.empty());
SetArg(kProperty, kValue);
SetArg(kProperty2, kValue2);
EXPECT_TRUE(driver_->AppendValueOption(kProperty, kOption, &options));
EXPECT_TRUE(driver_->AppendValueOption(kProperty2, kOption2, &options));
EXPECT_EQ(2, options.size());
EXPECT_EQ(base::StringPrintf("%s=%s", kOption, kValue), options[0]);
EXPECT_EQ(base::StringPrintf("%s=%s", kOption2, kValue2), options[1]);
}
TEST_F(L2TPIPSecDriverTest, AppendFlag) {
static const char kTrueOption[] = "--l2tpipsec-option";
static const char kFalseOption[] = "--nol2tpipsec-option";
static const char kProperty[] = "L2TPIPSec.SomeProperty";
static const char kTrueOption2[] = "--l2tpipsec-option2";
static const char kFalseOption2[] = "--nol2tpipsec-option2";
static const char kProperty2[] = "L2TPIPSec.SomeProperty2";
vector<string> options;
EXPECT_FALSE(driver_->AppendFlag("L2TPIPSec.UnknownProperty",
kTrueOption, kFalseOption, &options));
EXPECT_TRUE(options.empty());
SetArg(kProperty, "");
EXPECT_FALSE(
driver_->AppendFlag(kProperty, kTrueOption, kFalseOption, &options));
EXPECT_TRUE(options.empty());
SetArg(kProperty, "true");
SetArg(kProperty2, "false");
EXPECT_TRUE(
driver_->AppendFlag(kProperty, kTrueOption, kFalseOption, &options));
EXPECT_TRUE(
driver_->AppendFlag(kProperty2, kTrueOption2, kFalseOption2, &options));
EXPECT_EQ(2, options.size());
EXPECT_EQ(kTrueOption, options[0]);
EXPECT_EQ(kFalseOption2, options[1]);
}
TEST_F(L2TPIPSecDriverTest, GetLogin) {
static const char kUser[] = "joesmith";
static const char kPassword[] = "random-password";
string user, password;
SetArg(kL2tpIpsecUserProperty, kUser);
driver_->GetLogin(&user, &password);
EXPECT_TRUE(user.empty());
EXPECT_TRUE(password.empty());
SetArg(kL2tpIpsecUserProperty, "");
SetArg(kL2tpIpsecPasswordProperty, kPassword);
driver_->GetLogin(&user, &password);
EXPECT_TRUE(user.empty());
EXPECT_TRUE(password.empty());
SetArg(kL2tpIpsecUserProperty, kUser);
driver_->GetLogin(&user, &password);
EXPECT_EQ(kUser, user);
EXPECT_EQ(kPassword, password);
}
TEST_F(L2TPIPSecDriverTest, OnL2TPIPSecVPNDied) {
const int kPID = 123456;
driver_->service_ = service_;
EXPECT_CALL(*service_, SetFailure(Service::kFailureDNSLookup));
driver_->OnL2TPIPSecVPNDied(
kPID, vpn_manager::kServiceErrorResolveHostnameFailed << 8);
EXPECT_FALSE(driver_->service_);
}
TEST_F(L2TPIPSecDriverTest, SpawnL2TPIPSecVPN) {
Error error;
// Fail without sufficient arguments.
EXPECT_FALSE(driver_->SpawnL2TPIPSecVPN(&error));
EXPECT_TRUE(error.IsFailure());
// Provide the required arguments.
static const char kHost[] = "192.168.2.254";
SetArg(kProviderHostProperty, kHost);
// TODO(quiche): Instead of setting expectations based on what
// ExternalTask will call, mock out ExternalTask. Non-trivial,
// though, because ExternalTask is constructed during the
// call to driver_->Connect.
EXPECT_CALL(process_manager_, StartProcess(_, _, _, _, _, _))
.WillOnce(Return(-1))
.WillOnce(Return(1));
EXPECT_FALSE(driver_->SpawnL2TPIPSecVPN(&error));
EXPECT_FALSE(driver_->external_task_);
EXPECT_TRUE(driver_->SpawnL2TPIPSecVPN(&error));
EXPECT_NE(nullptr, driver_->external_task_);
}
TEST_F(L2TPIPSecDriverTest, Connect) {
EXPECT_CALL(*service_, SetState(Service::kStateConfiguring));
static const char kHost[] = "192.168.2.254";
SetArg(kProviderHostProperty, kHost);
// TODO(quiche): Instead of setting expectations based on what
// ExternalTask will call, mock out ExternalTask. Non-trivial,
// though, because ExternalTask is constructed during the
// call to driver_->Connect.
EXPECT_CALL(process_manager_, StartProcess(_, _, _, _, _, _))
.WillOnce(Return(1));
Error error;
driver_->Connect(service_, &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_TRUE(driver_->IsConnectTimeoutStarted());
}
TEST_F(L2TPIPSecDriverTest, Disconnect) {
driver_->device_ = device_;
driver_->service_ = service_;
EXPECT_CALL(*device_, DropConnection());
EXPECT_CALL(*device_, SetEnabled(false));
EXPECT_CALL(*service_, SetState(Service::kStateIdle));
driver_->Disconnect();
EXPECT_FALSE(driver_->device_);
EXPECT_FALSE(driver_->service_);
}
TEST_F(L2TPIPSecDriverTest, OnConnectionDisconnected) {
driver_->service_ = service_;
EXPECT_CALL(*service_, SetState(Service::kStateIdle));
driver_->OnConnectionDisconnected();
EXPECT_FALSE(driver_->service_);
}
TEST_F(L2TPIPSecDriverTest, OnConnectTimeout) {
StartConnectTimeout(0);
SetService(service_);
EXPECT_CALL(*service_, SetFailure(Service::kFailureConnect));
OnConnectTimeout();
EXPECT_FALSE(GetService());
EXPECT_FALSE(IsConnectTimeoutStarted());
}
TEST_F(L2TPIPSecDriverTest, InitPropertyStore) {
// Sanity test property store initialization.
PropertyStore store;
driver_->InitPropertyStore(&store);
const string kUser = "joe";
Error error;
EXPECT_TRUE(store.SetStringProperty(kL2tpIpsecUserProperty, kUser, &error));
EXPECT_TRUE(error.IsSuccess());
EXPECT_EQ(kUser, GetArgs()->LookupString(kL2tpIpsecUserProperty, ""));
}
TEST_F(L2TPIPSecDriverTest, GetProvider) {
PropertyStore store;
driver_->InitPropertyStore(&store);
{
KeyValueStore props;
Error error;
SetArg(kL2tpIpsecClientCertIdProperty, "");
EXPECT_TRUE(
store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
EXPECT_TRUE(props.LookupBool(kPassphraseRequiredProperty, false));
EXPECT_TRUE(props.LookupBool(kL2tpIpsecPskRequiredProperty, false));
}
{
KeyValueStore props;
Error error;
SetArg(kL2tpIpsecClientCertIdProperty, "some-cert-id");
EXPECT_TRUE(
store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
EXPECT_TRUE(props.LookupBool(kPassphraseRequiredProperty, false));
EXPECT_FALSE(props.LookupBool(kL2tpIpsecPskRequiredProperty, true));
SetArg(kL2tpIpsecClientCertIdProperty, "");
}
{
KeyValueStore props;
SetArg(kL2tpIpsecPasswordProperty, "random-password");
SetArg(kL2tpIpsecPskProperty, "random-psk");
Error error;
EXPECT_TRUE(
store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
EXPECT_FALSE(props.LookupBool(kPassphraseRequiredProperty, true));
EXPECT_FALSE(
props.LookupBool(kL2tpIpsecPskRequiredProperty, true));
EXPECT_FALSE(props.ContainsString(kL2tpIpsecPasswordProperty));
}
}
TEST_F(L2TPIPSecDriverTest, Notify) {
map<string, string> config{{kPPPInterfaceName, kInterfaceName}};
MockPPPDeviceFactory* mock_ppp_device_factory =
MockPPPDeviceFactory::GetInstance();
FilePath psk_file;
FilePath xauth_credentials_file;
FakeUpConnect(&psk_file, &xauth_credentials_file);
driver_->ppp_device_factory_ = mock_ppp_device_factory;
EXPECT_CALL(device_info_, GetIndex(kInterfaceName))
.WillOnce(Return(kInterfaceIndex));
EXPECT_CALL(*mock_ppp_device_factory,
CreatePPPDevice(_, _, _, _, kInterfaceName, kInterfaceIndex))
.WillOnce(Return(device_.get()));
// Make sure that a notification of an intermediate state doesn't cause
// the driver to fail the connection.
ASSERT_TRUE(driver_->service_.get());
VPNServiceConstRefPtr service = driver_->service_;
InvokeNotify(kPPPReasonAuthenticating, config);
InvokeNotify(kPPPReasonAuthenticated, config);
EXPECT_TRUE(driver_->service_.get());
EXPECT_FALSE(service->IsFailed());
ExpectDeviceConnected(config);
ExpectMetricsReported();
InvokeNotify(kPPPReasonConnect, config);
EXPECT_TRUE(IsPSKFileCleared(psk_file));
EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
EXPECT_FALSE(IsConnectTimeoutStarted());
}
TEST_F(L2TPIPSecDriverTest, NotifyWithExistingDevice) {
map<string, string> config{{kPPPInterfaceName, kInterfaceName}};
MockPPPDeviceFactory* mock_ppp_device_factory =
MockPPPDeviceFactory::GetInstance();
FilePath psk_file;
FilePath xauth_credentials_file;
FakeUpConnect(&psk_file, &xauth_credentials_file);
driver_->ppp_device_factory_ = mock_ppp_device_factory;
SetDevice(device_);
EXPECT_CALL(device_info_, GetIndex(kInterfaceName))
.WillOnce(Return(kInterfaceIndex));
EXPECT_CALL(*mock_ppp_device_factory,
CreatePPPDevice(_, _, _, _, _, _)).Times(0);
ExpectDeviceConnected(config);
ExpectMetricsReported();
InvokeNotify(kPPPReasonConnect, config);
EXPECT_TRUE(IsPSKFileCleared(psk_file));
EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
EXPECT_FALSE(IsConnectTimeoutStarted());
}
TEST_F(L2TPIPSecDriverTest, NotifyDisconnected) {
map<string, string> dict;
base::Callback<void(pid_t, int)> death_callback;
MockExternalTask* local_external_task =
new MockExternalTask(&control_, &process_manager_,
weak_ptr_factory_.GetWeakPtr(),
death_callback);
driver_->device_ = device_;
driver_->external_task_.reset(local_external_task); // passes ownership
EXPECT_CALL(*device_, DropConnection());
EXPECT_CALL(*device_, SetEnabled(false));
EXPECT_CALL(*local_external_task, OnDelete())
.Times(0); // Not until event loop.
driver_->Notify(kPPPReasonDisconnect, dict);
EXPECT_FALSE(driver_->device_);
EXPECT_FALSE(driver_->external_task_.get());
Mock::VerifyAndClearExpectations(local_external_task);
EXPECT_CALL(*local_external_task, OnDelete());
dispatcher_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
dispatcher_.DispatchForever();
}
} // namespace shill