Ejemplo n.º 1
0
def check_and_accept_offer (q, bus, conn, self_handle, remote_handle,
        content, codecs, offer_path = None, check_codecs_changed = True ):

    (path, handle, remote_codecs ) = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "CodecOffer", dbus_interface=dbus.PROPERTIES_IFACE)

    if offer_path != None:
        assertEquals (offer_path, path)

    assertNotEquals ("/", path)

    offer = bus.get_object (conn.bus_name, path)
    remote_codecs_property = offer.Get (cs.CALL_CONTENT_CODECOFFER,
        "RemoteContactCodecs", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals (remote_codecs, remote_codecs_property)

    offer.Accept (codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER)

    current_codecs = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "ContactCodecMap", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals (codecs,  current_codecs[self_handle])

    if check_codecs_changed:
        o = q.expect ('dbus-signal', signal='CodecsChanged')
def run_cancel_test(q, bus, conn, stream):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob')
    jt.prepare()

    for x in xrange (0, 10):
        (path, props) = create_muji_channel (q, conn, stream, muc, x > 0)
        channel = bus.get_object (conn.bus_name, path)

        contents = channel.Get (cs.CHANNEL_TYPE_CALL, "Contents",
            dbus_interface = dbus.PROPERTIES_IFACE)

        content = bus.get_object (conn.bus_name, contents[0])

        md = jt.get_call_audio_md_dbus()
        check_and_accept_offer (q, bus, conn, content, md)

        # Accept the channel
        channel.Accept()

        e = q.expect('stream-presence', to = muc + "/test")
        mujinode = xpath.queryForNodes("/presence/muji/preparing", e.stanza)
        assertNotEquals(None, mujinode)

        channel.Hangup(0, "", "",
            dbus_interface=cs.CHANNEL_TYPE_CALL)

        e = q.expect('stream-presence', to = muc + "/test")
        mujinode = xpath.queryForNodes("/presence/muji/preparing", e.stanza)
        assertEquals(None, mujinode)

        if x % 2 == 0:
            channel.Close()
Ejemplo n.º 3
0
def test_invisible_on_connect_fail(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()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    # Check its name
    assertNotEquals([],
        xpath.queryForNodes('/query/list/item/presence-out', create_list.query))
    acknowledge_iq(stream, create_list.stanza)

    set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    active = xpath.queryForNodes('//active', set_active.query)[0]
    assertEquals('invisible', active['name'])
    send_error_reply(stream, set_active.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal', signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{1: (6, 'dnd', '')}]),
        EventPattern('dbus-signal', signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
Ejemplo n.º 4
0
def check_and_accept_offer(
    q, bus, conn, self_handle, content, codecs, remote_handle=None, offer_path=None, codecs_changed=True
):

    [path, handle, remote_codecs] = content.Get(
        cs.CALL_CONTENT_IFACE_MEDIA, "CodecOffer", dbus_interface=dbus.PROPERTIES_IFACE
    )

    if offer_path != None:
        assertEquals(offer_path, path)

    assertNotEquals("/", path)

    offer = bus.get_object(conn.bus_name, path)
    codecmap_property = offer.Get(
        cs.CALL_CONTENT_CODECOFFER, "RemoteContactCodecs", dbus_interface=dbus.PROPERTIES_IFACE
    )

    assertEquals(remote_codecs, codecmap_property)

    offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER)

    current_codecs = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "ContactCodecMap", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals(codecs, current_codecs[self_handle])

    if codecs_changed:
        o = q.expect("dbus-signal", signal="CodecsChanged")
        codecs_should_be = {self_handle: codecs}

        if remote_handle is not None:
            codecs_should_be[remote_handle] = codecs

        assertEquals([codecs_should_be, []], o.args)
Ejemplo n.º 5
0
def test_create_invisible_list(q, bus, conn, stream):
    conn.SimplePresence.SetPresence("away", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply (stream, get_list.stanza, error)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
        xpath.queryForNodes('/query/list/item/presence-out', create_list.query))
    acknowledge_iq(stream, create_list.stanza)

    q.expect('dbus-signal', signal='StatusChanged',
        args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    assertContains("hidden",
        conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
Ejemplo n.º 6
0
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()

    stream.handle_get_all_privacy_lists(q, bus, conn, ['invisible'])

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    stream.send_privacy_list(get_list.stanza,
        [elem('item', action='deny', order='1')(elem('presence-out'))])

    set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    active = xpath.queryForNodes('//active', set_active.query)[0]
    assertEquals('invisible', active['name'])
    acknowledge_iq(stream, set_active.stanza)

    q.unforbid_events([presence_event_pattern])

    q.expect('dbus-signal', signal='StatusChanged',
        args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
Ejemplo n.º 7
0
def test_invisible_on_connect_fail_no_list(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()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    send_error_reply(stream, get_list.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal', signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{1: (6, 'dnd', '')}]),
        EventPattern('dbus-signal', signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertDoesNotContain("hidden",
        conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
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()

    stream.handle_get_all_privacy_lists(q, bus, conn, ['invisible'])

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    stream.send_privacy_list(
        get_list.stanza,
        [elem('item', action='deny', order='1')(elem('presence-out'))])

    set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    active = xpath.queryForNodes('//active', set_active.query)[0]
    assertEquals('invisible', active['name'])
    acknowledge_iq(stream, set_active.stanza)

    q.unforbid_events([presence_event_pattern])

    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def test_create_invisible_list_failed(q, bus, conn, stream):
    conn.SimplePresence.SetPresence("away", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply(stream, get_list.stanza, error)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
                    xpath.queryForNodes('/query/list/item/presence-out',
                                        create_list.query))
    send_error_reply(stream, create_list.stanza)

    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    assertDoesNotContain(
        "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
                                      "Statuses"))
Ejemplo n.º 10
0
    def check_and_accept_offer(self, content, md, md_changed = True,
            offer_path = None):
        [path, remote_md] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE)

        if offer_path != None:
            assertEquals(offer_path, path)

        assertNotEquals("/", path)

        offer = self.bus.get_object(self.conn.bus_name, path)
        codecmap_property = offer.Get(cs.CALL_CONTENT_MEDIA_DESCRIPTION,
                "Codecs", dbus_interface=dbus.PROPERTIES_IFACE)

        assertEquals(remote_md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs'],
                codecmap_property)

        offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION)

        current_md = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "LocalMediaDescriptions", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(md,  current_md[self.peer_handle])

        if md_changed:
            o = self.q.expect('dbus-signal',
                    signal='LocalMediaDescriptionChanged')
            assertEquals([md], o.args)
Ejemplo n.º 11
0
def check_and_accept_offer (q, bus, conn, content, md, in_remote_handle = 0,
        offer_path = None, md_changed = True):

    [path, remote_md] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE)

    remote_handle = remote_md[cs.CALL_CONTENT_MEDIADESCRIPTION + '.RemoteContact']

    if in_remote_handle != 0:
        assertEquals(remote_handle, in_remote_handle)

    if offer_path != None:
        assertEquals (offer_path, path)

    assertNotEquals ("/", path)

    offer = bus.get_object (conn.bus_name, path)
    codecmap_property = offer.Get (cs.CALL_CONTENT_MEDIADESCRIPTION,
        "Codecs", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals (remote_md[cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs'], codecmap_property)

    offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION)

    current_md = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "LocalMediaDescriptions", dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals (md,  current_md[remote_handle])

    if md_changed:
        o = q.expect ('dbus-signal', signal='LocalMediaDescriptionChanged')
        assertEquals ([md], o.args)
Ejemplo n.º 12
0
    def add_content(self, content_path, initial=False, incoming=None):

        if initial:
            incoming = self.incoming
        else:
            assert incoming is not None

        content = self.bus.get_object(self.conn.bus_name, content_path)

        content_props = content.GetAll(cs.CALL_CONTENT)
        if initial:
            assertEquals(cs.CALL_DISPOSITION_INITIAL,
                         content_props['Disposition'])
            if content_props['Type'] == cs.MEDIA_STREAM_TYPE_AUDIO:
                assertEquals(self.initial_audio_content_name,
                             content_props['Name'])
            elif content_props['Type'] == cs.MEDIA_STREAM_TYPE_VIDEO:
                assertEquals(self.initial_video_content_name,
                             content_props['Name'])
            else:
                assert Fale

        else:
            assertEquals(cs.CALL_DISPOSITION_NONE,
                         content_props['Disposition'])

        content.media_type = content_props['Type']

        cmedia_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA)
        assertLength(0, cmedia_props['RemoteMediaDescriptions'])
        assertLength(0, cmedia_props['LocalMediaDescriptions'])
        if incoming:
            assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0])
        else:
            assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0])
        assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP,
                     cmedia_props['Packetization'])
        assertEquals(cs.CALL_SENDING_STATE_NONE,
                     cmedia_props['CurrentDTMFState'])

        self.contents.append(content)

        self.__add_stream(content, content_props['Streams'][0], initial,
                          incoming)

        if incoming:
            md = self.bus.get_object(self.conn.bus_name,
                                     cmedia_props['MediaDescriptionOffer'][0])
            md.Accept(self.context.get_audio_md_dbus(self.remote_handle))
            o = self.q.expect_many(
                EventPattern('dbus-signal',
                             signal='MediaDescriptionOfferDone'),
                EventPattern('dbus-signal',
                             signal='LocalMediaDescriptionChanged'),
                EventPattern('dbus-signal',
                             signal='RemoteMediaDescriptionsChanged'))

        return content
Ejemplo n.º 13
0
def test(q, bus, conn, stream):
    statuses = conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses')

    # testbusy and testaway are provided by test plugin
    assertContains('testbusy', statuses)
    assertContains('testaway', statuses)

    assertEquals(statuses['testbusy'][0], cs.PRESENCE_BUSY)
    assertEquals(statuses['testaway'][0], cs.PRESENCE_AWAY)

    conn.SimplePresence.SetPresence('testbusy', '')

    conn.Connect()

    # ... gabble asks for all the available lists on the server ...
    stream.handle_get_all_privacy_lists(
        q, bus, conn, lists=["foo-list", "test-busy-list", "bar-list"])

    # ... gabble checks whether there's usable invisible list on the server ...
    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply(stream, get_list.stanza, error)

    # ... since there is none, Gabble creates it ...
    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
                    xpath.queryForNodes('/query/list/item/presence-out',
                                        create_list.query))
    acknowledge_iq(stream, create_list.stanza)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//active', get_list.query)[0]

    # ... and then activates the one linked with the requested status
    # Note: testbusy status is linked to test-busy-list by test plugin
    assertEquals('test-busy-list', list_node['name'])
    acknowledge_iq(stream, get_list.stanza)

    q.expect('dbus-signal',
             signal='PresencesChanged',
             args=[{
                 1: (cs.PRESENCE_BUSY, u'testbusy', '')
             }])
    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    # ... testaway is not supposed to be settable on us
    call_async(q, conn.SimplePresence, 'SetPresence', 'testaway', '')
    q.expect('dbus-error', method='SetPresence', name=cs.INVALID_ARGUMENT)
Ejemplo n.º 14
0
def test(q, bus, conn, stream):
    path, _ = conn.Future.EnsureSidecar(CONSOLE_PLUGIN_IFACE)
    console = ProxyWrapper(bus.get_object(conn.bus_name, path),
        CONSOLE_PLUGIN_IFACE)

    assert not console.Properties.Get(CONSOLE_PLUGIN_IFACE, 'SpewStanzas')
    es = [
        EventPattern('dbus-signal', signal='StanzaReceived'),
        EventPattern('dbus-signal', signal='StanzaSent'),
        ]
    q.forbid_events(es)

    call_async(q, console, 'SendIQ', 'get', STACY,
        '<coffee xmlns="urn:unimaginative"/>')
    e = q.expect('stream-iq', iq_type='get', query_ns='urn:unimaginative',
        query_name='coffee')
    acknowledge_iq(stream, e.stanza)
    e = q.expect('dbus-return', method='SendIQ')
    type_, body = e.value
    assertEquals('result', type_)
    # We just assume the body works.

    # Turn on signalling incoming and outgoing stanzas
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', True)
    sync_dbus(bus, q, conn)
    q.unforbid_events(es)

    send_unrecognised_get(q, stream)

    e = q.expect('dbus-signal', signal='StanzaReceived')
    xml, = e.args
    assertContains('<iq', xml)
    assertContains('<dont-handle-me-bro', xml)

    signal = q.expect('dbus-signal', signal='StanzaSent')
    assertContains('service-unavailable', signal.args[0])

    # Turn off spewing out stanzas; check it works.
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', False)
    q.forbid_events(es)
    send_unrecognised_get(q, stream)
    sync_dbus(bus, q, conn)

    # Try sending just any old stanza
    console.SendStanza('''
        <message to='%(stacy)s' type='headline'>
          <body>
            Hi sis.
          </body>
        </message>''' % { 'stacy': STACY })

    e = q.expect('stream-message', to=STACY, message_type='headline')
    # Wocky fills in xmlns='' for us if we don't specify a namespace... great.
    # So this means <message/> gets sent as <message xmlns=''/> and the server
    # kicks us off.
    assertNotEquals('', e.stanza.uri)
Ejemplo n.º 15
0
def test(q, bus, conn, stream):
    self_presence = q.expect('stream-presence')

    c = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]

    jid = '[email protected]/omg'

    # Gabble shouldn't send any disco requests to our contact during this test.
    q.forbid_events([
        EventPattern('stream-iq', to=jid, iq_type='get',
            query_ns=ns.DISCO_INFO),
    ])

    # Check that Gabble doesn't disco other clients with the same caps hash.
    p = make_presence(jid,
        caps={'node': c['node'],
              'hash': c['hash'],
              'ver':  c['ver'],
             })
    stream.send(p)
    sync_stream(q, stream)

    # Check that Gabble doesn't disco its own ext='' bundles (well, its own
    # bundles as advertised by Gabbles that don't do hashed caps)
    p = make_presence(jid,
        caps={'node': c['node'],
              'ver':  c['ver'],
              # omitting hash='' so Gabble doesn't ignore ext=''
              'ext':  'voice-v1 video-v1',
            })
    stream.send(p)
    sync_stream(q, stream)

    # Advertise some different capabilities, to change our own caps hash.
    add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1),
           (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1),
           (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)]
    remove = []
    caps = conn.Capabilities.AdvertiseCapabilities(add, remove)

    self_presence = q.expect('stream-presence')
    c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]
    assertNotEquals(c['ver'], c_['ver'])

    # But then someone asks us for our old caps
    iq = IQ(stream, 'get')
    iq['from'] = jid
    query = iq.addElement((ns.DISCO_INFO, 'query'))
    query['node'] = c['node'] + '#' + c['ver']
    stream.send(iq)

    # Gabble should still know what they are, and reply. This is actually quite
    # important: there's a bug in iChat where if you return an error to a disco
    # query, it just asks again, and again, and again...
    reply = q.expect('stream-iq', to=jid)
    assertEquals('result', reply.iq_type)
