##// END OF EJS Templates
begin testing message spec
MinRK -
Show More
@@ -7,34 +7,369 b''
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import re
10 import sys
11 import sys
11 import time
12 import time
13 from subprocess import PIPE
14 from Queue import Empty
12
15
13 import nose.tools as nt
16 import nose.tools as nt
14
17
15 from ..blockingkernelmanager import BlockingKernelManager
18 from ..blockingkernelmanager import BlockingKernelManager
16
19
17 from IPython.utils import io
20 from IPython.utils import io
21 from IPython.utils.traitlets import (
22 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum,
23 )
24
25 #-----------------------------------------------------------------------------
26 # Global setup and utilities
27 #-----------------------------------------------------------------------------
18
28
19 def setup():
29 def setup():
20 global KM
30 global KM
21 KM = BlockingKernelManager()
31 KM = BlockingKernelManager()
22
32
23 KM.start_kernel()
33 KM.start_kernel(stdout=PIPE, stderr=PIPE)
24 KM.start_channels()
34 KM.start_channels()
25 # Give the kernel a chance to come up.
26 time.sleep(1)
27
35
28 def teardown():
36 def teardown():
29 io.rprint('Entering teardown...') # dbg
30 io.rprint('Stopping channels and kernel...') # dbg
31 KM.stop_channels()
37 KM.stop_channels()
32 KM.kill_kernel()
38 KM.shutdown_kernel()
39
40 def flush_channels():
41 """flush any messages waiting on the queue"""
42 for channel in (KM.shell_channel, KM.sub_channel):
43 for msg in channel.get_msgs():
44 validate_message(msg)
45
46 def flush(f):
47 """decorator for flushing any incoming messages unhandled after the test"""
48
49 def wrapped(*args, **kwargs):
50 result = f(*args, **kwargs)
51 flush_channels()
52 return result
53
54 return wrapped
55
56 def flush_busy_pyin(msg_id=None):
57 """flush status=busy / pyin messages"""
58
59 def execute(code='', **kwargs):
60 """wrapper for doing common steps for validating an execution request"""
61 shell = KM.shell_channel
62 sub = KM.sub_channel
63
64 msg_id = shell.execute(code=code, **kwargs)
65 reply = shell.get_msg(timeout=2)
66 validate_message(reply, 'execute_reply', msg_id)
67 busy = sub.get_msg(timeout=2)
68 validate_message(busy, 'status', msg_id)
69 nt.assert_equals(busy['content']['execution_state'], 'busy')
70
71 if not kwargs.get('silent'):
72 pyin = sub.get_msg(timeout=2)
73 validate_message(pyin, 'pyin', msg_id)
74 nt.assert_equals(pyin['content']['code'], code)
75
76 return msg_id, reply['content']
77
78 #-----------------------------------------------------------------------------
79 # MSG Spec References
80 #-----------------------------------------------------------------------------
81
82
83 class Reference(HasTraits):
84
85 def check(self, d):
86 """validate a dict against our traits"""
87 for key in self.trait_names():
88 nt.assert_true(key in d, "Missing key: %r, should be found in %s" % (key, d))
89 # FIXME: always allow None, probably not a good idea
90 if d[key] is None:
91 continue
92 try:
93 setattr(self, key, d[key])
94 except TraitError as e:
95 nt.assert_true(False, str(e))
96
97
98 class RMessage(Reference):
99 msg_id = Unicode()
100 msg_type = Unicode()
101 header = Dict()
102 parent_header = Dict()
103 content = Dict()
104
105 class RHeader(Reference):
106 msg_id = Unicode()
107 msg_type = Unicode()
108 session = Unicode()
109 username = Unicode()
110
111 class RContent(Reference):
112 status = Enum((u'ok', u'error'))
113
114
115 class ExecuteReply(Reference):
116 execution_count = Integer()
117 status = Enum((u'ok', u'error'))
118
119 def check(self, d):
120 Reference.check(self, d)
121 if d['status'] == 'ok':
122 ExecuteReplyOkay().check(d)
123 elif d['status'] == 'error':
124 ExecuteReplyError().check(d)
125
33
126
127 class ExecuteReplyOkay(Reference):
128 payload = List(Dict)
129 user_variables = Dict()
130 user_expressions = Dict()
34
131
35 # Actual tests
132
133 class ExecuteReplyError(Reference):
134 ename = Unicode()
135 evalue = Unicode()
136 traceback = List(Unicode)
137
138
139 class OInfoReply(Reference):
140 name = Unicode()
141 found = Bool()
142 ismagic = Bool()
143 isalias = Bool()
144 namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
145 type_name = Unicode()
146 string_form = Unicode()
147 base_class = Unicode()
148 length = Integer()
149 file = Unicode()
150 definition = Unicode()
151 argspec = Dict()
152 init_definition = Unicode()
153 docstring = Unicode()
154 init_docstring = Unicode()
155 class_docstring = Unicode()
156 call_def = Unicode()
157 call_docstring = Unicode()
158 source = Unicode()
159
160 def check(self, d):
161 Reference.check(self, d)
162 if d['argspec'] is not None:
163 ArgSpec().check(d['argspec'])
164
165
166 class ArgSpec(Reference):
167 args = List(Unicode)
168 varargs = Unicode()
169 varkw = Unicode()
170 defaults = List(Unicode)
171
172
173 class Status(Reference):
174 execution_state = Enum((u'busy', u'idle'))
175
176
177 class CompleteReply(Reference):
178 matches = List(Unicode)
179
180
181 # IOPub messages
182
183 class PyIn(Reference):
184 code = Unicode()
185
186
187 PyErr = ExecuteReplyError
188
189
190 class Stream(Reference):
191 name = Enum((u'stdout', u'stderr'))
192 data = Unicode()
193
194
195 mime_pat = re.compile(r'\w+/\w+')
196
197 class DisplayData(Reference):
198 source = Unicode()
199 metadata = Dict()
200 data = Dict()
201 def _data_changed(self, name, old, new):
202 for k,v in new.iteritems():
203 nt.assert_true(mime_pat.match(k))
204 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
205
206
207 references = {
208 'execute_reply' : ExecuteReply(),
209 'object_info_reply' : OInfoReply(),
210 'status' : Status(),
211 'complete_reply' : CompleteReply(),
212 'pyin' : PyIn(),
213 'pyerr' : PyErr(),
214 'stream' : Stream(),
215 'display_data' : DisplayData(),
216 }
217
218
219 def validate_message(msg, msg_type=None, parent=None):
220 """validate a message"""
221 RMessage().check(msg)
222 if msg_type:
223 nt.assert_equals(msg['msg_type'], msg_type)
224 if parent:
225 nt.assert_equal(msg['parent_header']['msg_id'], parent)
226 content = msg['content']
227 ref = references[msg['msg_type']]
228 ref.check(content)
229
230
231 #-----------------------------------------------------------------------------
232 # Tests
233 #-----------------------------------------------------------------------------
234
235 # Shell channel
36
236
37 def test_execute():
237 def test_execute():
38 KM.shell_channel.execute(code='x=1')
238 shell = KM.shell_channel
39 KM.shell_channel.execute(code='print 1')
239 msg_id = shell.execute(code='x=1')
240 reply = shell.get_msg(timeout=2)
241 validate_message(reply, 'execute_reply', msg_id)
242
243 flush_channels()
244
245
246 def test_execute_silent():
247 msg_id, reply = execute(code='x=1', silent=True)
248
249 # flush status=idle
250 status = KM.sub_channel.get_msg(timeout=2)
251 validate_message(status, 'status', msg_id)
252 nt.assert_equals(status['content']['execution_state'], 'idle')
253
254 nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
255 count = reply['execution_count']
256
257 msg_id, reply = execute(code='x=2', silent=True)
258
259 # flush status=idle
260 status = KM.sub_channel.get_msg(timeout=2)
261 validate_message(status, 'status', msg_id)
262 nt.assert_equals(status['content']['execution_state'], 'idle')
263
264 nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
265 count_2 = reply['execution_count']
266 nt.assert_equals(count_2, count)
267
268 flush_channels()
269
270
271 def test_execute_error():
272
273 msg_id, reply = execute(code='1/0')
274 nt.assert_equals(reply['status'], 'error')
275 nt.assert_equals(reply['ename'], 'ZeroDivisionError')
276
277 pyerr = KM.sub_channel.get_msg(timeout=2)
278 validate_message(pyerr, 'pyerr', msg_id)
279
280 flush_channels()
281
282
283 def test_execute_inc():
284 """execute request should increment execution_count"""
285 msg_id, reply = execute(code='x=1')
286 count = reply['execution_count']
287
288 flush_channels()
40
289
290 msg_id, reply = execute(code='x=2')
291 count_2 = reply['execution_count']
292 nt.assert_equals(count_2, count+1)
293
294 flush_channels()
295
296
297 def test_user_variables():
298 msg_id, reply = execute(code='x=1', user_variables=['x'])
299 user_variables = reply['user_variables']
300 nt.assert_equals(user_variables, {u'x' : u'1'})
301
302 flush_channels()
303
304
305 def test_user_expressions():
306 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
307 user_expressions = reply['user_expressions']
308 nt.assert_equals(user_expressions, {u'foo' : u'2'})
309
310 flush_channels()
311
312
313 def test_oinfo():
314 shell = KM.shell_channel
315
316 msg_id = shell.object_info('a')
317 reply = shell.get_msg(timeout=2)
318 validate_message(reply, 'object_info_reply', msg_id)
319
320 flush_channels()
321
322
323 def test_oinfo_found():
324 shell = KM.shell_channel
325
326 msg_id, reply = execute(code='a=5')
327
328 msg_id = shell.object_info('a')
329 reply = shell.get_msg(timeout=2)
330 validate_message(reply, 'object_info_reply', msg_id)
331 content = reply['content']
332 nt.assert_true(content['found'])
333
334 flush_channels()
335
336
337 def test_complete():
338 shell = KM.shell_channel
339
340 msg_id, reply = execute(code="alpha = albert = 5")
341
342 msg_id = shell.complete('al', 'al', 2)
343 reply = shell.get_msg(timeout=2)
344 validate_message(reply, 'complete_reply', msg_id)
345 matches = reply['content']['matches']
346 for name in ('alpha', 'albert'):
347 nt.assert_true(name in matches, "Missing match: %r" % name)
348
349 flush_channels()
350
351
352 def test_stream():
353 msg_id, reply = execute("print('hi')")
354
355 stdout = KM.sub_channel.get_msg(timeout=2)
356 validate_message(stdout, 'stream', msg_id)
357 content = stdout['content']
358 nt.assert_equals(content['name'], u'stdout')
359 nt.assert_equals(content['data'], u'hi\n')
360
361 flush_channels()
362
363
364 def test_display():
365
366 msg_id, reply = execute("from IPython.core.display import display; display(1)")
367
368 display = KM.sub_channel.get_msg(timeout=2)
369 validate_message(display, 'display_data', parent=msg_id)
370 data = display['content']['data']
371 nt.assert_equals(data['text/plain'], u'1')
372
373 flush_channels()
374
375 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now