OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "Source/web/ServiceWorkerGlobalScopeProxy.h" | |
8 | |
9 #include "Source/bindings/core/v8/ScriptSourceCode.h" | |
10 #include "Source/core/dom/CrossThreadTask.h" | |
11 #include "platform/weborigin/KURL.cpp" | |
12 #include "public/platform/Platform.h" | |
13 #include "public/platform/WebThread.h" | |
14 #include "public/platform/WebUnitTestSupport.h" | |
15 #include "public/web/WebEmbeddedWorker.h" | |
16 #include "public/web/WebEmbeddedWorkerStartData.h" | |
17 #include "public/web/WebServiceWorkerContextClient.h" | |
18 #include "web/WebEmbeddedWorkerImpl.h" | |
19 #include "web/tests/URLTestHelpers.h" | |
20 #include <gmock/gmock.h> | |
21 #include <gtest/gtest.h> | |
22 #include <v8.h> | |
23 | |
24 using namespace blink; | |
25 using namespace WebCore; | |
26 | |
27 namespace { | |
28 | |
29 class ServiceWorkerGlobalScopeProxyTest : public testing::Test { | |
30 protected: | |
31 ServiceWorkerGlobalScopeProxyTest() | |
32 : m_baseUrl("http://www.test.com/") | |
33 { | |
34 } | |
35 | |
36 virtual ~ServiceWorkerGlobalScopeProxyTest() | |
37 { | |
38 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); | |
39 } | |
40 | |
41 // Remember to call serveAsynchronousMockedRequests() in order to handle the se mocked URLs. | |
42 void registerMockedHttpURLLoad(const std::string& fileName, const std::strin g& mimeType = "text/html") | |
43 { | |
44 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseU rl), WebString::fromUTF8(fileName), WebString::fromUTF8(mimeType)); | |
45 } | |
46 | |
47 const std::string m_baseUrl; | |
48 }; | |
49 | |
50 // Can repeatedly run the current thread's loop, but unlike Chrome's RunLoop, ca nnot be recursively reentered. | |
51 // QuitWhenIdle() must be called exactly once per Run() call. | |
52 class RunLoop { | |
Jeffrey Yasskin
2014/07/16 23:14:58
I was kind of shocked not to find anything like th
| |
53 public: | |
54 RunLoop() | |
55 : m_thread(blink::Platform::current()->currentThread()) | |
56 , m_isRunning(false) | |
57 , m_isQuitting(false) | |
58 { | |
59 } | |
60 | |
61 // Starts the thread's run loop, and returns when QuitWhenIdle() is called. | |
62 void Run() | |
63 { | |
64 EXPECT_FALSE(m_isRunning); | |
65 m_isRunning = true; | |
66 m_thread->enterRunLoop(); | |
67 EXPECT_TRUE(m_isQuitting); | |
68 m_isRunning = m_isQuitting = false; | |
69 } | |
70 | |
71 // This can be called before Run() or concurrently with it from another thre ad. | |
72 // The loop will terminate when it's idle. | |
73 void QuitWhenIdle() | |
74 { | |
75 EXPECT_FALSE(m_isQuitting); | |
76 m_isQuitting = true; | |
77 m_thread->postTask(new QuitTask(this)); | |
78 } | |
79 | |
80 bool isQuitting() | |
81 { | |
82 return m_isQuitting; | |
83 } | |
84 | |
85 private: | |
86 class QuitTask : public WebThread::Task { | |
87 public: | |
88 QuitTask(RunLoop* runLoop) | |
89 : m_runLoop(runLoop) | |
90 { | |
91 } | |
92 virtual void run() | |
93 { | |
94 EXPECT_TRUE(m_runLoop->m_isRunning); | |
95 EXPECT_TRUE(m_runLoop->m_isQuitting); | |
96 m_runLoop->m_thread->exitRunLoop(); | |
97 } | |
98 RunLoop* m_runLoop; | |
99 }; | |
100 | |
101 WebThread* m_thread; | |
102 bool m_isRunning; | |
103 bool m_isQuitting; | |
104 }; | |
105 | |
106 // Continuously pumps the mocked-requests queue during the current execution of runLoop->Run(), or next if Run() isn't currently running. | |
107 class ServeAsyncRequestsTask : public WebThread::Task { | |
108 public: | |
109 ServeAsyncRequestsTask(RunLoop* runLoop) | |
110 : m_runLoop(runLoop) | |
111 { | |
112 } | |
113 | |
114 virtual void run() OVERRIDE | |
115 { | |
116 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests( ); | |
Jeffrey Yasskin
2014/07/16 23:14:58
This gets flagged by https://code.google.com/p/chr
| |
117 // The RunLoop only finishes quitting when it has no tasks left, so this task has to end its chain explicitly. | |
118 if (!m_runLoop->isQuitting()) { | |
119 Platform::current()->currentThread()->postTask(new ServeAsyncRequest sTask(m_runLoop)); | |
120 } | |
121 } | |
122 | |
123 private: | |
124 RunLoop* m_runLoop; | |
125 }; | |
126 | |
127 class V8ContextTestSWContextClient : public WebServiceWorkerContextClient { | |
128 public: | |
129 virtual void workerContextFailedToStart() | |
130 { | |
131 ADD_FAILURE() << "workerContextFailedToStart"; | |
132 m_runLoop->QuitWhenIdle(); | |
133 } | |
134 | |
135 virtual void reportException(const WebString& errorMessage, int lineNumber, int columnNumber, const WebString& sourceURL) | |
136 { | |
137 ADD_FAILURE() << sourceURL.utf8() << "(" << lineNumber << ":" << columnN umber << ") error: " << errorMessage.utf8(); | |
138 m_runLoop->QuitWhenIdle(); | |
139 } | |
140 | |
141 virtual void workerContextStarted(WebServiceWorkerContextProxy* proxy) | |
142 { | |
143 m_proxy = proxy; | |
144 v8::HandleScope scope(v8::Isolate::GetCurrent()); | |
145 EXPECT_TRUE(*m_proxy->v8Context()) << "The v8 context should be valid as soon as the worker is started."; | |
146 m_runLoop->QuitWhenIdle(); | |
147 } | |
148 | |
149 void checkContextAccessibleAfterClose() | |
150 { | |
151 v8::HandleScope scope(v8::Isolate::GetCurrent()); | |
152 EXPECT_TRUE(*m_proxy->v8Context()) << "The v8 context should still be va lid."; | |
153 static_cast<ServiceWorkerGlobalScopeProxy*>(m_proxy)->evaluate(String::f romUTF8("self.close();")); | |
154 // The context continues to exist until non-cleanup tasks stop running. | |
155 checkContextStillExists(); | |
156 // close() will eventually terminate the worker, which will quit the | |
157 // RunLoop through workerContextDestroyed. | |
158 } | |
159 | |
160 void checkContextStillExists() | |
161 { | |
162 // The context isn't valid after willDestroyWorkerContext(). | |
163 if (!m_proxy) | |
164 return; | |
165 v8::HandleScope scope(v8::Isolate::GetCurrent()); | |
166 EXPECT_TRUE(*m_proxy->v8Context()); | |
167 static_cast<WebEmbeddedWorkerImpl*>(m_worker)->postTask(createCrossThrea dTask(&V8ContextTestSWContextClient::checkContextStillExists, this)); | |
168 } | |
169 | |
170 virtual void willDestroyWorkerContext() OVERRIDE | |
171 { | |
172 m_proxy = 0; | |
173 } | |
174 | |
175 virtual void workerContextDestroyed() OVERRIDE | |
176 { | |
177 // Now it's safe to finish the main test, which will destroy the WorkerT hread. | |
178 m_runLoop->QuitWhenIdle(); | |
179 } | |
180 | |
181 RunLoop* m_runLoop; | |
182 WebEmbeddedWorker* m_worker; | |
183 WebServiceWorkerContextProxy* m_proxy; | |
184 }; | |
185 | |
186 TEST_F(ServiceWorkerGlobalScopeProxyTest, V8ContextText) | |
187 { | |
188 V8ContextTestSWContextClient* contextClient = new V8ContextTestSWContextClie nt; | |
189 | |
190 RunLoop runLoop; | |
191 contextClient->m_runLoop = &runLoop; | |
192 | |
193 OwnPtr<WebEmbeddedWorker> worker = adoptPtr(WebEmbeddedWorker::create(contex tClient, 0)); | |
194 contextClient->m_worker = worker.get(); | |
195 | |
196 WebEmbeddedWorkerStartData startData; | |
197 registerMockedHttpURLLoad("blank.js", "text/javascript"); | |
198 startData.scriptURL = URLTestHelpers::toKURL(m_baseUrl + "blank.js"); | |
199 worker->startWorkerContext(startData); | |
200 // Serve requests until the message loop quits. | |
201 Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(&r unLoop)); | |
202 runLoop.Run(); // Wait for workerContextStarted(). | |
203 | |
204 static_cast<WebEmbeddedWorkerImpl&>(*worker).postTask( | |
205 createCrossThreadTask(&V8ContextTestSWContextClient::checkContextAccessi bleAfterClose, contextClient)); | |
206 runLoop.Run(); // Wait for workerContextDestroyed(). | |
207 } | |
208 | |
209 } // namespace | |
OLD | NEW |