Hey Guys,
Just getting started with tornado.
Im working on a little project using web sockets and i'm having a bit of trouble figuring the best way to write unit tests around the WebsocketHandler code. Ive googled around a bit and found a few things.
Heres the WebSocketHandler code that im testing against.
import os
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado.options import define, options, parse_command_line
define("port", default=8888, help="run on the given port", type=int)
TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
self.render(os.path.join(TEMPLATE_DIR, "index.html"))
clients = dict()
rooms = dict()
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self, room_id=None, *args, **kwargs):
self.stream.set_nodelay(True)
self.room_id = room_id
self.join()
def join(self):
access_token = self.get_argument('access_token', None)
clients[access_token] = {self.room_id: self}
room = rooms.setdefault(self.room_id, set())
room.add(access_token)
self.broadcast("{id} just joined the room".format(id=access_token))
def broadcast(self, message):
room = rooms[self.room_id]
for client_id in room:
connections = clients[client_id]
connections[self.room_id].write_message(message)
def on_message(self, message):
self.broadcast(message)
def on_close(self):
if self in clients:
self.clients.remove(self)
app = tornado.web.Application([
(r'/', IndexHandler),
(r'/rt/(?P<room_id>[a-zA-Z0-9\.:,_]+)/?', WebSocketHandler),
])
if __name__ == '__main__':
parse_command_line()
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
firstly was this little lib that looks fairly well maintained. I haven't been able to get this to run in a unit test yet though.
And here is the unit test i put together to see if i could get it working.
class AsyncWSClient(TornadoWebSocketClient):
"""
Asynchronous web socket client based on ws4py's tornadoclient
Sends a message and calls callback with received message
"""
def opened(self):
"""called when web socket opened"""
self._callback()
def run(self, callback, message=None):
"""Connects and sends message when connected"""
self._callback = callback
self.connect()
class WebSocketServerTests(testing.AsyncHTTPTestCase):
def get_app(self):
return app
def get_protocol(self):
return 'ws'
def test_room_registry(self):
url = '/rt/{room_id}/?access_token={token}'.format(room_id=1, token=1)
ws = AsyncWSClient(self.get_url(url))
ws.run(self.stop)
from myapp.realtime.server import rooms
self.assertIn('1', rooms)
self.wait()
This test fails and it never seems to connect or call the code from the WebSocketHandler.
The seoncd lib a found which doesnt seem to be maintained any more but i have managed to get working is this:
class WebSocketServerTests(testing.AsyncHTTPTestCase):
def get_app(self):
return app
def get_protocol(self):
return 'ws'
def test_client_registry(self):
url = '/rt/{room_id}/?access_token={token}'.format(room_id=1, token=1)
runner = self
class WSClient(websocket.WebSocket):
def on_open(self, *args, **kwargs):
from devscuss.realtime.server import rooms
runner.assertIn('1', rooms)
runner.io_loop.add_callback(runner.stop)
self.io_loop.add_callback(partial(WSClient,
self.get_url(url),
self.io_loop))
self.wait()
Im not to keen on this though and to be honest i dont really get whats going on.
So im hoping some of you can do two things for me.
A) Recommend the best way to approach writing tests for this stuff
B) If no other suggestions come to mind, please help me fix the first example as i think its much cleaner plus better maintained.
Hope to hear back soon