Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Unified Diff: content/browser/service_worker/embedded_worker_instance_unittest.cc

Issue 1569773002: ServiceWorker: Make start worker sequence cancelable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix test failures Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/service_worker/embedded_worker_instance_unittest.cc
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 9aebb0d246d79af357fbcd5e464d69f66d3631ad..4de6c3b6b8793e0a2c828383eeb04425b9815835 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <utility>
+#include <vector>
#include "base/macros.h"
#include "base/run_loop.h"
@@ -24,13 +25,6 @@ namespace content {
namespace {
-void DestroyWorker(scoped_ptr<EmbeddedWorkerInstance> worker,
- ServiceWorkerStatusCode* out_status,
- ServiceWorkerStatusCode status) {
- *out_status = status;
- worker.reset();
-}
-
void SaveStatusAndCall(ServiceWorkerStatusCode* out,
const base::Closure& callback,
ServiceWorkerStatusCode status) {
@@ -46,14 +40,36 @@ class EmbeddedWorkerInstanceTest : public testing::Test,
EmbeddedWorkerInstanceTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
- stopped_ = true;
- stopped_old_status_ = old_status;
+ enum EventType {
+ PROCESS_ALLOCATED,
+ START_WORKER_MESSAGE_SENT,
+ STARTED,
+ STOPPED,
+ DETACHED,
+ };
+
+ struct EventLog {
+ EventType type;
+ EmbeddedWorkerInstance::Status status;
+ };
+
+ void RecordEvent(
+ EventType type,
+ EmbeddedWorkerInstance::Status status = EmbeddedWorkerInstance::STOPPED) {
+ EventLog log = {type, status};
+ events_.push_back(log);
}
+ void OnProcessAllocated() override { RecordEvent(PROCESS_ALLOCATED); }
+ void OnStartWorkerMessageSent() override {
+ RecordEvent(START_WORKER_MESSAGE_SENT);
+ }
+ void OnStarted() override { RecordEvent(STARTED); }
+ void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
+ RecordEvent(STOPPED, old_status);
+ }
void OnDetached(EmbeddedWorkerInstance::Status old_status) override {
- detached_ = true;
- detached_old_status_ = old_status;
+ RecordEvent(DETACHED, old_status);
}
bool OnMessageReceived(const IPC::Message& message) override { return false; }
@@ -86,17 +102,39 @@ class EmbeddedWorkerInstanceTest : public testing::Test,
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
- bool detached_ = false;
- EmbeddedWorkerInstance::Status detached_old_status_ =
- EmbeddedWorkerInstance::STOPPED;
- bool stopped_ = false;
- EmbeddedWorkerInstance::Status stopped_old_status_ =
- EmbeddedWorkerInstance::STOPPED;
+ std::vector<EventLog> events_;
private:
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
+// A helper to simulate the start worker sequence is stalled in a worker
+// process.
+class StalledInStartWorkerHelper : public EmbeddedWorkerTestHelper {
+ public:
+ StalledInStartWorkerHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+ ~StalledInStartWorkerHelper() override{};
+
+ void OnStartWorker(int embedded_worker_id,
+ int64_t service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url) override {
+ if (!use_default_behavior_) {
+ // Do nothing to simulate a stall in the worker process.
falken 2016/01/14 07:30:00 nit: The negatives and meaning of "default" are a
nhiroki 2016/01/14 08:43:40 Done.
+ return;
+ }
+ EmbeddedWorkerTestHelper::OnStartWorker(
+ embedded_worker_id, service_worker_version_id, scope, script_url);
+ }
+
+ void set_use_default_behavior(bool use_default_behavior) {
+ use_default_behavior_ = use_default_behavior;
+ }
+
+ private:
+ bool use_default_behavior_ = false;
+};
+
class FailToSendIPCHelper : public EmbeddedWorkerTestHelper {
public:
FailToSendIPCHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
@@ -254,58 +292,177 @@ TEST_F(EmbeddedWorkerInstanceTest, RemoveWorkerInSharedProcess) {
worker2->Stop();
}
-// Test detaching in the middle of the start worker sequence.
-TEST_F(EmbeddedWorkerInstanceTest, DetachDuringStart) {
+TEST_F(EmbeddedWorkerInstanceTest, DetachDuringProcessAllocation) {
+ const int64_t version_id = 55L;
+ const GURL scope("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
worker->AddListener(this);
- scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
- new EmbeddedWorkerMsg_StartWorker_Params());
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ // Run the start worker sequence and detach during process allocation.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ worker->Start(
+ version_id, scope, url,
+ base::Bind(&SaveStatusAndCall, &status, base::Bind(&base::DoNothing)));
+ worker->Detach();
+ base::RunLoop().RunUntilIdle();
- // Pretend the worker got stopped before the start sequence reached
- // SendStartWorker.
- worker->status_ = EmbeddedWorkerInstance::STOPPED;
- base::RunLoop run_loop;
- worker->SendStartWorker(
- std::move(params),
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()),
- true /* is_new_process */, MSG_ROUTING_NONE,
- false /* wait_for_debugger */);
- run_loop.Run();
- EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
- // Don't expect SendStartWorker() to dispatch an OnStopped/Detached() message
- // since the worker was already stopped.
- EXPECT_FALSE(stopped_);
- EXPECT_FALSE(detached_);
-
- // Repeat, this time have the start callback destroy the worker, as is
- // usual when starting a worker fails, and ensure a crash doesn't occur.
- worker->status_ = EmbeddedWorkerInstance::STOPPED;
- EmbeddedWorkerInstance* worker_ptr = worker.get();
- worker_ptr->SendStartWorker(
- std::move(params),
- base::Bind(&DestroyWorker, base::Passed(&worker), &status),
- true /* is_new_process */, MSG_ROUTING_NONE,
- false /* wait_for_debugger */);
- // No crash.
- EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+ EXPECT_EQ(ChildProcessHost::kInvalidUniqueID, worker->process_id());
+
+ // The start callback should not be aborted by detach (see a comment on the
+ // dtor of EmbeddedWorkerInstance::StartTask).
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+
+ // "PROCESS_ALLOCATED" event should not be recorded.
+ ASSERT_EQ(1u, events_.size());
+ EXPECT_EQ(DETACHED, events_[0].type);
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, events_[0].status);
}
-// Test stopping in the middle of the start worker sequence, before
-// a process is allocated.
-TEST_F(EmbeddedWorkerInstanceTest, StopDuringStart) {
+TEST_F(EmbeddedWorkerInstanceTest, DetachAfterSendingStartWorkerMessage) {
+ const int64_t version_id = 55L;
+ const GURL scope("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ helper_.reset(new StalledInStartWorkerHelper());
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
worker->AddListener(this);
- // Pretend we stop during starting before we got a process allocated.
- worker->status_ = EmbeddedWorkerInstance::STARTING;
- worker->process_id_ = ChildProcessHost::kInvalidUniqueID;
+
+ // Run the start worker sequence until a start worker message is sent.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ worker->Start(
+ version_id, scope, url,
+ base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(2u, events_.size());
+ EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+ EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
+ events_.clear();
+
+ worker->Detach();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+ EXPECT_EQ(ChildProcessHost::kInvalidUniqueID, worker->process_id());
+
+ // The start callback should not be aborted by detach (see a comment on the
+ // dtor of EmbeddedWorkerInstance::StartTask).
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+
+ // "STARTED" event should not be recorded.
+ ASSERT_EQ(1u, events_.size());
+ EXPECT_EQ(DETACHED, events_[0].type);
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, events_[0].status);
+}
+
+TEST_F(EmbeddedWorkerInstanceTest, StopDuringProcessAllocation) {
+ const int64_t version_id = 55L;
+ const GURL scope("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ worker->AddListener(this);
+
+ // Stop the start worker sequence before a process is allocated.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ worker->Start(
+ version_id, scope, url,
+ base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
worker->Stop();
+ base::RunLoop().RunUntilIdle();
+
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
- EXPECT_TRUE(detached_);
- EXPECT_EQ(EmbeddedWorkerInstance::STARTING, detached_old_status_);
+ EXPECT_EQ(ChildProcessHost::kInvalidUniqueID, worker->process_id());
+
+ // The start callback should not be aborted by stop (see a comment on the dtor
+ // of EmbeddedWorkerInstance::StartTask).
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+
+ // "PROCESS_ALLOCATED" event should not be recorded.
+ ASSERT_EQ(1u, events_.size());
+ EXPECT_EQ(DETACHED, events_[0].type);
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, events_[0].status);
+ events_.clear();
+
+ // Restart the worker.
+ status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
+ worker->Start(version_id, scope, url, base::Bind(&SaveStatusAndCall, &status,
+ run_loop->QuitClosure()));
+ run_loop->Run();
+
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ ASSERT_EQ(3u, events_.size());
+ EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+ EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
+ EXPECT_EQ(STARTED, events_[2].type);
+
+ // Tear down the worker.
+ worker->Stop();
+}
+
+TEST_F(EmbeddedWorkerInstanceTest, StopAfterSendingStartWorkerMessage) {
+ const int64_t version_id = 55L;
+ const GURL scope("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ StalledInStartWorkerHelper* helper_ptr = new StalledInStartWorkerHelper;
+ helper_.reset(helper_ptr);
falken 2016/01/14 07:30:00 Is there a reason to introduce the helper_ptr vari
nhiroki 2016/01/14 08:43:40 "helper_" is not StalledInStartWorkerHelper but Em
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ worker->AddListener(this);
+
+ // Run the start worker sequence until a start worker message is sent.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ worker->Start(
+ version_id, scope, url,
+ base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(2u, events_.size());
+ EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+ EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
+ events_.clear();
+
+ worker->Stop();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+ EXPECT_EQ(ChildProcessHost::kInvalidUniqueID, worker->process_id());
+
+ // The start callback should not be aborted by stop (see a comment on the dtor
+ // of EmbeddedWorkerInstance::StartTask).
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+
+ // "STARTED" event should not be recorded.
+ ASSERT_EQ(1u, events_.size());
+ EXPECT_EQ(STOPPED, events_[0].type);
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, events_[0].status);
+ events_.clear();
+
+ // Restart the worker.
+ helper_ptr->set_use_default_behavior(true);
+ status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
+ worker->Start(version_id, scope, url, base::Bind(&SaveStatusAndCall, &status,
+ run_loop->QuitClosure()));
+ run_loop->Run();
+
+ // The worker should be started.
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ ASSERT_EQ(3u, events_.size());
+ EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+ EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
+ EXPECT_EQ(STARTED, events_[2].type);
+
+ // Tear down the worker.
+ worker->Stop();
}
TEST_F(EmbeddedWorkerInstanceTest, Detach) {
@@ -362,8 +519,10 @@ TEST_F(EmbeddedWorkerInstanceTest, FailToSendStartIPC) {
// The callback should have run, and we should have got an OnStopped message.
EXPECT_EQ(SERVICE_WORKER_ERROR_IPC_FAILED, status);
- EXPECT_TRUE(stopped_);
- EXPECT_EQ(EmbeddedWorkerInstance::STARTING, stopped_old_status_);
+ ASSERT_EQ(2u, events_.size());
+ EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
+ EXPECT_EQ(STOPPED, events_[1].type);
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, events_[1].status);
}
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698