Ejemplo n.º 16
0
def check_offer (bus, conn, content):
    [path, md] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE)

    assertNotEquals ("/", path)

    offer = bus.get_object (conn.bus_name, path)
    md_property = offer.Get (cs.CALL_CONTENT_MEDIA_DESCRIPTION,
       "Codecs", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals (md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"], md_property)
Ejemplo n.º 17
0
def check_offer (bus, conn, content):
    [path, handle, codecs] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA,
                "CodecOffer", dbus_interface=dbus.PROPERTIES_IFACE)

    assertNotEquals ("/", path)

    offer = bus.get_object (conn.bus_name, path)
    codecs_property = offer.Get (cs.CALL_CONTENT_CODECOFFER,
        "RemoteContactCodecs", dbus_interface=dbus.PROPERTIES_IFACE)

    assertEquals (codecs, codecs_property)
    def add_content(self, content_path, initial = False, incoming = None):

        if initial:
            incoming = self.incoming
        else:
            assert incoming is not None
        
        content = self.bus.get_object (self.conn.bus_name, content_path)
        
        content_props = content.GetAll(cs.CALL_CONTENT)
        if initial:
            assertEquals(cs.CALL_DISPOSITION_INITIAL,
            content_props['Disposition'])
            if content_props['Type'] == cs.MEDIA_STREAM_TYPE_AUDIO:
                assertEquals(self.initial_audio_content_name,
                             content_props['Name'])
            elif content_props['Type'] == cs.MEDIA_STREAM_TYPE_VIDEO:
                assertEquals(self.initial_video_content_name,
                             content_props['Name'])
            else:
                assert Fale

        else:
            assertEquals(cs.CALL_DISPOSITION_NONE,
            content_props['Disposition'])

        content.media_type = content_props['Type']

        cmedia_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA)
        assertLength(0, cmedia_props['RemoteMediaDescriptions'])
        assertLength(0, cmedia_props['LocalMediaDescriptions'])
        if incoming:
            assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0])
        else:
            assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0])
        assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP,
        cmedia_props['Packetization'])
        assertEquals(cs.CALL_SENDING_STATE_NONE, cmedia_props['CurrentDTMFState'])
        
        self.contents.append(content)

        self.__add_stream(content, content_props['Streams'][0], initial,
                          incoming)

        if incoming:
            md = self.bus.get_object (self.conn.bus_name,
                                 cmedia_props['MediaDescriptionOffer'][0])
            md.Accept(self.context.get_audio_md_dbus(self.remote_handle))
            o = self.q.expect_many(
                EventPattern('dbus-signal', signal='MediaDescriptionOfferDone'),
                EventPattern('dbus-signal', signal='LocalMediaDescriptionChanged'),
                EventPattern('dbus-signal', signal='RemoteMediaDescriptionsChanged'))

        return content                   
