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. 4 5 #include "chrome/browser/net/http_server_properties_manager.h" 6 7 #include "base/basictypes.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/prefs/pref_registry_simple.h" 10 #include "base/prefs/testing_pref_service.h" 11 #include "base/values.h" 12 #include "chrome/common/pref_names.h" 13 #include "content/public/test/test_browser_thread.h" 14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "url/gurl.h" 17 18 namespace chrome_browser_net { 19 20 namespace { 21 22 using ::testing::_; 23 using ::testing::Invoke; 24 using ::testing::Mock; 25 using ::testing::StrictMock; 26 using content::BrowserThread; 27 28 class TestingHttpServerPropertiesManager : public HttpServerPropertiesManager { 29 public: 30 explicit TestingHttpServerPropertiesManager(PrefService* pref_service) 31 : HttpServerPropertiesManager(pref_service) { 32 InitializeOnIOThread(); 33 } 34 35 virtual ~TestingHttpServerPropertiesManager() { 36 } 37 38 // Make these methods public for testing. 39 using HttpServerPropertiesManager::ScheduleUpdateCacheOnUI; 40 using HttpServerPropertiesManager::ScheduleUpdatePrefsOnIO; 41 42 // Post tasks without a delay during tests. 43 virtual void StartPrefsUpdateTimerOnIO(base::TimeDelta delay) OVERRIDE { 44 HttpServerPropertiesManager::StartPrefsUpdateTimerOnIO( 45 base::TimeDelta()); 46 } 47 48 void UpdateCacheFromPrefsOnUIConcrete() { 49 HttpServerPropertiesManager::UpdateCacheFromPrefsOnUI(); 50 } 51 52 // Post tasks without a delay during tests. 53 virtual void StartCacheUpdateTimerOnUI(base::TimeDelta delay) OVERRIDE { 54 HttpServerPropertiesManager::StartCacheUpdateTimerOnUI( 55 base::TimeDelta()); 56 } 57 58 void UpdatePrefsFromCacheOnIOConcrete(const base::Closure& callback) { 59 HttpServerPropertiesManager::UpdatePrefsFromCacheOnIO(callback); 60 } 61 62 MOCK_METHOD0(UpdateCacheFromPrefsOnUI, void()); 63 MOCK_METHOD1(UpdatePrefsFromCacheOnIO, void(const base::Closure&)); 64 MOCK_METHOD5(UpdateCacheFromPrefsOnIO, 65 void(std::vector<std::string>* spdy_servers, 66 net::SpdySettingsMap* spdy_settings_map, 67 net::AlternateProtocolMap* alternate_protocol_map, 68 net::AlternateProtocolExperiment experiment, 69 bool detected_corrupted_prefs)); 70 MOCK_METHOD3(UpdatePrefsOnUI, 71 void(base::ListValue* spdy_server_list, 72 net::SpdySettingsMap* spdy_settings_map, 73 net::AlternateProtocolMap* alternate_protocol_map)); 74 75 private: 76 DISALLOW_COPY_AND_ASSIGN(TestingHttpServerPropertiesManager); 77 }; 78 79 class HttpServerPropertiesManagerTest : public testing::Test { 80 protected: 81 HttpServerPropertiesManagerTest() 82 : ui_thread_(BrowserThread::UI, &loop_), 83 io_thread_(BrowserThread::IO, &loop_) { 84 } 85 86 virtual void SetUp() OVERRIDE { 87 pref_service_.registry()->RegisterDictionaryPref( 88 prefs::kHttpServerProperties); 89 http_server_props_manager_.reset( 90 new StrictMock<TestingHttpServerPropertiesManager>(&pref_service_)); 91 ExpectCacheUpdate(); 92 loop_.RunUntilIdle(); 93 } 94 95 virtual void TearDown() OVERRIDE { 96 if (http_server_props_manager_.get()) 97 http_server_props_manager_->ShutdownOnUIThread(); 98 loop_.RunUntilIdle(); 99 // Delete |http_server_props_manager_| while |io_thread_| is mapping IO to 100 // |loop_|. 101 http_server_props_manager_.reset(); 102 } 103 104 void ExpectCacheUpdate() { 105 EXPECT_CALL(*http_server_props_manager_, UpdateCacheFromPrefsOnUI()) 106 .WillOnce( 107 Invoke(http_server_props_manager_.get(), 108 &TestingHttpServerPropertiesManager:: 109 UpdateCacheFromPrefsOnUIConcrete)); 110 } 111 112 void ExpectPrefsUpdate() { 113 EXPECT_CALL(*http_server_props_manager_, UpdatePrefsFromCacheOnIO(_)) 114 .WillOnce( 115 Invoke(http_server_props_manager_.get(), 116 &TestingHttpServerPropertiesManager:: 117 UpdatePrefsFromCacheOnIOConcrete)); 118 } 119 120 void ExpectPrefsUpdateRepeatedly() { 121 EXPECT_CALL(*http_server_props_manager_, UpdatePrefsFromCacheOnIO(_)) 122 .WillRepeatedly( 123 Invoke(http_server_props_manager_.get(), 124 &TestingHttpServerPropertiesManager:: 125 UpdatePrefsFromCacheOnIOConcrete)); 126 } 127 128 base::MessageLoop loop_; 129 TestingPrefServiceSimple pref_service_; 130 scoped_ptr<TestingHttpServerPropertiesManager> http_server_props_manager_; 131 132 private: 133 content::TestBrowserThread ui_thread_; 134 content::TestBrowserThread io_thread_; 135 136 DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest); 137 }; 138 139 TEST_F(HttpServerPropertiesManagerTest, 140 SingleUpdateForTwoSpdyServerPrefChanges) { 141 ExpectCacheUpdate(); 142 143 // Set up the prefs for www.google.com:80 and mail.google.com:80 and then set 144 // it twice. Only expect a single cache update. 145 146 base::DictionaryValue* server_pref_dict = new base::DictionaryValue; 147 148 // Set supports_spdy for www.google.com:80. 149 server_pref_dict->SetBoolean("supports_spdy", true); 150 151 // Set up alternate_protocol for www.google.com:80. 152 base::DictionaryValue* alternate_protocol = new base::DictionaryValue; 153 alternate_protocol->SetInteger("port", 443); 154 alternate_protocol->SetString("protocol_str", "npn-spdy/3"); 155 server_pref_dict->SetWithoutPathExpansion( 156 "alternate_protocol", alternate_protocol); 157 158 // Set the server preference for www.google.com:80. 159 base::DictionaryValue* servers_dict = new base::DictionaryValue; 160 servers_dict->SetWithoutPathExpansion( 161 "www.google.com:80", server_pref_dict); 162 163 // Set the preference for mail.google.com server. 164 base::DictionaryValue* server_pref_dict1 = new base::DictionaryValue; 165 166 // Set supports_spdy for mail.google.com:80 167 server_pref_dict1->SetBoolean("supports_spdy", true); 168 169 // Set up alternate_protocol for mail.google.com:80 170 base::DictionaryValue* alternate_protocol1 = new base::DictionaryValue; 171 alternate_protocol1->SetInteger("port", 444); 172 alternate_protocol1->SetString("protocol_str", "npn-spdy/3.1"); 173 174 server_pref_dict1->SetWithoutPathExpansion( 175 "alternate_protocol", alternate_protocol1); 176 177 // Set the server preference for mail.google.com:80. 178 servers_dict->SetWithoutPathExpansion( 179 "mail.google.com:80", server_pref_dict1); 180 181 base::DictionaryValue* http_server_properties_dict = 182 new base::DictionaryValue; 183 HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); 184 http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict); 185 186 // Set the same value for kHttpServerProperties multiple times. 187 pref_service_.SetManagedPref(prefs::kHttpServerProperties, 188 http_server_properties_dict); 189 base::DictionaryValue* http_server_properties_dict2 = 190 http_server_properties_dict->DeepCopy(); 191 pref_service_.SetManagedPref(prefs::kHttpServerProperties, 192 http_server_properties_dict2); 193 194 loop_.RunUntilIdle(); 195 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 196 197 // Verify SupportsSpdy. 198 EXPECT_TRUE(http_server_props_manager_->SupportsSpdy( 199 net::HostPortPair::FromString("www.google.com:80"))); 200 EXPECT_TRUE(http_server_props_manager_->SupportsSpdy( 201 net::HostPortPair::FromString("mail.google.com:80"))); 202 EXPECT_FALSE(http_server_props_manager_->SupportsSpdy( 203 net::HostPortPair::FromString("foo.google.com:1337"))); 204 205 // Verify AlternateProtocol. 206 ASSERT_TRUE(http_server_props_manager_->HasAlternateProtocol( 207 net::HostPortPair::FromString("www.google.com:80"))); 208 ASSERT_TRUE(http_server_props_manager_->HasAlternateProtocol( 209 net::HostPortPair::FromString("mail.google.com:80"))); 210 net::PortAlternateProtocolPair port_alternate_protocol = 211 http_server_props_manager_->GetAlternateProtocol( 212 net::HostPortPair::FromString("www.google.com:80")); 213 EXPECT_EQ(443, port_alternate_protocol.port); 214 EXPECT_EQ(net::NPN_SPDY_3, port_alternate_protocol.protocol); 215 port_alternate_protocol = 216 http_server_props_manager_->GetAlternateProtocol( 217 net::HostPortPair::FromString("mail.google.com:80")); 218 EXPECT_EQ(444, port_alternate_protocol.port); 219 EXPECT_EQ(net::NPN_SPDY_3_1, port_alternate_protocol.protocol); 220 } 221 222 TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) { 223 ExpectPrefsUpdate(); 224 225 // Post an update task to the IO thread. SetSupportsSpdy calls 226 // ScheduleUpdatePrefsOnIO. 227 228 // Add mail.google.com:443 as a supporting spdy server. 229 net::HostPortPair spdy_server_mail("mail.google.com", 443); 230 EXPECT_FALSE(http_server_props_manager_->SupportsSpdy(spdy_server_mail)); 231 http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true); 232 233 // Run the task. 234 loop_.RunUntilIdle(); 235 236 EXPECT_TRUE(http_server_props_manager_->SupportsSpdy(spdy_server_mail)); 237 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 238 } 239 240 TEST_F(HttpServerPropertiesManagerTest, SetSpdySetting) { 241 ExpectPrefsUpdate(); 242 243 // Add SpdySetting for mail.google.com:443. 244 net::HostPortPair spdy_server_mail("mail.google.com", 443); 245 const net::SpdySettingsIds id1 = net::SETTINGS_UPLOAD_BANDWIDTH; 246 const net::SpdySettingsFlags flags1 = net::SETTINGS_FLAG_PLEASE_PERSIST; 247 const uint32 value1 = 31337; 248 http_server_props_manager_->SetSpdySetting( 249 spdy_server_mail, id1, flags1, value1); 250 251 // Run the task. 252 loop_.RunUntilIdle(); 253 254 const net::SettingsMap& settings_map1_ret = 255 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 256 ASSERT_EQ(1U, settings_map1_ret.size()); 257 net::SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); 258 EXPECT_TRUE(it1_ret != settings_map1_ret.end()); 259 net::SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; 260 EXPECT_EQ(net::SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); 261 EXPECT_EQ(value1, flags_and_value1_ret.second); 262 263 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 264 } 265 266 TEST_F(HttpServerPropertiesManagerTest, ClearSpdySetting) { 267 ExpectPrefsUpdateRepeatedly(); 268 269 // Add SpdySetting for mail.google.com:443. 270 net::HostPortPair spdy_server_mail("mail.google.com", 443); 271 const net::SpdySettingsIds id1 = net::SETTINGS_UPLOAD_BANDWIDTH; 272 const net::SpdySettingsFlags flags1 = net::SETTINGS_FLAG_PLEASE_PERSIST; 273 const uint32 value1 = 31337; 274 http_server_props_manager_->SetSpdySetting( 275 spdy_server_mail, id1, flags1, value1); 276 277 // Run the task. 278 loop_.RunUntilIdle(); 279 280 const net::SettingsMap& settings_map1_ret = 281 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 282 ASSERT_EQ(1U, settings_map1_ret.size()); 283 net::SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); 284 EXPECT_TRUE(it1_ret != settings_map1_ret.end()); 285 net::SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; 286 EXPECT_EQ(net::SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); 287 EXPECT_EQ(value1, flags_and_value1_ret.second); 288 289 // Clear SpdySetting for mail.google.com:443. 290 http_server_props_manager_->ClearSpdySettings(spdy_server_mail); 291 292 // Run the task. 293 loop_.RunUntilIdle(); 294 295 // Verify that there are no entries in the settings map for 296 // mail.google.com:443. 297 const net::SettingsMap& settings_map2_ret = 298 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 299 ASSERT_EQ(0U, settings_map2_ret.size()); 300 301 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 302 } 303 304 TEST_F(HttpServerPropertiesManagerTest, ClearAllSpdySetting) { 305 ExpectPrefsUpdateRepeatedly(); 306 307 // Add SpdySetting for mail.google.com:443. 308 net::HostPortPair spdy_server_mail("mail.google.com", 443); 309 const net::SpdySettingsIds id1 = net::SETTINGS_UPLOAD_BANDWIDTH; 310 const net::SpdySettingsFlags flags1 = net::SETTINGS_FLAG_PLEASE_PERSIST; 311 const uint32 value1 = 31337; 312 http_server_props_manager_->SetSpdySetting( 313 spdy_server_mail, id1, flags1, value1); 314 315 // Run the task. 316 loop_.RunUntilIdle(); 317 318 const net::SettingsMap& settings_map1_ret = 319 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 320 ASSERT_EQ(1U, settings_map1_ret.size()); 321 net::SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); 322 EXPECT_TRUE(it1_ret != settings_map1_ret.end()); 323 net::SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; 324 EXPECT_EQ(net::SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); 325 EXPECT_EQ(value1, flags_and_value1_ret.second); 326 327 // Clear All SpdySettings. 328 http_server_props_manager_->ClearAllSpdySettings(); 329 330 // Run the task. 331 loop_.RunUntilIdle(); 332 333 // Verify that there are no entries in the settings map. 334 const net::SpdySettingsMap& spdy_settings_map2_ret = 335 http_server_props_manager_->spdy_settings_map(); 336 ASSERT_EQ(0U, spdy_settings_map2_ret.size()); 337 338 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 339 } 340 341 TEST_F(HttpServerPropertiesManagerTest, HasAlternateProtocol) { 342 ExpectPrefsUpdate(); 343 344 net::HostPortPair spdy_server_mail("mail.google.com", 80); 345 EXPECT_FALSE( 346 http_server_props_manager_->HasAlternateProtocol(spdy_server_mail)); 347 http_server_props_manager_->SetAlternateProtocol( 348 spdy_server_mail, 443, net::NPN_SPDY_3); 349 350 // Run the task. 351 loop_.RunUntilIdle(); 352 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 353 354 ASSERT_TRUE( 355 http_server_props_manager_->HasAlternateProtocol(spdy_server_mail)); 356 net::PortAlternateProtocolPair port_alternate_protocol = 357 http_server_props_manager_->GetAlternateProtocol(spdy_server_mail); 358 EXPECT_EQ(443, port_alternate_protocol.port); 359 EXPECT_EQ(net::NPN_SPDY_3, port_alternate_protocol.protocol); 360 } 361 362 TEST_F(HttpServerPropertiesManagerTest, Clear) { 363 ExpectPrefsUpdate(); 364 365 net::HostPortPair spdy_server_mail("mail.google.com", 443); 366 http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true); 367 http_server_props_manager_->SetAlternateProtocol( 368 spdy_server_mail, 443, net::NPN_SPDY_3); 369 370 const net::SpdySettingsIds id1 = net::SETTINGS_UPLOAD_BANDWIDTH; 371 const net::SpdySettingsFlags flags1 = net::SETTINGS_FLAG_PLEASE_PERSIST; 372 const uint32 value1 = 31337; 373 http_server_props_manager_->SetSpdySetting( 374 spdy_server_mail, id1, flags1, value1); 375 376 // Run the task. 377 loop_.RunUntilIdle(); 378 379 EXPECT_TRUE(http_server_props_manager_->SupportsSpdy(spdy_server_mail)); 380 EXPECT_TRUE( 381 http_server_props_manager_->HasAlternateProtocol(spdy_server_mail)); 382 383 // Check SPDY settings values. 384 const net::SettingsMap& settings_map1_ret = 385 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 386 ASSERT_EQ(1U, settings_map1_ret.size()); 387 net::SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); 388 EXPECT_TRUE(it1_ret != settings_map1_ret.end()); 389 net::SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; 390 EXPECT_EQ(net::SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); 391 EXPECT_EQ(value1, flags_and_value1_ret.second); 392 393 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 394 395 ExpectPrefsUpdate(); 396 397 // Clear http server data, time out if we do not get a completion callback. 398 http_server_props_manager_->Clear(base::MessageLoop::QuitClosure()); 399 loop_.Run(); 400 401 EXPECT_FALSE(http_server_props_manager_->SupportsSpdy(spdy_server_mail)); 402 EXPECT_FALSE( 403 http_server_props_manager_->HasAlternateProtocol(spdy_server_mail)); 404 405 const net::SettingsMap& settings_map2_ret = 406 http_server_props_manager_->GetSpdySettings(spdy_server_mail); 407 EXPECT_EQ(0U, settings_map2_ret.size()); 408 409 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 410 } 411 412 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache0) { 413 // Post an update task to the UI thread. 414 http_server_props_manager_->ScheduleUpdateCacheOnUI(); 415 // Shutdown comes before the task is executed. 416 http_server_props_manager_->ShutdownOnUIThread(); 417 http_server_props_manager_.reset(); 418 // Run the task after shutdown and deletion. 419 loop_.RunUntilIdle(); 420 } 421 422 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache1) { 423 // Post an update task. 424 http_server_props_manager_->ScheduleUpdateCacheOnUI(); 425 // Shutdown comes before the task is executed. 426 http_server_props_manager_->ShutdownOnUIThread(); 427 // Run the task after shutdown, but before deletion. 428 loop_.RunUntilIdle(); 429 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 430 http_server_props_manager_.reset(); 431 loop_.RunUntilIdle(); 432 } 433 434 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache2) { 435 http_server_props_manager_->UpdateCacheFromPrefsOnUIConcrete(); 436 // Shutdown comes before the task is executed. 437 http_server_props_manager_->ShutdownOnUIThread(); 438 // Run the task after shutdown, but before deletion. 439 loop_.RunUntilIdle(); 440 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 441 http_server_props_manager_.reset(); 442 loop_.RunUntilIdle(); 443 } 444 445 // 446 // Tests for shutdown when updating prefs. 447 // 448 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs0) { 449 // Post an update task to the IO thread. 450 http_server_props_manager_->ScheduleUpdatePrefsOnIO(); 451 // Shutdown comes before the task is executed. 452 http_server_props_manager_->ShutdownOnUIThread(); 453 http_server_props_manager_.reset(); 454 // Run the task after shutdown and deletion. 455 loop_.RunUntilIdle(); 456 } 457 458 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs1) { 459 ExpectPrefsUpdate(); 460 // Post an update task. 461 http_server_props_manager_->ScheduleUpdatePrefsOnIO(); 462 // Shutdown comes before the task is executed. 463 http_server_props_manager_->ShutdownOnUIThread(); 464 // Run the task after shutdown, but before deletion. 465 loop_.RunUntilIdle(); 466 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 467 http_server_props_manager_.reset(); 468 loop_.RunUntilIdle(); 469 } 470 471 TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs2) { 472 // This posts a task to the UI thread. 473 http_server_props_manager_->UpdatePrefsFromCacheOnIOConcrete(base::Closure()); 474 // Shutdown comes before the task is executed. 475 http_server_props_manager_->ShutdownOnUIThread(); 476 // Run the task after shutdown, but before deletion. 477 loop_.RunUntilIdle(); 478 Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); 479 http_server_props_manager_.reset(); 480 loop_.RunUntilIdle(); 481 } 482 483 } // namespace 484 485 } // namespace chrome_browser_net 486