def setUp(self): self._setup_server() host, port = self.server.bind_address self.server_addr = (host, port) self.client = BlockingTestClient(self, host, port) self.client.start(timeout=1) self.assertTrue(self.client.wait_protocol(timeout=1))
def setUp(self): self.server = DeviceTestServer('', 0) self.server.start(timeout=0.1) host, port = self.server._sock.getsockname() self.client = BlockingTestClient(self, host, port) self.client.start(timeout=0.1)
def setUp(self): super(TestDeviceServerClientIntegrated, self).setUp() self._setup_server() host, port = self.server.bind_address self.server_addr = (host, port) self.client = BlockingTestClient(self, host, port) start_thread_with_cleanup(self, self.client, start_timeout=1) self.assertTrue(self.client.wait_protocol(timeout=1))
def setUp(self): self.server = DeviceTestServer('', 0) self.server.start(timeout=0.1) host, port = self.server._sock.getsockname() self.server_addr = (host, port) self.client = BlockingTestClient(self, host, port) self.client.start(timeout=0.1) self.assertTrue(self.client.wait_protocol(timeout=0.1))
class TestDeviceServerClientIntegrated(unittest.TestCase, TestUtilMixin): BLACKLIST = ("version-connect", "version", "build-state") def setUp(self): super(TestDeviceServerClientIntegrated, self).setUp() self._setup_server() host, port = self.server.bind_address self.server_addr = (host, port) self.client = BlockingTestClient(self, host, port) start_thread_with_cleanup(self, self.client, start_timeout=1) self.assertTrue(self.client.wait_protocol(timeout=1)) def _setup_server(self): self.server = DeviceTestServer('', 0) start_thread_with_cleanup(self, self.server, start_timeout=1) def test_log(self): get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) def tst(): with mock.patch('katcp.server.time.time') as m_time: m_time.return_value = 1234 self.server.log.error('An error') self.server.ioloop.add_callback(tst) get_msgs.wait_number(1) self._assert_msgs_equal(get_msgs(), [r"#log error 1234.000000 root An\_error"]) def test_simple_connect(self): """Test a simple server setup and teardown with client connect.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) # basic send self.client.request(katcp.Message.request("foo"), use_mid=False) # pipe-lined send self.client.raw_send("?bar-boom\r\n?baz\r") # broken up sends self.client.raw_send("?boo") self.client.raw_send("m arg1 arg2") self.client.raw_send("\n") self._assert_msgs_equal(get_msgs(min_number=4), [ r"!foo invalid Unknown\_request.", r"!bar-boom invalid Unknown\_request.", r"!baz invalid Unknown\_request.", r"!boom invalid Unknown\_request.", ]) def test_bad_requests(self): """Test request failure paths in device server.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) self.client.raw_send("bad msg\n") # wait for reply self.client.blocking_request(katcp.Message.request("watchdog"), use_mid=False) self._assert_msgs_like(get_msgs(), [ (r"#log error", "KatcpSyntaxError:" "\_Bad\_type\_character\_'b'.\\n"), (r"!watchdog ok", ""), ]) def test_slow_client(self): # Test that server does not choke sending messages to slow clients # Set max server write buffer size smaller so that it gives up earlier to make the # test faster self.server._server.MAX_WRITE_BUFFER_SIZE = 16384 self.client.wait_protocol(1) slow_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) slow_sock.connect(self.server_addr) slow_sock.settimeout(0.01) # Send a bunch of request to the server, but don't read anything from # the server try: slow_sock.sendall('?help\n' * 1000000) except (socket.error, socket.timeout): pass t0 = time.time() # Request should not have taken a very long time. self.client.assert_request_succeeds('help', informs_count=NO_HELP_MESSAGES) self.assertTrue(time.time() - t0 < 1) def test_server_ignores_informs_and_replies(self): """Test server ignores informs and replies.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) self.client.raw_send("#some inform\n") self.client.raw_send("!some reply\n") time.sleep(0.1) self.assertFalse(get_msgs()) def test_standard_requests(self): """Test standard request and replies.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) nomid_req = partial(self.client.blocking_request, use_mid=False) nomid_req(katcp.Message.request("watchdog")) nomid_req(katcp.Message.request("restart")) nomid_req(katcp.Message.request("log-level")) nomid_req(katcp.Message.request("log-level", "trace")) nomid_req(katcp.Message.request("log-level", "unknown")) nomid_req(katcp.Message.request("help")) nomid_req(katcp.Message.request("help", "watchdog")) nomid_req(katcp.Message.request("help", "unknown-request")) nomid_req(katcp.Message.request("client-list")) nomid_req(katcp.Message.request("version-list")) nomid_req(katcp.Message.request("sensor-list")) nomid_req(katcp.Message.request("sensor-list", "an.int")) nomid_req(katcp.Message.request("sensor-list", "an.unknown")) nomid_req(katcp.Message.request("sensor-value")) nomid_req(katcp.Message.request("sensor-value", "an.int")) nomid_req(katcp.Message.request("sensor-value", "an.unknown")) nomid_req(katcp.Message.request("sensor-sampling", "an.int")) nomid_req( katcp.Message.request("sensor-sampling", "an.int", "differential", "2")) nomid_req( katcp.Message.request("sensor-sampling", "an.int", "event-rate", "2", "3")) nomid_req(katcp.Message.request("sensor-sampling")) nomid_req( katcp.Message.request("sensor-sampling", "an.unknown", "auto")) nomid_req(katcp.Message.request("sensor-sampling", "an.int", "unknown")) def tst(): self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") self.server.ioloop.add_callback(tst) self.assertEqual(self.server.restart_queue.get_nowait(), self.server) expected_msgs = [ (r"!watchdog ok", ""), (r"!restart ok", ""), (r"!log-level ok warn", ""), (r"!log-level ok trace", ""), (r"!log-level fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help cancel-slow-command Cancel\_slow\_command\_request,\_" "resulting\_in\_it\_replying\_immediately", ""), (r"#help client-list", ""), (r"#help halt", ""), (r"#help help", ""), (r"#help log-level", ""), (r"#help new-command", ""), (r"#help raise-exception", ""), (r"#help raise-fail", ""), (r"#help restart", ""), (r"#help sensor-list", ""), (r"#help sensor-sampling", ""), (r"#help sensor-sampling-clear", ""), (r"#help sensor-value", ""), (r"#help slow-command", ""), (r"#help version-list", ""), (r"#help watchdog", ""), (r"!help ok %d" % NO_HELP_MESSAGES, ""), (r"#help watchdog", ""), (r"!help ok 1", ""), (r"!help fail", ""), (r"#client-list", ""), (r"!client-list ok 1", ""), (r"#version-list katcp-protocol", ""), (r"#version-list katcp-library", ""), (r"#version-list katcp-device", ""), (r"!version-list ok 3", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"!sensor-list fail", ""), (r"#sensor-value 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"#sensor-value 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"!sensor-value fail", ""), (r"!sensor-sampling ok an.int none", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling ok an.int differential 2", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling ok an.int event-rate 2 3", ""), (r"!sensor-sampling fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling fail Unknown\_sensor\_name:\_an.unknown.", ""), (r"!sensor-sampling fail Unknown\_strategy\_name:\_unknown.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ] self._assert_msgs_like(get_msgs(min_number=len(expected_msgs)), expected_msgs) def test_standard_requests_with_ids(self): """Test standard request and replies with message ids.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) current_id = [0] def mid(): current_id[0] += 1 return str(current_id[0]) def mid_req(*args): return katcp.Message.request(*args, mid=mid()) self.client.request(mid_req("watchdog")) self.client._next_id = mid # mock our mid generator for testing self.client.blocking_request(mid_req("restart")) self.client.request(mid_req("log-level")) self.client.request(mid_req("log-level", "trace")) self.client.request(mid_req("log-level", "unknown")) self.client.request(mid_req("help")) self.client.request(mid_req("help", "watchdog")) self.client.request(mid_req("help", "unknown-request")) self.client.request(mid_req("client-list")) self.client.request(mid_req("version-list")) self.client.request(mid_req("sensor-list")) self.client.request(mid_req("sensor-list", "an.int")) self.client.request(mid_req("sensor-list", "an.unknown")) self.client.request(mid_req("sensor-value")) self.client.request(mid_req("sensor-value", "an.int")) self.client.request(mid_req("sensor-value", "an.unknown")) self.client.blocking_request(mid_req("sensor-sampling", "an.int")) self.client.blocking_request( mid_req("sensor-sampling", "an.int", "differential", "2")) self.client.blocking_request( mid_req("sensor-sampling", "an.int", "event-rate", "2", "3")), self.client.blocking_request(mid_req("sensor-sampling")) self.client.blocking_request( mid_req("sensor-sampling", "an.unknown", "auto")) self.client.blocking_request( mid_req("sensor-sampling", "an.int", "unknown")) def tst(): self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") self.server.ioloop.add_callback(tst) expected_msgs = [ (r"!watchdog[1] ok", ""), (r"!restart[2] ok", ""), (r"!log-level[3] ok warn", ""), (r"!log-level[4] ok trace", ""), (r"!log-level[5] fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help[6] cancel-slow-command Cancel\_slow\_command\_request,\_" "resulting\_in\_it\_replying\_immediately", ""), (r"#help[6] client-list", ""), (r"#help[6] halt", ""), (r"#help[6] help", ""), (r"#help[6] log-level", ""), (r"#help[6] new-command", ""), (r"#help[6] raise-exception", ""), (r"#help[6] raise-fail", ""), (r"#help[6] restart", ""), (r"#help[6] sensor-list", ""), (r"#help[6] sensor-sampling", ""), (r"#help[6] sensor-sampling-clear", ""), (r"#help[6] sensor-value", ""), (r"#help[6] slow-command", ""), (r"#help[6] version-list", ""), (r"#help[6] watchdog", ""), (r"!help[6] ok %d" % NO_HELP_MESSAGES, ""), (r"#help[7] watchdog", ""), (r"!help[7] ok 1", ""), (r"!help[8] fail", ""), (r"#client-list[9]", ""), (r"!client-list[9] ok 1", ""), (r"#version-list[10] katcp-protocol", ""), (r"#version-list[10] katcp-library", ""), (r"#version-list[10] katcp-device", ""), (r"!version-list[10] ok 3", ""), (r"#sensor-list[11] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[11] ok 1", ""), (r"#sensor-list[12] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[12] ok 1", ""), (r"!sensor-list[13] fail", ""), (r"#sensor-value[14] 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value[14] ok 1", ""), (r"#sensor-value[15] 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value[15] ok 1", ""), (r"!sensor-value[16] fail", ""), (r"!sensor-sampling[17] ok an.int none", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling[18] ok an.int differential 2", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling[19] ok an.int event-rate 2 3", ""), (r"!sensor-sampling[20] fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling[21] fail Unknown\_sensor\_name:\_an.unknown.", ""), (r"!sensor-sampling[22] fail Unknown\_strategy\_name:\_unknown.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ] self.assertEqual(self.server.restart_queue.get_nowait(), self.server) self._assert_msgs_like(get_msgs(min_number=len(expected_msgs)), expected_msgs) def test_sensor_list_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "/a.*/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "//"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "/^int/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"!sensor-list ok 0", ]) def test_sensor_value_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "/a.*/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345.000000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "//"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345.000000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "/^int/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"!sensor-value ok 0", ]) def test_client_list(self): reply, informs = self.client.blocking_request( katcp.Message.request('client-list'), use_mid=False) self.assertEqual(str(reply), '!client-list ok 1') self.assertEqual(len(informs), 1) inform = str(informs[0]) self.assertTrue(inform.startswith('#client-list 127.0.0.1:')) _, addr = inform.split() host, port = addr.split(':') port = int(port) self.assertEqual((host, port), self.client.sockname) def test_halt_request(self): """Test halt request.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) self.client.request(katcp.Message.request("halt")) # hack to hide re-connect exception self.client.connect = lambda: None self.server.join() self._assert_msgs_equal(get_msgs(min_number=2), [ r"!halt[1] ok", r"#disconnect Device\_server\_shutting\_down.", ]) def test_bad_handlers(self): """Test that bad request and inform handlers are picked up.""" try: class BadServer(katcp.DeviceServer): def request_baz(self, req, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing request_ docstring.") try: class BadServer(katcp.DeviceServer): def inform_baz(self, req, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing inform_ docstring.") class SortOfOkayServer(katcp.DeviceServer): request_bar = 1 inform_baz = 2 assert ("bar" not in SortOfOkayServer._request_handlers) assert ("baz" not in SortOfOkayServer._inform_handlers) def test_handler_exceptions(self): """Test handling of failure replies and other exceptions.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) self.assertTrue(self.client.wait_protocol(timeout=1)) self.client.request(katcp.Message.request("raise-exception")) self.client.request(katcp.Message.request("raise-fail")) time.sleep(0.1) self._assert_msgs_like(get_msgs(), [ (r"!raise-exception[1] fail Traceback", ""), (r"!raise-fail[2] fail There\_was\_a\_problem\_with\_your\_request.", ""), ]) def test_stop_and_restart(self): """Test stopping and restarting the device server.""" # So we can wait for the client to disconnect self.client.notify_connected = WaitingMock() self.server.stop(timeout=0.1) self.server.join(timeout=1.0) self.assertFalse(self.server.running()) # Wait for client to be disconnected self.client.notify_connected.assert_wait_call_count(1) self.assertFalse(self.client.is_connected()) self.server.start(timeout=1.0) def test_bad_client_socket(self): """Test what happens when select is called on a dead client socket.""" # close client stream while the server isn't looking then wait for the server to # notice stream, client_conn = self.server._server._connections.items()[0] # Wait for the client to disconnect self.client.notify_connected = WaitingMock() self.server.ioloop.add_callback(stream.close) # Wait for the client to be disconnected, and to connect again self.client.notify_connected.assert_wait_call_count(2) self.server.sync_with_ioloop() # check that client stream was removed from the KATCPServer self.assertTrue( stream not in self.server._server._connections, "Expected %r to not be in %r" % (stream, self.server._server._connections)) # And check that the ClientConnection object was removed from the DeviceServer self.assertTrue( client_conn not in self.server._client_conns, "Expected %r to not be in %r" % (client_conn, self.server._client_conns)) def test_sampling(self): """Test sensor sampling.""" get_msgs = self.client.message_recorder(blacklist=self.BLACKLIST, replies=True) self.client.wait_protocol(timeout=1) self.client.request( katcp.Message.request("sensor-sampling", "an.int", "period", 1 / 32.)) # Wait for the request reply and for the sensor update messages to # arrive. We expect update one the moment the sensor-sampling request is # made, then four more over 4/32. of a second, resutling in 6 # messages. Wait 0.75 of a period longer just to be sure we get everything. self.assertTrue(get_msgs.wait_number(6, timeout=4.75 / 32.)) self.client.assert_request_succeeds("sensor-sampling", "an.int", "none") # Wait for reply to above request get_msgs.wait_number(7) msgs = get_msgs() updates = [x for x in msgs if x.name == "sensor-status"] others = [x for x in msgs if x.name != "sensor-status"] self.assertTrue( abs(len(updates) - 5) < 2, "Expected 5 informs, saw %d." % len(updates)) self._assert_msgs_equal(others, [ r"!sensor-sampling[1] ok an.int period %s" % (1 / 32.), r"!sensor-sampling[2] ok an.int none", ]) self.assertEqual(updates[0].arguments[1:], ["1", "an.int", "nominal", "3"]) ## Now clear the strategies on this sensor # There should only be on connection to the server, so it should be # the test client client_conn = list(self.server._client_conns)[0] self.server.ioloop.add_callback(self.server.clear_strategies, client_conn) self.server.sync_with_ioloop() self.client.assert_request_succeeds("sensor-sampling", "an.int", args_equal=["an.int", "none"]) # Check that we did not accidentally clobber the strategy datastructure # in the proccess self.client.assert_request_succeeds("sensor-sampling", "an.int", "period", 0.125) def test_add_remove_sensors(self): """Test adding and removing sensors from a running device.""" an_int = self.server._sensors["an.int"] self.server.remove_sensor(an_int) # TODO remove_sensor test that checks that everything is indeed gone self.server.add_sensor(an_int) self.test_sampling() def test_async_request_handler(self): """ Request handlers allowing other requests to be handled before replying """ # We use a coroutine running on the client's ioloop for this test @gen.coroutine def do_async_request_test(threadsafe_future, tornado_future): try: slow_wait_time = 20 # Kick off a slow, async request slow_f = self.client.future_request( katcp.Message.request('slow-command', slow_wait_time)) t0 = time.time() # Do another normal request that should reply before the slow # request reply, _ = yield self.client.future_request( katcp.Message.request('watchdog')) self.assertTrue(reply.reply_ok(), 'Normal request should succeed') # Normal request should reply quickly t1 = time.time() self.assertTrue( t1 - t0 < 0.1 * slow_wait_time, 'The normal request should reply almost immediately') # Slow request should still be outstanding self.assertFalse( slow_f.done(), 'slow async request should not be complete yet') # Now cancel the slow command reply, _ = yield self.client.future_request( katcp.Message.request('cancel-slow-command')) self.assertTrue(reply.reply_ok(), '?cancel-slow-command should succeed') slow_reply, _ = yield slow_f self.assertTrue( slow_reply.reply_ok(), '?slow-command should succeed after being cancelled') t2 = time.time() self.assertTrue( t2 - t1 < 0.1 * slow_wait_time, 'Slow request should be cancelled almost immediately') except Exception as exc: tornado_future.set_exc_info(sys.exc_info()) threadsafe_future.set_exception(exc) else: threadsafe_future.set_result(None) tornado_future = gen.Future() threadsafe_future = Future() self.client.ioloop.add_callback(do_async_request_test, threadsafe_future, tornado_future) try: threadsafe_future.result() except Exception: # Use the tornado future to get a usable traceback tornado_future.result()
class TestDeviceServerClientIntegrated(unittest.TestCase, TestUtilMixin): BLACKLIST = ("version-connect", "version", "build-state") def setUp(self): self.server = DeviceTestServer('', 0) self.server.start(timeout=0.1) host, port = self.server._sock.getsockname() self.server_addr = (host, port) self.client = BlockingTestClient(self, host, port) self.client.start(timeout=0.1) self.assertTrue(self.client.wait_protocol(timeout=0.1)) def tearDown(self): if self.client.running(): self.client.stop() self.client.join() if self.server.running(): self.server.stop() self.server.join() def test_log(self): get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) with mock.patch('katcp.server.time.time') as m_time: m_time.return_value = 1234 self.server.log.error('An error') get_msgs.wait_number(1) self._assert_msgs_equal( get_msgs(), [r"#log error 1234.000000 root An\_error"]) def test_simple_connect(self): """Test a simple server setup and teardown with client connect.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) # basic send self.client.request(katcp.Message.request("foo"), use_mid=False) # pipe-lined send self.client.raw_send("?bar-boom\r\n?baz\r") # broken up sends self.client.raw_send("?boo") self.client.raw_send("m arg1 arg2") self.client.raw_send("\n") time.sleep(0.1) self._assert_msgs_equal(get_msgs(), [ r"!foo invalid Unknown\_request.", r"!bar-boom invalid Unknown\_request.", r"!baz invalid Unknown\_request.", r"!boom invalid Unknown\_request.", ]) def test_bad_requests(self): """Test request failure paths in device server.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) self.client.raw_send("bad msg\n") # wait for reply self.client.blocking_request( katcp.Message.request("watchdog"), use_mid=False) self._assert_msgs_like(get_msgs(), [ (r"#log error", "KatcpSyntaxError:" "\_Bad\_type\_character\_'b'.\\n"), (r"!watchdog ok", ""), ]) def test_slow_client(self): # Test that server does not choke sending messages to slow clients self.server.send_timeout = 0.1 # Set a short sending timeout self.client.wait_protocol(1) slow_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) slow_sock.connect(self.server_addr) slow_sock.settimeout(0.1) # Send a bunch of request to the server, but don't read anything from # the server try: slow_sock.sendall('?help\n'*100000) except socket.timeout: pass t0 = time.time() # Request should not have taken a very long time. self.client.assert_request_succeeds('help', informs_count=NO_HELP_MESSAGES) self.assertTrue(time.time() - t0 < 1) def test_server_ignores_informs_and_replies(self): """Test server ignores informs and replies.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) self.client.raw_send("#some inform\n") self.client.raw_send("!some reply\n") time.sleep(0.1) self.assertFalse(get_msgs()) def test_standard_requests(self): """Test standard request and replies.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) nomid_req = partial(self.client.request, use_mid=False) nomid_req(katcp.Message.request("watchdog"), use_mid=False) nomid_req(katcp.Message.request("restart")) nomid_req(katcp.Message.request("log-level")) nomid_req(katcp.Message.request("log-level", "trace")) nomid_req(katcp.Message.request("log-level", "unknown")) nomid_req(katcp.Message.request("help")) nomid_req(katcp.Message.request("help", "watchdog")) nomid_req(katcp.Message.request("help", "unknown-request")) nomid_req(katcp.Message.request("client-list")) nomid_req(katcp.Message.request("version-list")) nomid_req(katcp.Message.request("sensor-list")) nomid_req(katcp.Message.request("sensor-list", "an.int")) nomid_req(katcp.Message.request("sensor-list", "an.unknown")) nomid_req(katcp.Message.request("sensor-value")) nomid_req(katcp.Message.request("sensor-value", "an.int")) nomid_req(katcp.Message.request("sensor-value", "an.unknown")) nomid_req(katcp.Message.request("sensor-sampling", "an.int")) nomid_req(katcp.Message.request("sensor-sampling", "an.int", "differential", "2")) nomid_req(katcp.Message.request("sensor-sampling", "an.int", "event-rate", "2", "3")) nomid_req(katcp.Message.request("sensor-sampling")) nomid_req(katcp.Message.request("sensor-sampling", "an.unknown", "auto")) self.client.blocking_request(katcp.Message.request( "sensor-sampling", "an.int", "unknown"), use_mid=False) time.sleep(0.1) self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") time.sleep(0.1) self.assertEqual(self.server.restart_queue.get_nowait(), self.server) self._assert_msgs_like(get_msgs(), [ (r"!watchdog ok", ""), (r"!restart ok", ""), (r"!log-level ok warn", ""), (r"!log-level ok trace", ""), (r"!log-level fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help cancel-slow-command Cancel\_slow\_command\_request,\_" "resulting\_in\_it\_replying\_immediately", ""), (r"#help client-list", ""), (r"#help halt", ""), (r"#help help", ""), (r"#help log-level", ""), (r"#help new-command", ""), (r"#help raise-exception", ""), (r"#help raise-fail", ""), (r"#help restart", ""), (r"#help sensor-list", ""), (r"#help sensor-sampling", ""), (r"#help sensor-sampling-clear", ""), (r"#help sensor-value", ""), (r"#help slow-command", ""), (r"#help version-list", ""), (r"#help watchdog", ""), (r"!help ok %d" % NO_HELP_MESSAGES, ""), (r"#help watchdog", ""), (r"!help ok 1", ""), (r"!help fail", ""), (r"#client-list", ""), (r"!client-list ok 1", ""), (r"#version-list katcp-protocol", ""), (r"#version-list katcp-library", ""), (r"#version-list katcp-device", ""), (r"!version-list ok 3", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"!sensor-list fail", ""), (r"#sensor-value 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"#sensor-value 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"!sensor-value fail", ""), (r"!sensor-sampling ok an.int none", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling ok an.int differential 2", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling ok an.int event-rate 2 3", ""), (r"!sensor-sampling fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling fail Unknown\_sensor\_name:\_an.unknown.", ""), (r"!sensor-sampling fail Unknown\_strategy\_name:\_unknown.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ]) def test_standard_requests_with_ids(self): """Test standard request and replies with message ids.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) current_id = [0] def mid(): current_id[0] += 1 return str(current_id[0]) def mid_req(*args): return katcp.Message.request(*args, mid=mid()) self.client.request(mid_req("watchdog")) self.client.request(mid_req("restart")) self.client.request(mid_req("log-level")) self.client.request(mid_req("log-level", "trace")) self.client.request(mid_req("log-level", "unknown")) self.client.request(mid_req("help")) self.client.request(mid_req("help", "watchdog")) self.client.request(mid_req("help", "unknown-request")) self.client.request(mid_req("client-list")) self.client.request(mid_req("version-list")) self.client.request(mid_req("sensor-list")) self.client.request(mid_req("sensor-list", "an.int")) self.client.request(mid_req("sensor-list", "an.unknown")) self.client.request(mid_req("sensor-value")) self.client.request(mid_req("sensor-value", "an.int")) self.client.request(mid_req("sensor-value", "an.unknown")) self.client._next_id = mid # mock our mid generator for testing self.client.blocking_request(mid_req("sensor-sampling", "an.int")) self.client.blocking_request(mid_req( "sensor-sampling", "an.int", "differential", "2")) self.client.blocking_request(mid_req( "sensor-sampling", "an.int", "event-rate", "2", "3")), self.client.blocking_request(mid_req("sensor-sampling")) self.client.blocking_request(mid_req( "sensor-sampling", "an.unknown", "auto")) self.client.blocking_request(mid_req( "sensor-sampling", "an.int", "unknown")) self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") time.sleep(0.1) self.assertEqual(self.server.restart_queue.get_nowait(), self.server) self._assert_msgs_like(get_msgs(), [ (r"!watchdog[1] ok", ""), (r"!restart[2] ok", ""), (r"!log-level[3] ok warn", ""), (r"!log-level[4] ok trace", ""), (r"!log-level[5] fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help[6] cancel-slow-command Cancel\_slow\_command\_request,\_" "resulting\_in\_it\_replying\_immediately", ""), (r"#help[6] client-list", ""), (r"#help[6] halt", ""), (r"#help[6] help", ""), (r"#help[6] log-level", ""), (r"#help[6] new-command", ""), (r"#help[6] raise-exception", ""), (r"#help[6] raise-fail", ""), (r"#help[6] restart", ""), (r"#help[6] sensor-list", ""), (r"#help[6] sensor-sampling", ""), (r"#help[6] sensor-sampling-clear", ""), (r"#help[6] sensor-value", ""), (r"#help[6] slow-command", ""), (r"#help[6] version-list", ""), (r"#help[6] watchdog", ""), (r"!help[6] ok %d" % NO_HELP_MESSAGES, ""), (r"#help[7] watchdog", ""), (r"!help[7] ok 1", ""), (r"!help[8] fail", ""), (r"#client-list[9]", ""), (r"!client-list[9] ok 1", ""), (r"#version-list[10] katcp-protocol", ""), (r"#version-list[10] katcp-library", ""), (r"#version-list[10] katcp-device", ""), (r"!version-list[10] ok 3", ""), (r"#sensor-list[11] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[11] ok 1", ""), (r"#sensor-list[12] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[12] ok 1", ""), (r"!sensor-list[13] fail", ""), (r"#sensor-value[14] 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value[14] ok 1", ""), (r"#sensor-value[15] 12345.000000 1 an.int nominal 3", ""), (r"!sensor-value[15] ok 1", ""), (r"!sensor-value[16] fail", ""), (r"!sensor-sampling[17] ok an.int none", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling[18] ok an.int differential 2", ""), (r"#sensor-status 12345.000000 1 an.int nominal 3", ""), (r"!sensor-sampling[19] ok an.int event-rate 2 3", ""), (r"!sensor-sampling[20] fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling[21] fail Unknown\_sensor\_name:\_an.unknown.", ""), (r"!sensor-sampling[22] fail Unknown\_strategy\_name:\_unknown.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ]) def test_sensor_list_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "/a.*/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "//"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-list", "/^int/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"!sensor-list ok 0", ]) def test_sensor_value_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "/a.*/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345.000000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "//"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345.000000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request( "sensor-value", "/^int/"), use_mid=False) self._assert_msgs_equal(informs + [reply], [ r"!sensor-value ok 0", ]) def test_client_list(self): reply, informs = self.client.blocking_request( katcp.Message.request('client-list'), use_mid=False) self.assertEqual(str(reply), '!client-list ok 1') self.assertEqual(len(informs), 1) inform = str(informs[0]) self.assertTrue(inform.startswith('#client-list 127.0.0.1:')) _, addr = inform.split() host, port = addr.split(':') port = int(port) self.assertEqual((host, port), self.client._sock.getsockname()) def test_halt_request(self): """Test halt request.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) self.client.request(katcp.Message.request("halt")) # hack to hide re-connect exception self.client.connect = lambda: None self.server.join() time.sleep(0.1) self._assert_msgs_equal(get_msgs(), [ r"!halt[1] ok", r"#disconnect Device\_server\_shutting\_down.", ]) def test_bad_handlers(self): """Test that bad request and inform handlers are picked up.""" try: class BadServer(katcp.DeviceServer): def request_baz(self, req, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing request_ docstring.") try: class BadServer(katcp.DeviceServer): def inform_baz(self, req, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing inform_ docstring.") class SortOfOkayServer(katcp.DeviceServer): request_bar = 1 inform_baz = 2 assert("bar" not in SortOfOkayServer._request_handlers) assert("baz" not in SortOfOkayServer._inform_handlers) def test_handler_exceptions(self): """Test handling of failure replies and other exceptions.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) self.assertTrue(self.client.wait_protocol(timeout=1)) self.client.request(katcp.Message.request("raise-exception")) self.client.request(katcp.Message.request("raise-fail")) time.sleep(0.1) self._assert_msgs_like(get_msgs(), [ (r"!raise-exception[1] fail Traceback", ""), (r"!raise-fail[2] fail There\_was\_a\_problem\_with\_your\_request.", ""), ]) def test_stop_and_restart(self): """Test stopping and restarting the device server.""" self.server.stop(timeout=0.1) self.server.join(timeout=1.0) self.assertEqual(self.server._thread, None) self.assertFalse(self.server._running.isSet()) self.server.start(timeout=1.0) def test_bad_client_socket(self): """Test what happens when select is called on a dead client socket.""" # wait for client to arrive time.sleep(0.1) # close socket while the server isn't looking # then wait for the server to notice sock = self.server._socks[0] sock.close() time.sleep(0.75) # check that client was removed self.assertTrue(sock not in self.server._socks, "Expected %r to not be in %r" % (sock, self.server._socks)) def test_bad_server_socket(self): """Test what happens when select is called on a dead server socket.""" # wait for client to arrive time.sleep(0.1) # close socket while the server isn't looking # then wait for the server to notice sock = self.server._sock sockname = sock.getsockname() sock.close() time.sleep(0.75) # check that server restarted self.assertTrue(sock is not self.server._sock, "Expected %r to not be %r" % (sock, self.server._sock)) self.assertEqual(sockname, self.server._sock.getsockname()) def test_daemon_value(self): """Test passing in a daemon value to server start method.""" self.server.stop(timeout=0.1) self.server.join(timeout=1.0) self.server.start(timeout=0.1, daemon=True) self.assertTrue(self.server._thread.isDaemon()) def test_excepthook(self): """Test passing in an excepthook to server start method.""" exceptions = [] except_event = threading.Event() def excepthook(etype, value, traceback): """Keep track of exceptions.""" exceptions.append(etype) except_event.set() self.server.stop(timeout=0.1) self.server.join(timeout=1.5) self.server.start(timeout=0.1, excepthook=excepthook) # force exception by deleteing _running old_running = self.server._running try: del self.server._running except_event.wait(1.5) self.assertEqual(exceptions, [AttributeError]) finally: self.server._running = old_running # close socket -- server didn't shut down correctly self.server._sock.close() self.server.stop(timeout=0.1) self.server.join(timeout=1.5) except_event.clear() del exceptions[:] self.server.start(timeout=0.1, excepthook=excepthook) # force exception in sample reactor and check that it makes # it back up reactor = self.server._reactor old_stop = reactor._stopEvent try: del reactor._stopEvent reactor._wakeEvent.set() except_event.wait(0.1) self.assertEqual(exceptions, [AttributeError]) finally: reactor._stopEvent = old_stop # close socket -- server didn't shut down correctly self.server._sock.close() def test_sampling(self): """Test sensor sampling.""" get_msgs = self.client.message_recorder( blacklist=self.BLACKLIST, replies=True) self.client.wait_protocol(timeout=1) self.client.request(katcp.Message.request( "sensor-sampling", "an.int", "period", 1/32.)) # Wait for the request reply and for the sensor update messages to # arrive. We expect update one the moment the sensor-sampling request is # made, then four more over 4/32. of a second, resutling in 6 # messages. Wait half a period longer just to be sure we get everything. self.assertTrue(get_msgs.wait_number(6, timeout=4.5/32.)) self.client.assert_request_succeeds("sensor-sampling", "an.int", "none") # Wait for reply to above request get_msgs.wait_number(7) msgs = get_msgs() updates = [x for x in msgs if x.name == "sensor-status"] others = [x for x in msgs if x.name != "sensor-status"] self.assertTrue(abs(len(updates) - 5) < 2, "Expected 5 informs, saw %d." % len(updates)) self._assert_msgs_equal(others, [ r"!sensor-sampling[1] ok an.int period %s" % (1/32.), r"!sensor-sampling[2] ok an.int none", ]) self.assertEqual(updates[0].arguments[1:], ["1", "an.int", "nominal", "3"]) ## Now clear the strategies on this sensor # There should only be on connection to the server, so it should be # the test client client_conn = self.server._sock_connections.values()[0] self.server.clear_strategies(client_conn) self.client.assert_request_succeeds("sensor-sampling", "an.int", args_equal=["an.int", "none"]) # Check that we did not accidentally clobber the strategy datastructure # in the proccess self.client.assert_request_succeeds( "sensor-sampling", "an.int", "period", 0.125) def test_add_remove_sensors(self): """Test adding and removing sensors from a running device.""" an_int = self.server._sensors["an.int"] self.server.remove_sensor(an_int) self.server.add_sensor(an_int) self.test_sampling()
class TestDeviceServer(unittest.TestCase, TestUtilMixin): def setUp(self): self.server = DeviceTestServer('', 0) self.server.start(timeout=0.1) host, port = self.server._sock.getsockname() self.client = BlockingTestClient(self, host, port) self.client.start(timeout=0.1) def tearDown(self): if self.client.running(): self.client.stop() self.client.join() if self.server.running(): self.server.stop() self.server.join() def test_simple_connect(self): """Test a simple server setup and teardown with client connect.""" # basic send self.client.request(katcp.Message.request("foo")) # pipe-lined send self.client.raw_send("?bar-boom\r\n?baz\r") # broken up sends self.client.raw_send("?boo") self.client.raw_send("m arg1 arg2") self.client.raw_send("\n") time.sleep(0.1) msgs = self.client.messages() self._assert_msgs_equal(msgs, [ r"#version device_stub-0.1", r"#build-state name-0.1", r"!foo invalid Unknown\_request.", r"!bar-boom invalid Unknown\_request.", r"!baz invalid Unknown\_request.", r"!boom invalid Unknown\_request.", ]) def test_bad_requests(self): """Test request failure paths in device server.""" self.client.raw_send("bad msg\n") # wait for reply self.client.blocking_request(katcp.Message.request("watchdog")) msgs = self.client.messages() self._assert_msgs_like(msgs, [ (r"#version device_stub-0.1", ""), (r"#build-state name-0.1", ""), (r"#log error", "KatcpSyntaxError:\_Bad\_type\_character\_'b'.\\n"), (r"!watchdog ok", ""), ]) def test_server_ignores_informs_and_replies(self): """Test server ignores informs and replies.""" self.client.raw_send("#some inform\n") self.client.raw_send("!some reply\n") time.sleep(0.1) msgs = self.client.messages() self._assert_msgs_like(msgs, [ (r"#version device_stub-0.1", ""), (r"#build-state name-0.1", ""), ]) def test_standard_requests(self): """Test standard request and replies.""" self.client.request(katcp.Message.request("watchdog")) self.client.request(katcp.Message.request("restart")) self.client.request(katcp.Message.request("log-level")) self.client.request(katcp.Message.request("log-level", "trace")) self.client.request(katcp.Message.request("log-level", "unknown")) self.client.request(katcp.Message.request("help")) self.client.request(katcp.Message.request("help", "watchdog")) self.client.request(katcp.Message.request("help", "unknown-request")) self.client.request(katcp.Message.request("client-list")) self.client.request(katcp.Message.request("sensor-list")) self.client.request(katcp.Message.request("sensor-list", "an.int")) self.client.request(katcp.Message.request("sensor-list", "an.unknown")) self.client.request(katcp.Message.request("sensor-value")) self.client.request(katcp.Message.request("sensor-value", "an.int")) self.client.request(katcp.Message.request("sensor-value", "an.unknown")) self.client.request(katcp.Message.request("sensor-sampling", "an.int")) self.client.request(katcp.Message.request("sensor-sampling", "an.int", "differential", "2")) self.client.request(katcp.Message.request("sensor-sampling")) self.client.request(katcp.Message.request("sensor-sampling", "an.unknown", "auto")) self.client.blocking_request(katcp.Message.request("sensor-sampling", "an.int", "unknown")) time.sleep(0.1) self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") time.sleep(0.1) msgs = self.client.messages() self.assertEqual(self.server.restart_queue.get_nowait(), self.server) self._assert_msgs_like(msgs, [ (r"#version device_stub-0.1", ""), (r"#build-state name-0.1", ""), (r"!watchdog ok", ""), (r"!restart ok", ""), (r"!log-level ok warn", ""), (r"!log-level ok trace", ""), (r"!log-level fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help client-list", ""), (r"#help halt", ""), (r"#help help", ""), (r"#help log-level", ""), (r"#help new-command", ""), (r"#help raise-exception", ""), (r"#help raise-fail", ""), (r"#help restart", ""), (r"#help sensor-list", ""), (r"#help sensor-sampling", ""), (r"#help sensor-value", ""), (r"#help slow-command", ""), (r"#help watchdog", ""), (r"!help ok 13", ""), (r"#help watchdog", ""), (r"!help ok 1", ""), (r"!help fail", ""), (r"#client-list", ""), (r"!client-list ok 1", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"#sensor-list an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list ok 1", ""), (r"!sensor-list fail", ""), (r"#sensor-value 12345000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"#sensor-value 12345000 1 an.int nominal 3", ""), (r"!sensor-value ok 1", ""), (r"!sensor-value fail", ""), (r"!sensor-sampling ok an.int none", ""), (r"#sensor-status 12345000 1 an.int nominal 3", ""), (r"!sensor-sampling ok an.int differential 2", ""), (r"!sensor-sampling fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling fail Unknown\_sensor\_name.", ""), (r"!sensor-sampling fail Unknown\_strategy\_name.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ]) def test_standard_requests_with_ids(self): """Test standard request and replies with message ids.""" current_id = [0] def mid(): current_id[0] += 1 return current_id[0] self.client.request(katcp.Message.request("watchdog", mid=mid())) self.client.request(katcp.Message.request("restart", mid=mid())) self.client.request(katcp.Message.request("log-level", mid=mid())) self.client.request(katcp.Message.request("log-level", "trace", mid=mid())) self.client.request(katcp.Message.request("log-level", "unknown", mid=mid())) self.client.request(katcp.Message.request("help", mid=mid())) self.client.request(katcp.Message.request("help", "watchdog", mid=mid())) self.client.request(katcp.Message.request("help", "unknown-request", mid=mid())) self.client.request(katcp.Message.request("client-list", mid=mid())) self.client.request(katcp.Message.request("sensor-list", mid=mid())) self.client.request(katcp.Message.request("sensor-list", "an.int", mid=mid())) self.client.request(katcp.Message.request("sensor-list", "an.unknown", mid=mid())) self.client.request(katcp.Message.request("sensor-value", mid=mid())) self.client.request(katcp.Message.request("sensor-value", "an.int", mid=mid())) self.client.request(katcp.Message.request("sensor-value", "an.unknown", mid=mid())) self.client.blocking_request(katcp.Message.request("sensor-sampling", "an.int", mid=mid())) self.client.blocking_request(katcp.Message.request("sensor-sampling", "an.int", "differential", "2", mid=mid())) self.client.blocking_request(katcp.Message.request("sensor-sampling", mid=mid())) self.client.blocking_request(katcp.Message.request("sensor-sampling", "an.unknown", "auto", mid=mid())) self.client.blocking_request(katcp.Message.request("sensor-sampling", "an.int", "unknown", mid=mid())) self.server.log.trace("trace-msg") self.server.log.debug("debug-msg") self.server.log.info("info-msg") self.server.log.warn("warn-msg") self.server.log.error("error-msg") self.server.log.fatal("fatal-msg") time.sleep(0.1) msgs = self.client.messages() self.assertEqual(self.server.restart_queue.get_nowait(), self.server) self._assert_msgs_like(msgs, [ (r"#version device_stub-0.1", ""), (r"#build-state name-0.1", ""), (r"!watchdog[1] ok", ""), (r"!restart[2] ok", ""), (r"!log-level[3] ok warn", ""), (r"!log-level[4] ok trace", ""), (r"!log-level[5] fail Unknown\_logging\_level\_name\_'unknown'", ""), (r"#help[6] client-list", ""), (r"#help[6] halt", ""), (r"#help[6] help", ""), (r"#help[6] log-level", ""), (r"#help[6] new-command", ""), (r"#help[6] raise-exception", ""), (r"#help[6] raise-fail", ""), (r"#help[6] restart", ""), (r"#help[6] sensor-list", ""), (r"#help[6] sensor-sampling", ""), (r"#help[6] sensor-value", ""), (r"#help[6] slow-command", ""), (r"#help[6] watchdog", ""), (r"!help[6] ok 13", ""), (r"#help[7] watchdog", ""), (r"!help[7] ok 1", ""), (r"!help[8] fail", ""), (r"#client-list[9]", ""), (r"!client-list[9] ok 1", ""), (r"#sensor-list[10] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[10] ok 1", ""), (r"#sensor-list[11] an.int An\_Integer. count integer -5 5", ""), (r"!sensor-list[11] ok 1", ""), (r"!sensor-list[12] fail", ""), (r"#sensor-value[13] 12345000 1 an.int nominal 3", ""), (r"!sensor-value[13] ok 1", ""), (r"#sensor-value[14] 12345000 1 an.int nominal 3", ""), (r"!sensor-value[14] ok 1", ""), (r"!sensor-value[15] fail", ""), (r"!sensor-sampling[16] ok an.int none", ""), (r"#sensor-status 12345000 1 an.int nominal 3", ""), (r"!sensor-sampling[17] ok an.int differential 2", ""), (r"!sensor-sampling[18] fail No\_sensor\_name\_given.", ""), (r"!sensor-sampling[19] fail Unknown\_sensor\_name.", ""), (r"!sensor-sampling[20] fail Unknown\_strategy\_name.", ""), (r"#log trace", r"root trace-msg"), (r"#log debug", r"root debug-msg"), (r"#log info", r"root info-msg"), (r"#log warn", r"root warn-msg"), (r"#log error", r"root error-msg"), (r"#log fatal", r"root fatal-msg"), ]) def test_sensor_list_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request("sensor-list", "/a.*/")) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request("sensor-list", "//")) self._assert_msgs_equal(informs + [reply], [ r"#sensor-list an.int An\_Integer. count integer -5 5", r"!sensor-list ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request("sensor-list", "/^int/")) self._assert_msgs_equal(informs + [reply], [ r"!sensor-list ok 0", ]) def test_sensor_value_regex(self): reply, informs = self.client.blocking_request(katcp.Message.request("sensor-value", "/a.*/")) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request("sensor-value", "//")) self._assert_msgs_equal(informs + [reply], [ r"#sensor-value 12345000 1 an.int nominal 3", r"!sensor-value ok 1", ]) reply, informs = self.client.blocking_request(katcp.Message.request("sensor-value", "/^int/")) self._assert_msgs_equal(informs + [reply], [ r"!sensor-value ok 0", ]) def test_halt_request(self): """Test halt request.""" self.client.request(katcp.Message.request("halt")) # hack to hide re-connect exception self.client.connect = lambda: None self.server.join() time.sleep(0.1) msgs = self.client.messages() self._assert_msgs_equal(msgs, [ r"#version device_stub-0.1", r"#build-state name-0.1", r"!halt ok", r"#disconnect Device\_server\_shutting\_down.", ]) def test_bad_handlers(self): """Test that bad request and inform handlers are picked up.""" try: class BadServer(katcp.DeviceServer): def request_baz(self, sock, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing request_ docstring.") try: class BadServer(katcp.DeviceServer): def inform_baz(self, sock, msg): pass except AssertionError: pass else: self.fail("Server metaclass accepted missing inform_ docstring.") class SortOfOkayServer(katcp.DeviceServer): request_bar = 1 inform_baz = 2 assert("bar" not in SortOfOkayServer._request_handlers) assert("baz" not in SortOfOkayServer._inform_handlers) def test_handler_exceptions(self): """Test handling of failure replies and other exceptions.""" self.client.request(katcp.Message.request("raise-exception")) self.client.request(katcp.Message.request("raise-fail")) time.sleep(0.1) msgs = self.client.messages() self._assert_msgs_like(msgs, [ (r"#version device_stub-0.1", ""), (r"#build-state name-0.1", ""), (r"!raise-exception fail Traceback", ""), (r"!raise-fail fail There\_was\_a\_problem\_with\_your\_request.", ""), ]) def test_stop_and_restart(self): """Test stopping and restarting the device server.""" self.server.stop(timeout=0.1) self.server.join(timeout=1.0) self.assertEqual(self.server._thread, None) self.assertFalse(self.server._running.isSet()) self.server.start(timeout=1.0) def test_bad_client_socket(self): """Test what happens when select is called on a dead client socket.""" # wait for client to arrive time.sleep(0.1) # close socket while the server isn't looking # then wait for the server to notice sock = self.server._socks[0] sock.close() time.sleep(0.75) # check that client was removed self.assertTrue(sock not in self.server._socks, "Expected %r to not be in %r" % (sock, self.server._socks)) def test_bad_server_socket(self): """Test what happens when select is called on a dead server socket.""" # wait for client to arrive time.sleep(0.1) # close socket while the server isn't looking # then wait for the server to notice sock = self.server._sock sockname = sock.getsockname() sock.close() time.sleep(0.75) # check that server restarted self.assertTrue(sock is not self.server._sock, "Expected %r to not be %r" % (sock, self.server._sock)) self.assertEqual(sockname, self.server._sock.getsockname()) def test_daemon_value(self): """Test passing in a daemon value to server start method.""" self.server.stop(timeout=0.1) self.server.join(timeout=1.0) self.server.start(timeout=0.1, daemon=True) self.assertTrue(self.server._thread.isDaemon()) def test_excepthook(self): """Test passing in an excepthook to server start method.""" exceptions = [] except_event = threading.Event() def excepthook(etype, value, traceback): """Keep track of exceptions.""" exceptions.append(etype) except_event.set() self.server.stop(timeout=0.1) self.server.join(timeout=1.5) self.server.start(timeout=0.1, excepthook=excepthook) # force exception by deleteing _running old_running = self.server._running try: del self.server._running except_event.wait(1.5) self.assertEqual(exceptions, [AttributeError]) finally: self.server._running = old_running # close socket -- server didn't shut down correctly self.server._sock.close() self.server.stop(timeout=0.1) self.server.join(timeout=1.5) except_event.clear() del exceptions[:] self.server.start(timeout=0.1, excepthook=excepthook) # force exception in sample reactor and check that it makes # it back up reactor = self.server._reactor old_stop = reactor._stopEvent try: del reactor._stopEvent reactor._wakeEvent.set() except_event.wait(0.1) self.assertEqual(exceptions, [AttributeError]) finally: reactor._stopEvent = old_stop # close socket -- server didn't shut down correctly self.server._sock.close() def test_sampling(self): """Test sensor sampling.""" self.client.request(katcp.Message.request("sensor-sampling", "an.int", "period", 100)) time.sleep(1.0) self.client.request(katcp.Message.request("sensor-sampling", "an.int", "none")) time.sleep(0.5) msgs = self.client.messages() updates = [x for x in msgs if x.name == "sensor-status"] others = [x for x in msgs if x.name != "sensor-status"] self.assertTrue(abs(len(updates) - 12) < 2, "Expected 12 informs, saw %d." % len(updates)) self._assert_msgs_equal(others, [ r"#version device_stub-0.1", r"#build-state name-0.1", r"!sensor-sampling ok an.int period 100", r"!sensor-sampling ok an.int none", ]) self.assertEqual(updates[0].arguments[1:], ["1", "an.int", "nominal", "3"]) def test_add_remove_sensors(self): """Test adding and removing sensors from a running device.""" an_int = self.server._sensors["an.int"] self.server.remove_sensor(an_int) self.server.add_sensor(an_int) self.test_sampling()