Ejemplo n.º 19
0
def test_invisible_on_connect_fail_invalid_list(q, bus, conn, stream,
                                                really_invalid=False):
    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()

    stream.handle_get_all_privacy_lists(q, bus, conn, ['invisible'])

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    if really_invalid:
        # At one point Gabble would crash if the reply was of type 'result' but
        # wasn't well-formed.
        acknowledge_iq(stream, get_list.stanza)
    else:
        stream.send_privacy_list(get_list.stanza,
            [elem('item', type='jid', value='*****@*****.**', action='allow',
                 order='1')(elem('presence-out')),
            elem('item', action='deny', order='2')(elem('presence-out'))])

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    created = xpath.queryForNodes('//list', create_list.stanza)[0]
    assertEquals(created["name"], 'invisible-gabble')
    acknowledge_iq (stream, create_list.stanza)

    q.unforbid_events([presence_event_pattern])

    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-gabble')
    acknowledge_iq (stream, activate_list.stanza)

    q.expect_many(
        EventPattern('dbus-signal', signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{1: (5, 'hidden', '')}]),
        EventPattern('dbus-signal', signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertContains("hidden",
        conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
Ejemplo n.º 20
0
def test(q, bus, conn, stream):
    statuses = conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
        'Statuses')

    # testbusy and testaway are provided by test plugin
    assertContains('testbusy', statuses)
    assertContains('testaway', statuses)

    assertEquals(statuses['testbusy'][0], cs.PRESENCE_BUSY)
    assertEquals(statuses['testaway'][0], cs.PRESENCE_AWAY)

    conn.SimplePresence.SetPresence('testbusy', '')

    conn.Connect()

    # ... gabble asks for all the available lists on the server ...
    stream.handle_get_all_privacy_lists(q, bus, conn,
        lists=["foo-list", "test-busy-list", "bar-list"])

    # ... gabble checks whether there's usable invisible list on the server ...
    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply (stream, get_list.stanza, error)

    # ... since there is none, Gabble creates it ...
    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
        xpath.queryForNodes('/query/list/item/presence-out',
            create_list.query))
    acknowledge_iq(stream, create_list.stanza)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//active', get_list.query)[0]

    # ... and then activates the one linked with the requested status
    # Note: testbusy status is linked to test-busy-list by test plugin
    assertEquals('test-busy-list', list_node['name'])
    acknowledge_iq(stream, get_list.stanza)

    q.expect('dbus-signal', signal='PresencesChanged',
        args=[{1L: (cs.PRESENCE_BUSY, u'testbusy', '')}])
def test(q, bus, conn, stream):
    props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE)
    assertNotEquals({}, props['Statuses'])
    conn.SimplePresence.SetPresence("away", "watching bees")

    conn.Connect()
    _, presence = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-presence'),
        )

    children = list(presence.stanza.elements())
    assertEquals('show', children[0].name)
    assertEquals('away', children[0].children[0])
    assertEquals('status', children[1].name)
    assertEquals('watching bees', children[1].children[0])
Ejemplo n.º 22
0
def test(q, bus, conn, stream):
    props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE)
    assertNotEquals({}, props['Statuses'])
    conn.SimplePresence.SetPresence("away", "watching bees")

    conn.Connect()
    _, presence = q.expect_many(
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-presence'),
    )

    children = list(presence.stanza.elements())
    assertEquals('show', children[0].name)
    assertEquals('away', children[0].children[0])
    assertEquals('status', children[1].name)
    assertEquals('watching bees', children[1].children[0])
Ejemplo n.º 23
0
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 test_invisible_on_connect_fail(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()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    # Check its name
    assertNotEquals([],
                    xpath.queryForNodes('/query/list/item/presence-out',
                                        create_list.query))
    acknowledge_iq(stream, create_list.stanza)

    set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    active = xpath.queryForNodes('//active', set_active.query)[0]
    assertEquals('invisible', active['name'])
    send_error_reply(stream, set_active.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{
                         1: (6, 'dnd', '')
                     }]),
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
def test_invisible_on_connect_fail_no_list(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()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    send_error_reply(stream, get_list.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{
                         1: (6, 'dnd', '')
                     }]),
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertDoesNotContain(
        "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
                                      "Statuses"))
Ejemplo n.º 26
0
def test(q, bus, conn, stream):
    self_presence = q.expect('stream-presence')

    c = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]

    jid = '[email protected]/omg'

    # Gabble shouldn't send any disco requests to our contact during this test.
    q.forbid_events([
        EventPattern('stream-iq', to=jid, iq_type='get',
            query_ns=ns.DISCO_INFO),
    ])

    # Check that Gabble doesn't disco other clients with the same caps hash.
    p = make_presence(jid,
        caps={'node': c['node'],
              'hash': c['hash'],
              'ver':  c['ver'],
             })
    stream.send(p)
    sync_stream(q, stream)

    # Check that Gabble doesn't disco its own ext='' bundles (well, its own
    # bundles as advertised by Gabbles that don't do hashed caps)
    p = make_presence(jid,
        caps={'node': c['node'],
              'ver':  c['ver'],
              # omitting hash='' so Gabble doesn't ignore ext=''
              'ext':  'voice-v1 video-v1',
            })
    stream.send(p)
    sync_stream(q, stream)

    conn.ContactCapabilities.UpdateCapabilities([
        (cs.CLIENT + '.AbiWord', [
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.STREAM_TUBE_SERVICE: 'x-abiword' },
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.STREAM_TUBE_SERVICE: 'x-abiword' },
        ], []),
        (cs.CLIENT + '.KCall', [
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL },
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_AUDIO: True},
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_VIDEO: True},
        ], [
            cs.CHANNEL_TYPE_CALL + '/gtalk-p2p',
            cs.CHANNEL_TYPE_CALL + '/ice-udp',
            cs.CHANNEL_TYPE_CALL + '/video/h264',
            ]),
        ])

    self_presence = q.expect('stream-presence')
    c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]
    assertNotEquals(c['ver'], c_['ver'])

    for suffix in [c['ver'], 'voice-v1', 'video-v1', 'camera-v1', 'share-v1',
            'pmuc-v1'] + list(c_['ext'].split()):
        # But then someone asks us for our old caps
        iq = IQ(stream, 'get')
        iq['from'] = jid
        query = iq.addElement((ns.DISCO_INFO, 'query'))
        query['node'] = c['node'] + '#' + suffix
        stream.send(iq)

        # Gabble should still know what they are, and reply. This is
        # actually quite important: there's a bug in iChat where if you
        # return an error to a disco query, it just asks again, and again,
        # and again...
        reply = q.expect('stream-iq', to=jid)
        assertEquals('result', reply.iq_type)
