Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: chrome/browser/chromeos/cros/network_library_unittest.cc

Issue 14192017: Extract certificate policy application from NetworkLibrary. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <cert.h>
6 #include <pk11pub.h> 5 #include <pk11pub.h>
7 6
8 #include <map> 7 #include <map>
9 #include <string> 8 #include <string>
10 #include <vector> 9 #include <vector>
11 10
12 #include "base/at_exit.h" 11 #include "base/at_exit.h"
13 #include "base/callback.h" 12 #include "base/callback.h"
14 #include "base/file_util.h" 13 #include "base/file_util.h"
15 #include "base/files/scoped_temp_dir.h" 14 #include "base/files/scoped_temp_dir.h"
16 #include "base/json/json_reader.h" 15 #include "base/json/json_reader.h"
17 #include "base/lazy_instance.h" 16 #include "base/lazy_instance.h"
18 #include "base/path_service.h" 17 #include "base/path_service.h"
19 #include "chrome/browser/chromeos/cros/cros_library.h" 18 #include "chrome/browser/chromeos/cros/cros_library.h"
20 #include "chrome/browser/chromeos/cros/network_library.h" 19 #include "chrome/browser/chromeos/cros/network_library.h"
21 #include "chrome/browser/chromeos/cros/network_library_impl_stub.h" 20 #include "chrome/browser/chromeos/cros/network_library_impl_stub.h"
22 #include "chrome/browser/chromeos/login/mock_user_manager.h" 21 #include "chrome/browser/chromeos/login/mock_user_manager.h"
23 #include "chrome/browser/chromeos/login/user_manager.h" 22 #include "chrome/browser/chromeos/login/user_manager.h"
24 #include "chrome/browser/google_apis/test_util.h" 23 #include "chrome/browser/google_apis/test_util.h"
25 #include "chrome/common/chrome_paths.h" 24 #include "chrome/common/chrome_paths.h"
26 #include "chromeos/network/onc/onc_certificate_importer.h" 25 #include "chromeos/network/onc/onc_certificate_importer.h"
27 #include "chromeos/network/onc/onc_constants.h" 26 #include "chromeos/network/onc/onc_constants.h"
28 #include "chromeos/network/onc/onc_test_utils.h" 27 #include "chromeos/network/onc/onc_test_utils.h"
29 #include "chromeos/network/onc/onc_utils.h" 28 #include "chromeos/network/onc/onc_utils.h"
30 #include "crypto/nss_util.h" 29 #include "crypto/nss_util.h"
31 #include "net/base/crypto_module.h" 30 #include "net/base/crypto_module.h"
32 #include "net/cert/nss_cert_database.h"
33 #include "net/cert/x509_certificate.h"
34 #include "testing/gmock/include/gmock/gmock.h" 31 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h" 32 #include "testing/gtest/include/gtest/gtest.h"
36 33
37 using ::testing::AnyNumber; 34 using ::testing::AnyNumber;
38 using ::testing::Return; 35 using ::testing::Return;
39 36
40 namespace chromeos { 37 namespace chromeos {
41 38
42 namespace { 39 namespace {
43 40
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 // predefined values, e.g. ethernet_available(). However, many other functions 133 // predefined values, e.g. ethernet_available(). However, many other functions
137 // such as connected_network() return values which are set indirectly and thus 134 // such as connected_network() return values which are set indirectly and thus
138 // we can test the logic of those setters. 135 // we can test the logic of those setters.
139 136
140 class NetworkLibraryStubTest : public ::testing::Test { 137 class NetworkLibraryStubTest : public ::testing::Test {
141 public: 138 public:
142 NetworkLibraryStubTest() : cros_(NULL) {} 139 NetworkLibraryStubTest() : cros_(NULL) {}
143 140
144 protected: 141 protected:
145 virtual void SetUp() { 142 virtual void SetUp() {
146 ASSERT_TRUE(test_nssdb_.is_open());
147
148 slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule();
149 cros_ = static_cast<NetworkLibraryImplStub*>( 143 cros_ = static_cast<NetworkLibraryImplStub*>(
150 CrosLibrary::Get()->GetNetworkLibrary()); 144 CrosLibrary::Get()->GetNetworkLibrary());
151 ASSERT_TRUE(cros_) << "GetNetworkLibrary() Failed!"; 145 ASSERT_TRUE(cros_) << "GetNetworkLibrary() Failed!";
152
153 // Test db should be empty at start of test.
154 EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
155 } 146 }
156 147
157 virtual void TearDown() { 148 virtual void TearDown() {
158 cros_ = NULL; 149 cros_ = NULL;
159 EXPECT_TRUE(CleanupSlotContents(slot_->os_module_handle()));
160 EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size());
161 } 150 }
162 151
163 // Load the ONC from |onc_file| using NetworkLibrary::LoadOncNetworks. Check 152 // Load the ONC from |onc_file| using NetworkLibrary::LoadOncNetworks. Check
164 // that return value matches |expect_successful_import| and the configuration 153 // that return value matches |expect_successful_import| and the configuration
165 // that would be sent to Shill matches |shill_json|. 154 // that would be sent to Shill matches |shill_json|.
166 void LoadOncAndVerifyNetworks(std::string onc_file, 155 void LoadOncAndVerifyNetworks(std::string onc_file,
167 std::string shill_json, 156 std::string shill_json,
168 onc::ONCSource source, 157 onc::ONCSource source,
169 bool expect_successful_import) { 158 bool expect_successful_import) {
170 MockUserManager* mock_user_manager = new MockUserManager; 159 MockUserManager* mock_user_manager = new MockUserManager;
171 // Takes ownership of |mock_user_manager|. 160 // Takes ownership of |mock_user_manager|.
172 ScopedUserManagerEnabler user_manager_enabler(mock_user_manager); 161 ScopedUserManagerEnabler user_manager_enabler(mock_user_manager);
173 mock_user_manager->SetActiveUser("madmax@my.domain.com"); 162 mock_user_manager->SetActiveUser("madmax@my.domain.com");
174 EXPECT_CALL(*mock_user_manager, IsUserLoggedIn()) 163 EXPECT_CALL(*mock_user_manager, IsUserLoggedIn())
175 .Times(AnyNumber()) 164 .Times(AnyNumber())
176 .WillRepeatedly(Return(true)); 165 .WillRepeatedly(Return(true));
177 166
178 std::string onc_blob = onc::test_utils::ReadTestData(onc_file); 167 scoped_ptr<base::DictionaryValue> onc_blob =
168 onc::test_utils::ReadTestDictionary(onc_file);
169 base::ListValue* onc_network_configs;
170 onc_blob->GetListWithoutPathExpansion(
171 onc::toplevel_config::kNetworkConfigurations,
172 &onc_network_configs);
173 ASSERT_TRUE(onc_network_configs);
179 174
180 scoped_ptr<base::Value> expected_value = 175 scoped_ptr<base::Value> expected_value =
181 google_apis::test_util::LoadJSONFile(shill_json); 176 google_apis::test_util::LoadJSONFile(shill_json);
182 base::DictionaryValue* expected_configs; 177 base::DictionaryValue* expected_configs;
183 expected_value->GetAsDictionary(&expected_configs); 178 expected_value->GetAsDictionary(&expected_configs);
184 179
185 net::CertificateList cert_list; 180 cros_->LoadOncNetworks(*onc_network_configs, source);
186 EXPECT_EQ(expect_successful_import,
187 cros_->LoadOncNetworks(onc_blob, "", source, &cert_list));
188 181
189 const std::map<std::string, base::DictionaryValue*>& configs = 182 const std::map<std::string, base::DictionaryValue*>& configs =
190 cros_->GetConfigurations(); 183 cros_->GetConfigurations();
191 184
192 EXPECT_EQ(expected_configs->size(), configs.size()); 185 EXPECT_EQ(expected_configs->size(), configs.size());
193 186
194 for (base::DictionaryValue::Iterator it(*expected_configs); !it.IsAtEnd(); 187 for (base::DictionaryValue::Iterator it(*expected_configs); !it.IsAtEnd();
195 it.Advance()) { 188 it.Advance()) {
196 const base::DictionaryValue* expected_config; 189 const base::DictionaryValue* expected_config;
197 it.value().GetAsDictionary(&expected_config); 190 it.value().GetAsDictionary(&expected_config);
198 191
199 std::map<std::string, base::DictionaryValue*>::const_iterator entry = 192 std::map<std::string, base::DictionaryValue*>::const_iterator entry =
200 configs.find(it.key()); 193 configs.find(it.key());
201 EXPECT_NE(entry, configs.end()); 194 EXPECT_NE(entry, configs.end());
202 base::DictionaryValue* actual_config = entry->second; 195 base::DictionaryValue* actual_config = entry->second;
203 EXPECT_TRUE(onc::test_utils::Equals(expected_config, actual_config)); 196 EXPECT_TRUE(onc::test_utils::Equals(expected_config, actual_config));
204 } 197 }
205 } 198 }
206 199
207 ScopedStubCrosEnabler cros_stub_; 200 ScopedStubCrosEnabler cros_stub_;
208 NetworkLibraryImplStub* cros_; 201 NetworkLibraryImplStub* cros_;
209 protected: 202 protected:
210 net::CertificateList ListCertsInSlot(PK11SlotInfo* slot) {
211 net::CertificateList result;
212 CERTCertList* cert_list = PK11_ListCertsInSlot(slot);
213 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
214 !CERT_LIST_END(node, cert_list);
215 node = CERT_LIST_NEXT(node)) {
216 result.push_back(net::X509Certificate::CreateFromHandle(
217 node->cert, net::X509Certificate::OSCertHandles()));
218 }
219 CERT_DestroyCertList(cert_list);
220
221 // Sort the result so that test comparisons can be deterministic.
222 std::sort(result.begin(), result.end(), net::X509Certificate::LessThan());
223 return result;
224 }
225
226 bool CleanupSlotContents(PK11SlotInfo* slot) {
227 bool ok = true;
228 net::CertificateList certs = ListCertsInSlot(slot);
229 for (size_t i = 0; i < certs.size(); ++i) {
230 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(certs[i]))
231 ok = false;
232 }
233 return ok;
234 }
235
236 scoped_refptr<net::CryptoModule> slot_; 203 scoped_refptr<net::CryptoModule> slot_;
237 crypto::ScopedTestNSSDB test_nssdb_; 204 crypto::ScopedTestNSSDB test_nssdb_;
238 }; 205 };
239 206
240 // Default stub state: 207 // Default stub state:
241 // vpn1: disconnected, L2TP/IPsec + PSK 208 // vpn1: disconnected, L2TP/IPsec + PSK
242 // vpn2: disconnected, L2TP/IPsec + user cert 209 // vpn2: disconnected, L2TP/IPsec + user cert
243 // vpn3: disconnected, OpenVpn 210 // vpn3: disconnected, OpenVpn
244 // eth1: connected (active network) 211 // eth1: connected (active network)
245 // wifi1: connected 212 // wifi1: connected
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 } 289 }
323 290
324 TEST_F(NetworkLibraryStubTest, NetworkConnectWifiWithCertPattern) { 291 TEST_F(NetworkLibraryStubTest, NetworkConnectWifiWithCertPattern) {
325 scoped_ptr<base::DictionaryValue> onc_root = 292 scoped_ptr<base::DictionaryValue> onc_root =
326 onc::test_utils::ReadTestDictionary("toplevel_wifi_eap_clientcert.onc"); 293 onc::test_utils::ReadTestDictionary("toplevel_wifi_eap_clientcert.onc");
327 base::ListValue* certificates; 294 base::ListValue* certificates;
328 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates, 295 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates,
329 &certificates); 296 &certificates);
330 297
331 onc::CertificateImporter importer(true /* allow trust imports */); 298 onc::CertificateImporter importer(true /* allow trust imports */);
332 net::CertificateList cert_list;
333 ASSERT_EQ(onc::CertificateImporter::IMPORT_OK, 299 ASSERT_EQ(onc::CertificateImporter::IMPORT_OK,
334 importer.ParseAndStoreCertificates(*certificates, &cert_list)); 300 importer.ParseAndStoreCertificates(*certificates, NULL));
335 301
336 WifiNetwork* wifi = cros_->FindWifiNetworkByPath("wifi_cert_pattern"); 302 WifiNetwork* wifi = cros_->FindWifiNetworkByPath("wifi_cert_pattern");
337 303
338 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate(); 304 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate();
339 wifi->SetEnrollmentDelegate(enrollment_delegate); 305 wifi->SetEnrollmentDelegate(enrollment_delegate);
340 EXPECT_FALSE(enrollment_delegate->did_enroll); 306 EXPECT_FALSE(enrollment_delegate->did_enroll);
341 EXPECT_FALSE(enrollment_delegate->correct_args); 307 EXPECT_FALSE(enrollment_delegate->correct_args);
342 308
343 ASSERT_NE(static_cast<const WifiNetwork*>(NULL), wifi); 309 ASSERT_NE(static_cast<const WifiNetwork*>(NULL), wifi);
344 EXPECT_FALSE(wifi->connected()); 310 EXPECT_FALSE(wifi->connected());
345 EXPECT_TRUE(cros_->CanConnectToNetwork(wifi)); 311 EXPECT_TRUE(cros_->CanConnectToNetwork(wifi));
346 EXPECT_FALSE(wifi->connected()); 312 EXPECT_FALSE(wifi->connected());
347 wifi->AttemptConnection( 313 wifi->AttemptConnection(
348 base::Bind(&WifiNetworkConnectCallback, cros_, wifi)); 314 base::Bind(&WifiNetworkConnectCallback, cros_, wifi));
349 EXPECT_TRUE(wifi->connected()); 315 EXPECT_TRUE(wifi->connected());
350 EXPECT_TRUE(enrollment_delegate->did_enroll); 316 EXPECT_TRUE(enrollment_delegate->did_enroll);
351 EXPECT_TRUE(enrollment_delegate->correct_args); 317 EXPECT_TRUE(enrollment_delegate->correct_args);
352 } 318 }
353 319
354 TEST_F(NetworkLibraryStubTest, NetworkConnectVPNWithCertPattern) { 320 TEST_F(NetworkLibraryStubTest, NetworkConnectVPNWithCertPattern) {
355 scoped_ptr<base::DictionaryValue> onc_root = 321 scoped_ptr<base::DictionaryValue> onc_root =
356 onc::test_utils::ReadTestDictionary("toplevel_openvpn_clientcert.onc"); 322 onc::test_utils::ReadTestDictionary("toplevel_openvpn_clientcert.onc");
357 base::ListValue* certificates; 323 base::ListValue* certificates;
358 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates, 324 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates,
359 &certificates); 325 &certificates);
360 326
361 onc::CertificateImporter importer(true /* allow trust imports */); 327 onc::CertificateImporter importer(true /* allow trust imports */);
362 net::CertificateList cert_list;
363 ASSERT_EQ(onc::CertificateImporter::IMPORT_OK, 328 ASSERT_EQ(onc::CertificateImporter::IMPORT_OK,
364 importer.ParseAndStoreCertificates(*certificates, &cert_list)); 329 importer.ParseAndStoreCertificates(*certificates, NULL));
365 330
366 VirtualNetwork* vpn = cros_->FindVirtualNetworkByPath("vpn_cert_pattern"); 331 VirtualNetwork* vpn = cros_->FindVirtualNetworkByPath("vpn_cert_pattern");
367 332
368 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate(); 333 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate();
369 vpn->SetEnrollmentDelegate(enrollment_delegate); 334 vpn->SetEnrollmentDelegate(enrollment_delegate);
370 EXPECT_FALSE(enrollment_delegate->did_enroll); 335 EXPECT_FALSE(enrollment_delegate->did_enroll);
371 EXPECT_FALSE(enrollment_delegate->correct_args); 336 EXPECT_FALSE(enrollment_delegate->correct_args);
372 337
373 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), vpn); 338 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), vpn);
374 EXPECT_FALSE(vpn->connected()); 339 EXPECT_FALSE(vpn->connected());
(...skipping 10 matching lines...) Expand all
385 VirtualNetwork* vpn1 = cros_->FindVirtualNetworkByPath("vpn1"); 350 VirtualNetwork* vpn1 = cros_->FindVirtualNetworkByPath("vpn1");
386 EXPECT_NE(static_cast<const VirtualNetwork*>(NULL), vpn1); 351 EXPECT_NE(static_cast<const VirtualNetwork*>(NULL), vpn1);
387 EXPECT_FALSE(vpn1->connected()); 352 EXPECT_FALSE(vpn1->connected());
388 EXPECT_TRUE(cros_->CanConnectToNetwork(vpn1)); 353 EXPECT_TRUE(cros_->CanConnectToNetwork(vpn1));
389 cros_->ConnectToVirtualNetwork(vpn1); 354 cros_->ConnectToVirtualNetwork(vpn1);
390 EXPECT_TRUE(vpn1->connected()); 355 EXPECT_TRUE(vpn1->connected());
391 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), cros_->virtual_network()); 356 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), cros_->virtual_network());
392 EXPECT_EQ("vpn1", cros_->virtual_network()->service_path()); 357 EXPECT_EQ("vpn1", cros_->virtual_network()->service_path());
393 } 358 }
394 359
395 TEST_F(NetworkLibraryStubTest, LoadOncNetworksWithInvalidConfig) {
396 LoadOncAndVerifyNetworks(
397 "toplevel_partially_invalid.onc",
398 "chromeos/net/shill_for_toplevel_partially_invalid.json",
399 onc::ONC_SOURCE_USER_POLICY,
400 false /* expect import to fail */);
401
402 EXPECT_EQ(ListCertsInSlot(slot_->os_module_handle()).size(), 1U);
403 }
404
405 namespace { 360 namespace {
406 361
407 struct ImportParams { 362 struct ImportParams {
408 // |onc_file|: Filename of source ONC, relative to 363 // |onc_file|: Filename of source ONC, relative to
409 // chromeos/test/data/network. 364 // chromeos/test/data/network.
410 // |shill_file|: Filename of expected Shill config, relative to 365 // |shill_file|: Filename of expected Shill config, relative to
411 // chrome/test/data). 366 // chrome/test/data).
412 // |onc_source|: The source of the ONC. 367 // |onc_source|: The source of the ONC.
413 // |expect_import_result|: The expected return value of LoadOncNetworks. 368 // |expect_import_result|: The expected return value of LoadOncNetworks.
414 ImportParams(const std::string& onc_file, 369 ImportParams(const std::string& onc_file,
(...skipping 22 matching lines...) Expand all
437 class LoadOncNetworksTest 392 class LoadOncNetworksTest
438 : public NetworkLibraryStubTest, 393 : public NetworkLibraryStubTest,
439 public ::testing::WithParamInterface<ImportParams> { 394 public ::testing::WithParamInterface<ImportParams> {
440 }; 395 };
441 396
442 TEST_P(LoadOncNetworksTest, VerifyNetworksAndCertificates) { 397 TEST_P(LoadOncNetworksTest, VerifyNetworksAndCertificates) {
443 LoadOncAndVerifyNetworks(GetParam().onc_file, 398 LoadOncAndVerifyNetworks(GetParam().onc_file,
444 GetParam().shill_file, 399 GetParam().shill_file,
445 GetParam().onc_source, 400 GetParam().onc_source,
446 GetParam().expect_import_result); 401 GetParam().expect_import_result);
447
448 scoped_ptr<base::DictionaryValue> onc_dict =
449 onc::test_utils::ReadTestDictionary(GetParam().onc_file);
450 base::ListValue* onc_certs;
451 onc_dict->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates,
452 &onc_certs);
453
454 EXPECT_EQ(onc_certs->GetSize(),
455 ListCertsInSlot(slot_->os_module_handle()).size());
456 } 402 }
457 403
458 INSTANTIATE_TEST_CASE_P( 404 INSTANTIATE_TEST_CASE_P(
459 LoadOncNetworksTest, 405 LoadOncNetworksTest,
460 LoadOncNetworksTest, 406 LoadOncNetworksTest,
461 ::testing::Values( 407 ::testing::Values(
462 ImportParams("managed_toplevel1.onc", 408 ImportParams("managed_toplevel1.onc",
463 "chromeos/net/shill_for_managed_toplevel1.json", 409 "chromeos/net/shill_for_managed_toplevel1.json",
464 onc::ONC_SOURCE_USER_POLICY), 410 onc::ONC_SOURCE_USER_POLICY),
465 ImportParams("managed_toplevel2.onc", 411 ImportParams("managed_toplevel2.onc",
(...skipping 19 matching lines...) Expand all
485 onc::ONC_SOURCE_USER_POLICY), 431 onc::ONC_SOURCE_USER_POLICY),
486 ImportParams( 432 ImportParams(
487 "toplevel_wifi_eap_clientcert.onc", 433 "toplevel_wifi_eap_clientcert.onc",
488 "chromeos/net/shill_for_toplevel_wifi_eap_clientcert.json", 434 "chromeos/net/shill_for_toplevel_wifi_eap_clientcert.json",
489 onc::ONC_SOURCE_USER_POLICY), 435 onc::ONC_SOURCE_USER_POLICY),
490 ImportParams("toplevel_openvpn_clientcert.onc", 436 ImportParams("toplevel_openvpn_clientcert.onc",
491 "chromeos/net/shill_for_toplevel_openvpn_clientcert.json", 437 "chromeos/net/shill_for_toplevel_openvpn_clientcert.json",
492 onc::ONC_SOURCE_USER_POLICY), 438 onc::ONC_SOURCE_USER_POLICY),
493 ImportParams("toplevel_wifi_remove.onc", 439 ImportParams("toplevel_wifi_remove.onc",
494 "chromeos/net/shill_for_toplevel_wifi_remove.json", 440 "chromeos/net/shill_for_toplevel_wifi_remove.json",
495 onc::ONC_SOURCE_USER_POLICY), 441 onc::ONC_SOURCE_USER_POLICY)));
496 ImportParams(
497 "toplevel_with_unknown_fields.onc",
498 "chromeos/net/shill_for_toplevel_with_unknown_fields.json",
499 onc::ONC_SOURCE_USER_POLICY,
500 false)));
501 442
502 // TODO(stevenjb): Test remembered networks. 443 // TODO(stevenjb): Test remembered networks.
503 444
504 // TODO(stevenjb): Test network profiles. 445 // TODO(stevenjb): Test network profiles.
505 446
506 // TODO(stevenjb): Test network devices. 447 // TODO(stevenjb): Test network devices.
507 448
508 // TODO(stevenjb): Test data plans. 449 // TODO(stevenjb): Test data plans.
509 450
510 // TODO(stevenjb): Test monitor network / device. 451 // TODO(stevenjb): Test monitor network / device.
511 452
512 } // namespace chromeos 453 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698