def _publish(): service_session = self._router._realm.session if session._session_id is None: options = types.PublishOptions( correlation=unsubscribe. correlation if unsubscribe else None) else: options = types.PublishOptions( # we exclude the client session from the set of receivers # for the WAMP session meta events (race conditions!) exclude=[session._session_id], correlation=unsubscribe.correlation if unsubscribe else None) if was_subscribed: service_session.publish( u'wamp.subscription.on_unsubscribe', session._session_id, subscription.id, options=options, ) if was_deleted: service_session.publish( u'wamp.subscription.on_delete', session._session_id, subscription.id, options=options, )
def test_publish(self): handler = ApplicationSession() MockTransport(handler) publication = yield handler.publish(u'com.myapp.topic1') self.assertEqual(publication, None) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3) self.assertEqual(publication, None) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello') self.assertEqual(publication, None) publication = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(exclude_me=False)) self.assertEqual(publication, None) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello', options=types.PublishOptions( exclude_me=False, exclude=[100, 200, 300])) self.assertEqual(publication, None)
def test_decorator_multi_subscribe(crossbar): """ subscribe with a class using decorators, multiple times """ # setup foo_pub = Deferred() bar_pub = Deferred() from autobahn import wamp class TestSession(HelperSession): @wamp.subscribe(u"test.foo") def foo(self, data): print("FOO:", data) foo_pub.callback(data) @wamp.subscribe(u"test.bar") def bar(self, data): print("BAR:", data) bar_pub.callback(data) def onJoin(self, details): HelperSession.onJoin(self, details) self.subscribe(self) sub_session = yield functest_session(session_factory=TestSession) pub_session = yield functest_session() # execute d0 = pub_session.publish( u"test.foo", "foo_arg", options=types.PublishOptions(acknowledge=True), ) d1 = pub_session.publish( u"test.bar", "bar_arg", options=types.PublishOptions(acknowledge=True), ) timeout = sleep(5) try: test_results = DeferredList([d0, d1, foo_pub, bar_pub], fireOnOneErrback=True) res = yield DeferredList([test_results, timeout], fireOnOneCallback=True, fireOnOneErrback=True) except Exception as e: print("ERROR", e) raise assert not timeout.called, "timed out" assert foo_pub.called, "test.foo should have been subscribed" assert bar_pub.called, "test.bar should have been subscribed"
def send(session, details): yield listening # this one should be small enough to go through yield session.publish(u"foo", u"a" * 20, options=types.PublishOptions(acknowledge=True)) # this will definitely be over 1500 and should fail (due to the other # side's decoder dropping it because the payload is too big). We can't # get an error here because the router accepts it, but the other # *client* will reject... yield session.publish(u"foo", u"a" * 2000, options=types.PublishOptions(acknowledge=True))
def test_blacklist_publish_authid(auth_crossbar): ''' One publisher, 3 subscribers and blacklisting ''' # setup pub_session = yield functest_auth_session(authid=u'steve') sub_session0 = yield functest_auth_session(authid=u'alice') sub_session1 = yield functest_auth_session(authid=u'bob') sub_session2 = yield functest_auth_session(authid=u'carol') alice = Deferred() bob = Deferred() carol = Deferred() sub0 = yield sub_session0.subscribe(alice.callback, u"test_topic") sub1 = yield sub_session1.subscribe(bob.callback, u"test_topic") sub2 = yield sub_session2.subscribe(carol.callback, u"test_topic") try: # execute yield pub_session.publish( u"test_topic", "nothing", options=types.PublishOptions(exclude_authid=[u'alice'])) # we should have received two publishes: for bob and carol but # *not* alice yield wait_for(bob, 1, "waiting for publish0") yield wait_for(carol, 1, "waiting for publish1") assert not alice.called finally: yield sub0.unsubscribe() yield sub1.unsubscribe() yield sub2.unsubscribe()
def _publish(): service_session = self._router._realm.session options = types.PublishOptions( correlation_id=subscribe.correlation_id, correlation_is_anchor=False, correlation_is_last=False, ) if is_first_subscriber: subscription_details = { u'id': subscription.id, u'created': subscription.created, u'uri': subscription.uri, u'match': subscription.match, } service_session.publish( u'wamp.subscription.on_create', session._session_id, subscription_details, options=options, ) if not was_already_subscribed: options.correlation_is_last = True service_session.publish( u'wamp.subscription.on_subscribe', session._session_id, subscription.id, options=options, )
def _publish(): service_session = self._router._realm.session if unsubscribe and self._router.is_traced: options = types.PublishOptions( correlation_id=unsubscribe.correlation_id, correlation_is_anchor=False, correlation_is_last=False) else: options = None if was_subscribed: service_session.publish( u'wamp.subscription.on_unsubscribe', session._session_id, subscription.id, options=options, ) if was_deleted: if options: options.correlation_is_last = True service_session.publish( u'wamp.subscription.on_delete', session._session_id, subscription.id, options=options, )
def _unregister(self, registration, session): # drop session from registration observers # was_registered, was_last_callee = self._registration_map.drop_observer(session, registration) if was_registered and was_last_callee: self._registration_map.delete_observation(registration) # remove registration from session->registrations map # if was_registered: self._session_to_registrations[session].discard(registration) # publish WAMP meta events # if self._router._realm: service_session = self._router._realm.session if service_session and not registration.uri.startswith(u'wamp.'): options = types.PublishOptions( correlation=None ) if was_registered: service_session.publish(u'wamp.registration.on_unregister', session._session_id, registration.id, options=options) if was_last_callee: service_session.publish(u'wamp.registration.on_delete', session._session_id, registration.id, options=options) return was_registered, was_last_callee
def _(session, details): connects.append(details) yield session.publish( u"multiverse", group=g, member=m, options=types.PublishOptions(acknowledge=True) ) yield session.leave()
def test_whitelist_publish_authid(auth_crossbar): ''' One publisher, 3 subscribers and blacklisting ''' # setup pub_session = yield functest_auth_session(authid=u'steve') sub_session0 = yield functest_auth_session(authid=u'alice') sub_session1 = yield functest_auth_session(authid=u'bob') sub_session2 = yield functest_auth_session(authid=u'carol') alice = Deferred() bob = Deferred() carol = Deferred() sub0 = yield sub_session0.subscribe(alice.callback, u"test_topic") sub1 = yield sub_session1.subscribe(bob.callback, u"test_topic") sub2 = yield sub_session2.subscribe(carol.callback, u"test_topic") try: # execute yield pub_session.publish( u"test_topic", "nothing", options=types.PublishOptions( eligible_authid=[u'alice', u'carol', u'eve'])) # alice, carol only should get the pub yield wait_for(alice, 1, "waiting for publish0") yield wait_for(carol, 1, "waiting for publish1") assert not bob.called finally: yield sub0.unsubscribe() yield sub1.unsubscribe() yield sub2.unsubscribe()
def test_double_subscribe(self): handler = ApplicationSession() MockTransport(handler) event0 = Deferred() event1 = Deferred() subscription0 = yield handler.subscribe( lambda: event0.callback(42), u'com.myapp.topic1') subscription1 = yield handler.subscribe( lambda: event1.callback('foo'), u'com.myapp.topic1') # same topic, same ID self.assertTrue(subscription0.id == subscription1.id) # do a publish (MockTransport fakes the acknowledgement # message) and then do an actual publish event. The IDs # are the same, so we just do one Event. publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) handler.onMessage(message.Event(subscription0.id, publish.id)) # ensure we actually got both callbacks self.assertTrue(event0.called, "Missing callback") self.assertTrue(event1.called, "Missing callback")
def test_publish_callback_exception(self): """ Ensure we handle an exception from the user code. """ handler = ApplicationSession() MockTransport(handler) error_instance = RuntimeError("we have a problem") got_err_d = Deferred() def observer(e, msg): if error_instance == e.value: got_err_d.callback(True) handler.onUserError = observer def boom(): raise error_instance sub = yield handler.subscribe(boom, u'com.myapp.topic1') # MockTransport gives us the ack reply and then we do our # own event message publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) msg = message.Event(sub.id, publish.id) handler.onMessage(msg) # we know it worked if our observer worked and did # .callback on our Deferred above. self.assertTrue(got_err_d.called)
def test_single_session_pub_sub_success(crossbar): """ Override exclude_me so we publish to ourselves as well. Note: not paramterized over publish_options because we need to know the status of "exclude_me" """ # setup session = yield functest_session() pub_d = Deferred() sub = yield session.subscribe(pub_d.callback, u"test_topic") try: assert not pub_d.called # execute yield session.publish(u"test_topic", "foo", options=types.PublishOptions(acknowledge=True, exclude_me=False)) # test yield wait_for(pub_d, 5, "Waiting for our publish callback") assert pub_d.called, "Should publish to ourselves with exclude_me=False" assert pub_d.result == "foo" finally: yield sub.unsubscribe()
def test_internal_uri(crossbar): """ publish to crossbar.* should be denied """ # setup pub_session = yield functest_session() # execute d0 = pub_session.publish( u"wamp.awesome", "arg", options=types.PublishOptions(acknowledge=True), ) d1 = sleep(5) try: res = yield DeferredList([d0, d1], fireOnOneCallback=True, fireOnOneErrback=True) assert False, "Should have gotten error" except FirstError as e: real_e = e.subFailure.value assert 'restricted topic' in str(real_e) assert not d1.called
def test_authenticated_two_session_pub_sub(auth_crossbar): """ authenticated publisher and subscriber """ # setup pub_session = yield functest_auth_session() sub_session = yield functest_auth_session() pub_d = Deferred() sub = yield sub_session.subscribe(pub_d.callback, u"auth_topic") try: assert not pub_d.called # execute pub = yield pub_session.publish( u"auth_topic", ("foo", "bar"), options=types.PublishOptions( acknowledge=True, # XXX need a "legitimate" way to get session id? eligible=[sub_session._session_id], )) yield wait_for(pub_d, 5, "waiting for two-session publish callback") # test assert pub_d.called, "Failed to get publish callback" # we should have published our two args # NOTE: any sequence converted to list... assert pub_d.result == ["foo", "bar"] finally: yield sub.unsubscribe()
def _publish(): service_session = self._router._realm.session options = types.PublishOptions( # we exclude the client session from the set of receivers # for the WAMP session meta events (race conditions!) exclude=[session._session_id], correlation=subscribe.correlation) if is_first_subscriber: subscription_details = { u'id': subscription.id, u'created': subscription.created, u'uri': subscription.uri, u'match': subscription.match, } service_session.publish( u'wamp.subscription.on_create', session._session_id, subscription_details, options=options, ) if not was_already_subscribed: service_session.publish( u'wamp.subscription.on_subscribe', session._session_id, subscription.id, options=options, )
def test_single_session_pub_sub_to_self(crossbar): ''' With exclude_me=False we should get our own publish ''' # setup session = yield functest_session() pub_session = session sub_session = session pub_d = Deferred() sub = yield sub_session.subscribe(pub_d.callback, u"test_topic") try: # execute assert not pub_d.called yield pub_session.publish(u"test_topic", "foo", options=types.PublishOptions( acknowledge=True, exclude_me=False)) # test try: yield wait_for(pub_d, 1, "Expected this timeout") except RuntimeError as e: assert False, "Should have gotten a publish" assert pub_d.called, "Should publish to ourselves with exclude_me=False" finally: yield sub.unsubscribe()
def test_single_session_pub_sub(crossbar): ''' Ensure we don't publish to our own session by default. ''' # setup session = yield functest_session() pub_session = session sub_session = session pub_d = Deferred() sub = yield sub_session.subscribe(pub_d.callback, u"test_topic") try: # execute assert not pub_d.called yield pub_session.publish( u"test_topic", "foo", options=types.PublishOptions(acknowledge=True)) # test try: yield wait_for(pub_d, 1, "Expected this timeout") assert False, "Should have gotten an exception" except RuntimeError as e: pass assert not pub_d.called, "Shouldn't publish to ourselves" finally: yield sub.unsubscribe()
def test_publish_undefined_exception(self): handler = ApplicationSession() MockTransport(handler) options = types.PublishOptions(acknowledge=True) yield self.assertFailure(handler.publish(u'de.myapp.topic1', options=options), ApplicationError) yield self.assertFailure(handler.publish(u'', options=options), ApplicationError)
def bob_join(session, details): print("bob joined: PID={x_cb_pid}".format(**details.authextra)) print("publishing 'test.a_thing'") p = yield session.publish("test.a_thing", 3, 2, 1, options=types.PublishOptions(acknowledge=True)) print("published {}".format(p)) res = yield session.call("test.rpc", 1, 2, 3) print("test.rpc returned: {}".format(res)) reactor.callLater(2, session.leave)
def test_publish_acknowledged(self): handler = ApplicationSession() MockTransport(handler) publication = yield handler.publish(u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True)) self.assertTrue(type(publication.id) in (int, long)) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, options=types.PublishOptions(acknowledge=True)) self.assertTrue(type(publication.id) in (int, long)) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello', options=types.PublishOptions(acknowledge=True)) self.assertTrue(type(publication.id) in (int, long)) publication = yield handler.publish(u'com.myapp.topic1', options=types.PublishOptions(exclude_me=False, acknowledge=True)) self.assertTrue(type(publication.id) in (int, long)) publication = yield handler.publish(u'com.myapp.topic1', 1, 2, 3, foo=23, bar='hello', options=types.PublishOptions(exclude_me=False, exclude=[100, 200, 300], acknowledge=True)) self.assertTrue(type(publication.id) in (int, long))
def on_authorize_success(authorization): if not authorization[u'allow']: # error reply since session is not authorized to register # reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to register procedure '{0}'".format(register.procedure)]) else: registration = self._registration_map.get_observation(register.procedure, register.match) if register.force_reregister and registration: for obs in registration.observers: self._registration_map.drop_observer(obs, registration) kicked = message.Unregistered( 0, registration=registration.id, reason=u"wamp.error.unregistered", ) kicked.correlation = register.correlation self._router.send(obs, kicked) self._registration_map.delete_observation(registration) # ok, session authorized to register. now get the registration # registration_extra = RegistrationExtra(register.invoke) registration_callee_extra = RegistrationCalleeExtra(register.concurrency) registration, was_already_registered, is_first_callee = self._registration_map.add_observer(session, register.procedure, register.match, registration_extra, registration_callee_extra) if not was_already_registered: self._session_to_registrations[session].add(registration) # publish WAMP meta events # if self._router._realm: service_session = self._router._realm.session if service_session and not registration.uri.startswith(u'wamp.'): options = types.PublishOptions( correlation=register.correlation ) if is_first_callee: registration_details = { u'id': registration.id, u'created': registration.created, u'uri': registration.uri, u'match': registration.match, u'invoke': registration.extra.invoke, } service_session.publish(u'wamp.registration.on_create', session._session_id, registration_details, options=options) if not was_already_registered: service_session.publish(u'wamp.registration.on_register', session._session_id, registration.id, options=options) # acknowledge register with registration ID # reply = message.Registered(register.request, registration.id) # send out reply to register requestor # reply.correlation = register.correlation self._router.send(session, reply)
def test_publish_defined_exception(self): handler = ApplicationSession() MockTransport(handler) options = types.PublishOptions(acknowledge=True) handler.define(NotAuthorized) yield self.assertFailure(handler.publish(u'de.myapp.topic1', options=options), NotAuthorized) handler.define(InvalidUri) yield self.assertFailure(handler.publish(u'', options=options), InvalidUri)
def test_double_subscribe_double_unsubscribe(self): ''' If we subscribe twice, and unsubscribe twice, we should then get an Unsubscribed message. ''' handler = ApplicationSession() MockTransport(handler) # monkey-patch ApplicationSession to ensure we get our message unsubscribed_d = Deferred() def onMessage(msg): if isinstance(msg, message.Unsubscribed): unsubscribed_d.callback(msg) return ApplicationSession.onMessage(handler, msg) handler.onMessage = onMessage event0 = Deferred() event1 = Deferred() subscription0 = yield handler.subscribe( lambda: event0.callback(42), u'com.myapp.topic1') subscription1 = yield handler.subscribe( lambda: event1.callback('foo'), u'com.myapp.topic1') self.assertTrue(subscription0.id == subscription1.id) yield subscription0.unsubscribe() yield subscription1.unsubscribe() # after the second unsubscribe, we should have gotten an # Unsubscribed message assert unsubscribed_d.called # do a publish (MockTransport fakes the acknowledgement # message) and then do an actual publish event. Sending # the Event should be an error, as we have no # subscriptions left. publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) try: handler.onMessage(message.Event(subscription0.id, publish.id)) self.fail("Expected ProtocolError") except ProtocolError: pass # since we unsubscribed the second event handler, we # should NOT have called its callback self.assertTrue(not event0.called, "First callback fired.") self.assertTrue(not event1.called, "Second callback fired.")
def onJoin(self, details): def on_event(i): print("Got event: {}".format(i)) yield self.subscribe(on_event, 'com.myapp.topic1') counter = 0 while True: self.publish('com.myapp.topic1', counter, options=types.PublishOptions(excludeMe=False)) counter += 1 yield sleep(1)
def test_double_subscribe_errors(self): """ Test various error-conditions when we try to add a second subscription-handler (its signature must match any existing handlers). """ handler = ApplicationSession() MockTransport(handler) event0 = Deferred() event1 = Deferred() def second(*args, **kw): # our EventDetails should have been passed as the # "boom" kwarg; see "details_arg=" below self.assertTrue('boom' in kw) self.assertTrue(isinstance(kw['boom'], types.EventDetails)) event1.callback(args) subscription0 = yield handler.subscribe( lambda arg: event0.callback(arg), u'com.myapp.topic1') subscription1 = yield handler.subscribe( second, u'com.myapp.topic1', types.SubscribeOptions(details_arg='boom'), ) # same topic, same ID self.assertTrue(subscription0.id == subscription1.id) # MockTransport gives us the ack reply and then we do our # own event message. publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) # note that the protocol serializer converts all sequences # to lists, so we pass "args" as a list, not a tuple on # purpose. handler.onMessage( message.Event(subscription0.id, publish.id, args=['arg0'])) # each callback should have gotten called, each with its # own args (we check the correct kwarg in second() above) self.assertTrue(event0.called) self.assertTrue(event1.called) self.assertEqual(event0.result, 'arg0') self.assertEqual(event1.result, ('arg0', ))
def _publish(): service_session = self._router._realm.session options = types.PublishOptions(correlation_id=None) if was_subscribed: service_session.publish( u'wamp.subscription.on_unsubscribe', session._session_id, subscription.id, options=options, ) if was_deleted: service_session.publish( u'wamp.subscription.on_delete', session._session_id, subscription.id, options=options, )
def test_whitelist_publish_authrole(auth_crossbar): ''' One publisher, 3 subscribers and blacklisting ''' # setup pub_session = yield functest_auth_session(authid=u'steve') sub_session0 = yield functest_auth_session(authid=u'alice') sub_session1 = yield functest_auth_session(authid=u'bob') sub_session2 = yield functest_auth_session(authid=u'carol') publishes = [] got_pubs = [ Deferred(), Deferred(), Deferred(), Deferred(), Deferred(), Deferred() ] notify_pubs = [x for x in got_pubs] alice = Deferred() bob = Deferred() carol = Deferred() sub0 = yield sub_session0.subscribe(alice.callback, u"test_topic") sub1 = yield sub_session1.subscribe(bob.callback, u"test_topic") sub2 = yield sub_session2.subscribe(carol.callback, u"test_topic") try: # execute yield pub_session.publish( u"test_topic", "nothing", options=types.PublishOptions(eligible_authrole=u'role1')) # we should have received two publishes: for alice and bob but # *not* carol (who is in role1 instead of role0) yield wait_for(carol, 1, "waiting for publish0") yield sleep(0.1) # give spurious alice, bob messages time to arrive assert not alice.called assert not bob.called finally: yield sub0.unsubscribe() yield sub1.unsubscribe() yield sub2.unsubscribe()
def test_publish_callback_exception(self): """ Ensure we handle an exception from the user code. """ handler = ApplicationSession() MockTransport(handler) error_instance = RuntimeError("we have a problem") got_err_d = Deferred() def observer(kw): if kw['isError'] and 'failure' in kw: fail = kw['failure'] fail.trap(RuntimeError) if error_instance == fail.value: got_err_d.callback(True) log.addObserver(observer) def boom(): raise error_instance try: sub = yield handler.subscribe(boom, u'com.myapp.topic1') # MockTransport gives us the ack reply and then we do our # own event message publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) msg = message.Event(sub.id, publish.id) handler.onMessage(msg) # we know it worked if our observer worked and did # .callback on our Deferred above. self.assertTrue(got_err_d.called) # ...otherwise trial will fail the test anyway self.flushLoggedErrors() finally: log.removeObserver(observer)
def test_double_subscribe_single_unsubscribe(self): ''' Make sure we correctly deal with unsubscribing one of our handlers from the same topic. ''' handler = ApplicationSession() MockTransport(handler) # monkey-patch ApplicationSession to ensure we DO NOT get # an Unsubscribed message -- since we only unsubscribe # from ONE of our handlers for com.myapp.topic1 def onMessage(msg): assert not isinstance(msg, message.Unsubscribed) return ApplicationSession.onMessage(handler, msg) handler.onMessage = onMessage event0 = Deferred() event1 = Deferred() subscription0 = yield handler.subscribe( lambda: event0.callback(42), u'com.myapp.topic1') subscription1 = yield handler.subscribe( lambda: event1.callback('foo'), u'com.myapp.topic1') self.assertTrue(subscription0.id == subscription1.id) yield subscription1.unsubscribe() # do a publish (MockTransport fakes the acknowledgement # message) and then do an actual publish event. Note the # IDs are the same, so there's only one Event. publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) handler.onMessage(message.Event(subscription0.id, publish.id)) # since we unsubscribed the second event handler, we # should NOT have called its callback self.assertTrue(event0.called, "Missing callback") self.assertTrue(not event1.called, "Second callback fired.")