blob: 548118654ad0214d8103e5e4c71ccfe9a62928c8 [file] [log] [blame]
// Copyright 2017 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 "chromeos/components/tether/wifi_hotspot_disconnector_impl.h"
#include <memory>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_task_environment.h"
#include "chromeos/components/tether/fake_network_configuration_remover.h"
#include "chromeos/components/tether/pref_names.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_state_test.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace chromeos {
namespace tether {
namespace {
const char kSuccessResult[] = "success";
const char kWifiNetworkGuid[] = "wifiNetworkGuid";
std::string CreateConnectedWifiConfigurationJsonString(
const std::string& wifi_network_guid) {
std::stringstream ss;
ss << "{"
<< " \"GUID\": \"" << wifi_network_guid << "\","
<< " \"Type\": \"" << shill::kTypeWifi << "\","
<< " \"State\": \"" << shill::kStateOnline << "\""
<< "}";
return ss.str();
}
class TestNetworkConnectionHandler : public NetworkConnectionHandler {
public:
explicit TestNetworkConnectionHandler(base::Closure disconnect_callback)
: disconnect_callback_(disconnect_callback) {}
~TestNetworkConnectionHandler() override = default;
std::string last_disconnect_service_path() {
return last_disconnect_service_path_;
}
base::Closure last_disconnect_success_callback() {
return last_disconnect_success_callback_;
}
network_handler::ErrorCallback last_disconnect_error_callback() {
return last_disconnect_error_callback_;
}
// NetworkConnectionHandler:
void DisconnectNetwork(
const std::string& service_path,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback) override {
last_disconnect_service_path_ = service_path;
last_disconnect_success_callback_ = success_callback;
last_disconnect_error_callback_ = error_callback;
disconnect_callback_.Run();
}
void ConnectToNetwork(const std::string& service_path,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback,
bool check_error_state,
ConnectCallbackMode mode) override {}
bool HasConnectingNetwork(const std::string& service_path) override {
return false;
}
bool HasPendingConnectRequest() override { return false; }
void Init(NetworkStateHandler* network_state_handler,
NetworkConfigurationHandler* network_configuration_handler,
ManagedNetworkConfigurationHandler*
managed_network_configuration_handler) override {}
private:
base::Closure disconnect_callback_;
std::string last_disconnect_service_path_;
base::Closure last_disconnect_success_callback_;
network_handler::ErrorCallback last_disconnect_error_callback_;
};
} // namespace
class WifiHotspotDisconnectorImplTest : public NetworkStateTest {
public:
WifiHotspotDisconnectorImplTest() = default;
~WifiHotspotDisconnectorImplTest() override = default;
void SetUp() override {
DBusThreadManager::Initialize();
NetworkStateTest::SetUp();
should_disconnect_successfully_ = true;
test_network_connection_handler_ =
base::WrapUnique(new TestNetworkConnectionHandler(
base::Bind(&WifiHotspotDisconnectorImplTest::
OnNetworkConnectionManagerDisconnect,
base::Unretained(this))));
fake_configuration_remover_ =
std::make_unique<FakeNetworkConfigurationRemover>();
test_pref_service_ =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
WifiHotspotDisconnectorImpl::RegisterPrefs(test_pref_service_->registry());
wifi_hotspot_disconnector_ = std::make_unique<WifiHotspotDisconnectorImpl>(
test_network_connection_handler_.get(), network_state_handler(),
test_pref_service_.get(), fake_configuration_remover_.get());
}
void TearDown() override {
wifi_hotspot_disconnector_.reset();
ShutdownNetworkState();
NetworkStateTest::TearDown();
DBusThreadManager::Shutdown();
}
void SimulateConnectionToWifiNetwork() {
wifi_service_path_ = ConfigureService(
CreateConnectedWifiConfigurationJsonString(kWifiNetworkGuid));
EXPECT_FALSE(wifi_service_path_.empty());
}
void SetWifiNetworkToDisconnected() {
EXPECT_FALSE(wifi_service_path_.empty());
SetServiceProperty(wifi_service_path_, shill::kStateProperty,
base::Value(shill::kStateIdle));
}
void SuccessCallback() { disconnection_result_ = kSuccessResult; }
void ErrorCallback(const std::string& error_name) {
disconnection_result_ = error_name;
}
void CallDisconnect(const std::string& wifi_network_guid) {
wifi_hotspot_disconnector_->DisconnectFromWifiHotspot(
wifi_network_guid,
base::Bind(&WifiHotspotDisconnectorImplTest::SuccessCallback,
base::Unretained(this)),
base::Bind(&WifiHotspotDisconnectorImplTest::ErrorCallback,
base::Unretained(this)));
}
void OnNetworkConnectionManagerDisconnect() {
EXPECT_EQ(wifi_service_path_,
test_network_connection_handler_->last_disconnect_service_path());
if (should_disconnect_successfully_) {
SetWifiNetworkToDisconnected();
}
// Before the callbacks are invoked, the network configuration should not
// yet have been cleared, and the disconnecting GUID should still be in
// prefs.
EXPECT_TRUE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
EXPECT_FALSE(GetDisconnectingWifiPathFromPrefs().empty());
if (should_disconnect_successfully_) {
EXPECT_FALSE(
test_network_connection_handler_->last_disconnect_success_callback()
.is_null());
test_network_connection_handler_->last_disconnect_success_callback()
.Run();
} else {
EXPECT_FALSE(
test_network_connection_handler_->last_disconnect_error_callback()
.is_null());
network_handler::RunErrorCallback(
test_network_connection_handler_->last_disconnect_error_callback(),
wifi_service_path_, NetworkConnectionHandler::kErrorDisconnectFailed,
std::string() /* error_detail */);
}
// Now that the callbacks have been invoked, both the network
// configuration and the disconnecting GUID should have cleared.
EXPECT_FALSE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
EXPECT_TRUE(GetDisconnectingWifiPathFromPrefs().empty());
}
std::string GetResultAndReset() {
std::string result;
result.swap(disconnection_result_);
return result;
}
std::string GetDisconnectingWifiPathFromPrefs() {
return test_pref_service_->GetString(prefs::kDisconnectingWifiNetworkPath);
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<TestNetworkConnectionHandler>
test_network_connection_handler_;
std::unique_ptr<FakeNetworkConfigurationRemover> fake_configuration_remover_;
std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
test_pref_service_;
std::string wifi_service_path_;
std::string disconnection_result_;
bool should_disconnect_successfully_;
std::unique_ptr<WifiHotspotDisconnectorImpl> wifi_hotspot_disconnector_;
private:
DISALLOW_COPY_AND_ASSIGN(WifiHotspotDisconnectorImplTest);
};
TEST_F(WifiHotspotDisconnectorImplTest, NetworkDoesNotExist) {
CallDisconnect("nonexistentWifiGuid");
EXPECT_EQ(NetworkConnectionHandler::kErrorNotFound, GetResultAndReset());
// Configuration should not have been removed.
EXPECT_TRUE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
}
TEST_F(WifiHotspotDisconnectorImplTest, NetworkNotActuallyConnected) {
// Start with the network disconnected.
SimulateConnectionToWifiNetwork();
SetWifiNetworkToDisconnected();
CallDisconnect(wifi_service_path_);
EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset());
// Configuration should not have been removed.
EXPECT_TRUE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
}
TEST_F(WifiHotspotDisconnectorImplTest, WifiDisconnectionFails) {
SimulateConnectionToWifiNetwork();
should_disconnect_successfully_ = false;
CallDisconnect(wifi_service_path_);
EXPECT_EQ(NetworkConnectionHandler::kErrorDisconnectFailed,
GetResultAndReset());
// The Wi-Fi network should still be connected since disconnection failed.
EXPECT_EQ(
shill::kStateOnline,
GetServiceStringProperty(wifi_service_path_, shill::kStateProperty));
// Configuration should have been removed despite the failure.
EXPECT_FALSE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
}
TEST_F(WifiHotspotDisconnectorImplTest, WifiDisconnectionSucceeds) {
SimulateConnectionToWifiNetwork();
CallDisconnect(wifi_service_path_);
EXPECT_EQ(kSuccessResult, GetResultAndReset());
// The Wi-Fi network should be disconnected.
EXPECT_EQ(shill::kStateIdle, GetServiceStringProperty(wifi_service_path_,
shill::kStateProperty));
// Configuration should have been removed.
EXPECT_FALSE(
fake_configuration_remover_->last_removed_wifi_network_path().empty());
}
} // namespace tether
} // namespace chromeos