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

Side by Side Diff: third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp

Issue 2011763002: Worker: Attempt to gracefully terminate WorkerThread as much as possible (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@reorder_functions
Patch Set: fix test expectations Created 4 years, 6 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/workers/WorkerThread.h" 5 #include "core/workers/WorkerThread.h"
6 6
7 #include "core/workers/WorkerThreadTestHelper.h" 7 #include "core/workers/WorkerThreadTestHelper.h"
8 #include "public/platform/WebScheduler.h" 8 #include "platform/testing/UnitTestHelpers.h"
9 #include "testing/gmock/include/gmock/gmock.h" 9 #include "testing/gmock/include/gmock/gmock.h"
10 #include "testing/gtest/include/gtest/gtest.h" 10 #include "testing/gtest/include/gtest/gtest.h"
11 11
12 using testing::_; 12 using testing::_;
13 using testing::AtMost; 13 using testing::AtMost;
14 using testing::Invoke;
15 using testing::Return;
16 using testing::Mock;
17 14
18 namespace blink { 15 namespace blink {
19 16
20 class WorkerThreadTest : public testing::Test { 17 class WorkerThreadTest : public ::testing::Test {
21 public: 18 public:
22 void SetUp() override 19 void SetUp() override
23 { 20 {
24 m_mockWorkerLoaderProxyProvider = adoptPtr(new MockWorkerLoaderProxyProv ider()); 21 m_mockWorkerLoaderProxyProvider = adoptPtr(new MockWorkerLoaderProxyProv ider());
25 m_mockWorkerReportingProxy = adoptPtr(new MockWorkerReportingProxy()); 22 m_mockWorkerReportingProxy = adoptPtr(new MockWorkerReportingProxy());
26 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http:// fake.url/")); 23 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http:// fake.url/"));
27 m_workerThread = adoptPtr(new WorkerThreadForTest( 24 m_workerThread = adoptPtr(new WorkerThreadForTest(
28 m_mockWorkerLoaderProxyProvider.get(), 25 m_mockWorkerLoaderProxyProvider.get(),
29 *m_mockWorkerReportingProxy)); 26 *m_mockWorkerReportingProxy));
30 } 27 }
31 28
32 void TearDown() override 29 void TearDown() override
33 { 30 {
34 m_workerThread->workerLoaderProxy()->detachProvider(m_mockWorkerLoaderPr oxyProvider.get()); 31 m_workerThread->workerLoaderProxy()->detachProvider(m_mockWorkerLoaderPr oxyProvider.get());
35 } 32 }
36 33
37 void start() 34 void start()
38 { 35 {
39 startWithSourceCode("//fake source code"); 36 m_workerThread->startWithSourceCode(m_securityOrigin.get(), "//fake sour ce code");
40 } 37 }
41 38
42 void startWithSourceCode(const String& source) 39 void startWithSourceCodeNotToFinish()
43 { 40 {
44 m_workerThread->startWithSourceCode(m_securityOrigin.get(), source); 41 // Use a JavaScript source code that makes an infinite loop so that we
42 // can catch some kind of issues as a timeout.
43 m_workerThread->startWithSourceCode(m_securityOrigin.get(), "while(true) {}");
45 } 44 }
46 45
47 void waitForInit() 46 void waitForShutdown()
48 { 47 {
49 m_workerThread->waitForInit(); 48 m_workerThread->m_shutdownEvent->wait();
49 }
50
51 void setForceTerminationDelayInMs(long long forceTerminationDelayInMs)
52 {
53 m_workerThread->setForceTerminationDelayInMsForTesting(forceTerminationD elayInMs);
54 }
55
56 bool isForceTerminationTaskScheduled()
57 {
58 return m_workerThread->m_scheduledForceTerminationTask.get();
50 } 59 }
51 60
52 protected: 61 protected:
53 void expectWorkerLifetimeReportingCalls() 62 void expectReportingCalls()
54 { 63 {
55 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1); 64 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1);
56 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1); 65 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1);
57 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1); 66 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
58 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1); 67 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1);
59 } 68 }
60 69
70 void expectReportingCallsForWorkerPossiblyTerminatedBeforeStarting()
71 {
72 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(AtMost(1));
73 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(_)).Tim es(AtMost(1));
74 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
75 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(AtMost(1));
76 }
77
78 void expectReportingCallsForWorkerForciblyTerminated()
79 {
80 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1);
81 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(false)) .Times(1);
82 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
83 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1);
84 }
85
61 RefPtr<SecurityOrigin> m_securityOrigin; 86 RefPtr<SecurityOrigin> m_securityOrigin;
62 OwnPtr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider; 87 OwnPtr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider;
63 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy; 88 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy;
64 OwnPtr<WorkerThreadForTest> m_workerThread; 89 OwnPtr<WorkerThreadForTest> m_workerThread;
65 }; 90 };
66 91
67 TEST_F(WorkerThreadTest, StartAndStop) 92 TEST_F(WorkerThreadTest, StartAndTerminate_AsyncTerminate)
68 { 93 {
69 expectWorkerLifetimeReportingCalls(); 94 expectReportingCalls();
70 start(); 95 start();
71 waitForInit(); 96 m_workerThread->waitForInit();
72 m_workerThread->terminateAndWait(); 97
98 // The worker thread is not being blocked, so the worker thread should be
99 // gracefully shut down.
100 m_workerThread->terminate();
101 EXPECT_TRUE(isForceTerminationTaskScheduled());
102 waitForShutdown();
103 EXPECT_EQ(WorkerThread::ExitCode::GracefullyTerminated, m_workerThread->getE xitCode());
73 } 104 }
74 105
75 TEST_F(WorkerThreadTest, StartAndStopImmediately) 106 TEST_F(WorkerThreadTest, StartAndTerminate_SyncTerminate)
76 { 107 {
77 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)) 108 expectReportingCalls();
78 .Times(AtMost(1));
79 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(_))
80 .Times(AtMost(1));
81 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated())
82 .Times(AtMost(1));
83 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope())
84 .Times(AtMost(1));
85 start(); 109 start();
110 m_workerThread->waitForInit();
86 m_workerThread->terminateAndWait(); 111 m_workerThread->terminateAndWait();
112 EXPECT_EQ(WorkerThread::ExitCode::SyncForciblyTerminated, m_workerThread->ge tExitCode());
87 } 113 }
88 114
89 TEST_F(WorkerThreadTest, StartAndStopOnScriptLoaded) 115 TEST_F(WorkerThreadTest, StartAndTerminateImmediately_AsyncTerminate)
90 { 116 {
91 // Use a JavaScript source code that makes an infinite loop so that we can 117 expectReportingCallsForWorkerPossiblyTerminatedBeforeStarting();
92 // catch some kind of issues as a timeout. 118 start();
93 const String source("while(true) {}");
94 119
95 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)) 120 // There are two possible cases depending on timing:
96 .Times(AtMost(1)); 121 // (1) If the thread hasn't been initialized on the worker thread yet,
97 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(_)) 122 // terminate() should not attempt to shut down the thread.
98 .Times(AtMost(1)); 123 // (2) If the thread has already been initialized on the worker thread,
99 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()) 124 // terminate() should gracefully shut down the thread.
100 .Times(AtMost(1)); 125 m_workerThread->terminate();
101 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) 126 waitForShutdown();
102 .Times(AtMost(1)); 127 WorkerThread::ExitCode exitCode = m_workerThread->getExitCode();
103 startWithSourceCode(source); 128 EXPECT_TRUE(WorkerThread::ExitCode::TerminatedBeforeStarting == exitCode || WorkerThread::ExitCode::GracefullyTerminated == exitCode);
104 m_workerThread->waitUntilScriptLoaded();
105 m_workerThread->terminateAndWait();
106 } 129 }
107 130
131 TEST_F(WorkerThreadTest, StartAndTerminateImmediately_SyncTerminate)
132 {
133 expectReportingCallsForWorkerPossiblyTerminatedBeforeStarting();
134 start();
135
136 // There are two possible cases depending on timing:
137 // (1) If the thread hasn't been initialized on the worker thread yet,
138 // terminateAndWait() should not attempt to shut down the thread.
139 // (2) If the thread has already been initialized on the worker thread,
140 // terminateAndWait() should synchronously forcibly terminates the worker
141 // execution.
142 m_workerThread->terminateAndWait();
143 WorkerThread::ExitCode exitCode = m_workerThread->getExitCode();
144 EXPECT_TRUE(WorkerThread::ExitCode::TerminatedBeforeStarting == exitCode || WorkerThread::ExitCode::SyncForciblyTerminated == exitCode);
145 }
146
147 TEST_F(WorkerThreadTest, TerminateBeforeStart_AsyncTerminate)
148 {
149 expectReportingCallsForWorkerPossiblyTerminatedBeforeStarting();
150 m_workerThread->terminate();
151 EXPECT_EQ(WorkerThread::ExitCode::TerminatedBeforeStarting, m_workerThread-> getExitCode());
152 EXPECT_FALSE(isForceTerminationTaskScheduled());
153
154 // Sync termination requests after the thread is terminated should not block
155 // the main thread.
156 m_workerThread->terminateAndWait();
157 WorkerThread::terminateAndWaitForAllWorkers();
158 }
159
160 TEST_F(WorkerThreadTest, TerminateBeforeStart_SyncTerminate)
161 {
162 expectReportingCallsForWorkerPossiblyTerminatedBeforeStarting();
163
164 // Terminating the worker thread that hasn't started yet does not block the
165 // main thread.
166 m_workerThread->terminateAndWait();
167 EXPECT_EQ(WorkerThread::ExitCode::TerminatedBeforeStarting, m_workerThread-> getExitCode());
168
169 // Async termination request after the thread is terminated should not
170 // schedule a delayed task.
171 m_workerThread->terminate();
172 EXPECT_FALSE(isForceTerminationTaskScheduled());
173
174 // Sync termination requests after the thread is terminated should not block
175 // the main thread.
176 m_workerThread->terminateAndWait();
177 WorkerThread::terminateAndWaitForAllWorkers();
178 }
179
180 TEST_F(WorkerThreadTest, StartAndTerminateOnScriptLoaded_SyncForciblyTerminate)
181 {
182 expectReportingCallsForWorkerForciblyTerminated();
183 startWithSourceCodeNotToFinish();
184 m_workerThread->waitUntilScriptLoaded();
185
186 // terminateAndWait() synchronously terminates the worker execution.
187 m_workerThread->terminateAndWait();
188 EXPECT_EQ(WorkerThread::ExitCode::SyncForciblyTerminated, m_workerThread->ge tExitCode());
189 }
190
191 TEST_F(WorkerThreadTest, StartAndTerminateOnScriptLoaded_AsyncForciblyTerminate)
192 {
193 const long long kForceTerminationDelayInMs = 10;
194 setForceTerminationDelayInMs(kForceTerminationDelayInMs);
195
196 expectReportingCallsForWorkerForciblyTerminated();
197 startWithSourceCodeNotToFinish();
198 m_workerThread->waitUntilScriptLoaded();
199
200 // terminate() schedules a force termination task.
201 m_workerThread->terminate();
202 EXPECT_TRUE(isForceTerminationTaskScheduled());
203 EXPECT_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->getExitCode ());
204
205 // Wait until the force termination task runs.
206 testing::runDelayedTasks(kForceTerminationDelayInMs);
207 waitForShutdown();
208 EXPECT_EQ(WorkerThread::ExitCode::AsyncForciblyTerminated, m_workerThread->g etExitCode());
209 }
210
211 TEST_F(WorkerThreadTest, StartAndTerminateOnScriptLoaded_AsyncForciblyTerminate_ MultipleTimes)
212 {
213 const long long kForceTerminationDelayInMs = 10;
214 setForceTerminationDelayInMs(kForceTerminationDelayInMs);
215
216 expectReportingCallsForWorkerForciblyTerminated();
217 startWithSourceCodeNotToFinish();
218 m_workerThread->waitUntilScriptLoaded();
219
220 // terminate() schedules a force termination task.
221 m_workerThread->terminate();
222 EXPECT_TRUE(isForceTerminationTaskScheduled());
223 EXPECT_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->getExitCode ());
224
225 // Multiple terminate() calls should not take effect.
226 m_workerThread->terminate();
227 m_workerThread->terminate();
228 EXPECT_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->getExitCode ());
229
230 // Wait until the force termination task runs.
231 testing::runDelayedTasks(kForceTerminationDelayInMs);
232 waitForShutdown();
233 EXPECT_EQ(WorkerThread::ExitCode::AsyncForciblyTerminated, m_workerThread->g etExitCode());
234 }
235
236 TEST_F(WorkerThreadTest, StartAndTerminateOnScriptLoaded_SyncForciblyTerminateAf terTerminationTaskIsScheduled)
237 {
238 const long long kForceTerminationDelayInMs = 10;
239 setForceTerminationDelayInMs(kForceTerminationDelayInMs);
240
241 expectReportingCallsForWorkerForciblyTerminated();
242 startWithSourceCodeNotToFinish();
243 m_workerThread->waitUntilScriptLoaded();
244
245 // terminate() schedules a force termination task.
246 m_workerThread->terminate();
247 EXPECT_TRUE(isForceTerminationTaskScheduled());
248 EXPECT_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->getExitCode ());
249
250 // terminateAndWait() should overtake the scheduled force termination task.
251 m_workerThread->terminateAndWait();
252 EXPECT_FALSE(isForceTerminationTaskScheduled());
253 EXPECT_EQ(WorkerThread::ExitCode::SyncForciblyTerminated, m_workerThread->ge tExitCode());
254 }
255
256 // TODO(nhiroki): Add tests for terminateAndWaitForAllWorkers.
257
108 } // namespace blink 258 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698