Ejemplo n.º 27
0
def test(q, bus, conn, stream):
    rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS,
                               'RequestableChannelClasses')

    fixed = {
        cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE,
        cs.TARGET_HANDLE_TYPE: cs.HT_NONE,
    }
    allowed = []
    assertContains((fixed, allowed), rccs)

    path, _ = conn.Requests.CreateChannel(
        {cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE})
    other_path, _ = conn.Requests.CreateChannel(
        {cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE})

    assertNotEquals(path, other_path)
    # leave the other one open, to test we don't crash on disconnect

    console = ProxyWrapper(bus.get_object(conn.bus_name, path),
                           CONSOLE_PLUGIN_IFACE, {'Channel': cs.CHANNEL})

    assert not console.Properties.Get(CONSOLE_PLUGIN_IFACE, 'SpewStanzas')
    es = [
        EventPattern('dbus-signal', signal='StanzaReceived'),
        EventPattern('dbus-signal', signal='StanzaSent'),
    ]
    q.forbid_events(es)

    call_async(q, console, 'SendIQ', 'get', STACY,
               '<coffee xmlns="urn:unimaginative"/>')
    e = q.expect('stream-iq',
                 iq_type='get',
                 query_ns='urn:unimaginative',
                 query_name='coffee')
    acknowledge_iq(stream, e.stanza)
    e = q.expect('dbus-return', method='SendIQ')
    type_, body = e.value
    assertEquals('result', type_)
    # We just assume the body works.

    # Turn on signalling incoming and outgoing stanzas
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', True)
    sync_dbus(bus, q, conn)
    q.unforbid_events(es)

    send_unrecognised_get(q, stream)

    e = q.expect('dbus-signal', signal='StanzaReceived')
    xml, = e.args
    assertContains('<iq', xml)
    assertContains('<dont-handle-me-bro', xml)

    signal = q.expect('dbus-signal', signal='StanzaSent')
    assertContains('service-unavailable', signal.args[0])

    # Turn off spewing out stanzas; check it works.
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', False)
    q.forbid_events(es)
    send_unrecognised_get(q, stream)
    sync_dbus(bus, q, conn)

    # Try sending just any old stanza
    console.SendStanza('''
        <message to='%(stacy)s' type='headline'>
          <body>
            Hi sis.
          </body>
        </message>''' % {'stacy': STACY})

    e = q.expect('stream-message', to=STACY, message_type='headline')

    # Make sure that Wocky has filled in the jabber:client namespace we
    # carelessly omitted.
    message = e.stanza
    assertEquals('message', message.name)
    assertEquals(ns.CLIENT, message.uri)
    body = message.firstChildElement()
    assertEquals('body', body.name)
    assertEquals(ns.CLIENT, body.uri)

    console.Channel.Close()
