Testapplication with python autobahn and asyncio

#1

Hi,
I have got a problem with Autobahn under Python which makes me become desperate and I hope I will find help here.
I’m supposed to write a Python test program which tests the websocketconnection of a mainprogram to make sure that the desired functionality is accurate.
I got a test framework on hand which opens the main program anew for each single test so that I always got the same test environment. However this means that I have to open the connection anew before each test.
Then I would need a blocking receive with a timeout so I could say „Now something is supposed to come“.
For the websocket connection I am supposed to use Autobahn with asyncio.

My tries yet:

To make asyncio work you need to somehow make the event-loop run. Thats why I thought I’d let all test run in a subroutine and await it with run-until-complete so that I subsequently can stop the test program. Inside of the loop I afterwards open a new connection for each test.
I can’t use the code of the examples anymore:
coro = loop.create_connection(factory, ‘127.0.0.1’, 9000)
loop.run_until_complete(coro)

``

A run_until_complete musn’t be called inbetween an event loop. The consideration „ the program is already in the loop anyway so I don’t need an extra call anymore“ isn’t productive either. Because there is a lot to do in the tests Autobahn has to wait his turn pretty long. That’s why as soon as there’s the time I get an error message that the handshake didn’t work out.

I tried in several different ways now but nothing would work out. But that might be because I haven’t seen through asyncio completely yet.

My second idea: I know threads! I let Autobahn run in a thread, the queue is threadsafe anyway, so the communication is clear.

from autobahn.asyncio.websocket import WebSocketClientProtocol,
WebSocketClientFactory
import asyncio
from queue import Queue
from _thread import start_new_thread

class MyClientProtocol(WebSocketClientProtocol):
def onOpen(self):
self.factory.client = self

def onMessage(self, payload, isBinary):
queue.put(payload.decode(‘utf8’))

def onClose(self, wasClean, code, reason):
self.factory.client = None

class MockFactory(WebSocketClientFactory):

def init(self, uri, queue, loop):
self.client = None
self.queue = queue

   WebSocketClientFactory.__init__(self, uri, loop=loop, debug=False)

