Home | History | Annotate | Download | only in service_worker
      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, &registration1));
    137   scoped_refptr<ServiceWorkerRegistration> registration2;
    138   storage_->FindRegistrationForDocument(
    139       GURL("http://www.example.com/"),
    140       SaveFoundRegistration(true, REGISTRATION_OK, &called, &registration2));
    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, &registration1));
    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, &registration2));
    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, &registration1));
    212   scoped_refptr<ServiceWorkerRegistration> registration2;
    213   storage_->FindRegistrationForDocument(
    214       GURL("http://www.example.com/two/"),
    215       SaveFoundRegistration(true, REGISTRATION_OK, &called2, &registration2));
    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, &registration));
    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, &registration));
    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, &registration));
    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