-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from btrinite/feat_unit_test
Add unit test covering JSON message extraction from TCP buffer
- Loading branch information
Showing
2 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
====================================================== | ||
Unit test | ||
====================================================== | ||
|
||
Part of source code (JSON extraction from TCP flow)) is tricky and could be subject to regression. | ||
This directory include a test program (client.test.py) that focus on testing this part. | ||
It creates a server, wait for client connection then send various payload and verify if client succeed to extract JSON messages | ||
|
||
To launch the test : | ||
|
||
* install the client to be used to test (from project root directory for example): | ||
|
||
.. code-block:: shell-session | ||
% pip3 install -e . | ||
* launch the test (from this directory): | ||
|
||
.. code-block:: shell-session | ||
% python3 client.test.py | ||
If everything is OK, Result should be like : | ||
|
||
.. code-block:: shell-session | ||
2020-11-10 21:02:24,165 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:24,167 - root - INFO - Incoming connection from ('127.0.0.1', 51598) | ||
2020-11-10 21:02:25,178 - root - INFO - Got {'msg_type': 'test3'} | ||
2020-11-10 21:02:25,179 - root - INFO - Got {'msg_type': 'test31'} | ||
.2020-11-10 21:02:26,175 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:26,186 - root - INFO - Incoming connection from ('127.0.0.1', 51600) | ||
2020-11-10 21:02:28,181 - root - INFO - Got {'msg_type': 'test5'} | ||
2020-11-10 21:02:28,182 - root - INFO - Got {'msg_type': 'test51'} | ||
.2020-11-10 21:02:29,183 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:29,193 - root - INFO - Incoming connection from ('127.0.0.1', 51602) | ||
2020-11-10 21:02:31,195 - root - INFO - Got {'msg_type': 'test6'} | ||
2020-11-10 21:02:31,196 - root - INFO - Got {'msg_type': 'test61'} | ||
.2020-11-10 21:02:32,189 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:32,200 - root - INFO - Incoming connection from ('127.0.0.1', 51604) | ||
2020-11-10 21:02:34,196 - root - INFO - Got {'msg_type': 'test7'} | ||
2020-11-10 21:02:34,196 - root - INFO - Got {'msg_type': 'test71'} | ||
2020-11-10 21:02:35,199 - root - INFO - Got {'msg_type': 'test72'} | ||
.2020-11-10 21:02:36,202 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:36,212 - root - INFO - Incoming connection from ('127.0.0.1', 51606) | ||
2020-11-10 21:02:38,216 - root - INFO - Got {'msg_type': 'test8'} | ||
2020-11-10 21:02:39,217 - root - INFO - Got {'msg_type': 'test81'} | ||
.2020-11-10 21:02:40,217 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:40,228 - root - INFO - Incoming connection from ('127.0.0.1', 51608) | ||
2020-11-10 21:02:42,222 - root - INFO - Got {'msg_type': 'test9'} | ||
2020-11-10 21:02:43,230 - root - INFO - Got {'msg_type': 'test91'} | ||
.2020-11-10 21:02:44,229 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:44,240 - root - INFO - Incoming connection from ('127.0.0.1', 51610) | ||
2020-11-10 21:02:45,241 - root - INFO - Got {'msg_type': 'test1'} | ||
.2020-11-10 21:02:46,237 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:46,248 - root - INFO - Incoming connection from ('127.0.0.1', 51612) | ||
2020-11-10 21:02:47,249 - root - INFO - Got {'msg_type': 'test2'} | ||
.2020-11-10 21:02:48,240 - gym_donkeycar.core.client - INFO - connecting to localhost:10000 | ||
2020-11-10 21:02:48,251 - root - INFO - Incoming connection from ('127.0.0.1', 51614) | ||
.2020-11-10 21:02:50,251 - root - INFO - Stoping Server | ||
2020-11-10 21:02:50,262 - root - INFO - Server stoped | ||
---------------------------------------------------------------------- | ||
Ran 9 tests in 27.100s | ||
OK |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import unittest | ||
import asyncore | ||
import socket | ||
import sys | ||
import time | ||
|
||
from gym_donkeycar.core.sim_client import SDClient | ||
|
||
import logging | ||
import sys | ||
|
||
from threading import Thread | ||
|
||
root = logging.getLogger() | ||
root.setLevel(logging.DEBUG) | ||
|
||
handler = logging.StreamHandler(sys.stdout) | ||
handler.setLevel(logging.DEBUG) | ||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') | ||
handler.setFormatter(formatter) | ||
root.addHandler(handler) | ||
|
||
host='localhost' | ||
port=10000 | ||
|
||
class EchoHandler(asyncore.dispatcher_with_send): | ||
|
||
def handle_read(self): | ||
data = self.recv(8192) | ||
if data: | ||
root.info ('Server got %s' % data) | ||
self.send(data) | ||
|
||
class TestServer (asyncore.dispatcher): | ||
def __init__(self, host, port): | ||
asyncore.dispatcher.__init__(self) | ||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) | ||
self.set_reuse_addr() | ||
self.bind((host, port)) | ||
self.listen(5) | ||
self.processing_loop=True | ||
self.handler=None | ||
self.th = Thread(target=self.loop, args=()) | ||
self.th.start() | ||
|
||
def handle_accept(self): | ||
pair = self.accept() | ||
if pair is not None: | ||
sock, addr = pair | ||
root.info ('Incoming connection from %s' % repr(addr)) | ||
self.handler = EchoHandler(sock) | ||
|
||
def stop(self): | ||
root.info ('Stoping Server') | ||
self.processing_loop = False | ||
self.th.join() | ||
root.info ('Server stoped') | ||
|
||
def loop(self): | ||
while (self.processing_loop): | ||
asyncore.loop(count=1) | ||
time.sleep(0.01) | ||
|
||
class SUT (SDClient): | ||
def __init__(self, address, ): | ||
super().__init__(*address, poll_socket_sleep_time=0.01) | ||
self.receivedMsg=None | ||
self.receivedCount=0 | ||
|
||
def on_msg_recv(self, json_packet): | ||
root.info ('Got %s' % json_packet) | ||
self.receivedMsg = json_packet | ||
self.receivedCount+=1 | ||
|
||
def reInit(self): | ||
self.receivedMsg = None | ||
self.receivedCount = 0 | ||
|
||
|
||
|
||
class SDClientTest (unittest.TestCase): | ||
|
||
@classmethod | ||
def setUpClass(self): | ||
self.server=TestServer(host, port) | ||
time.sleep(1) | ||
|
||
@classmethod | ||
def tearDownClass(self): | ||
self.server.stop() | ||
|
||
def setUp(self): | ||
self.SUT=SUT((host, port)) | ||
time.sleep(1) | ||
self.SUT.reInit() | ||
|
||
def tearDown(self): | ||
self.SUT.stop() | ||
|
||
def test_simpleMessage(self): | ||
self.server.handler.send(b'{"msg_type":"test1"}\n') | ||
time.sleep(1) | ||
self.assertTrue(self.SUT.receivedCount==1) | ||
|
||
def test_simpleMessageUndelimited(self): | ||
self.server.handler.send(b'{"msg_type":"test2"}') | ||
time.sleep(1) | ||
self.assertTrue(self.SUT.receivedCount==1) | ||
|
||
def test_SimpleConcat(self): | ||
self.server.handler.send(b'{"msg_type":"test3"}\n{"msg_type":"test31"}') | ||
time.sleep(1) | ||
self.assertTrue(self.SUT.receivedCount==2) | ||
|
||
def test_uncompletePayload(self): | ||
self.server.handler.send(b'{"msg_type":"test4","tutu":') | ||
time.sleep(1) | ||
self.assertTrue(self.SUT.receivedCount==0) | ||
|
||
def test_fragmentedPayload1(self): | ||
self.server.handler.send(b'{"msg_type":"test5"') | ||
time.sleep(1) | ||
self.server.handler.send(b'}\n{"msg_type":"test51"}\n') | ||
time.sleep(1) | ||
self.assertEqual(self.SUT.receivedCount,2) | ||
|
||
def test_fragmentedPayload2(self): | ||
self.server.handler.send(b'{"msg_type":') | ||
time.sleep(1) | ||
self.server.handler.send(b'"test6"}\n{"msg_type":"test61"}\n') | ||
time.sleep(1) | ||
self.assertEqual(self.SUT.receivedCount,2) | ||
|
||
def test_fragmentedPayload3(self): | ||
self.server.handler.send(b'{"msg_type":"test7"') | ||
time.sleep(1) | ||
self.server.handler.send(b'}\n{"msg_type":"test71"}\n{"msg_type":') | ||
time.sleep(1) | ||
self.server.handler.send(b'"test72"}') | ||
time.sleep(1) | ||
self.assertEqual(self.SUT.receivedCount,3) | ||
|
||
def test_fragmentedPayload4(self): | ||
self.server.handler.send(b'{"msg_type":"test8"') | ||
time.sleep(1) | ||
self.server.handler.send(b'}\n{"msg_type":') | ||
time.sleep(1) | ||
self.server.handler.send(b'"test81"}') | ||
time.sleep(1) | ||
self.assertEqual(self.SUT.receivedCount,2) | ||
|
||
def test_fragmentedPayload5(self): | ||
self.server.handler.send(b'{"msg_type":"test9"') | ||
time.sleep(1) | ||
self.server.handler.send(b'}\n{') | ||
time.sleep(1) | ||
self.server.handler.send(b'"msg_type":"test91"}\n') | ||
time.sleep(1) | ||
self.assertEqual(self.SUT.receivedCount,2) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |