1 // Copyright 2014 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 "base/basictypes.h" 6 #include "base/memory/weak_ptr.h" 7 #include "content/browser/service_worker/service_worker_context_core.h" 8 #include "content/browser/service_worker/service_worker_provider_host.h" 9 #include "content/browser/service_worker/service_worker_register_job.h" 10 #include "content/browser/service_worker/service_worker_registration.h" 11 #include "content/browser/service_worker/service_worker_version.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 static const int kRenderProcessId = 33; // Dummy process ID for testing. 18 19 class ServiceWorkerProviderHostTest : public testing::Test { 20 protected: 21 ServiceWorkerProviderHostTest() 22 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} 23 virtual ~ServiceWorkerProviderHostTest() {} 24 25 virtual void SetUp() OVERRIDE { 26 context_.reset( 27 new ServiceWorkerContextCore(base::FilePath(), 28 base::MessageLoopProxy::current(), 29 base::MessageLoopProxy::current(), 30 NULL, 31 NULL, 32 NULL)); 33 34 scope_ = GURL("http://www.example.com/*"); 35 script_url_ = GURL("http://www.example.com/service_worker.js"); 36 registration_ = new ServiceWorkerRegistration( 37 scope_, script_url_, 1L, context_->AsWeakPtr()); 38 version_ = new ServiceWorkerVersion( 39 registration_, 40 1L, context_->AsWeakPtr()); 41 42 // Prepare provider hosts (for the same process). 43 scoped_ptr<ServiceWorkerProviderHost> host1(new ServiceWorkerProviderHost( 44 kRenderProcessId, 1 /* provider_id */, 45 context_->AsWeakPtr(), NULL)); 46 scoped_ptr<ServiceWorkerProviderHost> host2(new ServiceWorkerProviderHost( 47 kRenderProcessId, 2 /* provider_id */, 48 context_->AsWeakPtr(), NULL)); 49 scoped_ptr<ServiceWorkerProviderHost> host3(new ServiceWorkerProviderHost( 50 kRenderProcessId, 3 /* provider_id */, 51 context_->AsWeakPtr(), NULL)); 52 provider_host1_ = host1->AsWeakPtr(); 53 provider_host2_ = host2->AsWeakPtr(); 54 provider_host3_ = host3->AsWeakPtr(); 55 context_->AddProviderHost(make_scoped_ptr(host1.release())); 56 context_->AddProviderHost(make_scoped_ptr(host2.release())); 57 context_->AddProviderHost(make_scoped_ptr(host3.release())); 58 } 59 60 virtual void TearDown() OVERRIDE { 61 version_ = 0; 62 registration_ = 0; 63 context_.reset(); 64 } 65 66 content::TestBrowserThreadBundle thread_bundle_; 67 scoped_ptr<ServiceWorkerContextCore> context_; 68 scoped_refptr<ServiceWorkerRegistration> registration_; 69 scoped_refptr<ServiceWorkerVersion> version_; 70 base::WeakPtr<ServiceWorkerProviderHost> provider_host1_; 71 base::WeakPtr<ServiceWorkerProviderHost> provider_host2_; 72 base::WeakPtr<ServiceWorkerProviderHost> provider_host3_; 73 GURL scope_; 74 GURL script_url_; 75 76 private: 77 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostTest); 78 }; 79 80 TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_ProcessStatus) { 81 ASSERT_FALSE(version_->HasProcessToRun()); 82 83 // Associating version_ to a provider_host's active version will internally 84 // add the provider_host's process ref to the version. 85 provider_host1_->SetActiveVersion(version_); 86 ASSERT_TRUE(version_->HasProcessToRun()); 87 88 // Re-associating the same version and provider_host should just work too. 89 provider_host1_->SetActiveVersion(version_); 90 ASSERT_TRUE(version_->HasProcessToRun()); 91 92 // Resetting the provider_host's active version should remove process refs 93 // from the version. 94 provider_host1_->SetActiveVersion(NULL); 95 ASSERT_FALSE(version_->HasProcessToRun()); 96 } 97 98 TEST_F(ServiceWorkerProviderHostTest, 99 SetActiveVersion_MultipleHostsForSameProcess) { 100 ASSERT_FALSE(version_->HasProcessToRun()); 101 102 // Associating version_ to two providers as active version. 103 provider_host1_->SetActiveVersion(version_); 104 provider_host2_->SetActiveVersion(version_); 105 ASSERT_TRUE(version_->HasProcessToRun()); 106 107 // Disassociating one provider_host shouldn't remove all process refs 108 // from the version yet. 109 provider_host1_->SetActiveVersion(NULL); 110 ASSERT_TRUE(version_->HasProcessToRun()); 111 112 // Disassociating the other provider_host will remove all process refs. 113 provider_host2_->SetActiveVersion(NULL); 114 ASSERT_FALSE(version_->HasProcessToRun()); 115 } 116 117 TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_ProcessStatus) { 118 ASSERT_FALSE(version_->HasProcessToRun()); 119 120 // Associating version_ to a provider_host's waiting version will internally 121 // add the provider_host's process ref to the version. 122 provider_host1_->SetWaitingVersion(version_); 123 ASSERT_TRUE(version_->HasProcessToRun()); 124 125 // Re-associating the same version and provider_host should just work too. 126 provider_host1_->SetWaitingVersion(version_); 127 ASSERT_TRUE(version_->HasProcessToRun()); 128 129 // Resetting the provider_host's waiting version should remove process refs 130 // from the version. 131 provider_host1_->SetWaitingVersion(NULL); 132 ASSERT_FALSE(version_->HasProcessToRun()); 133 } 134 135 TEST_F(ServiceWorkerProviderHostTest, 136 SetWaitingVersion_MultipleHostsForSameProcess) { 137 ASSERT_FALSE(version_->HasProcessToRun()); 138 139 // Associating version_ to two providers as active version. 140 provider_host1_->SetWaitingVersion(version_); 141 provider_host2_->SetWaitingVersion(version_); 142 ASSERT_TRUE(version_->HasProcessToRun()); 143 144 // Disassociating one provider_host shouldn't remove all process refs 145 // from the version yet. 146 provider_host1_->SetWaitingVersion(NULL); 147 ASSERT_TRUE(version_->HasProcessToRun()); 148 149 // Disassociating the other provider_host will remove all process refs. 150 provider_host2_->SetWaitingVersion(NULL); 151 ASSERT_FALSE(version_->HasProcessToRun()); 152 } 153 154 class ServiceWorkerProviderHostWaitingVersionTest : public testing::Test { 155 protected: 156 ServiceWorkerProviderHostWaitingVersionTest() 157 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), 158 next_provider_id_(1L) {} 159 virtual ~ServiceWorkerProviderHostWaitingVersionTest() {} 160 161 virtual void SetUp() OVERRIDE { 162 context_.reset( 163 new ServiceWorkerContextCore(base::FilePath(), 164 base::MessageLoopProxy::current(), 165 base::MessageLoopProxy::current(), 166 NULL, 167 NULL, 168 NULL)); 169 170 // Prepare provider hosts (for the same process). 171 provider_host1_ = CreateProviderHost(GURL("http://www.example.com/foo")); 172 provider_host2_ = CreateProviderHost(GURL("http://www.example.com/bar")); 173 provider_host3_ = CreateProviderHost(GURL("http://www.example.ca/foo")); 174 } 175 176 base::WeakPtr<ServiceWorkerProviderHost> CreateProviderHost( 177 const GURL& document_url) { 178 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 179 kRenderProcessId, next_provider_id_++, context_->AsWeakPtr(), NULL)); 180 host->SetDocumentUrl(document_url); 181 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 182 context_->AddProviderHost(host.Pass()); 183 return provider_host; 184 } 185 186 virtual void TearDown() OVERRIDE { 187 context_.reset(); 188 } 189 190 content::TestBrowserThreadBundle thread_bundle_; 191 scoped_ptr<ServiceWorkerContextCore> context_; 192 base::WeakPtr<ServiceWorkerProviderHost> provider_host1_; 193 base::WeakPtr<ServiceWorkerProviderHost> provider_host2_; 194 base::WeakPtr<ServiceWorkerProviderHost> provider_host3_; 195 196 private: 197 int64 next_provider_id_; 198 199 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostWaitingVersionTest); 200 }; 201 202 TEST_F(ServiceWorkerProviderHostWaitingVersionTest, 203 AssociateWaitingVersionToDocuments) { 204 const GURL scope1("http://www.example.com/*"); 205 const GURL script_url1("http://www.example.com/service_worker1.js"); 206 scoped_refptr<ServiceWorkerRegistration> registration1( 207 new ServiceWorkerRegistration( 208 scope1, script_url1, 1L, context_->AsWeakPtr())); 209 scoped_refptr<ServiceWorkerVersion> version1( 210 new ServiceWorkerVersion(registration1, 1L, context_->AsWeakPtr())); 211 212 ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments( 213 context_->AsWeakPtr(), version1.get()); 214 EXPECT_EQ(version1.get(), provider_host1_->waiting_version()); 215 EXPECT_EQ(version1.get(), provider_host2_->waiting_version()); 216 EXPECT_EQ(NULL, provider_host3_->waiting_version()); 217 218 // Version2 is associated with the same registration as version1, so the 219 // waiting version of host1 and host2 should be replaced. 220 scoped_refptr<ServiceWorkerVersion> version2( 221 new ServiceWorkerVersion(registration1, 2L, context_->AsWeakPtr())); 222 ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments( 223 context_->AsWeakPtr(), version2.get()); 224 EXPECT_EQ(version2.get(), provider_host1_->waiting_version()); 225 EXPECT_EQ(version2.get(), provider_host2_->waiting_version()); 226 EXPECT_EQ(NULL, provider_host3_->waiting_version()); 227 228 const GURL scope3(provider_host1_->document_url()); 229 const GURL script_url3("http://www.example.com/service_worker3.js"); 230 scoped_refptr<ServiceWorkerRegistration> registration3( 231 new ServiceWorkerRegistration( 232 scope3, script_url3, 3L, context_->AsWeakPtr())); 233 scoped_refptr<ServiceWorkerVersion> version3( 234 new ServiceWorkerVersion(registration3, 3L, context_->AsWeakPtr())); 235 236 // Although version3 can match longer than version2 for host1, it should be 237 // ignored because version3 is associated with a different registration from 238 // version2. 239 ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments( 240 context_->AsWeakPtr(), version3.get()); 241 EXPECT_EQ(version2.get(), provider_host1_->waiting_version()); 242 EXPECT_EQ(version2.get(), provider_host2_->waiting_version()); 243 EXPECT_EQ(NULL, provider_host3_->waiting_version()); 244 } 245 246 TEST_F(ServiceWorkerProviderHostWaitingVersionTest, 247 DisassociateWaitingVersionFromDocuments) { 248 const GURL scope1("http://www.example.com/*"); 249 const GURL script_url1("http://www.example.com/service_worker.js"); 250 scoped_refptr<ServiceWorkerRegistration> registration1( 251 new ServiceWorkerRegistration( 252 scope1, script_url1, 1L, context_->AsWeakPtr())); 253 scoped_refptr<ServiceWorkerVersion> version1( 254 new ServiceWorkerVersion(registration1, 1L, context_->AsWeakPtr())); 255 256 const GURL scope2("http://www.example.ca/*"); 257 const GURL script_url2("http://www.example.ca/service_worker.js"); 258 scoped_refptr<ServiceWorkerRegistration> registration2( 259 new ServiceWorkerRegistration( 260 scope2, script_url2, 2L, context_->AsWeakPtr())); 261 scoped_refptr<ServiceWorkerVersion> version2( 262 new ServiceWorkerVersion(registration2, 2L, context_->AsWeakPtr())); 263 264 ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments( 265 context_->AsWeakPtr(), version1.get()); 266 ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments( 267 context_->AsWeakPtr(), version2.get()); 268 269 // Host1 and host2 are associated with version1 as a waiting version, whereas 270 // host3 is associated with version2. 271 EXPECT_EQ(version1.get(), provider_host1_->waiting_version()); 272 EXPECT_EQ(version1.get(), provider_host2_->waiting_version()); 273 EXPECT_EQ(version2.get(), provider_host3_->waiting_version()); 274 275 // Disassociate version1 from host1 and host2. 276 ServiceWorkerRegisterJob::DisassociateWaitingVersionFromDocuments( 277 context_->AsWeakPtr(), version1->version_id()); 278 EXPECT_EQ(NULL, provider_host1_->waiting_version()); 279 EXPECT_EQ(NULL, provider_host2_->waiting_version()); 280 EXPECT_EQ(version2.get(), provider_host3_->waiting_version()); 281 } 282 283 } // namespace content 284