class MQTTAdapterTests(TestCase): def setUp(self): self.logs = LogCapturer() self.logs.__enter__() self.addCleanup(lambda: self.logs.__exit__(None, None, None)) def _test_basic_publish(self): reactor, router, server_factory, session_factory = build_mqtt_server() session, pump = connect_application_session( server_factory, ObservingSession, component_config=ComponentConfig(realm=u"mqtt")) client_transport, client_protocol, mqtt_pump = connect_mqtt_server(server_factory) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", flags=ConnectFlags(clean_session=False, username=True, password=True)).serialise()) mqtt_pump.flush() # We get a CONNECT self.assertEqual(client_protocol.data, ConnACK(session_present=False, return_code=0).serialise()) client_protocol.data = b"" client_transport.write( Publish(duplicate=False, qos_level=0, retain=False, topic_name=u"test", payload=b'{"kwargs": {"bar": "baz"}}').serialise()) mqtt_pump.flush() pump.flush() # This needs to be replaced with the real deal, see https://github.com/crossbario/crossbar/issues/885 self.assertEqual(len(session.events), 1) self.assertEqual( session.events, [{"args": tuple(), "kwargs": {u'bar': u'baz'}}]) def _test_tls_auth(self): """ A MQTT client can connect using mutually authenticated TLS authentication. """ reactor, router, server_factory, session_factory = build_mqtt_server() real_reactor = selectreactor.SelectReactor() logger = make_logger() session, pump = connect_application_session( server_factory, ObservingSession, component_config=ComponentConfig(realm=u"mqtt")) endpoint = create_listening_endpoint_from_config({ "type": "tcp", "port": 1099, "interface": "0.0.0.0", "tls": { "certificate": "server.crt", "key": "server.key", "dhparam": "dhparam", "ca_certificates": [ "ca.cert.pem", "intermediate.cert.pem" ]}, }, FilePath(__file__).sibling('certs').path, real_reactor, logger) client_endpoint = create_connecting_endpoint_from_config({ "type": "tcp", "host": "127.0.0.1", "port": 1099, "tls": { "certificate": "client.crt", "hostname": u"localhost", "key": "client.key", "ca_certificates": [ "ca.cert.pem", "intermediate.cert.pem" ]}, }, FilePath(__file__).sibling('certs').path, real_reactor, logger) p = [] l = endpoint.listen(server_factory) class TestProtocol(Protocol): data = b"" expected = (ConnACK(session_present=False, return_code=0).serialise() + PubACK(packet_identifier=1).serialise()) def dataReceived(self_, data): self_.data = self_.data + data if len(self_.data) == len(self_.expected): self.assertEqual(self_.data, self_.expected) real_reactor.stop() @l.addCallback def _listening(factory): d = client_endpoint.connect(Factory.forProtocol(TestProtocol)) @d.addCallback def _(proto): p.append(proto) proto.transport.write( Connect(client_id=u"test123", flags=ConnectFlags(clean_session=False)).serialise()) proto.transport.write( Publish(duplicate=False, qos_level=1, retain=False, topic_name=u"test", payload=b"{}", packet_identifier=1).serialise()) lc = LoopingCall(pump.flush) lc.clock = real_reactor lc.start(0.01) def timeout(): print("Timing out :(") real_reactor.stop() print(self.logs.log_text.getvalue()) # Timeout, just in case real_reactor.callLater(10, timeout) real_reactor.run() client_protocol = p[0] # We get a CONNECT self.assertEqual(client_protocol.data, ConnACK(session_present=False, return_code=0).serialise() + PubACK(packet_identifier=1).serialise()) client_protocol.data = b"" pump.flush() # This needs to be replaced with the real deal, see https://github.com/crossbario/crossbar/issues/885 self.assertEqual(len(session.events), 1) self.assertEqual( session.events, [{"args": tuple(), "kwargs": {}}]) def test_tls_auth_denied(self): """ A MQTT client offering the wrong certificate won't be authenticated. """ reactor, router, server_factory, session_factory = build_mqtt_server() real_reactor = selectreactor.SelectReactor() logger = make_logger() session, pump = connect_application_session( server_factory, ObservingSession, component_config=ComponentConfig(realm=u"mqtt")) endpoint = create_listening_endpoint_from_config({ "type": "tcp", "port": 1099, "interface": "0.0.0.0", "tls": { "certificate": "server.crt", "key": "server.key", "dhparam": "dhparam", "ca_certificates": [ "ca.cert.pem", "intermediate.cert.pem" ]}, }, FilePath(__file__).sibling('certs').path, real_reactor, logger) client_endpoint = create_connecting_endpoint_from_config({ "type": "tcp", "host": "127.0.0.1", "port": 1099, "tls": { # BAD key: trusted by the CA, but wrong ID "certificate": "client_1.crt", "hostname": u"localhost", "key": "client_1.key", "ca_certificates": [ "ca.cert.pem", "intermediate.cert.pem" ]}, }, FilePath(__file__).sibling('certs').path, real_reactor, logger) p = [] l = endpoint.listen(server_factory) class TestProtocol(Protocol): data = b"" expected = ( ConnACK(session_present=False, return_code=1).serialise()) def dataReceived(self_, data): self_.data = self_.data + data if len(self_.data) == len(self_.expected): self.assertEqual(self_.data, self_.expected) real_reactor.stop() @l.addCallback def _listening(factory): d = client_endpoint.connect(Factory.forProtocol(TestProtocol)) @d.addCallback def _(proto): p.append(proto) proto.transport.write( Connect(client_id=u"test123", flags=ConnectFlags(clean_session=False)).serialise()) proto.transport.write( Publish(duplicate=False, qos_level=1, retain=False, topic_name=u"test", payload=b"{}", packet_identifier=1).serialise()) lc = LoopingCall(pump.flush) lc.clock = real_reactor lc.start(0.01) def timeout(): print("Timing out :(") real_reactor.stop() print(self.logs.log_text.getvalue()) # Timeout, just in case real_reactor.callLater(10, timeout) real_reactor.run() client_protocol = p[0] # We get a CONNECT self.assertEqual(client_protocol.data, ConnACK(session_present=False, return_code=1).serialise()) client_protocol.data = b"" pump.flush() # No events! self.assertEqual(len(session.events), 0) def _test_basic_subscribe(self): """ The MQTT client can subscribe to a WAMP topic and get messages. """ reactor, router, server_factory, session_factory = build_mqtt_server() client_transport, client_protocol, mqtt_pump = connect_mqtt_server(server_factory) session, pump = connect_application_session( server_factory, ApplicationSession, component_config=ComponentConfig(realm=u"mqtt")) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", flags=ConnectFlags(clean_session=False, username=True, password=True)).serialise()) client_transport.write( Subscribe(packet_identifier=1, topic_requests=[ SubscriptionTopicRequest(topic_filter=u"com/test/wamp", max_qos=0) ]).serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, (ConnACK(session_present=False, return_code=0).serialise() + SubACK(packet_identifier=1, return_codes=[0]).serialise())) client_protocol.data = b"" session.publish(u"com.test.wamp", u"bar") pump.flush() reactor.advance(0.1) mqtt_pump.flush() self.assertEqual( client_protocol.data, Publish(duplicate=False, qos_level=0, retain=False, topic_name=u"com/test/wamp", payload=b'{"args":["bar"]}').serialise() ) def _test_retained(self): """ The MQTT client can set and receive retained messages. """ reactor, router, server_factory, session_factory = build_mqtt_server() client_transport, client_protocol, mqtt_pump = connect_mqtt_server(server_factory) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", flags=ConnectFlags(clean_session=False, username=True, password=True)).serialise()) client_transport.write( Publish(duplicate=False, qos_level=1, retain=True, topic_name=u"com/test/wamp", packet_identifier=123, payload=b'{}').serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, ( ConnACK(session_present=False, return_code=0).serialise() + PubACK(packet_identifier=123).serialise() )) client_protocol.data = b"" client_transport.write( Subscribe(packet_identifier=1, topic_requests=[ SubscriptionTopicRequest(topic_filter=u"com/test/wamp", max_qos=0) ]).serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, SubACK(packet_identifier=1, return_codes=[0]).serialise()) client_protocol.data = b"" reactor.advance(0.1) mqtt_pump.flush() # This needs to be replaced with the real deal, see https://github.com/crossbario/crossbar/issues/885 self.assertEqual( client_protocol.data, Publish(duplicate=False, qos_level=0, retain=True, topic_name=u"com/test/wamp", payload=json.dumps( {}, sort_keys=True).encode('utf8') ).serialise() ) def _test_lastwill(self): """ FIXME: reactivate this test. The MQTT client can set a last will message which will be published when it disconnects. """ reactor, router, server_factory, session_factory = build_mqtt_server() session, pump = connect_application_session( server_factory, ObservingSession, component_config=ComponentConfig(realm=u"mqtt")) client_transport, client_protocol, mqtt_pump = connect_mqtt_server(server_factory) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", will_topic=u"test", will_message=b'{"args":["foobar"]}', flags=ConnectFlags(clean_session=False, username=True, password=True, will=True)).serialise()) mqtt_pump.flush() # We get a CONNECT self.assertEqual(client_protocol.data, ConnACK(session_present=False, return_code=0).serialise()) client_protocol.data = b"" client_transport.write(Disconnect().serialise()) mqtt_pump.flush() pump.flush() self.assertEqual(client_transport.disconnected, True) # This needs to be replaced with the real deal, see https://github.com/crossbario/crossbar/issues/885 self.assertEqual(len(session.events), 1) self.assertEqual( session.events, [{"args": [u"foobar"]}])
class TestamentTests(unittest.TestCase): # FIXME: # [ERROR] Traceback (most recent call last): # File "/home/oberstet/scm/crossbario/crossbar/crossbar/router/test/test_testament.py", line 203, in test_one_scope_does_not_affect_other # d = session.call("wamp.session.add_testament", "com.test.dc", # builtins.AttributeError: 'NoneType' object has no attribute 'call' skip = True def setUp(self): self.logs = LogCapturer() self.logs.__enter__() self.addCleanup(lambda: self.logs.__exit__(None, None, None)) def test_destroy_testament_sent_on_destroy(self): """ If one session calls wamp.session.add_testament and then the session is destroyed, the message it filed as a testament will be sent to subscribers of the chosen topic. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), 'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) d = session.call("wamp.session.add_testament", "com.test.destroyed", ['hello'], {}) pump.flush() # Make sure it returns a publication ID self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Then leave... session.leave() pump.flush() ob_pump.flush() # Testament is sent self.assertEqual(ob_session.events, [{ 'args': ("hello", ), 'kwargs': {} }]) def test_destroy_testament_not_sent_when_cleared(self): """ If one session calls wamp.session.add_testament, then the same session calls wamp.session.flush_testaments, and then the session is destroyed, the message it filed as a testament will not be sent, as it was deleted. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), 'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) d = session.call("wamp.session.add_testament", "com.test.destroyed", ['hello'], {}) pump.flush() # Make sure it returns an integer (the testament event publication ID) self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the testament d = session.call("wamp.session.flush_testaments") pump.flush() # Make sure it returns flushed count 1 self.assertEqual(self.successResultOf(d), 1) # Then leave... session.leave() pump.flush() ob_pump.flush() # No testaments were sent self.assertEqual(ob_session.events, []) def test_add_testament_needs_valid_scope(self): """ Only 'detached' and 'destroyed' are valid scopes for add_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call("wamp.session.add_testament", "com.test.destroyed", ['hello'], {}, scope="bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, ("scope must be destroyed or detached", )) def test_flush_testament_needs_valid_scope(self): """ Only 'detached' and 'destroyed' are valid scopes for flush_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call("wamp.session.flush_testaments", scope="bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, ("scope must be destroyed or detached", )) def test_one_scope_does_not_affect_other(self): """ Adding a testament to one scope and flushing the other maintains the added testament. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), 'com.test.dc') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) # Add a destroyed testament d = session.call("wamp.session.add_testament", "com.test.dc", ['destroyed'], {}, scope="destroyed") pump.flush() self.assertIsInstance(self.successResultOf(d), (int, )) # Add a detached testament d = session.call("wamp.session.add_testament", "com.test.dc", ['detached'], {}, scope="detached") pump.flush() self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the destroyed testament d = session.call("wamp.session.flush_testaments", scope="destroyed") pump.flush() # Make sure it returns number of flushed testaments self.assertEqual(self.successResultOf(d), 1) # Then leave... session.leave() pump.flush() ob_pump.flush() # Just the detached testament is sent self.assertEqual(ob_session.events, [{ "args": ('detached', ), "kwargs": {} }])
class TestamentTests(unittest.TestCase): def setUp(self): self.logs = LogCapturer() self.logs.__enter__() self.addCleanup(lambda: self.logs.__exit__(None, None, None)) def test_destroy_testament_sent_on_destroy(self): """ If one session calls wamp.session.add_testament and then the session is destroyed, the message it filed as a testament will be sent to subscribers of the chosen topic. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Then leave... session.leave() pump.flush() ob_pump.flush() # Testament is sent self.assertEqual(ob_session.events, [{ 'args': (u"hello", ), 'kwargs': {} }]) def test_destroy_testament_not_sent_when_cleared(self): """ If one session calls wamp.session.add_testament, then the same session calls wamp.session.flush_testaments, and then the session is destroyed, the message it filed as a testament will not be sent, as it was deleted. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the testament d = session.call(u"wamp.session.flush_testaments") pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # Then leave... session.leave() pump.flush() ob_pump.flush() # No testaments were sent self.assertEqual(ob_session.events, []) def test_add_testament_needs_valid_scope(self): """ Only 'detatched' and 'destroyed' are valid scopes for add_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}, scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detatched", )) def test_flush_testament_needs_valid_scope(self): """ Only 'detatched' and 'destroyed' are valid scopes for flush_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.flush_testaments", scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detatched", )) def test_one_scope_does_not_affect_other(self): """ Adding a testament to one scope and flushing the other maintains the added testament. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({ 'args': a, 'kwargs': kw }), u'com.test.dc') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session( server_factory, ObservingSession) # Add a destroyed testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'destroyed'], {}, scope=u"destroyed") pump.flush() self.assertEqual(self.successResultOf(d), None) # Add a detatched testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'detatched'], {}, scope=u"detatched") pump.flush() self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the destroyed testament d = session.call(u"wamp.session.flush_testaments", scope=u"destroyed") pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # Then leave... session.leave() pump.flush() ob_pump.flush() # Just the detatched testament is sent self.assertEqual(ob_session.events, [{ "args": (u'detatched', ), "kwargs": {} }])
class TestamentTests(unittest.TestCase): # FIXME: # [ERROR] Traceback (most recent call last): # File "/home/oberstet/scm/crossbario/crossbar/crossbar/router/test/test_testament.py", line 203, in test_one_scope_does_not_affect_other # d = session.call(u"wamp.session.add_testament", u"com.test.dc", # builtins.AttributeError: 'NoneType' object has no attribute 'call' skip = True def setUp(self): self.logs = LogCapturer() self.logs.__enter__() self.addCleanup(lambda: self.logs.__exit__(None, None, None)) def test_destroy_testament_sent_on_destroy(self): """ If one session calls wamp.session.add_testament and then the session is destroyed, the message it filed as a testament will be sent to subscribers of the chosen topic. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns a publication ID self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Then leave... session.leave() pump.flush() ob_pump.flush() # Testament is sent self.assertEqual(ob_session.events, [{'args': (u"hello",), 'kwargs': {}}]) def test_destroy_testament_not_sent_when_cleared(self): """ If one session calls wamp.session.add_testament, then the same session calls wamp.session.flush_testaments, and then the session is destroyed, the message it filed as a testament will not be sent, as it was deleted. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns an integer (the testament event publication ID) self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the testament d = session.call(u"wamp.session.flush_testaments") pump.flush() # Make sure it returns flushed count 1 self.assertEqual(self.successResultOf(d), 1) # Then leave... session.leave() pump.flush() ob_pump.flush() # No testaments were sent self.assertEqual(ob_session.events, []) def test_add_testament_needs_valid_scope(self): """ Only 'detached' and 'destroyed' are valid scopes for add_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}, scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detached",)) def test_flush_testament_needs_valid_scope(self): """ Only 'detached' and 'destroyed' are valid scopes for flush_testament. """ router, server_factory, router_factory = make_router_and_realm() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.flush_testaments", scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detached",)) def test_one_scope_does_not_affect_other(self): """ Adding a testament to one scope and flushing the other maintains the added testament. """ router, server_factory, router_factory = make_router_and_realm() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.dc') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) # Add a destroyed testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'destroyed'], {}, scope=u"destroyed") pump.flush() self.assertIsInstance(self.successResultOf(d), (int, )) # Add a detached testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'detached'], {}, scope=u"detached") pump.flush() self.assertIsInstance(self.successResultOf(d), (int, )) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the destroyed testament d = session.call(u"wamp.session.flush_testaments", scope=u"destroyed") pump.flush() # Make sure it returns number of flushed testaments self.assertEqual(self.successResultOf(d), 1) # Then leave... session.leave() pump.flush() ob_pump.flush() # Just the detached testament is sent self.assertEqual(ob_session.events, [{"args": (u'detached',), "kwargs": {}}])
class TestamentTests(unittest.TestCase): def setUp(self): self.logs = LogCapturer() self.logs.__enter__() self.addCleanup(lambda: self.logs.__exit__(None, None, None)) def test_destroy_testament_sent_on_destroy(self): """ If one session calls wamp.session.add_testament and then the session is destroyed, the message it filed as a testament will be sent to subscribers of the chosen topic. """ router, server_factory = make_router() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Then leave... session.leave() pump.flush() ob_pump.flush() # Testament is sent self.assertEqual(ob_session.events, [{'args': (u"hello",), 'kwargs': {}}]) def test_destroy_testament_not_sent_when_cleared(self): """ If one session calls wamp.session.add_testament, then the same session calls wamp.session.flush_testaments, and then the session is destroyed, the message it filed as a testament will not be sent, as it was deleted. """ router, server_factory = make_router() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.destroyed') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}) pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the testament d = session.call(u"wamp.session.flush_testaments") pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # Then leave... session.leave() pump.flush() ob_pump.flush() # No testaments were sent self.assertEqual(ob_session.events, []) def test_add_testament_needs_valid_scope(self): """ Only 'detatched' and 'destroyed' are valid scopes for add_testament. """ router, server_factory = make_router() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.add_testament", u"com.test.destroyed", [u'hello'], {}, scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detatched",)) def test_flush_testament_needs_valid_scope(self): """ Only 'detatched' and 'destroyed' are valid scopes for flush_testament. """ router, server_factory = make_router() session, pump = connect_application_session(server_factory, ApplicationSession) d = session.call(u"wamp.session.flush_testaments", scope=u"bar") pump.flush() # Make sure it returns a failure failure = self.failureResultOf(d) self.assertEqual(failure.value.args, (u"scope must be destroyed or detatched",)) def test_one_scope_does_not_affect_other(self): """ Adding a testament to one scope and flushing the other maintains the added testament. """ router, server_factory = make_router() class ObservingSession(ApplicationSession): @inlineCallbacks def onJoin(self, details): self.events = [] self.s = yield self.subscribe( lambda *a, **kw: self.events.append({'args': a, 'kwargs': kw}), u'com.test.dc') session, pump = connect_application_session(server_factory, ApplicationSession) ob_session, ob_pump = connect_application_session(server_factory, ObservingSession) # Add a destroyed testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'destroyed'], {}, scope=u"destroyed") pump.flush() self.assertEqual(self.successResultOf(d), None) # Add a detatched testament d = session.call(u"wamp.session.add_testament", u"com.test.dc", [u'detatched'], {}, scope=u"detatched") pump.flush() self.assertEqual(self.successResultOf(d), None) # No testament sent yet pump.flush() ob_pump.flush() self.assertEqual(ob_session.events, []) # Flush the destroyed testament d = session.call(u"wamp.session.flush_testaments", scope=u"destroyed") pump.flush() # Make sure it returns None self.assertEqual(self.successResultOf(d), None) # Then leave... session.leave() pump.flush() ob_pump.flush() # Just the detatched testament is sent self.assertEqual(ob_session.events, [{"args": (u'detatched',), "kwargs": {}}])