blob: 428d2659d6f03d1bdce3d97a4e6d3ca994583cf6 [file] [log] [blame]
// Copyright 2015 The Chromium 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 <stddef.h>
#include <stdint.h>
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_shill_profile_client.h"
#include "chromeos/dbus/fake_shill_service_client.h"
#include "chromeos/dbus/fake_shill_third_party_vpn_driver_client.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_profile_handler.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/api/vpn_provider/vpn_provider_api.h"
#include "extensions/browser/api/vpn_provider/vpn_service.h"
#include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
#include "extensions/browser/api_test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/test/result_catcher.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using testing::_;
using testing::Invoke;
namespace chromeos {
namespace {
namespace api_vpn = extensions::api::vpn_provider;
const char kNetworkProfilePath[] = "/network/test";
const char kTestConfig[] = "testconfig";
const char* kParameterValues[] = {"10.10.10.10",
"24",
"63.145.213.129/32 63.145.212.0/24",
"0.0.0.0/0 63.145.212.128/25",
"8.8.8.8",
"1600",
"10.10.10.255",
"foo:bar"};
const char* kParameterKeys[] = {shill::kAddressParameterThirdPartyVpn,
shill::kSubnetPrefixParameterThirdPartyVpn,
shill::kExclusionListParameterThirdPartyVpn,
shill::kInclusionListParameterThirdPartyVpn,
shill::kDnsServersParameterThirdPartyVpn,
shill::kMtuParameterThirdPartyVpn,
shill::kBroadcastAddressParameterThirdPartyVpn,
shill::kDomainSearchParameterThirdPartyVpn};
void DoNothingFailureCallback(
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
EXPECT_EQ(true, false);
}
void DoNothingSuccessCallback(const std::string& service_path,
const std::string& guid) {}
} // namespace
// Records the number of calls and their parameters. Always replies successfully
// to calls.
class TestShillThirdPartyVpnDriverClient
: public FakeShillThirdPartyVpnDriverClient {
public:
void SetParameters(
const std::string& object_path_value,
const base::DictionaryValue& parameters,
const ShillClientHelper::StringCallback& callback,
const ShillClientHelper::ErrorCallback& error_callback) override {
set_parameters_counter_++;
parameters_ = parameters.DeepCopy();
FakeShillThirdPartyVpnDriverClient::SetParameters(
object_path_value, parameters, callback, error_callback);
}
void UpdateConnectionState(
const std::string& object_path_value,
const uint32_t connection_state,
const base::Closure& callback,
const ShillClientHelper::ErrorCallback& error_callback) override {
update_connection_state_counter_++;
connection_state_ = connection_state;
FakeShillThirdPartyVpnDriverClient::UpdateConnectionState(
object_path_value, connection_state, callback, error_callback);
}
void SendPacket(
const std::string& object_path_value,
const std::vector<char>& ip_packet,
const base::Closure& callback,
const ShillClientHelper::ErrorCallback& error_callback) override {
send_packet_counter_++;
ip_packet_ = ip_packet;
FakeShillThirdPartyVpnDriverClient::SendPacket(object_path_value, ip_packet,
callback, error_callback);
}
int set_parameters_counter_ = 0;
base::DictionaryValue* parameters_ = nullptr;
int update_connection_state_counter_ = 0;
uint32_t connection_state_;
int send_packet_counter_ = 0;
std::vector<char> ip_packet_;
};
class VpnProviderApiTest : public extensions::ExtensionApiTest {
public:
VpnProviderApiTest() {}
~VpnProviderApiTest() override {}
void SetUpInProcessBrowserTestFixture() override {
extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
test_client_ = new TestShillThirdPartyVpnDriverClient();
DBusThreadManager::GetSetterForTesting()->SetShillThirdPartyVpnDriverClient(
base::WrapUnique(test_client_));
}
void AddNetworkProfileForUser() {
static_cast<FakeShillProfileClient*>(
DBusThreadManager::Get()->GetShillProfileClient())
->AddProfile(
kNetworkProfilePath,
chromeos::ProfileHelper::GetUserIdHashFromProfile(profile()));
content::RunAllPendingInMessageLoop();
}
void LoadVpnExtension() {
extension_ = LoadExtension(test_data_dir_.AppendASCII("vpn_provider"));
extension_id_ = extension_->id();
service_ = VpnServiceFactory::GetForBrowserContext(profile());
content::RunAllPendingInMessageLoop();
}
bool RunExtensionTest(const std::string& test_name) {
GURL url = extension_->GetResourceURL("basic.html?#" + test_name);
return RunExtensionSubtest("vpn_provider", url.spec());
}
std::string GetKey(const std::string& config_name) {
return service_->GetKey(extension_id_, config_name);
}
bool DoesConfigExist(const std::string& config_name) {
return service_->VerifyConfigExistsForTesting(extension_id_, config_name);
}
bool IsConfigConnected() {
return service_->VerifyConfigIsConnectedForTesting(extension_id_);
}
std::string GetSingleServicePath() {
std::string service_path = service_->GetSingleServicepathForTesting();
EXPECT_FALSE(service_path.empty());
return service_path;
}
bool CreateConfigForTest(const std::string& name) {
scoped_refptr<extensions::VpnProviderCreateConfigFunction> create(
new extensions::VpnProviderCreateConfigFunction());
create->set_extension(GetSingleLoadedExtension());
return extensions::api_test_utils::RunFunction(
create.get(), "[\"" + name + "\"]", profile());
}
bool DestroyConfigForTest(const std::string& name) {
scoped_refptr<extensions::VpnProviderDestroyConfigFunction> destroy(
new extensions::VpnProviderDestroyConfigFunction());
destroy->set_extension(GetSingleLoadedExtension());
return extensions::api_test_utils::RunFunction(
destroy.get(), "[\"" + name + "\"]", profile());
}
void TriggerInternalRemove() {
NetworkHandler::Get()->network_configuration_handler()->RemoveConfiguration(
GetSingleServicePath(), base::DoNothing(),
base::Bind(DoNothingFailureCallback));
}
protected:
TestShillThirdPartyVpnDriverClient* test_client_ = nullptr;
VpnService* service_ = nullptr;
std::string extension_id_;
std::string service_path_;
const extensions::Extension* extension_ = nullptr;
};
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, ComboSuite) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("comboSuite"));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CreateConfigWithoutNetworkProfile) {
LoadVpnExtension();
EXPECT_TRUE(RunExtensionTest("createConfigWithoutNetworkProfile"));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CreateConfig) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("createConfigSuccess"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, DestroyConfig) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(CreateConfigForTest(kTestConfig));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
EXPECT_TRUE(RunExtensionTest("destroyConfigSuccess"));
EXPECT_FALSE(DoesConfigExist(kTestConfig));
EXPECT_FALSE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, DestroyConnectedConfig) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(CreateConfigForTest(kTestConfig));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
EXPECT_FALSE(IsConfigConnected());
const std::string object_path = shill::kObjectPathBase + GetKey(kTestConfig);
test_client_->OnPlatformMessage(object_path,
api_vpn::PLATFORM_MESSAGE_CONNECTED);
EXPECT_TRUE(IsConfigConnected());
EXPECT_TRUE(RunExtensionTest("destroyConnectedConfigSetup"));
EXPECT_TRUE(DestroyConfigForTest(kTestConfig));
EXPECT_FALSE(DoesConfigExist(kTestConfig));
EXPECT_FALSE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
extensions::ResultCatcher catcher;
ASSERT_TRUE(catcher.GetNextResult());
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, VpnSuccess) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("createConfigConnectAndDisconnect"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
EXPECT_FALSE(IsConfigConnected());
const std::string object_path = shill::kObjectPathBase + GetKey(kTestConfig);
extensions::ResultCatcher catcher;
EXPECT_EQ(0, test_client_->set_parameters_counter_);
EXPECT_EQ(0, test_client_->update_connection_state_counter_);
EXPECT_EQ(0, test_client_->send_packet_counter_);
test_client_->OnPlatformMessage(object_path,
api_vpn::PLATFORM_MESSAGE_CONNECTED);
EXPECT_TRUE(IsConfigConnected());
ASSERT_TRUE(catcher.GetNextResult());
EXPECT_EQ(1, test_client_->set_parameters_counter_);
EXPECT_EQ(1, test_client_->update_connection_state_counter_);
EXPECT_EQ(1, test_client_->send_packet_counter_);
EXPECT_EQ(api_vpn::VPN_CONNECTION_STATE_CONNECTED,
test_client_->update_connection_state_counter_);
for (size_t i = 0; i < base::size(kParameterValues); ++i) {
std::string value;
EXPECT_TRUE(
test_client_->parameters_->GetString(kParameterKeys[i], &value));
EXPECT_EQ(kParameterValues[i], value);
}
const char kPacket[] = "feebdaed";
std::vector<char> packet(&kPacket[0], &kPacket[8]);
EXPECT_EQ(packet, test_client_->ip_packet_);
packet.assign(test_client_->ip_packet_.rbegin(),
test_client_->ip_packet_.rend());
test_client_->OnPacketReceived(object_path, packet);
ASSERT_TRUE(catcher.GetNextResult());
test_client_->OnPlatformMessage(object_path,
api_vpn::PLATFORM_MESSAGE_DISCONNECTED);
ASSERT_TRUE(catcher.GetNextResult());
EXPECT_FALSE(IsConfigConnected());
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, ConfigInternalRemove) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("configInternalRemove"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
extensions::ResultCatcher catcher;
TriggerInternalRemove();
ASSERT_TRUE(catcher.GetNextResult());
EXPECT_FALSE(DoesConfigExist(kTestConfig));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CheckEvents) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("expectEvents"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
extensions::ResultCatcher catcher;
service_->SendPlatformError(extension_id_, kTestConfig, "error_message");
service_->SendShowAddDialogToExtension(extension_id_);
service_->SendShowConfigureDialogToExtension(extension_id_, kTestConfig);
EXPECT_TRUE(catcher.GetNextResult());
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, ConfigPersistence) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_FALSE(DoesConfigExist(kTestConfig));
base::DictionaryValue properties;
properties.SetKey(shill::kTypeProperty, base::Value(shill::kTypeVPN));
properties.SetKey(shill::kNameProperty, base::Value(kTestConfig));
properties.SetKey(shill::kProviderHostProperty, base::Value(extension_id_));
properties.SetKey(shill::kObjectPathSuffixProperty,
base::Value(GetKey(kTestConfig)));
properties.SetKey(shill::kProviderTypeProperty,
base::Value(shill::kProviderThirdPartyVpn));
properties.SetKey(shill::kProfileProperty, base::Value(kNetworkProfilePath));
NetworkHandler::Get()
->network_configuration_handler()
->CreateShillConfiguration(properties,
base::Bind(DoNothingSuccessCallback),
base::Bind(DoNothingFailureCallback));
content::RunAllPendingInMessageLoop();
EXPECT_TRUE(DoesConfigExist(kTestConfig));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CreateUninstall) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("createConfigSuccess"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
UninstallExtension(extension_id_);
content::RunAllPendingInMessageLoop();
EXPECT_FALSE(DoesConfigExist(kTestConfig));
EXPECT_FALSE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CreateDisable) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("createConfigSuccess"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
extensions::ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile())->extension_service();
extension_service->DisableExtension(
extension_id_, extensions::disable_reason::DISABLE_USER_ACTION);
content::RunAllPendingInMessageLoop();
EXPECT_FALSE(DoesConfigExist(kTestConfig));
EXPECT_FALSE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
}
IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, CreateBlacklist) {
LoadVpnExtension();
AddNetworkProfileForUser();
EXPECT_TRUE(RunExtensionTest("createConfigSuccess"));
EXPECT_TRUE(DoesConfigExist(kTestConfig));
const std::string service_path = GetSingleServicePath();
std::string profile_path;
base::DictionaryValue properties;
EXPECT_TRUE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
extensions::ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile())->extension_service();
extension_service->BlacklistExtensionForTest(extension_id_);
content::RunAllPendingInMessageLoop();
EXPECT_FALSE(DoesConfigExist(kTestConfig));
EXPECT_FALSE(DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface()
->GetService(service_path, &profile_path, &properties));
}
} // namespace chromeos