def test_too_slow(self, req1, req2, too_slow): """ Regression test for a bug where if the channel was closed before the HTTP responses arrived, the responses finally arriving crashed Gabble. """ # User gets bored, and ends the call. e = EventPattern('dbus-signal', signal='Closed', path=chan.object_path) if too_slow == TOO_SLOW_CLOSE: call_async(self.q, self.chan, 'Close', dbus_interface=cs.CHANNEL) elif too_slow == TOO_SLOW_REMOVE_SELF: self.chan.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL) elif too_slow == TOO_SLOW_DISCONNECT: disconnect_conn(q, conn, stream, [e]) try: chan.GetMembers() except dbus.DBusException, e: # This should fail because the object's gone away, not because # Gabble's crashed. assert cs.DBUS_ERROR_UNKNOWN_METHOD == e.get_dbus_name(), \ "maybe Gabble crashed? %s" % e else: # Gabble will probably also crash in a moment, because the http # request callbacks will be called after the channel's meant to # have died, which will cause the channel to try to call # methods on the (finalized) connection. assert False, "the channel should be dead by now" return
def worker(q, bus, conn, stream, should_decloak): decloak_automatically = conn.Get(cs.CONN_IFACE_GABBLE_DECLOAK, 'DecloakAutomatically', dbus_interface=cs.PROPERTIES_IFACE) assertEquals(should_decloak, decloak_automatically) amy_handle = conn.get_contact_handle_sync('*****@*****.**') # Amy directs presence to us presence = make_presence('[email protected]/panopticon') decloak = presence.addElement((ns.TEMPPRES, 'temppres')) decloak['reason'] = 'media' stream.send(presence) events = [ EventPattern('dbus-signal', signal='PresencesChanged', args=[{amy_handle: (cs.PRESENCE_AVAILABLE, 'available', '')}]), EventPattern('dbus-signal', signal='DecloakRequested', args=[amy_handle, 'media', should_decloak]), ] forbidden = [] if should_decloak: events.append(EventPattern('stream-presence', to='[email protected]/panopticon')) else: forbidden = [EventPattern('stream-presence')] q.forbid_events(forbidden) q.expect_many(*events) presence = make_presence('[email protected]/panopticon', type='unavailable') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{amy_handle: (cs.PRESENCE_OFFLINE, 'offline', '')}]) q.unforbid_events(forbidden)
def receiving_failed(self, content): self.receiving = False assert self.contents[0].stream.Properties.Get( cs.CALL_STREAM_IFACE_MEDIA, 'SendingState') == cs.CALL_STREAM_FLOW_STATE_STARTED content.stream.Media.ReportReceivingFailure( cs.CALL_STATE_CHANGE_REASON_MEDIA_ERROR, "", "receiving error") o = self.q.expect_many( EventPattern('dbus-signal', signal='ReceivingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_STOPPED], path=content.stream.__dbus_object_path__), EventPattern('dbus-signal', signal='RemoteMembersChanged', path=content.stream.__dbus_object_path__, predicate=lambda e: e.args[0] == { self.remote_handle: cs.CALL_SENDING_STATE_PENDING_STOP_SENDING }), EventPattern('sip-invite')) reinvite_event = o[2] assertContains('a=sendonly', reinvite_event.sip_message.body) self.context.check_call_sdp(reinvite_event.sip_message.body) body = reinvite_event.sip_message.body.replace( 'sendonly', self.sending and 'recvonly' or 'inactive') self.context.accept(reinvite_event.sip_message, body) ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0] self.q.expect('sip-ack', cseq=ack_cseq) self.start_receiving(content)
def returns_bees_from_search(q, stream, conn): server = 'hivemind.localhost' iq = call_create(q, conn, server) result = make_result_iq(stream, iq) query = result.firstChildElement() query.addElement("nick") stream.send(result) event = q.expect('dbus-return', method='CreateChannel') c = make_channel_proxy(conn, event.value[0], 'Channel') c_search = dbus.Interface(c, cs.CHANNEL_TYPE_CONTACT_SEARCH) call_async(q, c_search, 'Search', {'nickname': 'Buzzy'}) iq_event, _ = q.expect_many( EventPattern('stream-iq', to=server, query_ns=ns.SEARCH), EventPattern('dbus-signal', signal='SearchStateChanged'), ) iq = iq_event.stanza result = IQ(stream, 'result') result['id'] = iq['id'] result['from'] = iq['to'] result.addElement((ns.SEARCH, 'bees')).addElement('bzzzzzzz') stream.send(result) ssc = q.expect('dbus-signal', signal='SearchStateChanged') new_state, reason, details = ssc.args assert new_state == cs.SEARCH_FAILED, new_state assert reason == cs.NOT_AVAILABLE, reason # We call stop after the search has failed; it should succeed and do nothing. call_async(q, c_search, 'Stop') event = q.expect('dbus-return', method='Stop') c.Close()
def test_connect_success(q, bus, conn, stream): chan, hostname, certificate_path = connect_and_get_tls_objects( q, bus, conn) certificate = TlsCertificateWrapper( bus.get_object(conn.bus_name, certificate_path)) certificate.TLSCertificate.Accept() q.expect('dbus-signal', signal='Accepted') cert_props = dbus.Interface(certificate, cs.PROPERTIES_IFACE) state = cert_props.Get(cs.AUTH_TLS_CERT, 'State') rejections = cert_props.Get(cs.AUTH_TLS_CERT, 'Rejections') assertLength(0, rejections) chan.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
def close_and_check(self): self.channel.Close() state_event, event, _ = self.q.expect_many( EventPattern('dbus-signal', signal='FileTransferStateChanged', path=self.channel.object_path), EventPattern('stream-iq', stream=self.stream, iq_type='set', query_name='session'), EventPattern('dbus-signal', signal='Closed', path=self.channel.object_path)) state, reason = state_event.args assert state == cs.FT_STATE_CANCELLED assert reason == cs.FT_STATE_CHANGE_REASON_LOCAL_STOPPED while event.query.getAttribute('type') != 'terminate': event = self.q.expect('stream-iq', stream=self.stream, iq_type='set', query_name='session')
def test_privacy_list_push_valid(q, bus, conn, stream): test_invisible_on_connect(q, bus, conn, stream) set_id = stream.send_privacy_list_push_iq("invisible") _, req_list = q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id=set_id), EventPattern('stream-iq', query_ns=ns.PRIVACY, iq_type="get")) stream.send_privacy_list(req_list.stanza, [ elem('item', action='deny', order='1')(elem(u'presence-out')), elem('item', type='jid', value='*****@*****.**', action='deny', order='2')(elem(u'message')) ]) # We redundantly re-activate the 'invisible' list. These lines also # check to see that we didn't switch over to 'invisible-gabble' activate_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') active = xpath.queryForNodes('//active', activate_list.stanza)[0] assertEquals(active["name"], 'invisible') acknowledge_iq(stream, activate_list.stanza)
def abort_auth(q, chan, reason, message): reason_err_map = { cs.SASL_ABORT_REASON_USER_ABORT : cs.CANCELLED, cs.SASL_ABORT_REASON_INVALID_CHALLENGE : cs.SERVICE_CONFUSED } mapped_error = reason_err_map.get(reason, cs.CANCELLED) chan.SASLAuthentication.AbortSASL(reason, message) ssc, ce, _ = q.expect_many( EventPattern( 'dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, predicate=lambda e: e.args[0] == cs.SASL_STATUS_CLIENT_FAILED), EventPattern('dbus-signal', signal='ConnectionError'), EventPattern( 'dbus-signal', signal="StatusChanged", args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_AUTHENTICATION_FAILED])) assertEquals(cs.SASL_STATUS_CLIENT_FAILED, ssc.args[0]) assertEquals(mapped_error, ssc.args[1]) assertEquals(message, ssc.args[2].get('debug-message')), assertEquals(mapped_error, ce.args[0])
def expect_sasl_channel(q, bus, conn): signal, = q.expect_many( EventPattern('dbus-signal', signal='NewChannels', predicate=lambda e: e.args[0][0][1].get(cs.CHANNEL_TYPE) == cs.CHANNEL_TYPE_SERVER_AUTHENTICATION), ) path = signal.args[0][0][0] chan = SaslChannelWrapper(bus.get_object(conn.bus_name, path)) assertLength(1, signal.args[0]) props = signal.args[0][0][1] assertEquals(cs.CHANNEL_IFACE_SASL_AUTH, props.get(cs.AUTH_METHOD)) return chan, props
def test_plain_success(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) assertEquals(JID, props.get(cs.SASL_AUTHORIZATION_IDENTITY)) # On some servers we can't do DIGEST auth without this information. assertEquals('example.org', props.get(cs.SASL_DEFAULT_REALM)) # We can't necessarily do PLAIN auth without this information. assertEquals('test', props.get(cs.SASL_DEFAULT_USERNAME)) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) chan.SASLAuthentication.AcceptSASL() q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) e = q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def reject_start_receiving(self, content): self.stop_receiving(content) content.stream.RequestReceiving(self.remote_handle, True) self.q.expect('dbus-signal', signal='ReceivingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START], path=content.stream.__dbus_object_path__), content.stream.Media.CompleteReceivingStateChange( cs.CALL_STREAM_FLOW_STATE_STARTED) o = self.q.expect_many( EventPattern('dbus-signal', signal='ReceivingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_STARTED], path=content.stream.__dbus_object_path__), EventPattern('dbus-signal', signal='RemoteMembersChanged', path=content.stream.__dbus_object_path__), EventPattern('sip-invite')) assertLength(0, o[1].args[2]) assertLength(1, o[1].args[0]) assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, o[1].args[0][self.remote_handle]) assertEquals(self.self_handle, o[1].args[3][0]) assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o[1].args[3][1]) reinvite_event = o[2] assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body) assertDoesNotContain('a=inactive', reinvite_event.sip_message.body) self.context.check_call_sdp(reinvite_event.sip_message.body) body = reinvite_event.sip_message.body + 'a=recvonly\r\r' self.context.accept(reinvite_event.sip_message, body) ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0] self.q.expect_many(EventPattern('sip-ack', cseq=ack_cseq)) # Now let's restart receiving for real self.receiving = True self.context.reinvite() acc, rmb = self.q.expect_many( EventPattern('sip-response', code=200), EventPattern('dbus-signal', signal='RemoteMembersChanged', path=content.stream.__dbus_object_path__, predicate=lambda e: e.args[0] == {self.remote_handle: cs.CALL_SENDING_STATE_SENDING})) self.context.check_call_sdp(acc.sip_message.body, self.medias) self.context.ack(acc.sip_message)
def stop_sending(self, content): self.sending = False content.stream.SetSending(False) self.q.expect('dbus-signal', signal='SendingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP], path=content.stream.__dbus_object_path__) content.stream.Media.CompleteSendingStateChange( cs.CALL_STREAM_FLOW_STATE_STOPPED) o = self.q.expect_many( EventPattern('dbus-signal', signal='SendingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_STOPPED], path=content.stream.__dbus_object_path__), EventPattern('dbus-signal', signal='LocalSendingStateChanged', path=content.stream.__dbus_object_path__), EventPattern('sip-invite')) assertEquals(cs.CALL_SENDING_STATE_NONE, o[1].args[0]) assertEquals(self.self_handle, o[1].args[1][0]) reinvite_event = o[2] assertContains('a=recvonly', reinvite_event.sip_message.body) self.context.check_call_sdp(reinvite_event.sip_message.body) body = reinvite_event.sip_message.body.replace( 'recvonly', self.receiving and 'sendonly' or 'inactive') self.context.accept(reinvite_event.sip_message, body) ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0] self.q.expect('sip-ack', cseq=ack_cseq)
def test_join_bouncer(q, conn, stream, room): stream.sendJoin(room) new_channels = EventPattern('dbus-signal', signal='NewChannels') event = q.expect_many(new_channels)[0] q.forbid_events([new_channels]) channel_details = event.args[0] assertEquals(1, len(channel_details)) path, props = channel_details[0] assertEquals(HT_ROOM, props[TARGET_HANDLE_TYPE]) assertEquals(CHANNEL_TYPE_TEXT, props[CHANNEL_TYPE]) q.expect('dbus-signal', signal='MembersChanged') q.unforbid_events([new_channels]) return path
def send_file(self): s = self.create_socket() s.connect(self.address) s.send(self.file.data[self.file.offset:]) to_receive = self.file.size - self.file.offset self.count = 0 def bytes_changed_cb(bytes): self.count = bytes self.ft_channel.connect_to_signal('TransferredBytesChanged', bytes_changed_cb) # FileTransferStateChanged can be fired while we are receiving data # (in the SOCKS5 case for example) self.completed = False def ft_state_changed_cb(state, reason): if state == cs.FT_STATE_COMPLETED: self.completed = True self.ft_channel.connect_to_signal('FileTransferStateChanged', ft_state_changed_cb) # get data from bytestream data = b'' while len(data) < to_receive: data += self.bytestream.get_data() assert data == self.file.data[self.file.offset:] if self.completed: # FileTransferStateChanged has already been received waiting = [] else: waiting = [EventPattern('dbus-signal', signal='FileTransferStateChanged')] events = self.bytestream.wait_bytestream_closed(waiting) # If not all the bytes transferred have been announced using # TransferredBytesChanged, wait for them while self.count < to_receive: self.q.expect('dbus-signal', signal='TransferredBytesChanged') assert self.count == to_receive if len(waiting) > 1: state, reason = events[0].args assert state == cs.FT_STATE_COMPLETED assert reason == cs.FT_STATE_CHANGE_REASON_NONE
def test_limit(q, bus, conn, stream): chan = setup(q, bus, conn, stream) # do nothing, really forbidden = [EventPattern('stream-MODE'), EventPattern('dbus-signal', signal='PropertiesChanged')] q.forbid_events(forbidden) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Limit': dbus.UInt32(0)}) q.expect_many(EventPattern('dbus-return', method='UpdateConfiguration')) sync_stream(q, stream) q.unforbid_events(forbidden) # set a limit call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Limit': dbus.UInt32(1337)}) # totally 1337 q.expect_many(EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern('stream-MODE', data=['#test', '+l', '1337']), EventPattern('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'Limit': 1337}, []]) ) # unset the limit call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Limit': dbus.UInt32(0)}) q.expect_many(EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern('stream-MODE', data=['#test', '-l']), EventPattern('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'Limit': 0}, []]) )
def _socks5_expect_connection(self, expected_before, expected_after): events_before, _ = wait_events(self.q, expected_before, EventPattern('s5b-connected')) self._wait_auth_request() self._send_auth_reply() self._wait_connect_cmd() # pretend the hash was wrong and close the transport self.transport.loseConnection() iq_event = self.q.expect('stream-iq', iq_type='error', to=self.initiator) self.check_error_stanza(iq_event.stanza) return events_before, []
def _test_on_connect(q, bus, conn, stream, shared_status, show, msg, expected_show=None, min_version=None): expected_show = expected_show or show _status, _show, _invisible = shared_status stream.shared_status = shared_status if min_version is not None: stream.min_version = min_version forbidden_event_patterns = [ EventPattern('stream-presence'), EventPattern('stream-iq', query_ns=ns.PRIVACY, iq_type='get') ] q.forbid_events(forbidden_event_patterns) conn.SimplePresence.SetPresence(show, msg) conn.Connect() _, event = q.expect_many( EventPattern('stream-iq', query_ns=ns.GOOGLE_SHARED_STATUS, iq_type='get'), EventPattern('stream-iq', query_ns=ns.GOOGLE_SHARED_STATUS, iq_type='set')) shared_show, shared_invisible = _show_to_shared_status_show(show) _status = xpath.queryForNodes('//status', event.query)[0] assertEquals(msg, _status.children[0]) _show = xpath.queryForNodes('//show', event.query)[0] assertEquals(shared_show, _show.children[0]) _invisible = xpath.queryForNodes('//invisible', event.query)[0] assertEquals(shared_invisible, _invisible.getAttribute('value')) q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{ 1: (presence_types[expected_show], expected_show, msg) }]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])) q.unforbid_events(forbidden_event_patterns)
def recreate_text(q, bus, conn, stream): jid = '*****@*****.**' tube_chan, _, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) text_chan, text_path, text_props = text_channel(q, bus, conn, stream, 'CreateChannel', jid, presence=False) text_chan.Close() expect_close(q, text_path) assert_on_bus(q, tube_chan) assert_not_on_bus(q, text_chan) # now let's try and create the same text channel and hope we get # back the same channel q.forbid_events([EventPattern('stream-presence', to='%s/test' % jid)]) request_text_channel(q, bus, conn, 'CreateChannel', jid) ret = q.expect('dbus-return', method='CreateChannel') path, props = ret.value assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) new_sig = q.expect('dbus-signal', signal='NewChannels') channels = new_sig.args[0] assertEquals(1, len(channels)) assertEquals(path, channels[0][0]) assertEquals(props, channels[0][1]) # the channel should be identical given it's the same MucChannel assertEquals(text_path, path) assertEquals(text_props, props) assert_on_bus(q, tube_chan) assert_on_bus(q, text_chan) q.unforbid_all()
def open_bytestream(self, expected_before=[], expected_after=[]): # first propose to peer to connect using SOCKS5 # We set an invalid IP so that won't work self.socks5._send_socks5_init([ # Not working streamhost (self.initiator, 'invalid.invalid', 12345), ]) events_before, iq_event = wait_events( self.q, expected_before, EventPattern('stream-iq', iq_type='error', to=self.initiator)) self.socks5.check_error_stanza(iq_event.stanza) # socks5 failed, let's try IBB _, events_after = self.ibb.open_bytestream([], expected_after) return events_before, events_after
def _test_remote_status_away(q, bus, conn, stream, msg, show, list_attrs): events = [ EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{ 1: (presence_types[show], show, msg) }]) ] q.forbid_events(events) list_attrs['status'] = list_attrs.get('status', msg) stream.set_shared_status_lists(**list_attrs) q.expect('stream-iq', iq_type='result') sync_dbus(bus, q, conn) q.unforbid_events(events)
def test_invisible_on_connect(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) presence_event_pattern = EventPattern('stream-presence') q.forbid_events([presence_event_pattern]) conn.SimplePresence.SetPresence("hidden", "") conn.Connect() event = q.expect('stream-iq', query_name='invisible') acknowledge_iq(stream, event.stanza) q.unforbid_events([presence_event_pattern]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def during_call(self): content = self.contents[0] remote_hold_event = [ EventPattern('dbus-signal', signal='CallStateChanged') ] self.q.forbid_events(remote_hold_event) self.stop_start_sending_user_requested(content) self.stop_start_sending_remote_requested(content) self.stop_start_receiving_user_requested(content) self.running_check() self.reject_stop_receiving(content) self.stop_start_receiving_user_requested(content) self.reject_start_receiving(content) self.running_check() self.sending_failed(content) self.receiving_failed(content) self.running_check() direction_change_events = \ self.stream_dbus_signal_event('LocalSendingStateChanged') + \ self.stream_dbus_signal_event('RemoteMembersChanged') self.q.forbid_events(direction_change_events) self.hold() self.add_local_content_during_hold() self.add_remote_content_during_hold() self.unhold_fail(receiving=True) self.unhold_fail(receiving=False) self.unhold_succeed() self.q.unforbid_events(direction_change_events) self.q.unforbid_events(remote_hold_event) return calltest.CallTest.during_call(self)
def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, event.stanza) sync_stream(q, stream) sync_dbus(bus, q, conn) # A presence from a contact stream.send( make_presence('contact1@localhost/client', 'SHA1SUM-FOR-CONTACT1')) event = q.expect('dbus-signal', signal='AvatarUpdated') assert event.args[0] == 2, event.args assert event.args[1] == "SHA1SUM-FOR-CONTACT1", event.args AvatarRetrieved_event = EventPattern('dbus-signal', signal='AvatarRetrieved') AvatarUpdated_event = EventPattern('dbus-signal', signal='AvatarUpdated') StreamPresence_event = EventPattern('stream-presence') StreamIqVcard_event = EventPattern('stream-iq', query_ns='vcard-temp') # A presence from myself on another resource stream.send( make_presence('test@localhost/resource1', 'SHA1SUM-FOR-MYSELF-RES1')) q.forbid_events([AvatarRetrieved_event, AvatarUpdated_event]) stream_presence, stream_iq = q.expect_many( EventPattern('stream-presence'), EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard')) sync_dbus(bus, q, conn) q.unforbid_events([AvatarRetrieved_event, AvatarUpdated_event]) # If the server wrongly send a presence stanza with our resource, # AvatarUpdated must not be emitted q.forbid_events([ StreamPresence_event, StreamIqVcard_event, AvatarRetrieved_event, AvatarUpdated_event ]) stream.send(make_presence('test@localhost/Resource', 'SHA1SUM-FOR-MYSELF')) sync_dbus(bus, q, conn) sync_stream(q, stream) q.unforbid_events([ StreamPresence_event, StreamIqVcard_event, AvatarRetrieved_event, AvatarUpdated_event ])
def test(q, bus, conn): # Request a sidecar thate we support before we're connected; it should just # wait around until we're connected. call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE) conn.Connect() if PLUGINS_ENABLED: # Now we're connected, the call we made earlier should return. path, props = q.expect('dbus-return', method='EnsureSidecar').value # This sidecar doesn't even implement get_immutable_properties; it # should just get the empty dict filled in for it. assertEquals({}, props) # We should get the same sidecar if we request it again path2, props2 = conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE) assertEquals((path, props), (path2, props2)) else: # Only now does it fail. q.expect('dbus-error', method='EnsureSidecar') # This is not a valid interface name call_async(q, conn.Sidecars1, 'EnsureSidecar', 'not an interface') q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # The test plugin makes no reference to this interface. call_async(q, conn.Sidecars1, 'EnsureSidecar', 'unsupported.sidecar') q.expect('dbus-error', name=cs.NOT_IMPLEMENTED) call_async(q, conn, 'Disconnect') q.expect_many( EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_REQUESTED]), ) call_async(q, conn.Sidecars1, 'EnsureSidecar', 'zomg.what') # With older telepathy-glib this would be DISCONNECTED; # with newer telepathy-glib the Connection disappears from the bus # sooner, and you get UnknownMethod or something from dbus-glib. q.expect('dbus-error')
def double_server(q, bus, conn, stream): # For some reason the 2 proxies are actually the same. Check that we don't # set them twice in the SOCKS5 init stanza connect_and_announce_alice(q, bus, conn, stream) send_file_to_alice(q, conn) return_event, e1, e2 = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), proxy_query_events[0], proxy_query_events[1]) send_socks5_reply(stream, e1.stanza) # send the same reply for the second stanza with with a different port send_socks5_reply(stream, e2.stanza, 'fallback1-proxy.localhost', '127.0.0.1', '6789') proxies = wait_si_and_return_proxies(q, stream) # check that the proxy has been set only once check_proxies([('fallback1-proxy.localhost', '127.0.0.1', '6789')], proxies)
def connect_and_get_tls_objects(q, bus, conn, expect_example_jid=True): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) ev, = q.expect_many( EventPattern('dbus-signal', signal='NewChannels', predicate=is_server_tls_chan_event)) channels = ev.args[0] path, props = channels[0] chan = ServerTlsChanWrapper(bus.get_object(conn.bus_name, path)) hostname = props[cs.TLS_HOSTNAME] certificate_path = props[cs.TLS_CERT_PATH] if expect_example_jid: assertEquals(hostname, 'example.org') return chan, hostname, certificate_path
def send_file(q, bus, conn, stream): connect_and_announce_alice(q, bus, conn, stream) # Send a file; proxy queries are send when creating the FT channel send_file_to_alice(q, conn) return_event, e1, e2 = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), proxy_query_events[0], proxy_query_events[1]) send_socks5_reply(stream, e1.stanza) send_socks5_reply(stream, e2.stanza) # ensure that the same proxy is not queried more than once q.forbid_events(proxy_query_events) proxies = wait_si_and_return_proxies(q, stream) check_proxies([('fallback2-proxy.localhost', '127.0.0.1', '6789'), ('fallback1-proxy.localhost', '127.0.0.1', '12345')], proxies)
def proxy_error(q, bus, conn, stream): # Test if another proxy is queried if a query failed connect_and_announce_alice(q, bus, conn, stream) send_file_to_alice(q, conn) return_event, e1, e2, e3 = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS)) # Return errors for all the requests; the bugged proxies shouldn't be queried again q.forbid_events([ EventPattern('stream-iq', to=e1.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e1.stanza) # the fourth proxy is queried q.expect('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS) q.forbid_events([ EventPattern('stream-iq', to=e2.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e2.stanza) sync_stream(q, stream) q.forbid_events([ EventPattern('stream-iq', to=e3.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e3.stanza) sync_stream(q, stream)
def test(q, bus, conn, stream): # This sidecar sends a stanza, and waits for a reply, before being # created. pattern = EventPattern('stream-iq', to='sidecar.example.com', query_ns='http://example.com/sidecar') call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] # The server said yes, so we should get a sidecar back! acknowledge_iq(stream, e.stanza) q.expect('dbus-return', method='EnsureSidecar') identities = ["test/app-list//Test"] features = ["com.example.test1", "com.example.test2"] ver = compute_caps_hash(identities, features, {}) iq = IQ(stream, "get") query = iq.addElement((ns.DISCO_INFO, 'query')) query['node'] = ns.GABBLE_CAPS + '#' + ver stream.send(iq) e = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info') returned_features = [ feature['var'] for feature in xpath.queryForNodes('/iq/query/feature', e.stanza) ] assertEquals(features, returned_features) returned_identities = [ identity['category'] + "/" + identity['type'] + "//" + identity['name'] for identity in xpath.queryForNodes('/iq/query/identity', e.stanza) ] assertEquals(identities, returned_identities) new_ver = compute_caps_hash(returned_identities, returned_features, {}) assertEquals(new_ver, ver)
def test_caps(q, conn, stream, contact, features, audio, video, google=False): caps['ver'] = compute_caps_hash ([], features, {}) h = presence_and_disco(q, conn, stream, contact, True, client, caps, features) cflags = 0 call_expected_media_caps = [] if audio: cflags |= cs.MEDIA_CAP_AUDIO call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO) call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO_NAME) if video: cflags |= cs.MEDIA_CAP_VIDEO call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO) call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO_NAME) # If the contact can only do one of audio or video, or uses a Google # client, they'll have the ImmutableStreams cap. if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google: cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS else: call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS) event, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged') ) # Check Contact capabilities assertEquals(len(event.args), 1) assertEquals (event.args[0], get_contacts_capabilities_sync(conn, [h])) check_contact_caps (event.args[0][h], cs.CHANNEL_TYPE_CALL, call_expected_media_caps)
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) handle = conn.get_contact_handle_sync('*****@*****.**') conn.Avatars.RequestAvatars([handle]) conn.Avatars.RequestAvatars([handle]) conn.Avatars.RequestAvatars([handle]) conn.Avatars.RequestAvatars([handle]) iq_event = q.expect('stream-iq', to='*****@*****.**', query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode(b'hello').decode()) stream.send(iq) event = q.expect('dbus-signal', signal='AvatarRetrieved') q.forbid_events([EventPattern('dbus-signal', signal='AvatarRetrieved')])