def test_reply_to_request(self): req = Message.request('hello', 'world', mid=1) reply = Message.reply_to_request(req, 'test') self.assertEqual(reply.mtype, Message.REPLY) self.assertEqual(reply.name, 'hello') self.assertEqual(reply.arguments, [b'test']) self.assertEqual(reply.mid, b'1')
def test_reply_ok(self): """Test reply checking.""" self.assertEqual(Message.reply("foo", "ok").reply_ok(), True) self.assertEqual(Message.reply("foo", "ok", 1).reply_ok(), True) self.assertEqual(Message.reply("foo", "fail").reply_ok(), False) self.assertEqual(Message.reply("foo", "fail", "ok").reply_ok(), False) self.assertEqual(Message.request("foo", "ok").reply_ok(), False)
def setUp(self): self.client = katcp.DeviceClient('localhost', 0) self.assertFalse(self.client._received_protocol_info.isSet()) self.v4_build_state = Message.inform('build-state', 'blah-5.21a3') self.v4_version = Message.inform('version', '7.3') self.v5_version_connect_mid = Message.inform( 'version-connect', 'katcp-protocol', '5.0-I') self.v5_version_connect_nomid = Message.inform( 'version-connect', 'katcp-protocol', '5.0')
def setUp(self): self.client = katcp.DeviceClient('localhost', 0) self.assertFalse(self.client._received_protocol_info.isSet()) self.v4_build_state = Message.inform('build-state', 'blah-5.21a3') self.v4_version = Message.inform('version', '7.3') self.v5_version_connect_mid = Message.inform('version-connect', 'katcp-protocol', '5.0-I') self.v5_version_connect_nomid = Message.inform('version-connect', 'katcp-protocol', '5.0')
def test_stop_cleanup(self): yield self.client.until_protocol() mid = 564 future_reply = self.client.future_request(Message.request( 'slow-command', 1, mid=mid)) # Stop client self.client.stop() reply, informs = yield future_reply self.assertEqual(reply, Message.reply( 'slow-command', 'fail', 'Client stopped before reply was received', mid=mid))
def test_disconnect_cleanup(self): yield self.client.until_protocol() mid = 55 future_reply = self.client.future_request(Message.request( 'slow-command', 1, mid=mid)) # Force a disconnect self.client._disconnect() reply, informs = yield future_reply self.assertEqual(reply, Message.reply( 'slow-command', 'fail', 'Connection closed before reply was received', mid=mid))
def test_stop_cleanup(self): self.client.wait_protocol(timeout=1) mid = 56 future_reply = Future() self.client.ioloop.add_callback( lambda : gen.chain_future(self.client.future_request(Message.request( 'slow-command', 1, mid=mid)), future_reply)) # Force a disconnect self.client.stop() reply, informs = future_reply.result(timeout=1) self.assertEqual(reply, Message.reply( 'slow-command', 'fail', 'Client stopped before reply was received', mid=mid))
def test_blocking_request(self): """Test blocking_request.""" reply, informs = self.client.blocking_request( Message.request("watchdog")) self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, ["ok"]) self.assertEqual(remove_version_connect(informs), []) reply, informs = self.client.blocking_request(Message.request("help")) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(informs), int(reply.arguments[1]))
def test_str(self): msg = Message.reply('fail', 'on fire', mid=234) self.assertEqual(str(msg), '!fail[234] on\\_fire') # Expect slighty different results in case of invalid UTF-8 bytes for # PY2's native byte string compared to PY3's unicode msg = Message.reply('ok', b'invalid utf-8\xff\x00') if future.utils.PY2: self.assertEqual(str(msg), '!ok invalid\_utf-8\xff\\0') else: with self.assertRaises(UnicodeDecodeError): str(msg)
def _test_timeout(self, use_mid=None): """Test requests that timeout.""" replies = [] replied = threading.Event() informs = [] timeout = 0.001 @counting_callback() def reply_cb(msg): replies.append(msg) replied.set() def inform_cb(msg): informs.append(msg) self.assertTrue(self.client.wait_protocol(0.2)) self.client.callback_request( Message.request("slow-command", "0.1"), use_mid=use_mid, reply_cb=reply_cb, inform_cb=inform_cb, timeout=timeout, ) reply_cb.assert_wait(1) self.client.request(Message.request('cancel-slow-command')) msg = replies[0] self.assertEqual(msg.name, "slow-command") self.assertFalse(msg.reply_ok()) self.assertRegexpMatches( msg.arguments[1], r"Request slow-command timed out after 0\..* seconds.") self.assertEqual(len(remove_version_connect(informs)), 0) self.assertEqual(len(replies), 1) del replies[:] del informs[:] reply_cb.reset() # test next request succeeds self.client.callback_request( Message.request("slow-command", "0.05"), reply_cb=reply_cb, inform_cb=inform_cb, ) reply_cb.assert_wait() self.assertEqual(len(replies), 1) self.assertEqual(len(informs), 0) self.assertEqual([msg.name for msg in replies + informs], ["slow-command"] * len(replies + informs)) self.assertEqual([msg.arguments for msg in replies], [["ok"]])
def _test_timeout(self, use_mid=None): """Test requests that timeout.""" replies = [] replied = threading.Event() informs = [] timeout = 0.001 @counting_callback() def reply_cb(msg): replies.append(msg) replied.set() def inform_cb(msg): informs.append(msg) self.assertTrue(self.client.wait_protocol(0.2)) self.client.callback_request( Message.request("slow-command", "0.1"), use_mid=use_mid, reply_cb=reply_cb, inform_cb=inform_cb, timeout=timeout, ) reply_cb.assert_wait(1) self.client.request(Message.request('cancel-slow-command')) msg = replies[0] self.assertEqual(msg.name, "slow-command") self.assertFalse(msg.reply_ok()) self.assertRegexpMatches(msg.arguments[1], r"Request slow-command timed out after 0\..* seconds.") self.assertEqual(len(remove_version_connect(informs)), 0) self.assertEqual(len(replies), 1) del replies[:] del informs[:] reply_cb.reset() # test next request succeeds self.client.callback_request( Message.request("slow-command", "0.05"), reply_cb=reply_cb, inform_cb=inform_cb, ) reply_cb.assert_wait() self.assertEqual(len(replies), 1) self.assertEqual(len(informs), 0) self.assertEqual([msg.name for msg in replies + informs], ["slow-command"] * len(replies + informs)) self.assertEqual([msg.arguments for msg in replies], [["ok"]])
def test_blocking_request(self): """Test blocking_request.""" reply, informs = self.client.blocking_request( Message.request("watchdog")) self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, ["ok"]) self.assertEqual(remove_version_connect(informs), []) reply, informs = self.client.blocking_request( Message.request("help")) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(informs), int(reply.arguments[1]))
def test_callback_request(self): """Test callback request.""" watchdog_replies = [] watchdog_replied = threading.Event() def watchdog_reply(reply): self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, [b"ok"]) watchdog_replies.append(reply) watchdog_replied.set() self.assertTrue(self.client.wait_protocol(0.5)) self.client.callback_request( Message.request("watchdog"), reply_cb=watchdog_reply, ) watchdog_replied.wait(0.5) self.assertTrue(watchdog_replies) help_replies = [] help_informs = [] help_replied = threading.Event() def help_reply(reply): self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, [b"ok", b"%d" % NUM_HELP_MESSAGES]) self.assertEqual(len(help_informs), int(reply.arguments[1])) help_replies.append(reply) help_replied.set() def help_inform(inform): self.assertEqual(inform.name, "help") self.assertEqual(len(inform.arguments), 2) help_informs.append(inform) self.client.callback_request( Message.request("help"), reply_cb=help_reply, inform_cb=help_inform, ) help_replied.wait(1) self.assertTrue(help_replied.isSet()) help_replied.clear() help_replied.wait(0.05) # Check if (unwanted) late help replies arrive self.assertFalse(help_replied.isSet()) self.assertEqual(len(help_replies), 1) self.assertEqual(len(help_informs), NUM_HELP_MESSAGES)
def test_callback_request(self): """Test callback request.""" watchdog_replies = [] watchdog_replied = threading.Event() def watchdog_reply(reply): self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, ["ok"]) watchdog_replies.append(reply) watchdog_replied.set() self.assertTrue(self.client.wait_protocol(0.5)) self.client.callback_request( Message.request("watchdog"), reply_cb=watchdog_reply, ) watchdog_replied.wait(0.5) self.assertTrue(watchdog_replies) help_replies = [] help_informs = [] help_replied = threading.Event() def help_reply(reply): self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(help_informs), int(reply.arguments[1])) help_replies.append(reply) help_replied.set() def help_inform(inform): self.assertEqual(inform.name, "help") self.assertEqual(len(inform.arguments), 2) help_informs.append(inform) self.client.callback_request( Message.request("help"), reply_cb=help_reply, inform_cb=help_inform, ) help_replied.wait(1) self.assertTrue(help_replied.isSet()) help_replied.clear() help_replied.wait(0.05) # Check if (unwanted) late help replies arrive self.assertFalse(help_replied.isSet()) self.assertEqual(len(help_replies), 1) self.assertEqual(len(help_informs), NO_HELP_MESSAGES)
def test_disconnect_cleanup(self): yield self.client.until_protocol() mid = 55 future_reply = self.client.future_request( Message.request('slow-command', 1, mid=mid)) # Force a disconnect self.client._disconnect() reply, informs = yield future_reply self.assertEqual( reply, Message.reply('slow-command', 'fail', 'Connection closed before reply was received', mid=mid))
def test_stop_cleanup(self): yield self.client.until_protocol() mid = 564 future_reply = self.client.future_request( Message.request('slow-command', 1, mid=mid)) # Stop client self.client.stop() reply, informs = yield future_reply self.assertEqual( reply, Message.reply('slow-command', 'fail', 'Client stopped before reply was received', mid=mid))
def test_request(self): """Test request method.""" self.assertTrue(self.client.wait_protocol(1)) self.client.send_request(Message.request("watchdog")) self.client._server_supports_ids = False with self.assertRaises(katcp.core.KatcpVersionError): self.client.send_request(Message.request("watchdog", mid=56)) self.client._server_supports_ids = True self.client.send_request(Message.request("watchdog", mid=55)) msgs = self.server.until_messages(2).result(timeout=1) self._assert_msgs_equal(msgs, [ r"?watchdog", r"?watchdog[55]", ])
def test_message_argument_formatting(self): float_val = 2.35532342334233294e17 m = Message.request('req-name', 1, float_val, True, False, 'string') self.assertEqual( m.arguments, [b'1', repr(float_val).encode('ascii'), b'1', b'0', b'string'])
def test_inform_attributes(self): """Test inform message attributes.""" msg = Message.inform('hello', 'world', mid=1) self.assertEqual(msg.mtype, Message.INFORM) self.assertEqual(msg.name, 'hello') self.assertEqual(msg.arguments, [b'world']) self.assertEqual(msg.mid, b'1')
def test_request_attributes(self): """Test request message attributes.""" msg = Message.request('hello', 'world') self.assertEqual(msg.mtype, Message.REQUEST) self.assertEqual(msg.name, 'hello') self.assertEqual(msg.arguments, [b'world']) self.assertIsNone(msg.mid)
def test_reply_attributes(self): """Test reply message attributes.""" msg = Message.reply('hello', 'world', mid=None) self.assertEqual(msg.mtype, Message.REPLY) self.assertEqual(msg.name, 'hello') self.assertEqual(msg.arguments, [b'world']) self.assertIsNone(msg.mid)
def test_user_data(self): """Test callbacks with user data.""" help_replies = [] help_informs = [] done = threading.Event() def help_reply(reply, x, y): self.assertEqual(reply.name, "help") self.assertEqual(x, 5) self.assertEqual(y, "foo") help_replies.append(reply) done.set() def help_inform(inform, x, y): self.assertEqual(inform.name, "help") self.assertEqual(x, 5) self.assertEqual(y, "foo") help_informs.append(inform) self.client.callback_request( Message.request("help"), reply_cb=help_reply, inform_cb=help_inform, user_data=(5, "foo")) done.wait(1) # Wait a bit longer to see if spurious replies arrive time.sleep(0.01) self.assertEqual(len(help_replies), 1) self.assertEqual(len(remove_version_connect(help_informs)), NO_HELP_MESSAGES)
def test_stop_cleanup(self): self.client.wait_protocol(timeout=1) mid = 56 future_reply = Future() self.client.ioloop.add_callback(lambda: gen.chain_future( self.client.future_request( Message.request('slow-command', 1, mid=mid)), future_reply)) # Force a disconnect self.client.stop() reply, informs = future_reply.result(timeout=1) self.assertEqual( reply, Message.reply('slow-command', 'fail', 'Client stopped before reply was received', mid=mid))
def test_user_data(self): """Test callbacks with user data.""" help_replies = [] help_informs = [] done = threading.Event() def help_reply(reply, x, y): self.assertEqual(reply.name, "help") self.assertEqual(x, 5) self.assertEqual(y, "foo") help_replies.append(reply) done.set() def help_inform(inform, x, y): self.assertEqual(inform.name, "help") self.assertEqual(x, 5) self.assertEqual(y, "foo") help_informs.append(inform) self.client.callback_request(Message.request("help"), reply_cb=help_reply, inform_cb=help_inform, user_data=(5, "foo")) done.wait(1) # Wait a bit longer to see if spurious replies arrive time.sleep(0.01) self.assertEqual(len(help_replies), 1) self.assertEqual(len(remove_version_connect(help_informs)), NO_HELP_MESSAGES)
def test_future_request_simple(self): yield self.client.until_connected() reply, informs = yield self.client.future_request( Message.request('watchdog')) self.assertEqual(len(informs), 0) self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, ["ok"])
def test_future_request_with_informs(self): yield self.client.until_connected() reply, informs = yield self.client.future_request( Message.request('help')) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(informs), NO_HELP_MESSAGES)
def test_blocking_request_mid(self): ## Test that the blocking client does the right thing with message ## identifiers # Wait for the client to detect the server protocol. Server should # support message identifiers self.assertTrue(self.client.wait_protocol(1)) # Replace send_message so that we can check the message self.client.send_message = mock.Mock() # By default message identifiers should be enabled, and should start # counting at 1 self.client.blocking_request(Message.request('watchdog'), timeout=0) self.client.blocking_request(Message.request('watchdog'), timeout=0) self.client.blocking_request(Message.request('watchdog'), timeout=0) # Extract Message object .mid attributes from the mock calls to # send_message mids = [ args[0].mid # arg[0] should be the Message() object for args, kwargs in self.client.send_message.call_args_list ] self.assertEqual(mids, ['1', '2', '3']) self.client.send_message.reset_mock() # Explicitly ask for no mid to be used self.client.blocking_request(Message.request('watchdog'), use_mid=False, timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None) # Ask for a specific mid to be used self.client.send_message.reset_mock() self.client.blocking_request(Message.request('watchdog', mid=42), timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, '42') ## Check situation for a katcpv4 server self.client._server_supports_ids = False # Should fail if an mid is passed reply, inform = self.client.blocking_request(Message.request( 'watchdog', mid=42), timeout=0) self.assertFalse(reply.reply_ok()) # Should fail if an mid is requested reply, inform = self.client.blocking_request( Message.request('watchdog'), use_mid=True, timeout=0) self.assertFalse(reply.reply_ok()) # Should use no mid by default self.client.send_message.reset_mock() self.client.blocking_request(Message.request('watchdog'), timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None)
def test_send_message(self): """Test send_message method.""" self.client.send_message(Message.inform("random-inform")) msgs = self.server.until_messages(1).result(timeout=1) self._assert_msgs_equal(msgs, [ r"#random-inform", ])
def test_timeout(self): """Test calling blocking_request with a timeout.""" reply, informs = self.client.blocking_request( Message.request("slow-command", "0.5"), timeout=0.001) self.assertFalse(reply.reply_ok()) self.assertRegexpMatches( reply.arguments[1], r"Request slow-command timed out after 0\..* seconds.")
def test_inform_version_connect(self): # Test that the inform handler doesn't screw up with a non-katcp related # version-connect inform. self.client.handle_message(Message.inform( 'version-connect', 'not-katcp', '5.71a3')) # Should not raise any errors, but should also not set the protocol # infor received flag. self.assertFalse(self.client._received_protocol_info.isSet())
def test_inform_version_connect(self): # Test that the inform handler doesn't screw up with a non-katcp related # version-connect inform. self.client.handle_message( Message.inform('version-connect', 'not-katcp', '5.71a3')) # Should not raise any errors, but should also not set the protocol # infor received flag. self.assertFalse(self.client._received_protocol_info.isSet())
def test_stringy_arguments_to_bytes(self): """Test non-simple types get correctly converted to bytes.""" class Stringy(object): def __str__(self): return "string" req = Message.request('hello', Stringy()) self.assertEqual(req.arguments, [b"string"])
def test_init_basic(self): msg = Message(Message.REQUEST, 'hello', ['world', b'binary\xff\x00', 123, 4.5, True, False]) self.assertEqual(msg.mtype, Message.REQUEST) self.assertEqual(msg.name, 'hello') self.assertEqual( msg.arguments, [b'world', b'binary\xff\x00', b'123', b'4.5', b'1', b'0']) self.assertIsNone(msg.mid)
def test_timeout(self): """Test calling blocking_request with a timeout.""" reply, informs = self.client.blocking_request(Message.request( "slow-command", "0.5"), timeout=0.001) self.assertFalse(reply.reply_ok()) self.assertRegexpMatches( reply.arguments[1], r"Request slow-command timed out after 0\..* seconds.")
def test_bytes(self): msg = Message.request('hello', u'café', b'_bin ary\xff\x00\n\r\t\\\x1b', 123, 4.5, True, False, '') raw = bytes(msg) expected = ( b'?hello caf\xc3\xa9 _bin\\_ary\xff\\0\\n\\r\\t\\\\\\e 123 4.5 1 0 \\@' ) self.assertEqual(raw, expected)
def test_blocking_request_mid(self): ## Test that the blocking client does the right thing with message ## identifiers # Wait for the client to detect the server protocol. Server should # support message identifiers self.assertTrue(self.client.wait_protocol(1)) # Replace send_message so that we can check the message self.client.send_message = mock.Mock() # By default message identifiers should be enabled, and should start # counting at 1 self.client.blocking_request(Message.request('watchdog'), timeout=0) self.client.blocking_request(Message.request('watchdog'), timeout=0) self.client.blocking_request(Message.request('watchdog'), timeout=0) # Extract Message object .mid attributes from the mock calls to # send_message mids = [args[0].mid # arg[0] should be the Message() object for args, kwargs in self.client.send_message.call_args_list] self.assertEqual(mids, ['1','2','3']) self.client.send_message.reset_mock() # Explicitly ask for no mid to be used self.client.blocking_request(Message.request('watchdog'), use_mid=False, timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None) # Ask for a specific mid to be used self.client.send_message.reset_mock() self.client.blocking_request(Message.request( 'watchdog', mid=42), timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, '42') ## Check situation for a katcpv4 server self.client._server_supports_ids = False # Should fail if an mid is passed reply, inform = self.client.blocking_request(Message.request( 'watchdog', mid=42), timeout=0) self.assertFalse(reply.reply_ok()) # Should fail if an mid is requested reply, inform = self.client.blocking_request( Message.request('watchdog'), use_mid=True, timeout=0) self.assertFalse(reply.reply_ok()) # Should use no mid by default self.client.send_message.reset_mock() self.client.blocking_request(Message.request( 'watchdog'), timeout=0) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None)
def test_blocking_request(self): """Test the callback client's blocking request.""" reply, informs = self.client.blocking_request( Message.request("help"), ) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(remove_version_connect(informs)), NO_HELP_MESSAGES) reply, informs = self.client.blocking_request( Message.request("slow-command", "0.5"), timeout=0.001) self.assertEqual(reply.name, "slow-command") self.assertEqual(reply.arguments[0], "fail") self.assertRegexpMatches( reply.arguments[1], r"Request slow-command timed out after 0\..* seconds.")
def test_blocking_request(self): """Test the callback client's blocking request.""" reply, informs = self.client.blocking_request( Message.request("help"), ) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(remove_version_connect(informs)), NO_HELP_MESSAGES) reply, informs = self.client.blocking_request(Message.request( "slow-command", "0.5"), timeout=0.001) self.assertEqual(reply.name, "slow-command") self.assertEqual(reply.arguments[0], "fail") self.assertRegexpMatches( reply.arguments[1], r"Request slow-command timed out after 0\..* seconds.")
def test_versions(self): """Test that the versions parameter is populated.""" preamble_done = self.client.handle_reply = WaitingMock() # Do a request and wait for it to be done so that we can be sure we received the # full connection-header before testing self.client.request(Message.request('watchdog')) preamble_done.assert_wait_call_count(1, timeout=1) versions = self.client.versions self.assertIn('katcp', ' '.join(versions['katcp-library'])) self.assertIn('device', ' '.join(versions['katcp-device'])) self.assertTrue(' '.join(versions['katcp-protocol']))
def test_fifty_thread_mayhem(self): """Test using callbacks from fifty threads simultaneously.""" num_threads = 50 # map from thread_id -> (replies, informs) results = {} # list of thread objects threads = [] def reply_cb(reply, thread_id): results[thread_id][0].append(reply) results[thread_id][2].set() def inform_cb(inform, thread_id): results[thread_id][1].append(inform) def worker(thread_id, request): self.client.callback_request( request.copy(), reply_cb=reply_cb, inform_cb=inform_cb, user_data=(thread_id,), ) request = Message.request("help") for thread_id in range(num_threads): results[thread_id] = ([], [], threading.Event()) for thread_id in range(num_threads): thread = threading.Thread(target=worker, args=(thread_id, request)) threads.append(thread) for thread in threads: thread.start() for thread in threads: thread.join() for thread_id in range(num_threads): replies, informs, done = results[thread_id] done.wait(5.0) self.assertTrue(done.isSet()) self.assertEqual(len(replies), 1) self.assertEqual(replies[0].arguments[0], "ok") informs = remove_version_connect(informs) if len(informs) != NO_HELP_MESSAGES: print thread_id, len(informs) print [x.arguments[0] for x in informs] self.assertEqual(len(informs), NO_HELP_MESSAGES)
def test_fifty_thread_mayhem(self): """Test using callbacks from fifty threads simultaneously.""" num_threads = 50 # map from thread_id -> (replies, informs) results = {} # list of thread objects threads = [] def reply_cb(reply, thread_id): results[thread_id][0].append(reply) results[thread_id][2].set() def inform_cb(inform, thread_id): results[thread_id][1].append(inform) def worker(thread_id, request): self.client.callback_request( request.copy(), reply_cb=reply_cb, inform_cb=inform_cb, user_data=(thread_id, ), ) request = Message.request("help") for thread_id in range(num_threads): results[thread_id] = ([], [], threading.Event()) for thread_id in range(num_threads): thread = threading.Thread(target=worker, args=(thread_id, request)) threads.append(thread) for thread in threads: thread.start() for thread in threads: thread.join() for thread_id in range(num_threads): replies, informs, done = results[thread_id] done.wait(5.0) self.assertTrue(done.isSet()) self.assertEqual(len(replies), 1) self.assertEqual(replies[0].arguments[0], "ok") informs = remove_version_connect(informs) if len(informs) != NO_HELP_MESSAGES: print thread_id, len(informs) print[x.arguments[0] for x in informs] self.assertEqual(len(informs), NO_HELP_MESSAGES)
def test_repr(self): msg = Message.reply('ok', 'café', b'_bin ary\xff\x00\n\r\t\\\x1b', 123, 4.5, True, False, '', 'z' * 1100) # storing Message.arguments as byte string results in slightly different # reprs for PY2 compared to PY3. if future.utils.PY2: expected = ("<Message reply ok (caf\xc3\xa9, " "_bin\\_ary\xff\\0\\n\\r\\t\\\\\\e, " "123, 4.5, 1, 0, , " "{}..." ")>".format('z' * 1000)) else: expected = (r"<Message reply ok (b'caf\xc3\xa9', " r"b'_bin\\_ary\xff\\0\\n\\r\\t\\\\\\e', " r"b'123', b'4.5', b'1', b'0', b'', " r"b'{}...'" r")>".format('z' * 1000)) self.assertEqual(repr(msg), expected)
def test_equality(self): class AlwaysEqual(object): def __eq__(self, other): return True msg = Message.inform("foo", "a", "b") assert msg == Message.inform("foo", "a", "b") assert msg != Message.request("foo", "a", "b") assert msg != Message.inform("bar", "a", "b") assert msg != Message.inform("foo", "a", "b", "c") assert msg != Message.reply("foo", "a", "b") assert msg != 3 assert msg == AlwaysEqual()
def test_request_fail_on_raise(self): """Test that the callback is called even if send_message raises KatcpClientError.""" def raise_error(msg, timeout=None): raise katcp.KatcpClientError("Error %s" % msg.name) self.client.send_message = raise_error replies = [] @counting_callback() def reply_cb(msg): replies.append(msg) self.client.callback_request(Message.request("foo"), reply_cb=reply_cb, ) reply_cb.assert_wait() self.assertEqual(len(replies), 1) self.assertEqual(replies[0].name, "foo") self.assertEqual(replies[0].arguments, ["fail", "Error foo"])
def _test_timeout(self, timeout, set_request_timeout=False): request_timeout = timeout if set_request_timeout else None yield self.client.until_connected() t0 = self.io_loop.time() reply_future = self.client.future_request(Message.request('slow-command', timeout + 1), timeout=request_timeout) # Warp to just before the timeout expires and check that the future is not yet # resolved self.set_ioloop_time(t0 + timeout*0.9999) yield self.wake_ioloop() self.assertFalse(reply_future.done()) # Warp to just after the timeout expires, and check that it gives us a timeout # error reply self.set_ioloop_time(t0 + timeout*1.0001) yield self.wake_ioloop() self.assertTrue(reply_future.done()) reply, informs = reply_future.result() self.assertFalse(reply.reply_ok()) self.assertRegexpMatches( reply.arguments[1], r"Request slow-command timed out after .* seconds.")
def test_no_callback(self): """Test request without callback.""" help_messages = [] help_completed = threading.Event() def handle_help_message(client, msg): help_messages.append(msg) if msg.mtype == msg.REPLY: help_completed.set() self.client._inform_handlers["help"] = handle_help_message self.client._reply_handlers["help"] = handle_help_message # Set client._last_msg_id so we know that the ID is. Should be # _last_msg_id + 1 self.client._last_msg_id = 0 self.assertTrue(self.client.wait_protocol(0.2)) self.client.callback_request(Message.request("help")) help_completed.wait(1) self.assertTrue(help_completed.isSet()) self._assert_msgs_like(help_messages, [("#help[1] ", "")] * NO_HELP_MESSAGES + [("!help[1] ok %d" % NO_HELP_MESSAGES, "")])
def future_request(self, msg, timeout=None, use_mid=None): """Send a request messsage, with future replies. Parameters ---------- msg : Message object The request Message to send. timeout : float in seconds How long to wait for a reply. The default is the the timeout set when creating the AsyncClient. use_mid : boolean, optional Whether to use message IDs. Default is to use message IDs if the server supports them. Returns ------- A tornado.concurrent.Future that resolves with: reply : Message object The reply message received. informs : list of Message objects A list of the inform messages received. """ mid = self._get_mid_and_update_msg(msg, use_mid) if msg.name in self.request_handlers: req = FakeClientRequestConnection(self.client_connection, msg) reply_msg = yield tornado.gen.maybe_future(self.request_handlers[msg.name](req, msg)) reply_informs = req.informs_sent else: reply_msg = Message.reply(msg.name, "ok") reply_informs = [] reply_msg.mid = mid raise Return((reply_msg, reply_informs))
def inform(self, *args): inf_msg = Message.reply_inform(self.msg, *args) self.informs_sent.append(inf_msg)
def test_future_request_simple(self): yield self.client.until_connected() reply, informs = yield self.client.future_request(Message.request('watchdog')) self.assertEqual(len(informs), 0) self.assertEqual(reply.name, "watchdog") self.assertEqual(reply.arguments, ["ok"])
def test_future_request_with_informs(self): yield self.client.until_connected() reply, informs = yield self.client.future_request(Message.request('help')) self.assertEqual(reply.name, "help") self.assertEqual(reply.arguments, ["ok", "%d" % NO_HELP_MESSAGES]) self.assertEqual(len(informs), NO_HELP_MESSAGES)
def test_callback_request_mid(self): ## Test that the client does the right thing with message identifiers # Wait for the client to detect the server protocol. Server should # support message identifiers self.assertTrue(self.client.wait_protocol(0.2)) # Replace send_message so that we can check the message self.client.send_message = mock.Mock(wraps=self.client.send_message) # By default message identifiers should be enabled, and should start # counting at 1 cb = counting_callback(number_of_calls=3)(lambda *x: x) self.client.callback_request(Message.request('watchdog'), reply_cb=cb) self.client.callback_request(Message.request('watchdog'), reply_cb=cb) self.client.callback_request(Message.request('watchdog'), reply_cb=cb) cb.assert_wait() # Extract Message object .mid attributes from the mock calls to # send_message mids = [args[0].mid # args[0] should be the Message() object for args, kwargs in self.client.send_message.call_args_list] self.assertEqual(mids, ['1','2','3']) self.client.send_message.reset_mock() # Explicitly ask for no mid to be used cb = counting_callback(number_of_calls=1)(lambda *x: x) self.client.callback_request( Message.request('watchdog'), use_mid=False, reply_cb=cb) cb.assert_wait() mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None) # Ask for a specific mid to be used self.client.send_message.reset_mock() cb = counting_callback(number_of_calls=1)(lambda *x: x) self.client.callback_request( Message.request('watchdog', mid=42), reply_cb=cb) cb.assert_wait() mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, '42') ## Check situation for a katcpv4 server self.client._server_supports_ids = False # Should fail if an mid is passed reply = [None] @counting_callback() def cb(msg): reply[0] = msg self.client.callback_request( Message.request('watchdog', mid=42), reply_cb=cb) cb.assert_wait() self.assertFalse(reply[0].reply_ok()) # Should fail if an mid is requested reply = [None] cb.reset() self.client.callback_request( Message.request('watchdog'), use_mid=True, reply_cb=cb) cb.assert_wait() self.assertFalse(reply[0].reply_ok()) # Should use no mid by default self.client.send_message.reset_mock() cb = counting_callback(number_of_calls=1)(lambda *x: x) self.client.callback_request(Message.request('watchdog'), reply_cb=cb) cb.assert_wait(timeout=1) mid = self.client.send_message.call_args[0][0].mid self.assertEqual(mid, None)