Skip to content

Commit

Permalink
Merge pull request #52 from btrinite/feat_unit_test
Browse files Browse the repository at this point in the history
Add unit test covering JSON message extraction from TCP buffer
  • Loading branch information
tawnkramer committed Nov 10, 2020
2 parents 20df71c + ac03f1d commit ebb88e8
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 0 deletions.
66 changes: 66 additions & 0 deletions gym_donkeycar/test/README.rst
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
162 changes: 162 additions & 0 deletions gym_donkeycar/test/client.test.py
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()

0 comments on commit ebb88e8

Please sign in to comment.