1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.grinder.scriptengine.jython;
23
24 import static net.grinder.testutility.AssertUtilities.assertContains;
25 import static net.grinder.testutility.FileUtilities.createFile;
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertNotSame;
28 import static org.junit.Assert.assertSame;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31
32 import java.io.File;
33
34 import net.grinder.engine.common.EngineException;
35 import net.grinder.engine.common.ScriptLocation;
36 import net.grinder.scriptengine.ScriptEngineService.ScriptEngine;
37 import net.grinder.scriptengine.ScriptEngineService.WorkerRunnable;
38 import net.grinder.testutility.AbstractJUnit4FileTestCase;
39 import net.grinder.util.Directory;
40
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.python.core.PyObject;
44 import org.python.core.PySystemState;
45 import org.python.util.PythonInterpreter;
46
47
48
49
50
51
52
53 public class TestJythonScriptEngine extends AbstractJUnit4FileTestCase {
54
55 private static Object s_lastCallbackObject;
56
57 {
58 PySystemState.initialize();
59 }
60
61 private final PythonInterpreter m_interpreter =
62 new PythonInterpreter(null, new PySystemState());
63
64 private ScriptLocation m_script;
65
66 @Before public void initialise() throws Exception {
67 final File scriptFile = new File(getDirectory(), "script");
68
69 m_script = new ScriptLocation(new Directory(getDirectory()), scriptFile);
70 }
71
72 @Test public void testInitialiseNoFile() throws Exception {
73 try {
74 new JythonScriptEngine(m_script);
75 fail("Expected JythonScriptExecutionException");
76 }
77 catch (final JythonScriptExecutionException e) {
78 assertContains(e.getShortMessage(), "IOError");
79 }
80 }
81
82 @Test public void testInitialiseNoCallable() throws Exception {
83 createFile(m_script.getFile());
84
85 try {
86 new JythonScriptEngine(m_script);
87 fail("Expected EngineException");
88 }
89 catch (final EngineException e) {
90 assertContains(e.getMessage(), "no callable");
91 }
92 }
93
94 @Test public void testInitialiseNoCallable2() throws Exception {
95 createFile(m_script.getFile(),
96 "TestRunner = 1");
97
98 try {
99 new JythonScriptEngine(m_script);
100 fail("Expected EngineException");
101 }
102 catch (final EngineException e) {
103 assertContains(e.getMessage(), "no callable");
104 }
105 }
106
107 @Test public void testInitialise() throws Exception {
108 createFile(m_script.getFile(),
109 "class TestRunner:pass");
110
111 final ScriptEngine scriptEngine = new JythonScriptEngine(m_script);
112 assertContains(scriptEngine.getDescription(), "Jython");
113 scriptEngine.shutdown();
114 }
115
116 @Test public void testInitialiseJythonException() throws Exception {
117 final File directory = new File(getDirectory(), "bah/foo");
118 assertTrue(directory.mkdirs());
119
120
121 final ScriptLocation script =
122 new ScriptLocation(new Directory(new File("bah")),
123 new File(getDirectory(), "script"));
124
125 createFile(script.getFile(),
126 "import foo",
127 "class TestRunner:pass");
128
129 try {
130 new JythonScriptEngine(script);
131 fail("Expected JythonScriptExecutionException");
132 }
133 catch (final JythonScriptExecutionException e) {
134 assertContains(e.getShortMessage(), "ImportError");
135 }
136 }
137
138 @Test public void testInitialisePathScriptWorkingDirectory()
139 throws Exception {
140 final File directory = new File(getDirectory(), "bah/foo");
141 assertTrue(directory.mkdirs());
142
143
144 final ScriptLocation script =
145 new ScriptLocation(new Directory(new File(getDirectory(), "bah")),
146 new File(getDirectory(), "script"));
147
148 createFile(script.getFile(),
149 "import foo",
150 "class TestRunner:pass");
151
152 final ScriptEngine scriptEngine = new JythonScriptEngine(script);
153 scriptEngine.shutdown();
154 }
155
156 @Test public void testInitialisePathScriptDirectory() throws Exception {
157 final File directory = new File(getDirectory(), "bah/foo");
158 assertTrue(directory.mkdirs());
159
160
161 final ScriptLocation script =
162 new ScriptLocation(new Directory(new File("bah")),
163 new File(getDirectory(), "script"));
164
165 createFile(script.getFile(),
166 "import bah.foo",
167 "class TestRunner:pass");
168
169 final ScriptEngine scriptEngine = new JythonScriptEngine(script);
170 scriptEngine.shutdown();
171 }
172
173
174 @Test public void testShutdownExitHook() throws Exception {
175
176 callback(null);
177
178 createFile(
179 m_script.getFile(),
180 "from net.grinder.scriptengine.jython import TestJythonScriptEngine",
181 "import sys",
182 "def f():",
183 " TestJythonScriptEngine.callback(TestJythonScriptEngine)",
184 "sys.exitfunc = f",
185 "class TestRunner:pass");
186
187 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
188 scriptEngine.shutdown();
189
190 assertSame(TestJythonScriptEngine.class, s_lastCallbackObject);
191 }
192
193 @Test public void testShutdownBadHook() throws Exception {
194
195 createFile(
196 m_script.getFile(),
197 "import sys",
198 "def f():",
199 " raise Exception('a problem')",
200 "sys.exitfunc = f",
201 "class TestRunner:pass");
202
203 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
204
205 try {
206 scriptEngine.shutdown();
207 fail("Expected JythonScriptExecutionException");
208 }
209 catch (final JythonScriptExecutionException e) {
210 assertContains(e.getShortMessage(), "a problem");
211 }
212 }
213
214 @Test public void testWorkerRunnableNoCallable() throws Exception {
215
216 createFile(
217 m_script.getFile(),
218 "class TestRunner:pass");
219
220 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
221
222 try {
223 scriptEngine.createWorkerRunnable();
224 fail("Expected EngineException");
225 }
226 catch (final EngineException e) {
227 assertContains(e.getMessage(), "is not callable");
228 }
229 }
230
231 @Test public void testWorkerRunnableBadRunner() throws Exception {
232
233 createFile(
234 m_script.getFile(),
235 "class TestRunner:",
236 " def __init__(self): raise Exception('a problem')"
237 );
238
239 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
240
241 try {
242 scriptEngine.createWorkerRunnable();
243 fail("Expected JythonScriptExecutionException");
244 }
245 catch (final JythonScriptExecutionException e) {
246 assertContains(e.getShortMessage(), "a problem");
247 }
248 }
249
250 @Test public void testWorkerRunnable() throws Exception {
251
252 createFile(
253 m_script.getFile(),
254 "class TestRunner:",
255 " def __call__(self): pass"
256 );
257
258 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
259 final WorkerRunnable runnable1 = scriptEngine.createWorkerRunnable();
260 final WorkerRunnable runnable2 = scriptEngine.createWorkerRunnable();
261 assertNotSame(runnable1, runnable2);
262 runnable1.run();
263 runnable2.run();
264
265 runnable1.shutdown();
266 runnable2.shutdown();
267
268 scriptEngine.shutdown();
269 }
270
271 @Test public void testWorkerRunnableBadRunner2() throws Exception {
272
273 createFile(
274 m_script.getFile(),
275 "class TestRunner:",
276 " def __call__(self): raise Exception('a problem')");
277
278 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
279 final WorkerRunnable runnable = scriptEngine.createWorkerRunnable();
280
281 try {
282 runnable.run();
283 fail("Expected JythonScriptExecutionException");
284 }
285 catch (final JythonScriptExecutionException e) {
286 assertContains(e.getShortMessage(), "a problem");
287 }
288 }
289
290 @Test public void testWorkerRunnableBadRunner3() throws Exception {
291
292 createFile(
293 m_script.getFile(),
294 "class TestRunner:",
295 " def __call__(self): pass",
296 " def __del__(self): raise Exception('a problem')");
297
298 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
299 final WorkerRunnable runnable = scriptEngine.createWorkerRunnable();
300
301 try {
302 runnable.shutdown();
303 fail("Expected JythonScriptExecutionException");
304 }
305 catch (final JythonScriptExecutionException e) {
306 assertContains(e.getShortMessage(), "a problem");
307 }
308
309
310 runnable.shutdown();
311 }
312
313 @Test public void testNewWorkerRunnableWithTestRunner() throws Exception {
314 createFile(
315 m_script.getFile(),
316 "class TestRunner: pass");
317
318 final JythonScriptEngine scriptEngine = new JythonScriptEngine(m_script);
319
320 try {
321 scriptEngine.createWorkerRunnable(null);
322 fail("Expected JythonScriptExecutionException");
323 }
324 catch (final JythonScriptExecutionException e) {
325 assertContains(e.getMessage(), "is not callable");
326 }
327
328 final Object badRunner = new Object();
329
330 try {
331 scriptEngine.createWorkerRunnable(badRunner);
332 fail("Expected JythonScriptExecutionException");
333 }
334 catch (final JythonScriptExecutionException e) {
335 assertContains(e.getMessage(), "is not callable");
336 }
337
338 m_interpreter.exec("result=1");
339 m_interpreter.exec("def myRunner():\n global result\n result=99");
340 final PyObject goodRunner = m_interpreter.get("myRunner");
341
342 final WorkerRunnable workerRunnable =
343 scriptEngine.createWorkerRunnable(goodRunner);
344
345 assertEquals("1", m_interpreter.get("result").toString());
346
347 workerRunnable.run();
348 assertEquals("99", m_interpreter.get("result").toString());
349
350 final PyObject badRunner2 = m_interpreter.get("result");
351
352 try {
353 scriptEngine.createWorkerRunnable(badRunner2);
354 fail("Expected JythonScriptExecutionException");
355 }
356 catch (final JythonScriptExecutionException e) {
357 assertContains(e.getMessage(), "is not callable");
358 }
359 }
360
361 public static void callback(final Object o) {
362 s_lastCallbackObject = o;
363 }
364 }