def test_id(logger): ('XMLStream.id should return the id of its stream node') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) stream.stream_node = Stream.create(id='what') # Then the id is none stream.id.should.equal('what')
def test_route_nodes_undefined(logger): ('XMLStream.route_nodes() should warn about undefined nodes') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I call route_nodes with a bare Node empty = Node.create(type='character', name='romeo') stream.route_nodes(None, empty) # Then the logger should have been called appropriately logger.warning.assert_called_once_with( 'no model defined for %s: %r', '<xmpp-unknown name="romeo" type="character" />', empty )
def test_parse_noxml(logger): ('XMLStream.parse should return None when failed to parse') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I feed it with valid XML stream.feed( '''<monteque name="Romeo" Loves Julietmonteque''' ) # And call parse result = stream.parse() result.should.be.none
def test_handle_presence(): ('XMLStream.handle_presence() should forward the `on.presence` event') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # And an event handler handle_presence = EventHandlerMock('on_presence') stream.on.presence(handle_presence) # When I call handle presence presence = Presence.create() stream.handle_presence(presence) handle_presence.assert_called_once_with(ANY, presence)
def test_route_nodes_error(): ('XMLStream.route_nodes() should warn about error nodes') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # And an event handler handle_error = EventHandlerMock('on_error') stream.on.error(handle_error) # When I call route_nodes node = ServiceUnavailable.create() stream.route_nodes(None, node) handle_error.assert_called_once_with(ANY, node)
def test_handle_iq_result(): ('XMLStream.handle_iq() should forward the `on.iq_result` event') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # And an event handler handle_iq_result = EventHandlerMock('on_iq_result') stream.on.iq_result(handle_iq_result) # When I call handle iq node = IQ.create(type='result') stream.handle_iq(node) handle_iq_result.assert_called_once_with(ANY, node)
def test_handle_message(): ('XMLStream.handle_message() should forward the `on.message` event') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # And an event handler handle_message = EventHandlerMock('on_message') stream.on.message(handle_message) # When I call handle message message = Message.create() stream.route_nodes(None, message) handle_message.assert_called_once_with(ANY, message)
def test_id_empty(logger): ('XMLStream.id should return None if there is no stream node stored') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # Then the id is none stream.id.should.be.none
def test_stream_reader_open(context): ('XMLStream#feed should set the state to "open" if received the tag <stream> completely') # Given a connection connection = Mock(name='connection') # And an event handler event_handler = EventHandlerMock('on_open') # And a XMLStream stream = XMLStream(connection, debug=True) stream.on.open(event_handler) # When I feed the reader stream.feed( ' <stream:stream from="*****@*****.**" to="im.example.com" version="1.0" xml:lang="en" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams"> ') # Then it should have returned a Node object stream.state.should.equal('OPEN') # And it dispatched the expected signal event_handler.assert_called_once_with(ANY, stream.stream_node)
def test_parse_ok(logger): ('XMLStream.parse should return a node') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I feed it with valid XML stream.feed( '''<monteque name="Romeo">Loves Juliet</monteque>''' ) # And call parse result = stream.parse() result.should.be.a(Node) result.to_xml().should.look_like(''' <monteque name="Romeo">Loves Juliet</monteque> ''')
def test_send_message(): ('XMLStream.send_message() should send a message with body') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I call send_presence stream.send_message( 'Hello', **{ 'to': 'juliet@capulet', 'from': 'romeu@monteque', } ) # Then it should have sent the correct XML connection.output.should.equal([ '<message from="romeu@monteque" to="juliet@capulet" type="chat"><body>Hello</body></message>' ])
def test_send_presence_delay(): ('XMLStream.send_presence should be able to send delay') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I call send_presence stream.send_presence( **{ 'to': 'juliet@capulet', 'from': 'romeu@monteque', 'delay': 'foobar' } ) # Then it should have sent the correct XML connection.output.should.equal([ '<presence from="romeu@monteque" to="juliet@capulet"><delay from="romeu@monteque" stamp="foobar" xmlns="urn:xmpp:delay" /><priority>10</priority></presence>' ])
def test_send_presence_jid(): ('XMLStream.send_presence when no `from` ' 'defined fallbacks') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I call send_presence stream.send_presence( **{ 'to': 'juliet@capulet', 'from': 'romeu@monteque', } ) # Then it should have sent the correct XML connection.output.should.equal([ '<presence from="romeu@monteque" to="juliet@capulet"><priority>10</priority></presence>', ])
def test_stream_reader_set_invalid_State(context): ('XMLStream#set_state should raise an error when raising a wrong state') # Given a connection connection = Mock(name='connection') # And a XMLStream stream = XMLStream(connection) # When I call set_state with an invalid stage when_called = stream.set_state.when.called_with('wat') # Then it should have raised when_called.should.have.raised(TypeError, 'invalid state was given: wat')
def test_stream_parse_stream_features(context): ('XMLStream.feed can recognize StreamFeatures') open_stream = XML(''' <stream:stream from="my.server" id="c2a55811-7b4f-4429-919a-c3d91a666f83" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en"> ''') features = XML(''' <stream:features> <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> <mechanism>SCRAM-SHA-1</mechanism> </mechanisms> <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/> <register xmlns="http://jabber.org/features/iq-register"/> </stream:features> ''') # Given a connection connection = Mock(name='connection') # And a node handler node_handler = EventHandlerMock('on_node') unhandled_handler = EventHandlerMock('on_unhandled_xml') # And a XMLStream stream = XMLStream(connection) stream.on.node(node_handler) stream.on.unhandled_xml(unhandled_handler) # When I feed the reader stream.feed(open_stream) stream.feed(features) # Then it should have triggered the calls node_handler.assert_has_calls([ call(ANY, ANY), call(ANY, ANY), call(ANY, ANY), call(ANY, ANY), ]) nodes_from_call(node_handler).should.equal([ SASLMechanism, SASLMechanismSet, StartTLS, IQRegister, StreamFeatures ]) unhandled_handler.assert_has_calls([])
def test_send_presence_missing_jid(): ('XMLStream.send_presence() complains ' 'if there is no bound jid and no provided `from` jid') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) # When I call send_presence stream.send_presence.when.called_with( **{ 'to': 'juliet@capulet', } ).should.have.raised( MissingJID, 'Presence cannot be sent when missing the "from" jid' )
def test_send_presence(): ('XMLStream.send_presence when no `from` ' 'defined fallbacks to bound_jid') # Given a connection connection = FakeConnection() # And a XMLStream stream = XMLStream(connection) stream.handle_bound_jid( ResourceBind.create('juliet@capulet') ) # When I call send_presence stream.send_presence( to='romeo@monteque', ) # Then it should have sent the correct XML connection.output.should.equal([ '<presence from="juliet@capulet" to="romeo@monteque"><priority>10</priority></presence>' ])
def application(): # Setting up logs coloredlogs.install(level=DEBUG and logging.DEBUG or logging.INFO) # create a non-blocking XMPP-connection connection = XMPPConnection(DOMAIN, PORT, debug=DEBUG) # create a XML stream stream = XMLStream(connection, debug=DEBUG) # prepare the SASL mechanism sasl = SASLAuthenticationHandler(SASL_MECHANISM, jid, password) sasl.bind(stream) @stream.on.closed def stream_closed(event, node): connection.disconnect() connection.connect() stream.reset() @stream.on.presence def handle_presence(event, presence): if not presence.attr.get('from'): return logging.debug("presence from: %s %s(%s)", presence.attr['from'], presence.status.strip(), presence.show.strip()) @connection.on.tcp_established def step1_open_stream(event, host_ip): "sends a <stream:stream> to the XMPP server" logging.info("connected to %s", host_ip) stream.open_client(jid.domain) @stream.on.sasl_support def step2_send_sasl_auth(event, node): "sends a <auth /> to the XMPP server" sasl.authenticate() @sasl.on.success def step3_handle_success(event, result): "the SASL authentication succeeded, it's our time to reopen the stream" stream.open_client(jid.domain) @stream.on.bind_support def step4_bind_to_a_resource_name(event, node): "the server said it supports binding" stream.bind_to_resource(jid.resource) @stream.on.bound_jid def step5_send_presence(event, jid): stream.send_presence() logging.info("echobot jid: %s", jid.text) @stream.on.presence def step6_auto_subscribe(event, presence): if not presence.attr.get('from'): return presence_type = presence.attr.get('type') params = {'from': jid.bare, 'to': presence.attr['from']} if presence_type == 'subscribe': stream.send_presence(type='subscribed', **params) elif presence_type == 'subscribed': stream.add_contact(presence.attr['from']) else: stream.send_presence(**params) @connection.on.ready_to_write def keep_alive(event, connection): "send whitespace keep alive every 60 seconds" if stream.has_gone_through_sasl() and (time.time() % 60 == 0): print 'keepalive' connection.send_whitespace_keepalive() connection.connect() try: while connection.is_alive(): connection.loop_once() except KeyboardInterrupt as e: print "\r{0}".format(traceback.format_exc(e)) raise SystemExit(1)
def application(): # Setting up logs coloredlogs.install(level=DEBUG and logging.DEBUG or logging.INFO) # create a non-blocking XMPP-connection connection = XMPPConnection(DOMAIN, PORT, debug=DEBUG) # create a XML stream stream = XMLStream(connection, debug=DEBUG) @stream.on.closed def auto_reconnect(event, node): logging.warning("server closed stream %s:", node) @stream.on.error def stream_error(event, error): logging.error(error.to_xml()) @connection.on.ready_to_write def keep_alive(event, connection): "send whitespace keep alive every 60 seconds" if stream.is_authenticated_component() and (int(time.time()) % 60 == 0): print 'keepalive' connection.send_whitespace_keepalive() @connection.on.tcp_established def step1_open_stream(event, host_ip): "sends a <stream:stream> to the XMPP server" logging.info("connected to %s", host_ip) stream.open_component(COMPONENT_NAME) @stream.on.open def step2_send_handshake(event, node): "sends a <auth /> to the XMPP server" stream.send_secret_handshake(COMPONENT_SECRET) @stream.on.presence def step3_auto_subscribe(event, presence): from_jid = presence.attr['to'] presence_type = presence.attr.get('type') params = {'from': from_jid, 'to': presence.attr['from']} if presence_type == 'subscribe': stream.send_presence(type='subscribed', **params) elif presence_type == 'subscribed': stream.send_presence(**params) @stream.on.success_handshake def send_presence(event, node): stream.send_presence(**{ 'from': random.choice(PRESENCE_JIDS), 'to': 'falcao.it' }) connection.connect() try: while connection.is_alive(): connection.loop_once() from_jid = random.choice(PRESENCE_JIDS) if stream.is_authenticated_component(): stream.send_presence(**{'from': from_jid, 'to': MANAGER_JID}) connection.loop_once() stream.add_contact(MANAGER_JID, from_jid=from_jid) connection.loop_once() except KeyboardInterrupt as e: print "\r{0}".format(traceback.format_exc(e)) raise SystemExit(1)
def application(): # Setting up logs coloredlogs.install(level=DEBUG and logging.DEBUG or logging.INFO) # create a non-blocking XMPP-connection connection = XMPPConnection(DOMAIN, 5222, debug=DEBUG) # create a XML stream stream = XMLStream(connection, debug=DEBUG) # prepare the SASL mechanism sasl = SASLAuthenticationHandler(SASL_MECHANISM, jid, password) sasl.bind(stream) # prepare service discovery helper service_discovery = stream.extension['0030'] @stream.on.closed def stream_closed(event, node): connection.disconnect() connection.connect() stream.reset() @stream.on.presence def handle_presence(event, presence): logging.debug("presence from: %s %s(%s)", presence.attr['from'], presence.status.strip(), presence.show.strip()) @connection.on.tcp_established def step1_open_stream(event, host_ip): "sends a <stream:stream> to the XMPP server" logging.info("connected to %s", host_ip) stream.open_client(jid.domain) @stream.on.sasl_support def step2_send_sasl_auth(event, node): "sends a <auth /> to the XMPP server" sasl.authenticate() @sasl.on.success def step3_handle_success(event, result): "the SASL authentication succeeded, it's our time to reopen the stream" stream.open_client(jid.domain) @stream.on.bind_support def step4_bind_to_a_resource_name(event, node): "the server said it supports binding" stream.bind_to_resource(jid.resource) @stream.on.bound_jid def step5_send_presence(event, jid): stream.send_presence() logging.info("Querying %s for disco items", jid.domain) service_discovery.query_items(to=jid.domain) logging.info("Querying %s for disco features and components", jid.domain) service_discovery.query_info(to=jid.domain) @stream.on.presence def step6_ensure_connectivity(event, presence): if presence.delay: stream.send_presence() @connection.on.ready_to_write def keep_alive(event, connection): if stream.has_gone_through_sasl() and (time.time() % 60 == 0): print 'keepalive' connection.send_whitespace_keepalive() @service_discovery.on.query_items def handle_disco_items(event, query): logging.info("Disco Items:\n%s", "\n".join(map(repr, query.get_children()))) @service_discovery.on.query_info def handle_disco_info(event, query): logging.info("Disco Features and Components:\n%s", "\n".join(map(repr, query.get_children()))) connection.connect() try: while connection.is_alive(): connection.loop_once() except KeyboardInterrupt as e: print "\r{0}".format(traceback.format_exc(e)) raise SystemExit(1)
def application(): # Setting up logs coloredlogs.install(level=DEBUG and logging.DEBUG or logging.INFO) # create a non-blocking XMPP-connection connection = XMPPConnection(DOMAIN, 5222, debug=DEBUG) # create a XML stream stream = XMLStream(connection, debug=DEBUG) # prepare the SASL mechanism sasl = SASLAuthenticationHandler(SASL_MECHANISM, jid, password) sasl.bind(stream) @stream.on.closed def stream_closed(event, node): connection.disconnect() connection.connect() stream.reset() @stream.on.presence def handle_presence(event, presence): logging.debug("presence from: %s %s(%s)", presence.attr['from'], presence.status.strip(), presence.show.strip()) @connection.on.tcp_established def step1_open_stream(event, host_ip): "sends a <stream:stream> to the XMPP server" logging.info("connected to %s", host_ip) stream.open_client(jid.domain) @stream.on.sasl_support def step2_send_sasl_auth(event, node): "sends a <auth /> to the XMPP server" sasl.authenticate() @sasl.on.success def step3_handle_success(event, result): "the SASL authentication succeeded, it's our time to reopen the stream" stream.open_client(jid.domain) @stream.on.bind_support def step4_bind_to_a_resource_name(event, node): "the server said it supports binding" stream.bind_to_resource(jid.resource) @stream.on.bound_jid def step5_send_presence(event, jid): stream.send_presence() logging.info("echobot jid: %s", jid.text) @stream.on.presence def step6_ensure_connectivity(event, presence): if presence.delay: stream.send_presence() @connection.on.ready_to_write def keep_alive(event, connection): if stream.has_gone_through_sasl() and (time.time() % 60 == 0): print 'keepalive' connection.send_whitespace_keepalive() @stream.on.message def auto_reply(event, message): stream.send_presence() from_jid = JID(message.attr['from']) if message.is_composing(): logging.warning("%s is composing", from_jid.nick) if message.is_active(): logging.warning("%s is active", from_jid.nick) body = message.get_body() if body: logging.critical("%s says: %s", from_jid.nick, body) stream.send_message(body, to=from_jid.text) stream.send_presence(to=from_jid.text) connection.connect() try: while connection.is_alive(): connection.loop_once() except KeyboardInterrupt as e: print "\r{0}".format(traceback.format_exc(e)) raise SystemExit(1)