##// END OF EJS Templates
trying to add history test
Narahari -
Show More
@@ -1,432 +1,443 b''
1 1 """Test suite for our zeromq-based message specification."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import re
7 7 import sys
8 8 from distutils.version import LooseVersion as V
9 9 try:
10 10 from queue import Empty # Py 3
11 11 except ImportError:
12 12 from Queue import Empty # Py 2
13 13
14 14 import nose.tools as nt
15 15
16 16 from IPython.utils.traitlets import (
17 17 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum,
18 18 )
19 19 from IPython.utils.py3compat import string_types, iteritems
20 20
21 21 from .utils import TIMEOUT, start_global_kernel, flush_channels, execute
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Globals
25 25 #-----------------------------------------------------------------------------
26 26 KC = None
27 27
28 28 def setup():
29 29 global KC
30 30 KC = start_global_kernel()
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Message Spec References
34 34 #-----------------------------------------------------------------------------
35 35
36 36 class Reference(HasTraits):
37 37
38 38 """
39 39 Base class for message spec specification testing.
40 40
41 41 This class is the core of the message specification test. The
42 42 idea is that child classes implement trait attributes for each
43 43 message keys, so that message keys can be tested against these
44 44 traits using :meth:`check` method.
45 45
46 46 """
47 47
48 48 def check(self, d):
49 49 """validate a dict against our traits"""
50 50 for key in self.trait_names():
51 51 nt.assert_in(key, d)
52 52 # FIXME: always allow None, probably not a good idea
53 53 if d[key] is None:
54 54 continue
55 55 try:
56 56 setattr(self, key, d[key])
57 57 except TraitError as e:
58 58 assert False, str(e)
59 59
60 60
61 61 class Version(Unicode):
62 62 def __init__(self, *args, **kwargs):
63 63 self.min = kwargs.pop('min', None)
64 64 self.max = kwargs.pop('max', None)
65 65 kwargs['default_value'] = self.min
66 66 super(Version, self).__init__(*args, **kwargs)
67 67
68 68 def validate(self, obj, value):
69 69 if self.min and V(value) < V(self.min):
70 70 raise TraitError("bad version: %s < %s" % (value, self.min))
71 71 if self.max and (V(value) > V(self.max)):
72 72 raise TraitError("bad version: %s > %s" % (value, self.max))
73 73
74 74
75 75 class RMessage(Reference):
76 76 msg_id = Unicode()
77 77 msg_type = Unicode()
78 78 header = Dict()
79 79 parent_header = Dict()
80 80 content = Dict()
81 81
82 82 def check(self, d):
83 83 super(RMessage, self).check(d)
84 84 RHeader().check(self.header)
85 85 if self.parent_header:
86 86 RHeader().check(self.parent_header)
87 87
88 88 class RHeader(Reference):
89 89 msg_id = Unicode()
90 90 msg_type = Unicode()
91 91 session = Unicode()
92 92 username = Unicode()
93 93 version = Version(min='5.0')
94 94
95 95 mime_pat = re.compile(r'^[\w\-\+\.]+/[\w\-\+\.]+$')
96 96
97 97 class MimeBundle(Reference):
98 98 metadata = Dict()
99 99 data = Dict()
100 100 def _data_changed(self, name, old, new):
101 101 for k,v in iteritems(new):
102 102 assert mime_pat.match(k)
103 103 nt.assert_is_instance(v, string_types)
104 104
105 105 # shell replies
106 106
107 107 class ExecuteReply(Reference):
108 108 execution_count = Integer()
109 109 status = Enum((u'ok', u'error'))
110 110
111 111 def check(self, d):
112 112 Reference.check(self, d)
113 113 if d['status'] == 'ok':
114 114 ExecuteReplyOkay().check(d)
115 115 elif d['status'] == 'error':
116 116 ExecuteReplyError().check(d)
117 117
118 118
119 119 class ExecuteReplyOkay(Reference):
120 120 payload = List(Dict)
121 121 user_expressions = Dict()
122 122
123 123
124 124 class ExecuteReplyError(Reference):
125 125 ename = Unicode()
126 126 evalue = Unicode()
127 127 traceback = List(Unicode)
128 128
129 129
130 130 class InspectReply(MimeBundle):
131 131 found = Bool()
132 132
133 133
134 134 class ArgSpec(Reference):
135 135 args = List(Unicode)
136 136 varargs = Unicode()
137 137 varkw = Unicode()
138 138 defaults = List()
139 139
140 140
141 141 class Status(Reference):
142 142 execution_state = Enum((u'busy', u'idle', u'starting'))
143 143
144 144
145 145 class CompleteReply(Reference):
146 146 matches = List(Unicode)
147 147 cursor_start = Integer()
148 148 cursor_end = Integer()
149 149 status = Unicode()
150 150
151 151 class LanguageInfo(Reference):
152 152 name = Unicode('python')
153 153 version = Unicode(sys.version.split()[0])
154 154
155 155 class KernelInfoReply(Reference):
156 156 protocol_version = Version(min='5.0')
157 157 implementation = Unicode('ipython')
158 158 implementation_version = Version(min='2.1')
159 159 language_info = Dict()
160 160 banner = Unicode()
161 161
162 162 def check(self, d):
163 163 Reference.check(self, d)
164 164 LanguageInfo().check(d['language_info'])
165 165
166 166
167 167 class IsCompleteReply(Reference):
168 168 status = Enum((u'complete', u'incomplete', u'invalid', u'unknown'))
169 169
170 170 def check(self, d):
171 171 Reference.check(self, d)
172 172 if d['status'] == 'incomplete':
173 173 IsCompleteReplyIncomplete().check(d)
174 174
175 175 class IsCompleteReplyIncomplete(Reference):
176 176 indent = Unicode()
177 177
178 178
179 179 # IOPub messages
180 180
181 181 class ExecuteInput(Reference):
182 182 code = Unicode()
183 183 execution_count = Integer()
184 184
185 185
186 186 Error = ExecuteReplyError
187 187
188 188
189 189 class Stream(Reference):
190 190 name = Enum((u'stdout', u'stderr'))
191 191 text = Unicode()
192 192
193 193
194 194 class DisplayData(MimeBundle):
195 195 pass
196 196
197 197
198 198 class ExecuteResult(MimeBundle):
199 199 execution_count = Integer()
200 200
201 class HistoryReply(MimeBundle):
202 history = List(Unicode)
203
201 204
202 205 references = {
203 206 'execute_reply' : ExecuteReply(),
204 207 'inspect_reply' : InspectReply(),
205 208 'status' : Status(),
206 209 'complete_reply' : CompleteReply(),
207 210 'kernel_info_reply': KernelInfoReply(),
208 211 'is_complete_reply': IsCompleteReply(),
209 212 'execute_input' : ExecuteInput(),
210 213 'execute_result' : ExecuteResult(),
214 'history_reply' : HistoryReply(),
211 215 'error' : Error(),
212 216 'stream' : Stream(),
213 217 'display_data' : DisplayData(),
214 218 'header' : RHeader(),
215 219 }
216 220 """
217 221 Specifications of `content` part of the reply messages.
218 222 """
219 223
220 224
221 225 def validate_message(msg, msg_type=None, parent=None):
222 226 """validate a message
223 227
224 228 This is a generator, and must be iterated through to actually
225 229 trigger each test.
226 230
227 231 If msg_type and/or parent are given, the msg_type and/or parent msg_id
228 232 are compared with the given values.
229 233 """
230 234 RMessage().check(msg)
231 235 if msg_type:
232 236 nt.assert_equal(msg['msg_type'], msg_type)
233 237 if parent:
234 238 nt.assert_equal(msg['parent_header']['msg_id'], parent)
235 239 content = msg['content']
236 240 ref = references[msg['msg_type']]
237 241 ref.check(content)
238 242
239 243
240 244 #-----------------------------------------------------------------------------
241 245 # Tests
242 246 #-----------------------------------------------------------------------------
243 247
244 248 # Shell channel
245 249
246 250 def test_execute():
247 251 flush_channels()
248 252
249 253 msg_id = KC.execute(code='x=1')
250 254 reply = KC.get_shell_msg(timeout=TIMEOUT)
251 255 validate_message(reply, 'execute_reply', msg_id)
252 256
253 257
254 258 def test_execute_silent():
255 259 flush_channels()
256 260 msg_id, reply = execute(code='x=1', silent=True)
257 261
258 262 # flush status=idle
259 263 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
260 264 validate_message(status, 'status', msg_id)
261 265 nt.assert_equal(status['content']['execution_state'], 'idle')
262 266
263 267 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
264 268 count = reply['execution_count']
265 269
266 270 msg_id, reply = execute(code='x=2', silent=True)
267 271
268 272 # flush status=idle
269 273 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
270 274 validate_message(status, 'status', msg_id)
271 275 nt.assert_equal(status['content']['execution_state'], 'idle')
272 276
273 277 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
274 278 count_2 = reply['execution_count']
275 279 nt.assert_equal(count_2, count)
276 280
277 281
278 282 def test_execute_error():
279 283 flush_channels()
280 284
281 285 msg_id, reply = execute(code='1/0')
282 286 nt.assert_equal(reply['status'], 'error')
283 287 nt.assert_equal(reply['ename'], 'ZeroDivisionError')
284 288
285 289 error = KC.iopub_channel.get_msg(timeout=TIMEOUT)
286 290 validate_message(error, 'error', msg_id)
287 291
288 292
289 293 def test_execute_inc():
290 294 """execute request should increment execution_count"""
291 295 flush_channels()
292 296
293 297 msg_id, reply = execute(code='x=1')
294 298 count = reply['execution_count']
295 299
296 300 flush_channels()
297 301
298 302 msg_id, reply = execute(code='x=2')
299 303 count_2 = reply['execution_count']
300 304 nt.assert_equal(count_2, count+1)
301 305
302 306
303 307 def test_user_expressions():
304 308 flush_channels()
305 309
306 310 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
307 311 user_expressions = reply['user_expressions']
308 312 nt.assert_equal(user_expressions, {u'foo': {
309 313 u'status': u'ok',
310 314 u'data': {u'text/plain': u'2'},
311 315 u'metadata': {},
312 316 }})
313 317
314 318
315 319 def test_user_expressions_fail():
316 320 flush_channels()
317 321
318 322 msg_id, reply = execute(code='x=0', user_expressions=dict(foo='nosuchname'))
319 323 user_expressions = reply['user_expressions']
320 324 foo = user_expressions['foo']
321 325 nt.assert_equal(foo['status'], 'error')
322 326 nt.assert_equal(foo['ename'], 'NameError')
323 327
324 328
325 329 def test_oinfo():
326 330 flush_channels()
327 331
328 332 msg_id = KC.inspect('a')
329 333 reply = KC.get_shell_msg(timeout=TIMEOUT)
330 334 validate_message(reply, 'inspect_reply', msg_id)
331 335
332 336
333 337 def test_oinfo_found():
334 338 flush_channels()
335 339
336 340 msg_id, reply = execute(code='a=5')
337 341
338 342 msg_id = KC.inspect('a')
339 343 reply = KC.get_shell_msg(timeout=TIMEOUT)
340 344 validate_message(reply, 'inspect_reply', msg_id)
341 345 content = reply['content']
342 346 assert content['found']
343 347 text = content['data']['text/plain']
344 348 nt.assert_in('Type:', text)
345 349 nt.assert_in('Docstring:', text)
346 350
347 351
348 352 def test_oinfo_detail():
349 353 flush_channels()
350 354
351 355 msg_id, reply = execute(code='ip=get_ipython()')
352 356
353 357 msg_id = KC.inspect('ip.object_inspect', cursor_pos=10, detail_level=1)
354 358 reply = KC.get_shell_msg(timeout=TIMEOUT)
355 359 validate_message(reply, 'inspect_reply', msg_id)
356 360 content = reply['content']
357 361 assert content['found']
358 362 text = content['data']['text/plain']
359 363 nt.assert_in('Definition:', text)
360 364 nt.assert_in('Source:', text)
361 365
362 366
363 367 def test_oinfo_not_found():
364 368 flush_channels()
365 369
366 370 msg_id = KC.inspect('dne')
367 371 reply = KC.get_shell_msg(timeout=TIMEOUT)
368 372 validate_message(reply, 'inspect_reply', msg_id)
369 373 content = reply['content']
370 374 nt.assert_false(content['found'])
371 375
372 376
373 377 def test_complete():
374 378 flush_channels()
375 379
376 380 msg_id, reply = execute(code="alpha = albert = 5")
377 381
378 382 msg_id = KC.complete('al', 2)
379 383 reply = KC.get_shell_msg(timeout=TIMEOUT)
380 384 validate_message(reply, 'complete_reply', msg_id)
381 385 matches = reply['content']['matches']
382 386 for name in ('alpha', 'albert'):
383 387 nt.assert_in(name, matches)
384 388
385 389
386 390 def test_kernel_info_request():
387 391 flush_channels()
388 392
389 393 msg_id = KC.kernel_info()
390 394 reply = KC.get_shell_msg(timeout=TIMEOUT)
391 395 validate_message(reply, 'kernel_info_reply', msg_id)
392 396
393 397
394 398 def test_single_payload():
395 399 flush_channels()
396 400 msg_id, reply = execute(code="for i in range(3):\n"+
397 401 " x=range?\n")
398 402 payload = reply['payload']
399 403 next_input_pls = [pl for pl in payload if pl["source"] == "set_next_input"]
400 404 nt.assert_equal(len(next_input_pls), 1)
401 405
402 406 def test_is_complete():
403 407 flush_channels()
404
408 a
405 409 msg_id = KC.is_complete("a = 1")
406 410 reply = KC.get_shell_msg(timeout=TIMEOUT)
407 411 validate_message(reply, 'is_complete_reply', msg_id)
408 412
413 def test_history():
414 flush_channels()
415
416 msg_id = KC.history("range", True, True)
417 reply = KC.get_shell_msg(timeout=TIMEOUT)
418 validate_message(reply, 'history_reply', msg_id)
419
409 420 # IOPub channel
410 421
411 422
412 423 def test_stream():
413 424 flush_channels()
414 425
415 426 msg_id, reply = execute("print('hi')")
416 427
417 428 stdout = KC.iopub_channel.get_msg(timeout=TIMEOUT)
418 429 validate_message(stdout, 'stream', msg_id)
419 430 content = stdout['content']
420 431 nt.assert_equal(content['text'], u'hi\n')
421 432
422 433
423 434 def test_display_data():
424 435 flush_channels()
425 436
426 437 msg_id, reply = execute("from IPython.core.display import display; display(1)")
427 438
428 439 display = KC.iopub_channel.get_msg(timeout=TIMEOUT)
429 440 validate_message(display, 'display_data', parent=msg_id)
430 441 data = display['content']['data']
431 442 nt.assert_equal(data['text/plain'], u'1')
432 443
General Comments 0
You need to be logged in to leave comments. Login now