Add some instrumentation for jank in URLRequest::Start.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler_unittest.cc
blob8e059c9178dace7b0f46b32b66108734da529fbe
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/network/network_connection_handler.h"
7 #include <map>
8 #include <set>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/stringprintf.h"
18 #include "chromeos/cert_loader.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_device_client.h"
21 #include "chromeos/dbus/shill_manager_client.h"
22 #include "chromeos/dbus/shill_profile_client.h"
23 #include "chromeos/dbus/shill_service_client.h"
24 #include "chromeos/network/managed_network_configuration_handler_impl.h"
25 #include "chromeos/network/network_configuration_handler.h"
26 #include "chromeos/network/network_connection_observer.h"
27 #include "chromeos/network/network_profile_handler.h"
28 #include "chromeos/network/network_state_handler.h"
29 #include "chromeos/network/onc/onc_utils.h"
30 #include "components/onc/onc_constants.h"
31 #include "crypto/scoped_nss_types.h"
32 #include "crypto/scoped_test_nss_db.h"
33 #include "net/base/net_errors.h"
34 #include "net/base/test_data_directory.h"
35 #include "net/cert/nss_cert_database_chromeos.h"
36 #include "net/cert/x509_certificate.h"
37 #include "net/test/cert_test_util.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 #include "third_party/cros_system_api/dbus/service_constants.h"
41 namespace chromeos {
43 namespace {
45 const char* kSuccessResult = "success";
46 const char* kUsernameHash = "userhash";
48 void ConfigureCallback(const dbus::ObjectPath& result) {
51 void ConfigureErrorCallback(const std::string& error_name,
52 const std::string& error_message) {
55 class TestNetworkConnectionObserver : public NetworkConnectionObserver {
56 public:
57 TestNetworkConnectionObserver() {}
58 ~TestNetworkConnectionObserver() override {}
60 // NetworkConnectionObserver
61 void ConnectToNetworkRequested(const std::string& service_path) override {
62 requests_.insert(service_path);
65 void ConnectSucceeded(const std::string& service_path) override {
66 results_[service_path] = kSuccessResult;
69 void ConnectFailed(const std::string& service_path,
70 const std::string& error_name) override {
71 results_[service_path] = error_name;
74 void DiconnectRequested(const std::string& service_path) override {
75 requests_.insert(service_path);
78 bool GetRequested(const std::string& service_path) {
79 return requests_.count(service_path) != 0;
82 std::string GetResult(const std::string& service_path) {
83 auto iter = results_.find(service_path);
84 if (iter == results_.end())
85 return "";
86 return iter->second;
89 private:
90 std::set<std::string> requests_;
91 std::map<std::string, std::string> results_;
93 DISALLOW_COPY_AND_ASSIGN(TestNetworkConnectionObserver);
96 } // namespace
98 class NetworkConnectionHandlerTest : public testing::Test {
99 public:
100 NetworkConnectionHandlerTest()
101 : test_manager_client_(nullptr), test_service_client_(nullptr) {}
103 ~NetworkConnectionHandlerTest() override {}
105 void SetUp() override {
106 ASSERT_TRUE(test_nssdb_.is_open());
108 // Use the same DB for public and private slot.
109 test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
110 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())),
111 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))));
112 test_nsscertdb_->SetSlowTaskRunnerForTest(message_loop_.task_runner());
114 CertLoader::Initialize();
115 CertLoader::ForceHardwareBackedForTesting();
117 DBusThreadManager::Initialize();
118 DBusThreadManager* dbus_manager = DBusThreadManager::Get();
119 test_manager_client_ =
120 dbus_manager->GetShillManagerClient()->GetTestInterface();
121 test_service_client_ =
122 dbus_manager->GetShillServiceClient()->GetTestInterface();
124 test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */);
125 dbus_manager->GetShillDeviceClient()->GetTestInterface()->AddDevice(
126 "/device/wifi1", shill::kTypeWifi, "wifi_device1");
127 test_manager_client_->AddTechnology(shill::kTypeCellular,
128 true /* enabled */);
129 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
130 "shared_profile_path", std::string() /* shared profile */);
131 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
132 "user_profile_path", kUsernameHash);
134 base::RunLoop().RunUntilIdle();
135 LoginState::Initialize();
136 network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
137 network_config_handler_.reset(
138 NetworkConfigurationHandler::InitializeForTest(
139 network_state_handler_.get(),
140 nullptr /* network_device_handler */));
142 network_profile_handler_.reset(new NetworkProfileHandler());
143 network_profile_handler_->Init();
145 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
146 managed_config_handler_->Init(
147 network_state_handler_.get(), network_profile_handler_.get(),
148 network_config_handler_.get(), nullptr /* network_device_handler */);
150 network_connection_handler_.reset(new NetworkConnectionHandler);
151 network_connection_handler_->Init(network_state_handler_.get(),
152 network_config_handler_.get(),
153 managed_config_handler_.get());
154 network_connection_observer_.reset(new TestNetworkConnectionObserver);
155 network_connection_handler_->AddObserver(
156 network_connection_observer_.get());
158 base::RunLoop().RunUntilIdle();
161 void TearDown() override {
162 managed_config_handler_.reset();
163 network_profile_handler_.reset();
164 network_connection_handler_->RemoveObserver(
165 network_connection_observer_.get());
166 network_connection_observer_.reset();
167 network_connection_handler_.reset();
168 network_config_handler_.reset();
169 network_state_handler_.reset();
170 CertLoader::Shutdown();
171 LoginState::Shutdown();
172 DBusThreadManager::Shutdown();
175 protected:
176 bool Configure(const std::string& json_string) {
177 scoped_ptr<base::DictionaryValue> json_dict =
178 onc::ReadDictionaryFromJson(json_string);
179 if (!json_dict) {
180 LOG(ERROR) << "Error parsing json: " << json_string;
181 return false;
183 DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
184 *json_dict,
185 base::Bind(&ConfigureCallback),
186 base::Bind(&ConfigureErrorCallback));
187 base::RunLoop().RunUntilIdle();
188 return true;
191 void Connect(const std::string& service_path) {
192 const bool check_error_state = true;
193 network_connection_handler_->ConnectToNetwork(
194 service_path,
195 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
196 base::Unretained(this)),
197 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
198 base::Unretained(this)),
199 check_error_state);
200 base::RunLoop().RunUntilIdle();
203 void Disconnect(const std::string& service_path) {
204 network_connection_handler_->DisconnectNetwork(
205 service_path,
206 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
207 base::Unretained(this)),
208 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
209 base::Unretained(this)));
210 base::RunLoop().RunUntilIdle();
213 void SuccessCallback() {
214 result_ = kSuccessResult;
217 void ErrorCallback(const std::string& error_name,
218 scoped_ptr<base::DictionaryValue> error_data) {
219 result_ = error_name;
222 std::string GetResultAndReset() {
223 std::string result;
224 result.swap(result_);
225 return result;
228 std::string GetServiceStringProperty(const std::string& service_path,
229 const std::string& key) {
230 std::string result;
231 const base::DictionaryValue* properties =
232 test_service_client_->GetServiceProperties(service_path);
233 if (properties)
234 properties->GetStringWithoutPathExpansion(key, &result);
235 return result;
238 void StartCertLoader() {
239 CertLoader::Get()->StartWithNSSDB(test_nsscertdb_.get());
240 base::RunLoop().RunUntilIdle();
243 void LoginToRegularUser() {
244 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
245 LoginState::LOGGED_IN_USER_REGULAR);
246 base::RunLoop().RunUntilIdle();
249 scoped_refptr<net::X509Certificate> ImportTestClientCert() {
250 net::CertificateList ca_cert_list(net::CreateCertificateListFromFile(
251 net::GetTestCertsDirectory(), "client_1_ca.pem",
252 net::X509Certificate::FORMAT_AUTO));
253 if (ca_cert_list.empty()) {
254 LOG(ERROR) << "No CA cert loaded.";
255 return nullptr;
257 net::NSSCertDatabase::ImportCertFailureList failures;
258 EXPECT_TRUE(test_nsscertdb_->ImportCACerts(
259 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
260 if (!failures.empty()) {
261 LOG(ERROR) << net::ErrorToString(failures[0].net_error);
262 return nullptr;
265 // Import a client cert signed by that CA.
266 scoped_refptr<net::X509Certificate> client_cert(
267 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(),
268 "client_1.pem", "client_1.pk8",
269 test_nssdb_.slot()));
270 return client_cert;
273 void SetupPolicy(const std::string& network_configs_json,
274 const base::DictionaryValue& global_config,
275 bool user_policy) {
276 std::string error;
277 scoped_ptr<base::Value> network_configs_value(
278 base::JSONReader::ReadAndReturnError(network_configs_json,
279 base::JSON_ALLOW_TRAILING_COMMAS,
280 nullptr, &error));
281 ASSERT_TRUE(network_configs_value) << error;
283 base::ListValue* network_configs = nullptr;
284 ASSERT_TRUE(network_configs_value->GetAsList(&network_configs));
286 if (user_policy) {
287 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY,
288 kUsernameHash, *network_configs,
289 global_config);
290 } else {
291 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY,
292 std::string(), // no username hash
293 *network_configs,
294 global_config);
296 base::RunLoop().RunUntilIdle();
299 scoped_ptr<NetworkStateHandler> network_state_handler_;
300 scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
301 scoped_ptr<NetworkConnectionHandler> network_connection_handler_;
302 scoped_ptr<TestNetworkConnectionObserver> network_connection_observer_;
303 scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
304 scoped_ptr<NetworkProfileHandler> network_profile_handler_;
305 ShillManagerClient::TestInterface* test_manager_client_;
306 ShillServiceClient::TestInterface* test_service_client_;
307 crypto::ScopedTestNSSDB test_nssdb_;
308 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_;
309 base::MessageLoopForUI message_loop_;
310 std::string result_;
312 private:
313 DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerTest);
316 namespace {
318 const char* kNoNetwork = "no-network";
319 const char* kWifi0 = "wifi0";
320 const char* kWifi1 = "wifi1";
321 const char* kWifi2 = "wifi2";
322 const char* kWifi3 = "wifi3";
324 const char* kConfigConnectable =
325 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"idle\", "
326 " \"Connectable\": true }";
327 const char* kConfigConnected =
328 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"online\" }";
329 const char* kConfigConnecting =
330 "{ \"GUID\": \"wifi2\", \"Type\": \"wifi\", \"State\": \"association\" }";
331 const char* kConfigRequiresPassphrase =
332 "{ \"GUID\": \"wifi3\", \"Type\": \"wifi\", "
333 " \"PassphraseRequired\": true }";
335 } // namespace
337 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectSuccess) {
338 EXPECT_TRUE(Configure(kConfigConnectable));
339 Connect(kWifi0);
340 EXPECT_EQ(kSuccessResult, GetResultAndReset());
341 EXPECT_EQ(shill::kStateOnline,
342 GetServiceStringProperty(kWifi0, shill::kStateProperty));
343 // Observer expectations
344 EXPECT_TRUE(network_connection_observer_->GetRequested(kWifi0));
345 EXPECT_EQ(kSuccessResult, network_connection_observer_->GetResult(kWifi0));
348 // Handles basic failure cases.
349 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectFailure) {
350 Connect(kNoNetwork);
351 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
352 GetResultAndReset());
353 EXPECT_TRUE(network_connection_observer_->GetRequested(kNoNetwork));
354 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
355 network_connection_observer_->GetResult(kNoNetwork));
357 EXPECT_TRUE(Configure(kConfigConnected));
358 Connect(kWifi1);
359 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected, GetResultAndReset());
360 EXPECT_TRUE(network_connection_observer_->GetRequested(kWifi1));
361 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected,
362 network_connection_observer_->GetResult(kWifi1));
364 EXPECT_TRUE(Configure(kConfigConnecting));
365 Connect(kWifi2);
366 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting, GetResultAndReset());
367 EXPECT_TRUE(network_connection_observer_->GetRequested(kWifi2));
368 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting,
369 network_connection_observer_->GetResult(kWifi2));
371 EXPECT_TRUE(Configure(kConfigRequiresPassphrase));
372 Connect(kWifi3);
373 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired,
374 GetResultAndReset());
375 EXPECT_TRUE(network_connection_observer_->GetRequested(kWifi3));
376 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired,
377 network_connection_observer_->GetResult(kWifi3));
380 namespace {
382 const char* kPolicyWithCertPatternTemplate =
383 "[ { \"GUID\": \"wifi4\","
384 " \"Name\": \"wifi4\","
385 " \"Type\": \"WiFi\","
386 " \"WiFi\": {"
387 " \"Security\": \"WPA-EAP\","
388 " \"SSID\": \"wifi_ssid\","
389 " \"EAP\": {"
390 " \"Outer\": \"EAP-TLS\","
391 " \"ClientCertType\": \"Pattern\","
392 " \"ClientCertPattern\": {"
393 " \"Subject\": {"
394 " \"CommonName\" : \"%s\""
395 " }"
396 " }"
397 " }"
398 " }"
399 "} ]";
401 } // namespace
403 // Handle certificates.
404 TEST_F(NetworkConnectionHandlerTest, ConnectCertificateMissing) {
405 StartCertLoader();
406 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate, "unknown"),
407 base::DictionaryValue(), // no global config
408 true); // load as user policy
410 Connect("wifi4");
411 EXPECT_EQ(NetworkConnectionHandler::kErrorCertificateRequired,
412 GetResultAndReset());
415 TEST_F(NetworkConnectionHandlerTest, ConnectWithCertificateSuccess) {
416 StartCertLoader();
417 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert();
418 ASSERT_TRUE(cert.get());
420 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate,
421 cert->subject().common_name.c_str()),
422 base::DictionaryValue(), // no global config
423 true); // load as user policy
425 Connect("wifi4");
426 EXPECT_EQ(kSuccessResult, GetResultAndReset());
429 // Disabled, see http://crbug.com/396729.
430 TEST_F(NetworkConnectionHandlerTest,
431 DISABLED_ConnectWithCertificateRequestedBeforeCertsAreLoaded) {
432 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert();
433 ASSERT_TRUE(cert.get());
435 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate,
436 cert->subject().common_name.c_str()),
437 base::DictionaryValue(), // no global config
438 true); // load as user policy
440 Connect("wifi4");
442 // Connect request came before the cert loader loaded certificates, so the
443 // connect request should have been throttled until the certificates are
444 // loaded.
445 EXPECT_EQ("", GetResultAndReset());
447 StartCertLoader();
449 // |StartCertLoader| should have triggered certificate loading.
450 // When the certificates got loaded, the connection request should have
451 // proceeded and eventually succeeded.
452 EXPECT_EQ(kSuccessResult, GetResultAndReset());
455 TEST_F(NetworkConnectionHandlerTest,
456 NetworkConnectionHandlerDisconnectSuccess) {
457 EXPECT_TRUE(Configure(kConfigConnected));
458 Disconnect(kWifi1);
459 EXPECT_TRUE(network_connection_observer_->GetRequested(kWifi1));
460 EXPECT_EQ(kSuccessResult, GetResultAndReset());
463 TEST_F(NetworkConnectionHandlerTest,
464 NetworkConnectionHandlerDisconnectFailure) {
465 Connect(kNoNetwork);
466 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
467 GetResultAndReset());
469 EXPECT_TRUE(Configure(kConfigConnectable));
470 Disconnect(kWifi0);
471 EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset());
474 } // namespace chromeos