summaryrefslogtreecommitdiffstats
path: root/content/browser/service_worker
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-24 10:30:31 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-24 10:30:31 +0000
commit08b79a53cd703b5a4ebe45f7150cb89a7c03ab87 (patch)
tree86929e40673de4981a4ca19bf6a2f9185f8347ba /content/browser/service_worker
parent4b25517f5424c656b5ade5e3ccf900081163c1af (diff)
downloadchromium_src-08b79a53cd703b5a4ebe45f7150cb89a7c03ab87.zip
chromium_src-08b79a53cd703b5a4ebe45f7150cb89a7c03ab87.tar.gz
chromium_src-08b79a53cd703b5a4ebe45f7150cb89a7c03ab87.tar.bz2
In-process EmbeddedWorker test helper
Testing starting/stopping EmbeddedWorker without creating a child process is not very easy, so I've implemented a test helper class that can be used for in-process EW tests, and revised EmbeddedWorkerInstanceTest to use the helper so that how it can be used becomes clear. The EmbeddedWorkerTestHelper class does: - Record IPC messages sent via EmbeddedWorkerRegistry - Provide customizable methods to respond to StartWorker/StopWorker/MessageToWorker messages Depends on SW/EW separation patch (https://codereview.chromium.org/140893002/) This patch doesn't include install flow yet. BUG=313530 TEST=EmbeddedWorkerInstanceTest.* TBR=jam Review URL: https://codereview.chromium.org/138903005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246834 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/service_worker')
-rw-r--r--content/browser/service_worker/embedded_worker_instance_unittest.cc80
-rw-r--r--content/browser/service_worker/embedded_worker_registry.cc8
-rw-r--r--content/browser/service_worker/embedded_worker_registry.h3
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.cc155
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.h104
5 files changed, 298 insertions, 52 deletions
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index d6fcfb0..a08809f 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -3,44 +3,18 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/run_loop.h"
#include "base/stl_util.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/public/test/test_browser_thread_bundle.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_sender.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
-namespace {
-
-typedef std::vector<IPC::Message*> MessageList;
-
-class FakeSender : public IPC::Sender {
- public:
- FakeSender() {}
- virtual ~FakeSender() {
- STLDeleteContainerPointers(sent_messages_.begin(), sent_messages_.end());
- }
-
- // IPC::Sender implementation.
- virtual bool Send(IPC::Message* message) OVERRIDE {
- sent_messages_.push_back(message);
- return true;
- }
-
- const MessageList& sent_messages() { return sent_messages_; }
-
- private:
- MessageList sent_messages_;
- DISALLOW_COPY_AND_ASSIGN(FakeSender);
-};
-
-} // namespace
-
class EmbeddedWorkerInstanceTest : public testing::Test {
protected:
EmbeddedWorkerInstanceTest()
@@ -48,9 +22,11 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
virtual void SetUp() OVERRIDE {
context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL));
+ helper_.reset(new EmbeddedWorkerTestHelper(context_.get()));
}
virtual void TearDown() OVERRIDE {
+ helper_.reset();
context_.reset();
}
@@ -59,8 +35,11 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
return context_->embedded_worker_registry();
}
+ IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
+
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<ServiceWorkerContextCore> context_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
@@ -70,9 +49,8 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
embedded_worker_registry()->CreateWorker();
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
- FakeSender fake_sender;
+ const int embedded_worker_id = worker->embedded_worker_id();
const int process_id = 11;
- const int thread_id = 33;
const int64 service_worker_version_id = 55L;
const GURL url("http://example.com/worker.js");
@@ -81,32 +59,30 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
// Simulate adding one process to the worker.
- worker->AddProcessReference(process_id);
- embedded_worker_registry()->AddChildProcessSender(process_id, &fake_sender);
+ helper_->SimulateAddProcess(embedded_worker_id, process_id);
// Start should succeed.
EXPECT_TRUE(worker->Start(service_worker_version_id, url));
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
+ base::RunLoop().RunUntilIdle();
- // Simulate an upcall from embedded worker to notify that it's started.
- worker->OnStarted(thread_id);
+ // Worker started message should be notified (by EmbeddedWorkerTestHelper).
EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
EXPECT_EQ(process_id, worker->process_id());
- EXPECT_EQ(thread_id, worker->thread_id());
// Stop the worker.
EXPECT_TRUE(worker->Stop());
EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
+ base::RunLoop().RunUntilIdle();
- // Simulate an upcall from embedded worker to notify that it's stopped.
- worker->OnStopped();
+ // Worker stopped message should be notified (by EmbeddedWorkerTestHelper).
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
// Verify that we've sent two messages to start and terminate the worker.
- const MessageList& messages = fake_sender.sent_messages();
- ASSERT_EQ(2U, messages.size());
- ASSERT_EQ(EmbeddedWorkerMsg_StartWorker::ID, messages[0]->type());
- ASSERT_EQ(EmbeddedWorkerMsg_StopWorker::ID, messages[1]->type());
+ ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
+ EmbeddedWorkerMsg_StartWorker::ID));
+ ASSERT_TRUE(ipc_sink()->GetUniqueMessageMatching(
+ EmbeddedWorkerMsg_StopWorker::ID));
}
TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
@@ -114,24 +90,24 @@ TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
embedded_worker_registry()->CreateWorker();
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
- FakeSender fake_sender;
-
// Simulate adding processes to the worker.
// Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs.
- worker->AddProcessReference(1);
- worker->AddProcessReference(2);
- worker->AddProcessReference(2);
- worker->AddProcessReference(3);
- worker->AddProcessReference(3);
- worker->AddProcessReference(3);
- embedded_worker_registry()->AddChildProcessSender(1, &fake_sender);
- embedded_worker_registry()->AddChildProcessSender(2, &fake_sender);
- embedded_worker_registry()->AddChildProcessSender(3, &fake_sender);
+ const int embedded_worker_id = worker->embedded_worker_id();
+ helper_->SimulateAddProcess(embedded_worker_id, 1);
+ helper_->SimulateAddProcess(embedded_worker_id, 2);
+ helper_->SimulateAddProcess(embedded_worker_id, 2);
+ helper_->SimulateAddProcess(embedded_worker_id, 3);
+ helper_->SimulateAddProcess(embedded_worker_id, 3);
+ helper_->SimulateAddProcess(embedded_worker_id, 3);
// Process 3 has the biggest # of references and it should be chosen.
EXPECT_TRUE(worker->Start(1L, GURL("http://example.com/worker.js")));
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
EXPECT_EQ(3, worker->process_id());
+
+ // Wait until started message is sent back.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
}
} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc
index fab3172..d939cfb 100644
--- a/content/browser/service_worker/embedded_worker_registry.cc
+++ b/content/browser/service_worker/embedded_worker_registry.cc
@@ -97,6 +97,14 @@ void EmbeddedWorkerRegistry::RemoveChildProcessSender(int process_id) {
}
}
+EmbeddedWorkerInstance* EmbeddedWorkerRegistry::GetWorker(
+ int embedded_worker_id) {
+ WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
+ if (found == worker_map_.end())
+ return NULL;
+ return found->second;
+}
+
EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {}
bool EmbeddedWorkerRegistry::Send(int process_id, IPC::Message* message) {
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h
index d9c9d96..43efaa6 100644
--- a/content/browser/service_worker/embedded_worker_registry.h
+++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -59,6 +59,9 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
void AddChildProcessSender(int process_id, IPC::Sender* sender);
void RemoveChildProcessSender(int process_id);
+ // Returns an embedded worker instance for given |embedded_worker_id|.
+ EmbeddedWorkerInstance* GetWorker(int embedded_worker_id);
+
private:
friend class base::RefCounted<EmbeddedWorkerRegistry>;
friend class EmbeddedWorkerInstance;
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
new file mode 100644
index 0000000..267ba4f2
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -0,0 +1,155 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+
+#include "base/bind.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
+ ServiceWorkerContextCore* context)
+ : context_(context->AsWeakPtr()),
+ next_thread_id_(0),
+ weak_factory_(this) {
+}
+
+EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
+}
+
+void EmbeddedWorkerTestHelper::SimulateAddProcess(
+ int embedded_worker_id,
+ int process_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker);
+ registry()->AddChildProcessSender(process_id, this);
+ worker->AddProcessReference(process_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateRemoveProcess(
+ int embedded_worker_id, int process_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker);
+ registry()->RemoveChildProcessSender(process_id);
+ worker->ReleaseProcessReference(process_id);
+}
+
+bool EmbeddedWorkerTestHelper::Send(IPC::Message* message) {
+ OnMessageReceived(*message);
+ delete message;
+ return true;
+}
+
+bool EmbeddedWorkerTestHelper::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerTestHelper, message)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_StartWorker, OnStartWorkerStub)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_StopWorker, OnStopWorkerStub)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerContextMsg_SendMessageToWorker,
+ OnSendMessageToWorkerStub)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ // IPC::TestSink only records messages that are not handled by filters,
+ // so we just forward all messages to the separate sink.
+ sink_.OnMessageReceived(message);
+
+ return handled;
+}
+
+void EmbeddedWorkerTestHelper::OnStartWorker(
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url) {
+ // By default just notify the sender that the worker is started.
+ SimulateWorkerStarted(next_thread_id_++, embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::OnStopWorker(int embedded_worker_id) {
+ // By default just notify the sender that the worker is stopped.
+ SimulateWorkerStopped(embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::OnSendMessageToWorker(
+ int thread_id,
+ int embedded_worker_id,
+ const IPC::Message& message) {
+ // Do nothing on the message by default.
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerStarted(
+ int thread_id, int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ registry()->OnWorkerStarted(
+ worker->process_id(),
+ thread_id,
+ embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerStopped(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateSendMessageToBrowser(
+ int embedded_worker_id, const IPC::Message& message) {
+ registry()->OnSendMessageToBrowser(embedded_worker_id, message);
+}
+
+void EmbeddedWorkerTestHelper::OnStartWorkerStub(
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EmbeddedWorkerTestHelper::OnStartWorker,
+ weak_factory_.GetWeakPtr(),
+ embedded_worker_id,
+ service_worker_version_id,
+ script_url));
+}
+
+void EmbeddedWorkerTestHelper::OnStopWorkerStub(int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EmbeddedWorkerTestHelper::OnStopWorker,
+ weak_factory_.GetWeakPtr(),
+ embedded_worker_id));
+}
+
+void EmbeddedWorkerTestHelper::OnSendMessageToWorkerStub(
+ int thread_id,
+ int embedded_worker_id,
+ const IPC::Message& message) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ EXPECT_EQ(worker->thread_id(), thread_id);
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EmbeddedWorkerTestHelper::OnSendMessageToWorker,
+ weak_factory_.GetWeakPtr(),
+ thread_id,
+ embedded_worker_id,
+ message));
+}
+
+EmbeddedWorkerRegistry* EmbeddedWorkerTestHelper::registry() {
+ DCHECK(context_);
+ return context_->embedded_worker_registry();
+}
+
+} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
new file mode 100644
index 0000000..5fafc5e
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -0,0 +1,104 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_TEST_HELPER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_TEST_HELPER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_test_sink.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class GURL;
+
+namespace content {
+
+class EmbeddedWorkerRegistry;
+class EmbeddedWorkerTestHelper;
+class ServiceWorkerContextCore;
+
+// In-Process EmbeddedWorker test helper.
+//
+// Create an instance of this class for a ServiceWorkerContextCore,
+// set up process association by calling Simulate{Add,Remove}Process
+// and test to interact with an embedded worker without creating
+// a child process.
+//
+// By default this class just notifies back WorkerStarted and WorkerStopped
+// for StartWorker and StopWorker requests, and ignores any messages sent
+// to the worker.
+//
+// Alternatively consumers can subclass this helper and override
+// OnStartWorker(), OnStopWorker() and OnSendMessageToWorker() to add
+// their own logic/verification code.
+//
+// See embedded_worker_instance_unittest.cc for example usages.
+//
+class EmbeddedWorkerTestHelper : public IPC::Sender,
+ public IPC::Listener {
+ public:
+ EmbeddedWorkerTestHelper(ServiceWorkerContextCore* context);
+ virtual ~EmbeddedWorkerTestHelper();
+
+ // Call this to simulate add/associate a process to a worker.
+ void SimulateAddProcess(int embedded_worker_id, int process_id);
+ void SimulateRemoveProcess(int embedded_worker_id, int process_id);
+
+ // IPC::Sender implementation.
+ virtual bool Send(IPC::Message* message) OVERRIDE;
+
+ // IPC::Listener implementation.
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+
+ IPC::TestSink* ipc_sink() { return &sink_; }
+
+ protected:
+ // Called when StartWorker, StopWorker and SendMessageToWorker message
+ // is sent to the embedded worker. Override if necessary. By default
+ // they verify given parameters and:
+ // - call SimulateWorkerStarted for OnStartWorker
+ // - call SimulateWorkerStoped for OnStopWorker
+ // - do nothing for OnSendMessageToWorker
+ virtual void OnStartWorker(int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url);
+ virtual void OnStopWorker(int embedded_worker_id);
+ virtual void OnSendMessageToWorker(int thread_id,
+ int embedded_worker_id,
+ const IPC::Message& message);
+
+ // Call this to simulate sending WorkerStarted, WorkerStopped and
+ // SendMessageToBrowser to the browser.
+ void SimulateWorkerStarted(int thread_id, int embedded_worker_id);
+ void SimulateWorkerStopped(int embedded_worker_id);
+ void SimulateSendMessageToBrowser(int embedded_worker_id,
+ const IPC::Message& message);
+
+ private:
+ void OnStartWorkerStub(int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url);
+ void OnStopWorkerStub(int embedded_worker_id);
+ void OnSendMessageToWorkerStub(int thread_id,
+ int embedded_worker_id,
+ const IPC::Message& message);
+
+ EmbeddedWorkerRegistry* registry();
+
+ base::WeakPtr<ServiceWorkerContextCore> context_;
+ IPC::TestSink sink_;
+ int next_thread_id_;
+ std::vector<IPC::Message> messages_;
+ base::WeakPtrFactory<EmbeddedWorkerTestHelper> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerTestHelper);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_TEST_HELPER_H_