1 // Copyright 2013 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 "content/browser/service_worker/service_worker_storage.h" 6 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/logging.h" 9 #include "base/run_loop.h" 10 #include "content/browser/browser_thread_impl.h" 11 #include "content/browser/service_worker/service_worker_registration.h" 12 #include "content/public/test/test_browser_thread_bundle.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace content { 16 17 namespace { 18 19 void SaveRegistrationCallback( 20 ServiceWorkerRegistrationStatus expected_status, 21 bool* called, 22 scoped_refptr<ServiceWorkerRegistration>* registration, 23 ServiceWorkerRegistrationStatus status, 24 const scoped_refptr<ServiceWorkerRegistration>& result) { 25 EXPECT_EQ(expected_status, status); 26 *called = true; 27 *registration = result; 28 } 29 30 void SaveFoundRegistrationCallback( 31 bool expected_found, 32 ServiceWorkerRegistrationStatus expected_status, 33 bool* called, 34 scoped_refptr<ServiceWorkerRegistration>* registration, 35 bool found, 36 ServiceWorkerRegistrationStatus status, 37 const scoped_refptr<ServiceWorkerRegistration>& result) { 38 EXPECT_EQ(expected_found, found); 39 EXPECT_EQ(expected_status, status); 40 *called = true; 41 *registration = result; 42 } 43 44 // Creates a callback which both keeps track of if it's been called, 45 // as well as the resulting registration. Whent the callback is fired, 46 // it ensures that the resulting status matches the expectation. 47 // 'called' is useful for making sure a sychronous callback is or 48 // isn't called. 49 ServiceWorkerStorage::RegistrationCallback SaveRegistration( 50 ServiceWorkerRegistrationStatus expected_status, 51 bool* called, 52 scoped_refptr<ServiceWorkerRegistration>* registration) { 53 *called = false; 54 return base::Bind( 55 &SaveRegistrationCallback, expected_status, called, registration); 56 } 57 58 ServiceWorkerStorage::FindRegistrationCallback SaveFoundRegistration( 59 bool expected_found, 60 ServiceWorkerRegistrationStatus expected_status, 61 bool* called, 62 scoped_refptr<ServiceWorkerRegistration>* registration) { 63 *called = false; 64 return base::Bind(&SaveFoundRegistrationCallback, 65 expected_found, 66 expected_status, 67 called, 68 registration); 69 } 70 71 void SaveUnregistrationCallback(ServiceWorkerRegistrationStatus expected_status, 72 bool* called, 73 ServiceWorkerRegistrationStatus status) { 74 EXPECT_EQ(expected_status, status); 75 *called = true; 76 } 77 78 ServiceWorkerStorage::UnregistrationCallback SaveUnregistration( 79 ServiceWorkerRegistrationStatus expected_status, 80 bool* called) { 81 *called = false; 82 return base::Bind(&SaveUnregistrationCallback, expected_status, called); 83 } 84 85 } // namespace 86 87 class ServiceWorkerStorageTest : public testing::Test { 88 public: 89 ServiceWorkerStorageTest() 90 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} 91 92 virtual void SetUp() OVERRIDE { 93 storage_.reset(new ServiceWorkerStorage(base::FilePath(), NULL)); 94 } 95 96 virtual void TearDown() OVERRIDE { storage_.reset(); } 97 98 protected: 99 TestBrowserThreadBundle browser_thread_bundle_; 100 scoped_ptr<ServiceWorkerStorage> storage_; 101 }; 102 103 TEST_F(ServiceWorkerStorageTest, PatternMatches) { 104 ASSERT_TRUE(ServiceWorkerStorage::PatternMatches( 105 GURL("http://www.example.com/*"), GURL("http://www.example.com/"))); 106 ASSERT_TRUE(ServiceWorkerStorage::PatternMatches( 107 GURL("http://www.example.com/*"), 108 GURL("http://www.example.com/page.html"))); 109 110 ASSERT_FALSE(ServiceWorkerStorage::PatternMatches( 111 GURL("http://www.example.com/*"), GURL("https://www.example.com/"))); 112 ASSERT_FALSE(ServiceWorkerStorage::PatternMatches( 113 GURL("http://www.example.com/*"), 114 GURL("https://www.example.com/page.html"))); 115 116 ASSERT_FALSE(ServiceWorkerStorage::PatternMatches( 117 GURL("http://www.example.com/*"), GURL("http://www.foo.com/"))); 118 ASSERT_FALSE(ServiceWorkerStorage::PatternMatches( 119 GURL("http://www.example.com/*"), GURL("https://www.foo.com/page.html"))); 120 } 121 122 TEST_F(ServiceWorkerStorageTest, SameDocumentSameRegistration) { 123 scoped_refptr<ServiceWorkerRegistration> original_registration; 124 bool called; 125 storage_->Register( 126 GURL("http://www.example.com/*"), 127 GURL("http://www.example.com/service_worker.js"), 128 SaveRegistration(REGISTRATION_OK, &called, &original_registration)); 129 EXPECT_FALSE(called); 130 base::RunLoop().RunUntilIdle(); 131 EXPECT_TRUE(called); 132 133 scoped_refptr<ServiceWorkerRegistration> registration1; 134 storage_->FindRegistrationForDocument( 135 GURL("http://www.example.com/"), 136 SaveFoundRegistration(true, REGISTRATION_OK, &called, ®istration1)); 137 scoped_refptr<ServiceWorkerRegistration> registration2; 138 storage_->FindRegistrationForDocument( 139 GURL("http://www.example.com/"), 140 SaveFoundRegistration(true, REGISTRATION_OK, &called, ®istration2)); 141 142 ServiceWorkerRegistration* null_registration(NULL); 143 ASSERT_EQ(null_registration, registration1); 144 ASSERT_EQ(null_registration, registration2); 145 EXPECT_FALSE(called); 146 base::RunLoop().RunUntilIdle(); 147 EXPECT_TRUE(called); 148 ASSERT_NE(null_registration, registration1); 149 ASSERT_NE(null_registration, registration2); 150 151 ASSERT_EQ(registration1, registration2); 152 } 153 154 TEST_F(ServiceWorkerStorageTest, SameMatchSameRegistration) { 155 bool called; 156 scoped_refptr<ServiceWorkerRegistration> original_registration; 157 storage_->Register( 158 GURL("http://www.example.com/*"), 159 GURL("http://www.example.com/service_worker.js"), 160 SaveRegistration(REGISTRATION_OK, &called, &original_registration)); 161 EXPECT_FALSE(called); 162 base::RunLoop().RunUntilIdle(); 163 EXPECT_TRUE(called); 164 ASSERT_NE(static_cast<ServiceWorkerRegistration*>(NULL), 165 original_registration.get()); 166 167 scoped_refptr<ServiceWorkerRegistration> registration1; 168 storage_->FindRegistrationForDocument( 169 GURL("http://www.example.com/one"), 170 SaveFoundRegistration(true, REGISTRATION_OK, &called, ®istration1)); 171 172 EXPECT_FALSE(called); 173 base::RunLoop().RunUntilIdle(); 174 EXPECT_TRUE(called); 175 176 scoped_refptr<ServiceWorkerRegistration> registration2; 177 storage_->FindRegistrationForDocument( 178 GURL("http://www.example.com/two"), 179 SaveFoundRegistration(true, REGISTRATION_OK, &called, ®istration2)); 180 EXPECT_FALSE(called); 181 base::RunLoop().RunUntilIdle(); 182 EXPECT_TRUE(called); 183 184 ASSERT_EQ(registration1, registration2); 185 } 186 187 TEST_F(ServiceWorkerStorageTest, DifferentMatchDifferentRegistration) { 188 bool called1; 189 scoped_refptr<ServiceWorkerRegistration> original_registration1; 190 storage_->Register( 191 GURL("http://www.example.com/one/*"), 192 GURL("http://www.example.com/service_worker.js"), 193 SaveRegistration(REGISTRATION_OK, &called1, &original_registration1)); 194 195 bool called2; 196 scoped_refptr<ServiceWorkerRegistration> original_registration2; 197 storage_->Register( 198 GURL("http://www.example.com/two/*"), 199 GURL("http://www.example.com/service_worker.js"), 200 SaveRegistration(REGISTRATION_OK, &called2, &original_registration2)); 201 202 EXPECT_FALSE(called1); 203 EXPECT_FALSE(called2); 204 base::RunLoop().RunUntilIdle(); 205 EXPECT_TRUE(called2); 206 EXPECT_TRUE(called1); 207 208 scoped_refptr<ServiceWorkerRegistration> registration1; 209 storage_->FindRegistrationForDocument( 210 GURL("http://www.example.com/one/"), 211 SaveFoundRegistration(true, REGISTRATION_OK, &called1, ®istration1)); 212 scoped_refptr<ServiceWorkerRegistration> registration2; 213 storage_->FindRegistrationForDocument( 214 GURL("http://www.example.com/two/"), 215 SaveFoundRegistration(true, REGISTRATION_OK, &called2, ®istration2)); 216 217 EXPECT_FALSE(called1); 218 EXPECT_FALSE(called2); 219 base::RunLoop().RunUntilIdle(); 220 EXPECT_TRUE(called2); 221 EXPECT_TRUE(called1); 222 223 ASSERT_NE(registration1, registration2); 224 } 225 226 // Make sure basic registration is working. 227 TEST_F(ServiceWorkerStorageTest, Register) { 228 bool called = false; 229 scoped_refptr<ServiceWorkerRegistration> registration; 230 storage_->Register(GURL("http://www.example.com/*"), 231 GURL("http://www.example.com/service_worker.js"), 232 SaveRegistration(REGISTRATION_OK, &called, ®istration)); 233 234 ASSERT_FALSE(called); 235 base::RunLoop().RunUntilIdle(); 236 ASSERT_TRUE(called); 237 238 ASSERT_NE(scoped_refptr<ServiceWorkerRegistration>(NULL), registration); 239 } 240 241 // Make sure registrations are cleaned up when they are unregistered. 242 TEST_F(ServiceWorkerStorageTest, Unregister) { 243 GURL pattern("http://www.example.com/*"); 244 245 bool called; 246 scoped_refptr<ServiceWorkerRegistration> registration; 247 storage_->Register(pattern, 248 GURL("http://www.example.com/service_worker.js"), 249 SaveRegistration(REGISTRATION_OK, &called, ®istration)); 250 251 ASSERT_FALSE(called); 252 base::RunLoop().RunUntilIdle(); 253 ASSERT_TRUE(called); 254 255 storage_->Unregister(pattern, SaveUnregistration(REGISTRATION_OK, &called)); 256 257 ASSERT_FALSE(called); 258 base::RunLoop().RunUntilIdle(); 259 ASSERT_TRUE(called); 260 261 ASSERT_TRUE(registration->HasOneRef()); 262 263 storage_->FindRegistrationForPattern( 264 pattern, 265 SaveFoundRegistration(false, REGISTRATION_OK, &called, ®istration)); 266 267 ASSERT_FALSE(called); 268 base::RunLoop().RunUntilIdle(); 269 ASSERT_TRUE(called); 270 271 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(NULL), registration); 272 } 273 274 // Make sure that when a new registration replaces an existing 275 // registration, that the old one is cleaned up. 276 TEST_F(ServiceWorkerStorageTest, RegisterNewScript) { 277 GURL pattern("http://www.example.com/*"); 278 279 bool called; 280 scoped_refptr<ServiceWorkerRegistration> old_registration; 281 storage_->Register( 282 pattern, 283 GURL("http://www.example.com/service_worker.js"), 284 SaveRegistration(REGISTRATION_OK, &called, &old_registration)); 285 286 ASSERT_FALSE(called); 287 base::RunLoop().RunUntilIdle(); 288 ASSERT_TRUE(called); 289 290 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern; 291 storage_->FindRegistrationForPattern( 292 pattern, 293 SaveFoundRegistration( 294 true, REGISTRATION_OK, &called, &old_registration_by_pattern)); 295 296 ASSERT_FALSE(called); 297 base::RunLoop().RunUntilIdle(); 298 ASSERT_TRUE(called); 299 300 ASSERT_EQ(old_registration, old_registration_by_pattern); 301 old_registration_by_pattern = NULL; 302 303 scoped_refptr<ServiceWorkerRegistration> new_registration; 304 storage_->Register( 305 pattern, 306 GURL("http://www.example.com/service_worker_new.js"), 307 SaveRegistration(REGISTRATION_OK, &called, &new_registration)); 308 309 ASSERT_FALSE(called); 310 base::RunLoop().RunUntilIdle(); 311 ASSERT_TRUE(called); 312 313 ASSERT_TRUE(old_registration->HasOneRef()); 314 315 ASSERT_NE(old_registration, new_registration); 316 317 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern; 318 storage_->FindRegistrationForPattern( 319 pattern, 320 SaveFoundRegistration(true, REGISTRATION_OK, &called, &new_registration)); 321 322 ASSERT_FALSE(called); 323 base::RunLoop().RunUntilIdle(); 324 ASSERT_TRUE(called); 325 326 ASSERT_NE(new_registration_by_pattern, old_registration); 327 } 328 329 // Make sure that when registering a duplicate pattern+script_url 330 // combination, that the same registration is used. 331 TEST_F(ServiceWorkerStorageTest, RegisterDuplicateScript) { 332 GURL pattern("http://www.example.com/*"); 333 GURL script_url("http://www.example.com/service_worker.js"); 334 335 bool called; 336 scoped_refptr<ServiceWorkerRegistration> old_registration; 337 storage_->Register( 338 pattern, 339 script_url, 340 SaveRegistration(REGISTRATION_OK, &called, &old_registration)); 341 342 ASSERT_FALSE(called); 343 base::RunLoop().RunUntilIdle(); 344 ASSERT_TRUE(called); 345 346 scoped_refptr<ServiceWorkerRegistration> old_registration_by_pattern; 347 storage_->FindRegistrationForPattern( 348 pattern, 349 SaveFoundRegistration( 350 true, REGISTRATION_OK, &called, &old_registration_by_pattern)); 351 ASSERT_FALSE(called); 352 base::RunLoop().RunUntilIdle(); 353 ASSERT_TRUE(called); 354 355 ASSERT_TRUE(old_registration_by_pattern); 356 357 scoped_refptr<ServiceWorkerRegistration> new_registration; 358 storage_->Register( 359 pattern, 360 script_url, 361 SaveRegistration(REGISTRATION_OK, &called, &new_registration)); 362 363 ASSERT_FALSE(called); 364 base::RunLoop().RunUntilIdle(); 365 ASSERT_TRUE(called); 366 367 ASSERT_EQ(old_registration, new_registration); 368 369 ASSERT_FALSE(old_registration->HasOneRef()); 370 371 scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern; 372 storage_->FindRegistrationForPattern( 373 pattern, 374 SaveFoundRegistration( 375 true, REGISTRATION_OK, &called, &new_registration_by_pattern)); 376 377 ASSERT_FALSE(called); 378 base::RunLoop().RunUntilIdle(); 379 ASSERT_TRUE(called); 380 381 ASSERT_EQ(new_registration, old_registration); 382 } 383 384 } // namespace content 385