blob: 45b2f29dc7fdcdb8314f8bc1eefd3689c91c9bbd [file] [log] [blame]
// Copyright 2013 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 "base/basictypes.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/service_worker_context_core.h"
#include "content/common/service_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()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
virtual void SetUp() OVERRIDE {
context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL));
}
virtual void TearDown() OVERRIDE {
context_.reset();
}
EmbeddedWorkerRegistry* embedded_worker_registry() {
DCHECK(context_);
return context_->embedded_worker_registry();
}
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<ServiceWorkerContextCore> context_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
FakeSender fake_sender;
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");
// This fails as we have no available process yet.
EXPECT_FALSE(worker->Start(service_worker_version_id, url));
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);
// Start should succeed.
EXPECT_TRUE(worker->Start(service_worker_version_id, url));
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
// Simulate an upcall from embedded worker to notify that it's started.
worker->OnStarted(thread_id);
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());
// Simulate an upcall from embedded worker to notify that it's stopped.
worker->OnStopped();
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(ServiceWorkerMsg_StartWorker::ID, messages[0]->type());
ASSERT_EQ(ServiceWorkerMsg_TerminateWorker::ID, messages[1]->type());
}
TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
scoped_ptr<EmbeddedWorkerInstance> worker =
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);
// 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());
}
} // namespace content