def test(q, bus, conn, stream):
    self_presence = q.expect('stream-presence')

    c = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]

    jid = '[email protected]/omg'

    # Gabble shouldn't send any disco requests to our contact during this test.
    q.forbid_events([
        EventPattern('stream-iq',
                     to=jid,
                     iq_type='get',
                     query_ns=ns.DISCO_INFO),
    ])

    # Check that Gabble doesn't disco other clients with the same caps hash.
    p = make_presence(jid,
                      caps={
                          'node': c['node'],
                          'hash': c['hash'],
                          'ver': c['ver'],
                      })
    stream.send(p)
    sync_stream(q, stream)

    # Check that Gabble doesn't disco its own ext='' bundles (well, its own
    # bundles as advertised by Gabbles that don't do hashed caps)
    p = make_presence(
        jid,
        caps={
            'node': c['node'],
            'ver': c['ver'],
            # omitting hash='' so Gabble doesn't ignore ext=''
            'ext': 'voice-v1 video-v1',
        })
    stream.send(p)
    sync_stream(q, stream)

    conn.ContactCapabilities.UpdateCapabilities([
        (cs.CLIENT + '.AbiWord', [
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
                cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
                cs.STREAM_TUBE_SERVICE: 'x-abiword'
            },
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
                cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                cs.STREAM_TUBE_SERVICE: 'x-abiword'
            },
        ], []),
        (cs.CLIENT + '.KCall', [
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL
            },
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_AUDIO: True
            },
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_VIDEO: True
            },
        ], [
            cs.CHANNEL_TYPE_CALL + '/gtalk-p2p',
            cs.CHANNEL_TYPE_CALL + '/ice-udp',
            cs.CHANNEL_TYPE_CALL + '/video/h264',
        ]),
    ])

    self_presence = q.expect('stream-presence')
    c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0]
    assertNotEquals(c['ver'], c_['ver'])

    for suffix in [
            c['ver'], 'voice-v1', 'video-v1', 'camera-v1', 'share-v1',
            'pmuc-v1'
    ] + list(c_['ext'].split()):
        # But then someone asks us for our old caps
        iq = IQ(stream, 'get')
        iq['from'] = jid
        query = iq.addElement((ns.DISCO_INFO, 'query'))
        query['node'] = c['node'] + '#' + suffix
        stream.send(iq)

        # Gabble should still know what they are, and reply. This is
        # actually quite important: there's a bug in iChat where if you
        # return an error to a disco query, it just asks again, and again,
        # and again...
        reply = q.expect('stream-iq', to=jid)
        assertEquals('result', reply.iq_type)
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    jid = '*****@*****.**'
    full_jid = '[email protected]/Foo'
    foo_handle = conn.get_contact_handle_sync(jid)

    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: foo_handle,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    presence = make_presence(full_jid,
                             status='hello',
                             caps={
                                 'node':
                                 'http://telepathy.freedesktop.org/homeopathy',
                                 'ver': '0.1',
                             })
    stream.send(presence)

    version_event = q.expect(
        'stream-iq',
        to=full_jid,
        query_ns=ns.DISCO_INFO,
        query_node='http://telepathy.freedesktop.org/homeopathy#0.1')

    result = make_result_iq(stream, version_event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = ns.CHAT_STATES
    stream.send(result)

    sync_stream(q, stream)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Receiving chat states:

    # Composing...
    stream.send(make_message(full_jid, state='composing'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_COMPOSING,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Message!
    stream.send(make_message(full_jid, body='hello', state='active'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_ACTIVE, state)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_INACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # Assert that a redundant chat-state change doesn't emit a signal

    forbidden = [
        EventPattern('dbus-signal',
                     signal='ChatStateChanged',
                     args=[foo_handle, cs.CHAT_STATE_ACTIVE])
    ]
    q.forbid_events(forbidden)

    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Foo'
    m['type'] = 'chat'
    m.addElement((ns.CHAT_STATES, 'active'))
    m.addElement('body', content='hello')
    stream.send(m)

    sync_dbus(bus, q, conn)
    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # Sending chat states:

    # Composing...
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_COMPOSING,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    # XEP 0085:
    #   every content message SHOULD contain an <active/> notification.
    chan.send_msg_sync('hi.')

    stream_message = q.expect('stream-message')
    elem = stream_message.stanza
    assertEquals('chat', elem['type'])

    check_state_notification(elem, 'active', allow_body=True)

    states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates')
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(self_handle, cs.CHAT_STATE_INACTIVE))
    assertEquals(cs.CHAT_STATE_ACTIVE,
                 states.get(foo_handle, cs.CHAT_STATE_INACTIVE))

    def is_body(e):
        if e.name == 'body':
            assert e.children[0] == u'hi.', e.toXml()
            return True
        return False

    assert len([x for x in elem.elements() if is_body(x)]) == 1, elem.toXml()

    # Close the channel without acking the received message. The peer should
    # get a <gone/> notification, and the channel should respawn.
    chan.Close()

    gone, _ = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Closed'),
    )
    check_state_notification(gone.stanza, 'gone')

    # Reusing the proxy object because we happen to know it'll be at the same
    # path...

    # Destroy the channel. The peer shouldn't get a <gone/> notification, since
    # we already said we were gone and haven't sent them any messages to the
    # contrary.
    es = [EventPattern('stream-message')]
    q.forbid_events(es)

    chan.Destroyable.Destroy()
    sync_stream(q, stream)

    # Make the channel anew.
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: foo_handle,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # Close it immediately; the peer should again not get a <gone/>
    # notification, since we haven't sent any notifications on that channel.
    chan.Close()
    sync_stream(q, stream)
    q.unforbid_events(es)

    # XEP-0085 §5.1 defines how to negotiate support for chat states with a
    # contact in the absence of capabilities. This is useful when talking to
    # invisible contacts, for example.

    # First, if we receive a message from a contact, containing an <active/>
    # notification, they support chat states, so we should send them.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'

    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    stream.send(make_message(full_jid, body='i am invisible', state='active'))

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    assertEquals(cs.CHAT_STATE_ACTIVE, changed.args[1])

    # We've seen them send a chat state notification, so we should send them
    # notifications when the UI tells us to.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'composing')

    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    chan.send_msg_sync('very convincing')
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # Now, test the case where we start the negotiation, and the contact
    # turns out to support chat state notifications.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # We shouldn't send any notifications until we actually send a message.
    # But ChatStateChanged is still emitted locally
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_ACTIVE, cs.CHAT_STATE_COMPOSING,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_INACTIVE
    ]:
        chan.ChatState.SetChatState(i)
        changed = q.expect('dbus-signal',
                           signal='ChatStateChanged',
                           path=chan.object_path)
        handle, state = changed.args
        assertEquals(i, state)
        assertEquals(self_handle, handle)

    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.send_msg_sync('is anyone there?')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # The D-Bus property changes, too
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_ACTIVE, state)
    assertEquals(self_handle, handle)

    # We get a notification back from our contact.
    stream.send(make_message(full_jid, state='composing'))

    # Wait until gabble tells us the chat-state of the remote party has
    # changed so we know gabble knows chat state notification are supported
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertNotEquals(foo_handle, handle)

    # So now we know they support notification, so should send notifications.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    # This doesn't check whether we're sending to the bare jid, or the
    # jid+resource. In fact, the notification is sent to the bare jid, because
    # we only update which jid we send to when we actually receive a message,
    # not when we receive a notification. wjt thinks this is less surprising
    # than the alternative:
    #
    #  • I'm talking to you on my N900, and signed in on my laptop;
    #  • I enter one character in a tab to you on my laptop, and then delete
    #    it;
    #  • Now your messages to me appear on my laptop (until I send you another
    #    one from my N900)!
    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # The D-Bus property changes, too
    changed = q.expect('dbus-signal',
                       signal='ChatStateChanged',
                       path=chan.object_path)
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    # But! Now they start messaging us from a different client, which *doesn't*
    # support notifications.
    other_jid = jid + '/Library'
    stream.send(make_message(other_jid, body='grr, library computers'))
    q.expect('dbus-signal', signal='MessageReceived')

    # Okay, we should stop sending typing notifications.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # Now, test the case where we start the negotiation, and the contact
    # does not support chat state notifications

    jid = '*****@*****.**'
    full_jid = jid + '/Nonsense'
    path = conn.Requests.CreateChannel({
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_ID: jid,
    })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.send_msg_sync('#n900 #maemo #zomg #woo #yay http://bit.ly/n900')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # They reply without a chat state.
    stream.send(make_message(full_jid, body="posted."))
    q.expect('dbus-signal', signal='MessageReceived')

    # Okay, we shouldn't send any more.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [
            cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
            cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE
    ]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    chan.send_msg_sync('@stephenfry simmer down')
    message = q.expect('stream-message')
    states = [x for x in message.stanza.elements() if x.uri == ns.CHAT_STATES]
    assertLength(0, states)
