##// END OF EJS Templates
Merge pull request #2340 from JanSchulz/client-clear-cache...
Merge pull request #2340 from JanSchulz/client-clear-cache Initial Code to reduce parallel.Client caching adds: client.purge_local_results client.purge_hub_results client.purge_results (does both above) client.purge_everything (includes history, etc.)

File last commit:

r8905:834bea19
r9153:9d021a36 merge
Show More
test_message_spec.py
497 lines | 13.1 KiB | text/x-python | PythonLexer
/ IPython / zmq / tests / test_message_spec.py
Fernando Perez
Rework messaging to better conform to our spec....
r2926 """Test suite for our zeromq-based messaging specification.
"""
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
update copyright to 2011/20xx-2011...
r5390 # Copyright (C) 2010-2011 The IPython Development Team
Fernando Perez
Rework messaging to better conform to our spec....
r2926 #
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING.txt, distributed as part of this software.
#-----------------------------------------------------------------------------
MinRK
begin testing message spec
r6554 import re
Fernando Perez
Rework messaging to better conform to our spec....
r2926 import sys
import time
MinRK
begin testing message spec
r6554 from subprocess import PIPE
from Queue import Empty
Fernando Perez
Rework messaging to better conform to our spec....
r2926
import nose.tools as nt
from ..blockingkernelmanager import BlockingKernelManager
MinRK
use parametric tests in message_spec...
r6558
from IPython.testing import decorators as dec
Fernando Perez
Rework messaging to better conform to our spec....
r2926 from IPython.utils import io
MinRK
begin testing message spec
r6554 from IPython.utils.traitlets import (
Takafumi Arakaki
Rewrite VersionReply spec using List and Unicode
r8865 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum, Any,
MinRK
begin testing message spec
r6554 )
#-----------------------------------------------------------------------------
# Global setup and utilities
#-----------------------------------------------------------------------------
Fernando Perez
Rework messaging to better conform to our spec....
r2926
def setup():
global KM
KM = BlockingKernelManager()
MinRK
begin testing message spec
r6554 KM.start_kernel(stdout=PIPE, stderr=PIPE)
Fernando Perez
Rework messaging to better conform to our spec....
r2926 KM.start_channels()
MinRK
handle pyout messages in test_message_spec...
r6664
# wait for kernel to be ready
KM.shell_channel.execute("pass")
KM.shell_channel.get_msg(block=True, timeout=5)
flush_channels()
Fernando Perez
Rework messaging to better conform to our spec....
r2926
MinRK
use parametric tests in message_spec...
r6558
Fernando Perez
Rework messaging to better conform to our spec....
r2926 def teardown():
KM.stop_channels()
MinRK
begin testing message spec
r6554 KM.shutdown_kernel()
MinRK
use parametric tests in message_spec...
r6558
MinRK
begin testing message spec
r6554 def flush_channels():
"""flush any messages waiting on the queue"""
for channel in (KM.shell_channel, KM.sub_channel):
MinRK
use parametric tests in message_spec...
r6558 while True:
try:
msg = channel.get_msg(block=True, timeout=0.1)
except Empty:
break
else:
MinRK
evaluate a few dangling validate_message generators...
r6573 list(validate_message(msg))
MinRK
begin testing message spec
r6554
def execute(code='', **kwargs):
"""wrapper for doing common steps for validating an execution request"""
shell = KM.shell_channel
sub = KM.sub_channel
msg_id = shell.execute(code=code, **kwargs)
reply = shell.get_msg(timeout=2)
MinRK
evaluate a few dangling validate_message generators...
r6573 list(validate_message(reply, 'execute_reply', msg_id))
MinRK
begin testing message spec
r6554 busy = sub.get_msg(timeout=2)
MinRK
evaluate a few dangling validate_message generators...
r6573 list(validate_message(busy, 'status', msg_id))
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(busy['content']['execution_state'], 'busy')
MinRK
begin testing message spec
r6554
if not kwargs.get('silent'):
pyin = sub.get_msg(timeout=2)
MinRK
evaluate a few dangling validate_message generators...
r6573 list(validate_message(pyin, 'pyin', msg_id))
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(pyin['content']['code'], code)
MinRK
begin testing message spec
r6554
return msg_id, reply['content']
#-----------------------------------------------------------------------------
# MSG Spec References
#-----------------------------------------------------------------------------
class Reference(HasTraits):
Takafumi Arakaki
Document how test_message_spec works
r8829
"""
Base class for message spec specification testing.
This class is the core of the message specification test. The
idea is that child classes implement trait attributes for each
message keys, so that message keys can be tested against these
traits using :meth:`check` method.
"""
MinRK
begin testing message spec
r6554 def check(self, d):
"""validate a dict against our traits"""
for key in self.trait_names():
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_true(key in d, "Missing key: %r, should be found in %s" % (key, d))
MinRK
begin testing message spec
r6554 # FIXME: always allow None, probably not a good idea
if d[key] is None:
continue
try:
setattr(self, key, d[key])
except TraitError as e:
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_true(False, str(e))
MinRK
begin testing message spec
r6554
class RMessage(Reference):
msg_id = Unicode()
msg_type = Unicode()
header = Dict()
parent_header = Dict()
content = Dict()
class RHeader(Reference):
msg_id = Unicode()
msg_type = Unicode()
session = Unicode()
username = Unicode()
class RContent(Reference):
status = Enum((u'ok', u'error'))
class ExecuteReply(Reference):
execution_count = Integer()
status = Enum((u'ok', u'error'))
def check(self, d):
MinRK
use parametric tests in message_spec...
r6558 for tst in Reference.check(self, d):
yield tst
MinRK
begin testing message spec
r6554 if d['status'] == 'ok':
MinRK
use parametric tests in message_spec...
r6558 for tst in ExecuteReplyOkay().check(d):
yield tst
MinRK
begin testing message spec
r6554 elif d['status'] == 'error':
MinRK
use parametric tests in message_spec...
r6558 for tst in ExecuteReplyError().check(d):
yield tst
MinRK
begin testing message spec
r6554
Fernando Perez
Rework messaging to better conform to our spec....
r2926
MinRK
begin testing message spec
r6554 class ExecuteReplyOkay(Reference):
payload = List(Dict)
user_variables = Dict()
user_expressions = Dict()
Fernando Perez
Rework messaging to better conform to our spec....
r2926
MinRK
begin testing message spec
r6554
class ExecuteReplyError(Reference):
ename = Unicode()
evalue = Unicode()
traceback = List(Unicode)
class OInfoReply(Reference):
name = Unicode()
found = Bool()
ismagic = Bool()
isalias = Bool()
namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
type_name = Unicode()
string_form = Unicode()
base_class = Unicode()
length = Integer()
file = Unicode()
definition = Unicode()
argspec = Dict()
init_definition = Unicode()
docstring = Unicode()
init_docstring = Unicode()
class_docstring = Unicode()
call_def = Unicode()
call_docstring = Unicode()
source = Unicode()
def check(self, d):
MinRK
use parametric tests in message_spec...
r6558 for tst in Reference.check(self, d):
yield tst
MinRK
begin testing message spec
r6554 if d['argspec'] is not None:
MinRK
use parametric tests in message_spec...
r6558 for tst in ArgSpec().check(d['argspec']):
yield tst
MinRK
begin testing message spec
r6554
class ArgSpec(Reference):
args = List(Unicode)
varargs = Unicode()
varkw = Unicode()
MinRK
use parametric tests in message_spec...
r6558 defaults = List()
MinRK
begin testing message spec
r6554
class Status(Reference):
execution_state = Enum((u'busy', u'idle'))
class CompleteReply(Reference):
matches = List(Unicode)
Takafumi Arakaki
Rewrite VersionReply spec using List and Unicode
r8865 def Version(num, trait=Integer):
return List(trait, default_value=[0] * num, minlen=num, maxlen=num)
Takafumi Arakaki
Rename version_rep/req to kernel_info_rep/req
r8879 class KernelInfoReply(Reference):
Takafumi Arakaki
Rewrite VersionReply spec using List and Unicode
r8865
protocol_version = Version(2)
ipython_version = Version(4, Any)
language_version = Version(3)
language = Unicode()
def _ipython_version_changed(self, name, old, new):
for v in new:
nt.assert_true(
isinstance(v, int) or isinstance(v, basestring),
Takafumi Arakaki
Fix test failure in Python 2.6
r8875 'expected int or string as version component, got {0!r}'
Takafumi Arakaki
Rewrite VersionReply spec using List and Unicode
r8865 .format(v))
Takafumi Arakaki
Add a test for version_request in test_message_spec.py
r8831
MinRK
begin testing message spec
r6554 # IOPub messages
class PyIn(Reference):
code = Unicode()
MinRK
include execution_count in pyin check
r6559 execution_count = Integer()
MinRK
begin testing message spec
r6554
PyErr = ExecuteReplyError
class Stream(Reference):
name = Enum((u'stdout', u'stderr'))
data = Unicode()
mime_pat = re.compile(r'\w+/\w+')
class DisplayData(Reference):
source = Unicode()
metadata = Dict()
data = Dict()
def _data_changed(self, name, old, new):
for k,v in new.iteritems():
nt.assert_true(mime_pat.match(k))
nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
MinRK
handle pyout messages in test_message_spec...
r6664 class PyOut(Reference):
execution_count = Integer()
data = Dict()
def _data_changed(self, name, old, new):
for k,v in new.iteritems():
nt.assert_true(mime_pat.match(k))
nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
MinRK
begin testing message spec
r6554 references = {
'execute_reply' : ExecuteReply(),
'object_info_reply' : OInfoReply(),
'status' : Status(),
'complete_reply' : CompleteReply(),
Takafumi Arakaki
Rename version_rep/req to kernel_info_rep/req
r8879 'kernel_info_reply': KernelInfoReply(),
MinRK
begin testing message spec
r6554 'pyin' : PyIn(),
MinRK
handle pyout messages in test_message_spec...
r6664 'pyout' : PyOut(),
MinRK
begin testing message spec
r6554 'pyerr' : PyErr(),
'stream' : Stream(),
'display_data' : DisplayData(),
}
Takafumi Arakaki
Document how test_message_spec works
r8829 """
Specifications of `content` part of the reply messages.
"""
MinRK
begin testing message spec
r6554
def validate_message(msg, msg_type=None, parent=None):
MinRK
evaluate a few dangling validate_message generators...
r6573 """validate a message
This is a generator, and must be iterated through to actually
trigger each test.
If msg_type and/or parent are given, the msg_type and/or parent msg_id
are compared with the given values.
"""
MinRK
begin testing message spec
r6554 RMessage().check(msg)
if msg_type:
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(msg['msg_type'], msg_type)
MinRK
begin testing message spec
r6554 if parent:
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_equal(msg['parent_header']['msg_id'], parent)
MinRK
begin testing message spec
r6554 content = msg['content']
ref = references[msg['msg_type']]
MinRK
use parametric tests in message_spec...
r6558 for tst in ref.check(content):
yield tst
MinRK
begin testing message spec
r6554
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
# Shell channel
Fernando Perez
Rework messaging to better conform to our spec....
r2926
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
Fernando Perez
Rework messaging to better conform to our spec....
r2926 def test_execute():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 shell = KM.shell_channel
msg_id = shell.execute(code='x=1')
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'execute_reply', msg_id):
yield tst
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_execute_silent():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='x=1', silent=True)
# flush status=idle
status = KM.sub_channel.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(status, 'status', msg_id):
yield tst
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(status['content']['execution_state'], 'idle')
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
MinRK
begin testing message spec
r6554 count = reply['execution_count']
msg_id, reply = execute(code='x=2', silent=True)
# flush status=idle
status = KM.sub_channel.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(status, 'status', msg_id):
yield tst
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(status['content']['execution_state'], 'idle')
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
MinRK
begin testing message spec
r6554 count_2 = reply['execution_count']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(count_2, count)
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_execute_error():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554
msg_id, reply = execute(code='1/0')
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(reply['status'], 'error')
yield nt.assert_equal(reply['ename'], 'ZeroDivisionError')
MinRK
begin testing message spec
r6554
pyerr = KM.sub_channel.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(pyerr, 'pyerr', msg_id):
yield tst
MinRK
begin testing message spec
r6554
def test_execute_inc():
"""execute request should increment execution_count"""
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='x=1')
count = reply['execution_count']
flush_channels()
Fernando Perez
Rework messaging to better conform to our spec....
r2926
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='x=2')
count_2 = reply['execution_count']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(count_2, count+1)
MinRK
begin testing message spec
r6554
def test_user_variables():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='x=1', user_variables=['x'])
user_variables = reply['user_variables']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(user_variables, {u'x' : u'1'})
MinRK
begin testing message spec
r6554
def test_user_expressions():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
user_expressions = reply['user_expressions']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 nt.assert_equal(user_expressions, {u'foo' : u'2'})
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_oinfo():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 shell = KM.shell_channel
msg_id = shell.object_info('a')
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'object_info_reply', msg_id):
yield tst
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_oinfo_found():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 shell = KM.shell_channel
MinRK
begin testing message spec
r6554 msg_id, reply = execute(code='a=5')
msg_id = shell.object_info('a')
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'object_info_reply', msg_id):
yield tst
MinRK
begin testing message spec
r6554 content = reply['content']
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_true(content['found'])
MinRK
more detail in oinfo tests
r6560 argspec = content['argspec']
yield nt.assert_true(argspec is None, "didn't expect argspec dict, got %r" % argspec)
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
a couple more oinfo tests
r6557 def test_oinfo_detail():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
a couple more oinfo tests
r6557
MinRK
use parametric tests in message_spec...
r6558 shell = KM.shell_channel
MinRK
a couple more oinfo tests
r6557 msg_id, reply = execute(code='ip=get_ipython()')
MinRK
use parametric tests in message_spec...
r6558
MinRK
a couple more oinfo tests
r6557 msg_id = shell.object_info('ip.object_inspect', detail_level=2)
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'object_info_reply', msg_id):
yield tst
MinRK
a couple more oinfo tests
r6557 content = reply['content']
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_true(content['found'])
MinRK
more detail in oinfo tests
r6560 argspec = content['argspec']
yield nt.assert_true(isinstance(argspec, dict), "expected non-empty argspec dict, got %r" % argspec)
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(argspec['defaults'], [0])
MinRK
a couple more oinfo tests
r6557
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
a couple more oinfo tests
r6557 def test_oinfo_not_found():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
a couple more oinfo tests
r6557
MinRK
use parametric tests in message_spec...
r6558 shell = KM.shell_channel
MinRK
a couple more oinfo tests
r6557 msg_id = shell.object_info('dne')
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'object_info_reply', msg_id):
yield tst
MinRK
a couple more oinfo tests
r6557 content = reply['content']
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_false(content['found'])
MinRK
a couple more oinfo tests
r6557
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_complete():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 shell = KM.shell_channel
msg_id, reply = execute(code="alpha = albert = 5")
msg_id = shell.complete('al', 'al', 2)
reply = shell.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(reply, 'complete_reply', msg_id):
yield tst
MinRK
begin testing message spec
r6554 matches = reply['content']['matches']
for name in ('alpha', 'albert'):
MinRK
use parametric tests in message_spec...
r6558 yield nt.assert_true(name in matches, "Missing match: %r" % name)
MinRK
begin testing message spec
r6554
Takafumi Arakaki
Add a test for version_request in test_message_spec.py
r8831 @dec.parametric
Takafumi Arakaki
Rename version_rep/req to kernel_info_rep/req
r8879 def test_kernel_info_request():
Takafumi Arakaki
Add a test for version_request in test_message_spec.py
r8831 flush_channels()
shell = KM.shell_channel
Takafumi Arakaki
Rename remnant of version_request/reply protocol
r8905 msg_id = shell.kernel_info()
Takafumi Arakaki
Add a test for version_request in test_message_spec.py
r8831 reply = shell.get_msg(timeout=2)
Takafumi Arakaki
Rename version_rep/req to kernel_info_rep/req
r8879 for tst in validate_message(reply, 'kernel_info_reply', msg_id):
Takafumi Arakaki
Add a test for version_request in test_message_spec.py
r8831 yield tst
MinRK
mark IOPub channel tests
r6561 # IOPub channel
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
MinRK
begin testing message spec
r6554 def test_stream():
MinRK
use parametric tests in message_spec...
r6558 flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute("print('hi')")
stdout = KM.sub_channel.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(stdout, 'stream', msg_id):
yield tst
MinRK
begin testing message spec
r6554 content = stdout['content']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(content['name'], u'stdout')
yield nt.assert_equal(content['data'], u'hi\n')
MinRK
begin testing message spec
r6554
MinRK
use parametric tests in message_spec...
r6558 @dec.parametric
def test_display_data():
flush_channels()
MinRK
begin testing message spec
r6554 msg_id, reply = execute("from IPython.core.display import display; display(1)")
display = KM.sub_channel.get_msg(timeout=2)
MinRK
use parametric tests in message_spec...
r6558 for tst in validate_message(display, 'display_data', parent=msg_id):
yield tst
MinRK
begin testing message spec
r6554 data = display['content']['data']
Bradley M. Froehle
s/nt.assert_equals/nt.assert_equal/
r7875 yield nt.assert_equal(data['text/plain'], u'1')
MinRK
begin testing message spec
r6554