class WebSocketClientMock:
def init(self):
self.queue = Queue()
self.loop = asyncio.get_event_loop()
self.factory = MockFactory("ws://127.0.0.1:9000“, self.queue, self.loop)
self.factory.protocol = MyClientProtocol

def websocket_thread(self):
coro = self.loop.create_connection(self.factory, ‘127.0.0.1’, 9000)
self.loop.run_until_complete(coro)
self.loop.run_forever()
self.loop.close()

def connect(self):
start_new_thread(self.websocket_thread, ())

def close(self):
if self.factory.client is not None:
self.factory.client.sendClose()
self.factory.client = None

   with self.queue.mutex:
       self.queue.queue.clear()

def receive(self, timeout=2):
return self.queue.get(True, timeout)

``

This is the latest version of my numerous tries. For example with new_event_loop in the thread ( get_event_loop doesn’t work because I always get the error message „There is no current event loop in thread 'Dummy-2‘.“)
Or I also tried to not build up the thread in connect each time but to do it once in init. The method websocket_thread remained as in the example, just the carrying out of create_connection was done in the method connect. But this didn’t work out.

The current version doesn’t work either, but gives the following error message:
File “/usr/lib/python3.3/site-packages/autobahn/asyncio/websocket.py”, line 54, in connection_made
self._consume()
File “/usr/lib/python3.3/site-packages/autobahn/asyncio/websocket.py”, line 72, in _consume
self.waiter = Future()
File “/usr/lib/python3.3/site-packages/asyncio/futures.py”, line 148, in init
self._loop = events.get_event_loop()
File “/usr/lib/python3.3/site-packages/asyncio/events.py”, line 465, in get_event_loop
return get_event_loop_policy().get_event_loop()
File “/usr/lib/python3.3/site-packages/asyncio/events.py”, line 413, in get_event_loop
threading.current_thread().name)
AssertionError: There is no current event loop in thread 'Dummy-2‘.

``

I always give the loop to the factory-constructor but internally a feature without the loop gets opened. Thats is why the feature tries again to get the loop by executing the function get_event_loop.

That you very much for your support.

Ulrikop

0 Likes

#2

Hi,

Hi,
I have got a problem with Autobahn under Python which makes me become
desperate and I hope I will find help here.
I’m supposed to write a Python test program which tests the
websocketconnection of a mainprogram to make sure that the desired
functionality is accurate.
I got a test framework on hand which opens the main program anew for
each single test so that I always got the same test environment. However
this means that I have to open the connection anew before each test.

Understood. So you want your test driver open new WebSocket connections to the testee - for each test a complete new connection.

Of course this is possible with both Twisted and asyncio.

For example, with Twisted, here is how Autobahn testsuite does this

https://github.com/tavendo/AutobahnTestSuite/blob/master/autobahntestsuite/autobahntestsuite/fuzzing.py#L1249

For asyncio, you will need to call `loop.create_connection` again and again for each new connection.

E.g. in the connection close handler, fire up a new connection or do nothing (which means the program will end).

Then I would need a blocking receive with a timeout so I could say „Now
something is supposed to come“.

The way you approach that in asynchronous frameworks like Twisted or asyncio is not by doing a "blocking read" (which simply doesn't exist), but instead:

- setup a timer
- buffer anything received
- when "enough" has been received, cancel the timer
- when the timer fires, not enough data has been received, so handle that

For the websocket connection I am supposed to use Autobahn with asyncio.

My tries yet:

To make asyncio work you need to somehow make the event-loop run. Thats
why I thought I’d let all test run in a subroutine and await it with
run-until-complete so that I subsequently can stop the test program.
Inside of the loop I afterwards open a new connection for each test.
I can’t use the code of the examples anymore:
>
coro =loop.create_connection(factory,'127.0.0.1',9000)
loop.run_until_complete(coro)
>

A run_until_complete musn’t be called inbetween an event loop. The
consideration „ the program is already in the loop anyway so I don’t
need an extra call anymore“ isn’t productive either. Because there is a
lot to do in the tests Autobahn has to wait his turn pretty long. That’s
why as soon as there’s the time I get an error message that the
handshake didn’t work out.

The way all those asynch frameworks work is this:

1) setup/wire all your asynch logic
2) start the event loop

2) is done exactly once in a program, and this call will only return when the whole program is finished. And the program is finished when there are no future things to be done anymore.

I tried in several different ways now but nothing would work out. But
that might be because I haven’t seen through asyncio completely yet.

If you are completely new to asynchronous network programming (that is you are coming from synch/blocking/threads), there are new paradigms no learn. This isn't just throwing in some library to use. It's a complete style of programming. Expect a phase of confusion until "you see the light".

My second idea: I know threads! I let Autobahn run in a thread, the
queue is threadsafe anyway, so the communication is clear.

I wouldn't go that road. Threads are evil. Threads are unneeded (in this case definitely).

This is the latest version of my numerous tries. For example with
new_event_loop in the thread ( get_event_loop doesn’t work because I
always get the error message „There is no current event loop in thread
'Dummy-2‘.“)

You must setup and start a new event loop on the new thread. Initially, your program will only have one on the main thread. But as said, I wouldn't encourage using threads.

I always give the loop to the factory-constructor but internally a
feature without the loop gets opened. Thats is why the feature tries
again to get the loop by executing the function get_event_loop.

That you very much for your support.

I'm a bit under time pressure .. otherwise I would just add another example right away. Anyway, hoe above already helps a little. As your questions are more of general nature (not Autobahn specific), this is the asynchio/tulip list: https://groups.google.com/forum/#!forum/python-tulip

People are quite helpful there as well ..

Cheers,
/Tobias

···

Am 19.07.2014 15:29, schrieb Ulrikop:

Ulrikop

--
You received this message because you are subscribed to the Google
Groups "Autobahn" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to autobahnws+...@googlegroups.com
<mailto:autobahnws+...@googlegroups.com>.
To post to this group, send email to autob...@googlegroups.com
<mailto:autob...@googlegroups.com>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/autobahnws/d05939b6-2fe9-47c6-8154-edcbe9601d28%40googlegroups.com
<https://groups.google.com/d/msgid/autobahnws/d05939b6-2fe9-47c6-8154-edcbe9601d28%40googlegroups.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.

0 Likes