Ejemplo n.º 30
0
def test(q, bus, conn, stream):
    conn.Connect()
    q.expect('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    id = '1845a1a9-f7bc-4a2e-a885-633aadc81e1b'

    # <message type="chat"><body>hello</body</message>
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Pidgin'
    m['id'] = id
    m['type'] = 'chat'
    m.addElement('body', content='hello')
    stream.send(m)

    event = q.expect('dbus-signal', signal='NewChannel')
    text_chan = wrap_channel(
        bus.get_object(conn.bus_name, event.args[0]), 'Text', ['Messages'])
    assert event.args[1] == cs.CHANNEL_TYPE_TEXT
    assert event.args[2] == cs.HT_CONTACT
    foo_at_bar_dot_com_handle = event.args[3]
    jid = conn.InspectHandles(1, [foo_at_bar_dot_com_handle])[0]
    assert jid == '*****@*****.**'
    assert event.args[4] == False   # suppress handler

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = text_chan.Properties.GetAll(cs.CHANNEL)
    assert channel_props.get('TargetHandle') == event.args[3],\
            (channel_props.get('TargetHandle'), event.args[3])
    assert channel_props.get('TargetHandleType') == cs.HT_CONTACT,\
            channel_props.get('TargetHandleType')
    assert channel_props.get('ChannelType') == \
            cs.CHANNEL_TYPE_TEXT,\
            channel_props.get('ChannelType')
    assert cs.CHANNEL_IFACE_CHAT_STATE in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert cs.CHANNEL_IFACE_MESSAGES in \
            channel_props.get('Interfaces', ()), \
            channel_props.get('Interfaces')
    assert channel_props['TargetID'] == jid,\
            (channel_props['TargetID'], jid)
    assert channel_props['Requested'] == False
    assert channel_props['InitiatorHandle'] == event.args[3],\
            (channel_props['InitiatorHandle'], event.args[3])
    assert channel_props['InitiatorID'] == jid,\
            (channel_props['InitiatorID'], jid)

    received, message_received = q.expect_many(
        EventPattern('dbus-signal', signal='Received'),
        EventPattern('dbus-signal', signal='MessageReceived'),
        )

    # Check that C.T.Text.Received looks right
    # message type: normal
    assert received.args[3] == 0
    # flags: none
    assert received.args[4] == 0
    # body
    assert received.args[5] == 'hello'


    # Check that C.I.Messages.MessageReceived looks right.
    message = message_received.args[0]

    # message should have two parts: the header and one content part
    assert len(message) == 2, message
    header, body = message

    assert header['message-sender'] == foo_at_bar_dot_com_handle, header
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, header

    # This looks wrong, but is correct. We don't know if our contacts generate
    # message id='' attributes which are unique enough for our requirements, so
    # we should not use them as the message-token for incoming messages.
    assertNotEquals(id, header['message-token'])

    assert body['content-type'] == 'text/plain', body
    assert body['content'] == 'hello', body

    # Remove the message from the pending message queue, and check that
    # PendingMessagesRemoved fires.
    message_id = header['pending-message-id']

    text_chan.Text.AcknowledgePendingMessages([message_id])

    removed = q.expect('dbus-signal', signal='PendingMessagesRemoved')

    removed_ids = removed.args[0]
    assert len(removed_ids) == 1, removed_ids
    assert removed_ids[0] == message_id, (removed_ids, message_id)

    # Send a Notice using the Messages API
    greeting = [
        dbus.Dictionary({ 'message-type': 2, # Notice
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"what up",
        }
    ]

    sent_token = text_chan.Messages.SendMessage(greeting, dbus.UInt32(0))

    stream_message, sent, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Sent'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'normal'
    body = list(stream_message.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'what up'

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 2, header # Notice
    assert header['message-token'] == sent_token, header
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'what up', body

    assert message_sent.args[2] == sent_token

    assert sent.args[1] == 2, sent.args # Notice
    assert sent.args[2] == u'what up', sent.args


    # Send a message using Channel.Type.Text API
    text_chan.Text.Send(0, 'goodbye')

    stream_message, sent, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Sent'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat'
    body = list(stream_message.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, header
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    assert sent.args[1] == 0, sent.args # message type normal
    assert sent.args[2] == u'goodbye', sent.args
def test_invisible_on_connect_fail_invalid_list(q,
                                                bus,
                                                conn,
                                                stream,
                                                really_invalid=False):
    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()

    stream.handle_get_all_privacy_lists(q, bus, conn, ['invisible'])

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    if really_invalid:
        # At one point Gabble would crash if the reply was of type 'result' but
        # wasn't well-formed.
        acknowledge_iq(stream, get_list.stanza)
    else:
        stream.send_privacy_list(get_list.stanza, [
            elem('item',
                 type='jid',
                 value='*****@*****.**',
                 action='allow',
                 order='1')(elem('presence-out')),
            elem('item', action='deny', order='2')(elem('presence-out'))
        ])

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    created = xpath.queryForNodes('//list', create_list.stanza)[0]
    assertEquals(created["name"], 'invisible-gabble')
    acknowledge_iq(stream, create_list.stanza)

    q.unforbid_events([presence_event_pattern])

    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-gabble')
    acknowledge_iq(stream, activate_list.stanza)

    q.expect_many(
        EventPattern('dbus-signal',
                     signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{
                         1: (5, 'hidden', '')
                     }]),
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertContains(
        "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
                                      "Statuses"))
Ejemplo n.º 32
0
def test_call(jp, q, bus, conn, stream,
         expected_stun_servers=None, google=False, google_push_replacements=None,
         expected_relays=[]):
    # Initialize the test values
    jt, remote_handle = init_test(jp, q, conn, stream, google, google_push_replacements)

    # Advertise that we can do new style calls
    conn.ContactCapabilities.UpdateCapabilities([
        (cs.CLIENT + ".CallHandler", [
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_AUDIO: True},
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_VIDEO: True},
            ], [
                cs.CHANNEL_TYPE_CALL + '/gtalk-p2p',
                cs.CHANNEL_TYPE_CALL + '/ice',
                cs.CHANNEL_TYPE_CALL + '/video/h264',
            ]),
        ])

    # Remote end calls us
    jt.incoming_call()

    e = q.expect('dbus-signal', signal='ServerInfoRetrieved')
    assertLength(0, e.args)
    assertEquals(e.interface, cs.CALL_STREAM_IFACE_MEDIA)

    e = q.expect('dbus-signal', signal='NewChannels',
        predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args)
    assert e.args[0][0][0]

    call_chan = make_channel_proxy(conn, e.args[0][0][0], 'Channel')

    # Exercise channel properties
    channel_props = call_chan.GetAll(
        cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(remote_handle, channel_props['TargetHandle'])
    assertEquals(1, channel_props['TargetHandleType'])
    assertEquals('*****@*****.**', channel_props['TargetID'])
    assertEquals(False, channel_props['Requested'])
    assertEquals('*****@*****.**', channel_props['InitiatorID'])
    assertEquals(remote_handle, channel_props['InitiatorHandle'])

    # Get the call's Content object
    channel_props = call_chan.Get(cs.CHANNEL_TYPE_CALL, 'Contents',
        dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength(1, channel_props)
    assert len(channel_props[0]) > 0
    assertNotEquals('/', channel_props[0])

    # Get the call's Stream object
    call_content = make_channel_proxy(conn,
        channel_props[0], 'Call.Content.Draft')
    content_props = call_content.Get(cs.CALL_CONTENT, 'Streams',
        dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength(1, content_props)
    assert len(content_props[0]) > 0
    assertNotEquals('/', content_props[0])

    # Test the call's Stream's properties
    call_stream = make_channel_proxy(conn,
        content_props[0], 'Call.Stream.Interface.Media.Draft')
    stream_props = call_stream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
        dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(cs.CALL_STREAM_TRANSPORT_GTALK_P2P, stream_props['Transport'])

    test_stun_server(stream_props['STUNServers'], expected_stun_servers)

    assertEquals(expected_relays, stream_props['RelayInfo'])
    assertEquals(True, stream_props['HasServerInfo'])
def test_call(jp,
              q,
              bus,
              conn,
              stream,
              expected_stun_servers=None,
              google=False,
              google_push_replacements=None,
              expected_relays=[]):
    # Initialize the test values
    jt, remote_handle = init_test(jp, q, conn, stream, google,
                                  google_push_replacements)

    # Advertise that we can do new style calls
    conn.ContactCapabilities.UpdateCapabilities([
        (cs.CLIENT + ".CallHandler", [
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_AUDIO: True
            },
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.CALL_INITIAL_VIDEO: True
            },
        ], [
            cs.CHANNEL_TYPE_CALL + '/gtalk-p2p',
            cs.CHANNEL_TYPE_CALL + '/ice',
            cs.CHANNEL_TYPE_CALL + '/video/h264',
        ]),
    ])

    # Remote end calls us
    jt.incoming_call()

    e = q.expect('dbus-signal', signal='ServerInfoRetrieved')
    assertLength(0, e.args)
    assertEquals(e.interface, cs.CALL_STREAM_IFACE_MEDIA)

    e = q.expect(
        'dbus-signal',
        signal='NewChannels',
        predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args)
    assert e.args[0][0][0]

    call_chan = make_channel_proxy(conn, e.args[0][0][0], 'Channel')

    # Exercise channel properties
    channel_props = call_chan.GetAll(cs.CHANNEL,
                                     dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(remote_handle, channel_props['TargetHandle'])
    assertEquals(1, channel_props['TargetHandleType'])
    assertEquals('*****@*****.**', channel_props['TargetID'])
    assertEquals(False, channel_props['Requested'])
    assertEquals('*****@*****.**', channel_props['InitiatorID'])
    assertEquals(remote_handle, channel_props['InitiatorHandle'])

    # Get the call's Content object
    channel_props = call_chan.Get(cs.CHANNEL_TYPE_CALL,
                                  'Contents',
                                  dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength(1, channel_props)
    assert len(channel_props[0]) > 0
    assertNotEquals('/', channel_props[0])

    # Get the call's Stream object
    call_content = make_channel_proxy(conn, channel_props[0],
                                      'Call.Content.Draft')
    content_props = call_content.Get(cs.CALL_CONTENT,
                                     'Streams',
                                     dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength(1, content_props)
    assert len(content_props[0]) > 0
    assertNotEquals('/', content_props[0])

    # Test the call's Stream's properties
    call_stream = make_channel_proxy(conn, content_props[0],
                                     'Call.Stream.Interface.Media.Draft')
    stream_props = call_stream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                                      dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(cs.CALL_STREAM_TRANSPORT_GTALK_P2P, stream_props['Transport'])

    test_stun_server(stream_props['STUNServers'], expected_stun_servers)

    assertEquals(expected_relays, stream_props['RelayInfo'])
    assertEquals(True, stream_props['HasServerInfo'])
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    muc = '*****@*****.**'
    _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Bob offers a stream tube
    bob_bus_name = ':2.Ym9i'
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['initiator'] = '[email protected]/bob'
    tube['stream-id'] = '10'
    tube['id'] = '1'
    tube['service'] = 'com.example.Test'
    tube['dbus-name'] = bob_bus_name
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')
    stream.send(presence)

    # tube channel is created
    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    event = q.expect('dbus-signal',
                     signal='NewChannels',
                     predicate=new_chan_predicate)
    channels = event.args[0]
    path, props = channels[0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/bob', props[cs.INITIATOR_ID])
    bob_handle = props[cs.INITIATOR_HANDLE]
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME])
    assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS])
    assertEquals([
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS])

    tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube')

    # only Bob is in DBusNames
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name}, dbus_names)

    call_async(q, tube_chan.DBusTube, 'Accept', access_control)

    return_event, names_changed1, names_changed2, presence_event = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     predicate=lambda e: t.presence_contains_tube(e)))

    tube_addr = return_event.value[0]
    assert len(tube_addr) > 0

    # check presence stanza
    tube_node = xpath.queryForNodes('/presence/tubes/tube',
                                    presence_event.stanza)[0]
    assertEquals('[email protected]/bob', tube_node['initiator'])
    assertEquals('com.example.Test', tube_node['service'])
    assertEquals('10', tube_node['stream-id'])
    assertEquals('dbus', tube_node['type'])
    assertEquals('1', tube_node['id'])
    self_bus_name = tube_node['dbus-name']

    tubes_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                 'SelfHandle')
    assertNotEquals(0, tubes_self_handle)

    # both of us are in DBusNames now
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({
        bob_handle: bob_bus_name,
        tubes_self_handle: self_bus_name
    }, dbus_names)

    added, removed = names_changed1.args
    assertEquals({bob_handle: bob_bus_name}, added)
    assertEquals([], removed)

    added, removed = names_changed2.args
    assertEquals({tubes_self_handle: self_bus_name}, added)
    assertEquals([], removed)

    tube_chan.Channel.Close()
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream, access_control):
    conn.Connect()

    _, iq_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged',
            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'))

    acknowledge_iq(stream, iq_event.stanza)

    muc = '*****@*****.**'
    _, _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Bob offers a stream tube
    bob_bus_name = ':2.Ym9i'
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['initiator'] = '[email protected]/bob'
    tube['stream-id'] = '10'
    tube['id'] = '1'
    tube['service'] = 'com.example.Test'
    tube['dbus-name'] = bob_bus_name
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')
    stream.send(presence)

    # tubes channel is created
    event = q.expect('dbus-signal', signal='NewChannels')
    channels = event.args[0]
    path, props = channels[0]

    # tube channel is created
    event = q.expect('dbus-signal', signal='NewChannels')
    channels = event.args[0]
    path, props = channels[0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/bob', props[cs.INITIATOR_ID])
    bob_handle = props[cs.INITIATOR_HANDLE]
    assertEquals([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
        props[cs.INTERFACES])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME])
    assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS])
    assertEquals([cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
                    cs.SOCKET_ACCESS_CONTROL_LOCALHOST],
        props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS])

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_IFACE_TUBE)
    dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE)
    tube_chan_iface = dbus.Interface(tube_chan, cs.CHANNEL)

    # only Bob is in DBusNames
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name}, dbus_names)

    call_async(q, dbus_tube_iface, 'Accept', access_control)

    return_event, names_changed1, names_changed2, presence_event = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('stream-presence', to='[email protected]/test'))

    tube_addr = return_event.value[0]
    assert len(tube_addr) > 0

    # check presence stanza
    tube_node = xpath.queryForNodes('/presence/tubes/tube', presence_event.stanza)[0]
    assertEquals('[email protected]/bob', tube_node['initiator'])
    assertEquals('com.example.Test', tube_node['service'])
    assertEquals('10', tube_node['stream-id'])
    assertEquals('dbus', tube_node['type'])
    assertEquals('1', tube_node['id'])
    self_bus_name = tube_node['dbus-name']

    tubes_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP)
    assertNotEquals(0, tubes_self_handle)

    # both of us are in DBusNames now
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name, tubes_self_handle: self_bus_name}, dbus_names)

    added, removed = names_changed1.args
    assertEquals({bob_handle: bob_bus_name}, added)
    assertEquals([], removed)

    added, removed = names_changed2.args
    assertEquals({tubes_self_handle: self_bus_name}, added)
    assertEquals([], removed)

    tube_chan_iface.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream, peer='[email protected]/Foo'):
    jp = JingleProtocol031()

    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', peer)
    jt.prepare()

    # Remote end calls us
    jt.incoming_call(audio = "Audio", video = "Video")

    e = q.expect ('dbus-signal', signal='NewSessionHandler')
    handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
    handler.Ready()

    events = q.expect_many (
        EventPattern('dbus-signal', signal='NewStreamHandler'),
        EventPattern('dbus-signal', signal='NewStreamHandler')
    )
    for e in events:
        handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')
        handler.Ready([])

    candidate0 = (
        "1.2.3.4", # host
        666, # port
        0, # protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP
        "RTP", # protocol subtype
        "AVP", # profile
        1.0, # preference
        0, # transport type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL,
        "username",
        "password" )

    candidate1 = (
        "5.6.7.8", # host
        999, # port
        0, # protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP
        "RTP", # protocol subtype
        "AVP", # profile
        1.0, # preference
        0, # transport type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL,
        "username",
        "password" )

    node = jp.SetIq(jt.peer, jt.jid, [
        jp.Jingle(jt.sid, jt.peer, 'transport-info', [
            jp.Content('Audio', 'initiator', 'both',
                transport = jp.TransportGoogleP2P([candidate0])),
            jp.Content('Video', 'initiator', 'both',
                transport = jp.TransportGoogleP2P([candidate1])),
        ] ) ])

    stream.send(jp.xml(node))

    q.expect ('stream-iq', iq_type='result')
    (c0, c1) = q.expect_many(
        EventPattern('dbus-signal',  signal='AddRemoteCandidate'),
        EventPattern('dbus-signal',  signal='AddRemoteCandidate'))

    assertNotEquals(c0.path, c1.path)

    mapping = { 666: candidate0, 999: candidate1}

    # Candidate without component number to compare
    candidate = c0.args[1][0][1:]
    assertEquals(mapping[candidate[1]], candidate)

    candidate = c1.args[1][0][1:]
    assertEquals(mapping[candidate[1]], candidate)
