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 "base/basictypes.h"
      6 #include "base/run_loop.h"
      7 #include "base/stl_util.h"
      8 #include "content/browser/service_worker/embedded_worker_instance.h"
      9 #include "content/browser/service_worker/embedded_worker_registry.h"
     10 #include "content/browser/service_worker/embedded_worker_test_helper.h"
     11 #include "content/browser/service_worker/service_worker_context_core.h"
     12 #include "content/browser/service_worker/service_worker_context_wrapper.h"
     13 #include "content/common/service_worker/embedded_worker_messages.h"
     14 #include "content/public/test/test_browser_thread_bundle.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace content {
     19 
     20 static const int kRenderProcessId = 11;
     21 
     22 class EmbeddedWorkerInstanceTest : public testing::Test {
     23  protected:
     24   EmbeddedWorkerInstanceTest()
     25       : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
     26 
     27   virtual void SetUp() OVERRIDE {
     28     helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
     29   }
     30 
     31   virtual void TearDown() OVERRIDE {
     32     helper_.reset();
     33   }
     34 
     35   ServiceWorkerContextCore* context() { return helper_->context(); }
     36 
     37   EmbeddedWorkerRegistry* embedded_worker_registry() {
     38     DCHECK(context());
     39     return context()->embedded_worker_registry();
     40   }
     41 
     42   IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
     43 
     44   TestBrowserThreadBundle thread_bundle_;
     45   scoped_ptr<EmbeddedWorkerTestHelper> helper_;
     46 
     47   DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
     48 };
     49 
     50 static void SaveStatusAndCall(ServiceWorkerStatusCode* out,
     51                               const base::Closure& callback,
     52                               ServiceWorkerStatusCode status) {
     53   *out = status;
     54   callback.Run();
     55 }
     56 
     57 TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
     58   scoped_ptr<EmbeddedWorkerInstance> worker =
     59       embedded_worker_registry()->CreateWorker();
     60   EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
     61 
     62   const int embedded_worker_id = worker->embedded_worker_id();
     63   const int64 service_worker_version_id = 55L;
     64   const GURL scope("http://example.com/*");
     65   const GURL url("http://example.com/worker.js");
     66 
     67   // Simulate adding one process to the worker.
     68   helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
     69 
     70   // Start should succeed.
     71   ServiceWorkerStatusCode status;
     72   base::RunLoop run_loop;
     73   worker->Start(
     74       service_worker_version_id,
     75       scope,
     76       url,
     77       std::vector<int>(),
     78       base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     79   run_loop.Run();
     80   EXPECT_EQ(SERVICE_WORKER_OK, status);
     81   EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
     82   base::RunLoop().RunUntilIdle();
     83 
     84   // Worker started message should be notified (by EmbeddedWorkerTestHelper).
     85   EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
     86   EXPECT_EQ(kRenderProcessId, worker->process_id());
     87 
     88   // Stop the worker.
     89   EXPECT_EQ(SERVICE_WORKER_OK, worker->Stop());
     90   EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
     91   base::RunLoop().RunUntilIdle();
     92 
     93   // Worker stopped message should be notified (by EmbeddedWorkerTestHelper).
     94   EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
     95 
     96   // Verify that we've sent two messages to start and terminate the worker.
     97   ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
     98       EmbeddedWorkerMsg_StartWorker::ID));
     99   ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
    100       EmbeddedWorkerMsg_StopWorker::ID));
    101 }
    102 
    103 TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
    104   scoped_ptr<EmbeddedWorkerInstance> worker =
    105       embedded_worker_registry()->CreateWorker();
    106   EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
    107 
    108   const int64 service_worker_version_id = 55L;
    109   const GURL scope("http://example.com/*");
    110   const GURL url("http://example.com/worker.js");
    111 
    112   ServiceWorkerStatusCode status;
    113   base::RunLoop run_loop;
    114   // Begin starting the worker.
    115   std::vector<int> available_process;
    116   available_process.push_back(kRenderProcessId);
    117   worker->Start(
    118       service_worker_version_id,
    119       scope,
    120       url,
    121       available_process,
    122       base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
    123   // But destroy it before it gets a chance to complete.
    124   worker.reset();
    125   run_loop.Run();
    126   EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
    127 
    128   // Verify that we didn't send the message to start the worker.
    129   ASSERT_FALSE(
    130       ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID));
    131 }
    132 
    133 TEST_F(EmbeddedWorkerInstanceTest, SortProcesses) {
    134   scoped_ptr<EmbeddedWorkerInstance> worker =
    135       embedded_worker_registry()->CreateWorker();
    136   EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
    137 
    138   // Simulate adding processes to the worker.
    139   // Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs.
    140   const int embedded_worker_id = worker->embedded_worker_id();
    141   helper_->SimulateAddProcessToWorker(embedded_worker_id, 1);
    142   helper_->SimulateAddProcessToWorker(embedded_worker_id, 2);
    143   helper_->SimulateAddProcessToWorker(embedded_worker_id, 2);
    144   helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
    145   helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
    146   helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
    147 
    148   // Process 3 has the biggest # of references and it should be chosen.
    149   EXPECT_THAT(worker->SortProcesses(std::vector<int>()),
    150               testing::ElementsAre(3, 2, 1));
    151   EXPECT_EQ(-1, worker->process_id());
    152 
    153   // Argument processes are added to the existing set, but only for a single
    154   // call.
    155   std::vector<int> registering_processes;
    156   registering_processes.push_back(1);
    157   registering_processes.push_back(1);
    158   registering_processes.push_back(1);
    159   registering_processes.push_back(4);
    160   EXPECT_THAT(worker->SortProcesses(registering_processes),
    161               testing::ElementsAre(1, 3, 2, 4));
    162 
    163   EXPECT_THAT(worker->SortProcesses(std::vector<int>()),
    164               testing::ElementsAre(3, 2, 1));
    165 }
    166 
    167 }  // namespace content
    168