diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-24 10:30:31 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-24 10:30:31 +0000 |
commit | 08b79a53cd703b5a4ebe45f7150cb89a7c03ab87 (patch) | |
tree | 86929e40673de4981a4ca19bf6a2f9185f8347ba /content/browser/service_worker | |
parent | 4b25517f5424c656b5ade5e3ccf900081163c1af (diff) | |
download | chromium_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')
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_ |