Ejemplo n.º 37
0
def test(q, bus, conn, stream):
    self_handle = conn.GetSelfHandle()

    jid = '*****@*****.**'
    full_jid = '[email protected]/Foo'
    foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0]

    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    presence = make_presence(full_jid, status='hello',
        caps={
            'node': 'http://telepathy.freedesktop.org/homeopathy',
            'ver' : '0.1',
        })
    stream.send(presence)

    version_event = q.expect('stream-iq', to=full_jid,
        query_ns=ns.DISCO_INFO,
        query_node='http://telepathy.freedesktop.org/homeopathy#0.1')

    result = make_result_iq(stream, version_event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = ns.CHAT_STATES
    stream.send(result)

    sync_stream(q, stream)

    # Receiving chat states:

    # Composing...
    stream.send(make_message(full_jid, state='composing'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_COMPOSING, state)

    # Message!
    stream.send(make_message(full_jid, body='hello', state='active'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(foo_handle, handle)
    assertEquals(cs.CHAT_STATE_ACTIVE, state)

    # Sending chat states:

    # Composing...
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # XEP 0085:
    #   every content message SHOULD contain an <active/> notification.
    chan.Text.Send(0, 'hi.')

    stream_message = q.expect('stream-message')
    elem = stream_message.stanza
    assertEquals('chat', elem['type'])

    check_state_notification(elem, 'active', allow_body=True)

    def is_body(e):
        if e.name == 'body':
            assert e.children[0] == u'hi.', e.toXml()
            return True
        return False

    assert len([x for x in elem.elements() if is_body(x)]) == 1, elem.toXml()

    # Close the channel without acking the received message. The peer should
    # get a <gone/> notification, and the channel should respawn.
    chan.Close()

    gone, _, _ = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='NewChannel'),
        )
    check_state_notification(gone.stanza, 'gone')

    # Reusing the proxy object because we happen to know it'll be at the same
    # path...

    # Destroy the channel. The peer shouldn't get a <gone/> notification, since
    # we already said we were gone and haven't sent them any messages to the
    # contrary.
    es = [EventPattern('stream-message')]
    q.forbid_events(es)

    chan.Destroyable.Destroy()
    sync_stream(q, stream)

    # Make the channel anew.
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_HANDLE: foo_handle,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState', 'Destroyable'])

    # Close it immediately; the peer should again not get a <gone/>
    # notification, since we haven't sent any notifications on that channel.
    chan.Close()
    sync_stream(q, stream)
    q.unforbid_events(es)

    # XEP-0085 §5.1 defines how to negotiate support for chat states with a
    # contact in the absence of capabilities. This is useful when talking to
    # invisible contacts, for example.

    # First, if we receive a message from a contact, containing an <active/>
    # notification, they support chat states, so we should send them.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'

    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    stream.send(make_message(full_jid, body='i am invisible', state='active'))

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    assertEquals(cs.CHAT_STATE_ACTIVE, changed.args[1])

    # We've seen them send a chat state notification, so we should send them
    # notifications when the UI tells us to.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'composing')

    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertEquals(self_handle, handle)

    chan.Text.Send(0, 'very convincing')
    stream_message = q.expect('stream-message', to=full_jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # Now, test the case where we start the negotiation, and the contact
    # turns out to support chat state notifications.

    jid = '*****@*****.**'
    full_jid = jid + '/GTalk'
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.Text.Send(0, 'is anyone there?')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # We get a notification back from our contact.
    stream.send(make_message(full_jid, state='composing'))

    # Wait until gabble tells us the chat-state of the remote party has
    # changed so we know gabble knows chat state notification are supported
    changed = q.expect('dbus-signal', signal='ChatStateChanged')
    handle, state = changed.args
    assertEquals(cs.CHAT_STATE_COMPOSING, state)
    assertNotEquals(self_handle, handle)

    # So now we know they support notification, so should send notifications.
    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)

    # This doesn't check whether we're sending to the bare jid, or the
    # jid+resource. In fact, the notification is sent to the bare jid, because
    # we only update which jid we send to when we actually receive a message,
    # not when we receive a notification. wjt thinks this is less surprising
    # than the alternative:
    #
    #  • I'm talking to you on my N900, and signed in on my laptop;
    #  • I enter one character in a tab to you on my laptop, and then delete
    #    it;
    #  • Now your messages to me appear on my laptop (until I send you another
    #    one from my N900)!
    stream_message = q.expect('stream-message')
    check_state_notification(stream_message.stanza, 'composing')

    # But! Now they start messaging us from a different client, which *doesn't*
    # support notifications.
    other_jid = jid + '/Library'
    stream.send(make_message(other_jid, body='grr, library computers'))
    q.expect('dbus-signal', signal='Received')

    # Okay, we should stop sending typing notifications.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # Now, test the case where we start the negotiation, and the contact
    # does not support chat state notifications

    jid = '*****@*****.**'
    full_jid = jid + '/Nonsense'
    path = conn.Requests.CreateChannel(
            { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
              cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
              cs.TARGET_ID: jid,
              })[0]
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['ChatState'])

    # We shouldn't send any notifications until we actually send a message.
    e = EventPattern('stream-message', to=jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    # When we send a message, say we're active.
    chan.Text.Send(0, '#n900 #maemo #zomg #woo #yay http://bit.ly/n900')
    stream_message = q.expect('stream-message', to=jid)
    check_state_notification(stream_message.stanza, 'active', allow_body=True)

    # They reply without a chat state.
    stream.send(make_message(full_jid, body="posted."))
    q.expect('dbus-signal', signal='Received')

    # Okay, we shouldn't send any more.
    e = EventPattern('stream-message', to=other_jid)
    q.forbid_events([e])
    for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE,
              cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]:
        chan.ChatState.SetChatState(i)
    sync_stream(q, stream)
    q.unforbid_events([e])

    chan.Text.Send(0, '@stephenfry simmer down')
    message = q.expect('stream-message')
    states = [x for x in message.stanza.elements() if x.uri == ns.CHAT_STATES]
    assertLength(0, states)
Ejemplo n.º 38
0
def test(q, bus, conn, stream):
    rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS,
        'RequestableChannelClasses')

    fixed = {
        cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE,
        cs.TARGET_HANDLE_TYPE: cs.HT_NONE,
    }
    allowed = []
    assertContains((fixed, allowed), rccs)

    path, _ = conn.Requests.CreateChannel({ cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE })
    other_path, _ = conn.Requests.CreateChannel({ cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE })

    assertNotEquals(path, other_path)
    # leave the other one open, to test we don't crash on disconnect

    console = ProxyWrapper(bus.get_object(conn.bus_name, path),
        CONSOLE_PLUGIN_IFACE,
        {'Channel': cs.CHANNEL})

    assert not console.Properties.Get(CONSOLE_PLUGIN_IFACE, 'SpewStanzas')
    es = [
        EventPattern('dbus-signal', signal='StanzaReceived'),
        EventPattern('dbus-signal', signal='StanzaSent'),
        ]
    q.forbid_events(es)

    call_async(q, console, 'SendIQ', 'get', STACY,
        '<coffee xmlns="urn:unimaginative"/>')
    e = q.expect('stream-iq', iq_type='get', query_ns='urn:unimaginative',
        query_name='coffee')
    acknowledge_iq(stream, e.stanza)
    e = q.expect('dbus-return', method='SendIQ')
    type_, body = e.value
    assertEquals('result', type_)
    # We just assume the body works.

    # Turn on signalling incoming and outgoing stanzas
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', True)
    sync_dbus(bus, q, conn)
    q.unforbid_events(es)

    send_unrecognised_get(q, stream)

    e = q.expect('dbus-signal', signal='StanzaReceived')
    xml, = e.args
    assertContains('<iq', xml)
    assertContains('<dont-handle-me-bro', xml)

    signal = q.expect('dbus-signal', signal='StanzaSent')
    assertContains('service-unavailable', signal.args[0])

    # Turn off spewing out stanzas; check it works.
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', False)
    q.forbid_events(es)
    send_unrecognised_get(q, stream)
    sync_dbus(bus, q, conn)

    # Try sending just any old stanza
    console.SendStanza('''
        <message to='%(stacy)s' type='headline'>
          <body>
            Hi sis.
          </body>
        </message>''' % { 'stacy': STACY })

    e = q.expect('stream-message', to=STACY, message_type='headline')

    # Make sure that Wocky has filled in the jabber:client namespace we
    # carelessly omitted.
    message = e.stanza
    assertEquals('message', message.name)
    assertEquals(ns.CLIENT, message.uri)
    body = message.firstChildElement()
    assertEquals('body', body.name)
    assertEquals(ns.CLIENT, body.uri)

    console.Channel.Close()