def disco_caps(q, stream, presence):
    c_nodes = xpath.queryForNodes('/presence/c', presence.stanza)
    assert c_nodes is not None
    assertLength(1, c_nodes)
    hash = c_nodes[0].attributes['hash']
    ver = c_nodes[0].attributes['ver']
    node = c_nodes[0].attributes['node']
    assertEquals('sha-1', hash)

    # ask caps
    request = \
        elem_iq(stream, 'get', from_='[email protected]/resource')(
          elem(ns.DISCO_INFO, 'query', node=(node + '#' + ver))
        )
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq', query_ns=ns.DISCO_INFO, iq_id=request['id'])

    # Check that Gabble's announcing the identity we think it should be.
    (identities, features, dataforms) = extract_disco_parts(event.stanza)

    # Check if the hash matches the announced capabilities
    assertEquals(compute_caps_hash(identities, features, dataforms), ver)

    return (event, features, dataforms)
def extract_disco_parts(stanza):
    identity_nodes = xpath.queryForNodes('/iq/query/identity', stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % (identity_node['type'], identity_node['name'])

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', stanza):
        features.append(feature['var'])

    # a quick and ugly data form extractor
    x_nodes = xpath.queryForNodes('/iq/query/x', stanza) or []
    dataforms = {}
    for form in x_nodes:
        name = None
        fields = {}
        for field in xpath.queryForNodes('/x/field', form):
            if field['var'] == 'FORM_TYPE':
                name = str(field.firstChildElement())
            else:
                values = [str(x) for x in xpath.queryForNodes('/field/value', field)]

                fields[field['var']] = values

        if name is not None:
            dataforms[name] = fields

    return ([identity], features, dataforms)
def send_presence(q, conn, stream, contact, caps, initial=True, show=None):
    h = conn.RequestHandles(cs.HT_CONTACT, [contact])[0]

    if initial:
        stream.send(make_presence(contact, status='hello'))

        q.expect_many(
            EventPattern('dbus-signal',
                         signal='PresenceUpdate',
                         args=[{
                             h: (0L, {
                                 u'available': {
                                     'message': 'hello'
                                 }
                             })
                         }]),
            EventPattern('dbus-signal',
                         signal='PresencesChanged',
                         args=[{
                             h: (2, u'available', 'hello')
                         }]))

        # no special capabilities
        assertEquals([(h, cs.CHANNEL_TYPE_TEXT, 3, 0)],
                     conn.Capabilities.GetCapabilities([h]))

    # send updated presence with caps info
    stream.send(make_presence(contact, show=show, status='hello', caps=caps))

    return h
def disco_caps(q, stream, presence):
    c_nodes = xpath.queryForNodes('/presence/c', presence.stanza)
    assert c_nodes is not None
    assertLength(1, c_nodes)
    hash = c_nodes[0].attributes['hash']
    ver = c_nodes[0].attributes['ver']
    node = c_nodes[0].attributes['node']
    assertEquals('sha-1', hash)

    # ask caps
    request = \
        elem_iq(stream, 'get', from_='[email protected]/resource')(
          elem(ns.DISCO_INFO, 'query', node=(node + '#' + ver))
        )
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq', query_ns=ns.DISCO_INFO, iq_id=request['id'])

    # Check that Gabble's announcing the identity we think it should be.
    (identities, features, dataforms) = extract_disco_parts(event.stanza)

    # Check if the hash matches the announced capabilities
    assertEquals(compute_caps_hash(identities, features, dataforms), ver)

    return (event, features, dataforms)
def extract_disco_parts(stanza):
    identity_nodes = xpath.queryForNodes('/iq/query/identity', stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % (identity_node['type'], identity_node['name'])

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', stanza):
        features.append(feature['var'])

    # a quick and ugly data form extractor
    x_nodes = xpath.queryForNodes('/iq/query/x', stanza) or []
    dataforms = {}
    for form in x_nodes:
        name = None
        fields = {}
        for field in xpath.queryForNodes('/x/field', form):
            if field['var'] == 'FORM_TYPE':
                name = str(field.firstChildElement())
            else:
                values = [
                    str(x) for x in xpath.queryForNodes('/field/value', field)
                ]

                fields[field['var']] = values

        if name is not None:
            dataforms[name] = fields

    return ([identity], features, dataforms)
def test(q, bus, conn, stream):
    call_async(q, conn.Future, 'EnsureSidecar', STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)
def test(q, bus, conn, stream):
    call_async(q, conn.Future, 'EnsureSidecar', STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)
def outgoing_reply(q, bus, conn, stream):
    path, stanza = setup_outgoing_tests(q, bus, conn, stream)

    # reply with nothing
    reply = make_result_iq(stream, stanza)
    stream.send(reply)

    e = q.expect('dbus-signal', signal='Replied', path=path)
    args, xml = e.args
    assertEquals({}, args)
    assertEquals('<?xml version="1.0" encoding="UTF-8"?>\n' \
                 + '<message xmlns="urn:ytstenut:message"/>\n', xml)
def outgoing_reply(q, bus, conn, stream):
    path, stanza = setup_outgoing_tests(q, bus, conn, stream)

    # reply with nothing
    reply = make_result_iq(stream, stanza)
    stream.send(reply)

    e = q.expect('dbus-signal', signal='Replied', path=path)
    args, xml = e.args
    assertEquals({}, args)
    assertEquals('<?xml version="1.0" encoding="UTF-8"?>\n' \
                 + '<message xmlns="urn:ytstenut:message"/>\n', xml)
    def bindIq(self, iq):
        resource = xpath.queryForString('/iq/bind/resource', iq)
        if self.resource is not None:
            assertEquals(self.resource, resource)
        else:
            assert resource is not None

        result = IQ(self.xmlstream, "result")
        result["id"] = iq["id"]
        bind = result.addElement((ns.NS_XMPP_BIND, 'bind'))
        self.bare_jid = '%s@localhost' % self.username
        self.full_jid = '%s/%s' % (self.bare_jid, resource)
        jid = bind.addElement('jid', content=self.full_jid)
        self.xmlstream.send(result)

        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
    def respondToSecondIq(self, iq):
        username = xpath.queryForNodes('/iq/query/username', iq)
        assert map(str, username) == [self.username]

        digest = xpath.queryForNodes('/iq/query/digest', iq)
        expect = hashlib.sha1(self.xmlstream.sid + self.password).hexdigest()
        assert map(str, digest) == [expect]

        resource = xpath.queryForNodes('/iq/query/resource', iq)
        assertLength(1, resource)
        if self.resource is not None:
            assertEquals(self.resource, str(resource[0]))

        self.bare_jid = '%s@localhost' % self.username
        self.full_jid = '%s/%s' % (self.bare_jid, resource)

        result = IQ(self.xmlstream, "result")
        result["id"] = iq["id"]
        self.xmlstream.send(result)
        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
Beispiel #12
0
def setup_outgoing_tests(q, bus, conn, stream, announce=True):
    handle, _, _ = setup_tests(q, bus, conn, stream, announce)

    # okay we got our contact, let's go
    request_props = {
        cs.CHANNEL_TYPE: ycs.CHANNEL_IFACE,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: handle,
        ycs.REQUEST_TYPE: ycs.REQUEST_TYPE_GET,
        ycs.REQUEST_ATTRIBUTES: {
            'hi': 'mom'
        },
        ycs.TARGET_SERVICE: 'the.target.service',
        ycs.INITIATOR_SERVICE: 'the.initiator.service'
    }

    call_async(q, conn.Requests, 'CreateChannel', request_props)

    e, _ = q.expect_many(EventPattern('dbus-return', method='CreateChannel'),
                         EventPattern('dbus-signal', signal='NewChannels'))
    path, props = e.value

    for k, v in request_props.items():
        assertEquals(v, props[k])

    # finally we have our channel
    chan = wrap_channel(bus, conn, path)

    # let's check we can't call Fail()/Reply()
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol': 'whut'}, '')
    q.expect('dbus-error', method='Reply')

    # okay enough, let's move on.
    call_async(q, chan, 'Request')

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='Request'))

    assertEquals('get', e.iq_type)
    assertEquals('message', e.query_name)
    assertEquals('urn:ytstenut:message', e.query_ns)

    # we shouldn't be able to call this again
    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')

    return path, e.stanza
def send_presence(q, conn, stream, contact, caps, initial=True, show=None):
    h = conn.RequestHandles(cs.HT_CONTACT, [contact])[0]

    if initial:
        stream.send(make_presence(contact, status='hello'))

        q.expect_many(
            EventPattern('dbus-signal', signal='PresenceUpdate',
                args=[{h:
                   (0L, {u'available': {'message': 'hello'}})}]),
            EventPattern('dbus-signal', signal='PresencesChanged',
                args=[{h:
                   (2, u'available', 'hello')}]))

        # no special capabilities
        assertEquals([(h, cs.CHANNEL_TYPE_TEXT, 3, 0)],
            conn.Capabilities.GetCapabilities([h]))

    # send updated presence with caps info
    stream.send(make_presence(contact, show=show, status='hello', caps=caps))

    return h
def setup_outgoing_tests(q, bus, conn, stream, announce=True):
    handle, _, _ = setup_tests(q, bus, conn, stream, announce)

    # okay we got our contact, let's go
    request_props = {
        cs.CHANNEL_TYPE: ycs.CHANNEL_IFACE,
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.TARGET_HANDLE: handle,
        ycs.REQUEST_TYPE: ycs.REQUEST_TYPE_GET,
        ycs.REQUEST_ATTRIBUTES: {'hi': 'mom'},
        ycs.TARGET_SERVICE: 'the.target.service',
        ycs.INITIATOR_SERVICE: 'the.initiator.service'
        }

    call_async(q, conn.Requests, 'CreateChannel', request_props)

    e, _ = q.expect_many(EventPattern('dbus-return', method='CreateChannel'),
                         EventPattern('dbus-signal', signal='NewChannels'))
    path, props = e.value

    for k, v in request_props.items():
        assertEquals(v, props[k])

    # finally we have our channel
    chan = wrap_channel(bus, conn, path)

    # let's check we can't call Fail()/Reply()
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol':'whut'}, '')
    q.expect('dbus-error', method='Reply')

    # okay enough, let's move on.
    call_async(q, chan, 'Request')

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='Request'))

    assertEquals('get', e.iq_type)
    assertEquals('message', e.query_name)
    assertEquals('urn:ytstenut:message', e.query_ns)

    # we shouldn't be able to call this again
    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')

    return path, e.stanza
Beispiel #15
0
def outgoing_fail(q, bus, conn, stream):
    path, stanza = setup_outgoing_tests(q, bus, conn, stream)

    # construct a nice error reply
    reply = IQ(None, 'error')
    reply['id'] = stanza['id']
    reply['from'] = stanza['to']
    error = reply.addElement('error')
    error['type'] = 'cancel'
    error['code'] = '409'
    error.addElement((ns.STANZA, 'conflict'))
    error.addElement((ycs.MESSAGE_NS, 'yodawg'))
    text = error.addElement((ns.STANZA, 'text'), content='imma let you finish')

    stream.send(reply)

    e = q.expect('dbus-signal', signal='Failed', path=path)
    error_type, stanza_error_name, yst_error_name, text = e.args
    assertEquals(ycs.ERROR_TYPE_CANCEL, error_type)
    assertEquals('conflict', stanza_error_name)
    assertEquals('yodawg', yst_error_name)
    assertEquals('imma let you finish', text)
def outgoing_fail(q, bus, conn, stream):
    path, stanza = setup_outgoing_tests(q, bus, conn, stream)

    # construct a nice error reply
    reply = IQ(None, 'error')
    reply['id'] = stanza['id']
    reply['from'] = stanza['to']
    error = reply.addElement('error')
    error['type'] = 'cancel'
    error['code'] = '409'
    error.addElement((ns.STANZA, 'conflict'))
    error.addElement((ycs.MESSAGE_NS, 'yodawg'))
    text = error.addElement((ns.STANZA, 'text'),
                            content='imma let you finish')

    stream.send(reply)

    e = q.expect('dbus-signal', signal='Failed', path=path)
    error_type, stanza_error_name, yst_error_name, text = e.args
    assertEquals(ycs.ERROR_TYPE_CANCEL, error_type)
    assertEquals('conflict', stanza_error_name)
    assertEquals('yodawg', yst_error_name)
    assertEquals('imma let you finish', text)
def setup_incoming_tests(q, bus, conn, stream):
    handle, bare_jid, full_jid = setup_tests(q, bus, conn, stream)

    self_handle = conn.GetSelfHandle()
    self_handle_name =  conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0]

    iq = IQ(None, 'get')
    iq['id'] = 'le-loldongs'
    iq['from'] = full_jid
    iq['to'] = self_handle_name
    msg = iq.addElement((ycs.MESSAGE_NS, 'message'))
    msg['from-service'] = 'the.from.service'
    msg['to-service'] = 'the.to.service'
    msg['owl-companions'] = 'the pussy cat'
    msg['destination'] = 'sea'
    msg['seacraft'] = 'beautiful pea green boat'

    lol = msg.addElement((None, 'lol'))
    lol['some'] = 'stuff'
    lol['to'] = 'fill'
    lol['the'] = 'time'
    lol.addElement((None, 'look-into-my-eyes'),
                   content='and tell me how boring writing these tests is')

    stream.send(iq)

    e = q.expect('dbus-signal', signal='NewChannels', predicate=lambda e:
                     e.args[0][0][1][cs.CHANNEL_TYPE] == ycs.CHANNEL_IFACE)
    path, props = e.args[0][0]

    assertEquals(handle, props[cs.INITIATOR_HANDLE])
    assertEquals(bare_jid, props[cs.INITIATOR_ID])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals(handle, props[cs.TARGET_HANDLE])
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    assertEquals(bare_jid, props[cs.TARGET_ID])

    assertEquals('the.from.service', props[ycs.INITIATOR_SERVICE])
    assertEquals('the.to.service', props[ycs.TARGET_SERVICE])
    assertEquals(ycs.REQUEST_TYPE_GET, props[ycs.REQUEST_TYPE])
    assertEquals({'destination': 'sea',
                  'owl-companions': 'the pussy cat',
                  'seacraft': 'beautiful pea green boat'},
                 props[ycs.REQUEST_ATTRIBUTES])

    assertEquals('<?xml version="1.0" encoding="UTF-8"?>\n' \
                     '<message seacraft="beautiful pea green boat" ' \
                     'from-service="the.from.service" destination="sea" ' \
                     'owl-companions="the pussy cat" to-service="the.to.service" ' \
                     'xmlns="urn:ytstenut:message">' \
                     '<lol to="fill" the="time" some="stuff">' \
                     '<look-into-my-eyes>and tell me how boring ' \
                     'writing these tests is</look-into-my-eyes>' \
                     '</lol></message>\n', props[ycs.REQUEST_BODY])

    # finally we have our channel
    chan = wrap_channel(bus, conn, path)

    # let's check we can't call Request()
    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')

    return chan, bare_jid, full_jid, self_handle_name
Beispiel #18
0
def check_pep_set(iq):
    pubsub = iq.children[0]
    publish = pubsub.children[0]
    item = publish.children[0]
    status_el = item.children[0]

    desc = None
    if status_el.children:
        desc = status_el.children[0]

    assertEquals('set', iq['type'])
    assertEquals(1, len(iq.children))

    assertEquals('pubsub', pubsub.name)
    assertEquals(ns.PUBSUB, pubsub.uri)
    assertEquals(1, len(pubsub.children))

    assertEquals('publish', publish.name)
    assertEquals(CAP_NAME, publish['node'])
    assertEquals(1, len(publish.children))

    assertEquals('item', item.name)
    assertEquals(1, len(item.children))

    assertEquals('status', status_el.name)

    if desc:
        assertEquals(1, len(status_el.children))

        assertEquals('description', desc.name)
        assertEquals(1, len(desc.children))

    return status_el, desc
Beispiel #19
0
def test(q, bus, conn, stream):
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/LikeLava"

    call_async(q, conn.Future, 'EnsureSidecar', ycs.STATUS_IFACE)
    conn.Connect()

    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])

    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)

    self_handle = conn.GetSelfHandle()
    self_handle_name =  conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0]

    caps = {'ver': '0.1', 'node': client}
    presence_and_disco(q, conn, stream, full_jid, True, client, caps,
                       features, identity, {}, True, None)

    # now update the caps
    conn.ContactCapabilities.UpdateCapabilities([
        ('well.gnome.name', [],
         ['com.meego.xpmn.ytstenut.Channel/uid/org.gnome.Banshee',
          'com.meego.xpmn.ytstenut.Channel/type/application',
          'com.meego.xpmn.ytstenut.Channel/name/en_GB/Banshee Media Player',
          'com.meego.xpmn.ytstenut.Channel/name/fr/Banshee Lecteur de Musique',
          'com.meego.xpmn.ytstenut.Channel/caps/urn:ytstenut:capabilities:yts-caps-audio',
          'com.meego.xpmn.ytstenut.Channel/caps/urn:ytstenut:data:jingle:rtp'])])


    _, e = q.expect_many(EventPattern('dbus-signal', signal='ServiceAdded'),
                         EventPattern('stream-presence'))

    e, _, _ = disco_caps(q, stream, e)

    iq = e.stanza
    query = iq.children[0]

    x = None
    for child in query.children:
        if child.name == 'x' and child.uri == ns.X_DATA:
            # we should only have one child
            assert x is None
            x = child
            # don't break here as we can waste time to make sure x
            # isn't assigned twice

    assert x is not None

    for field in x.children:
        if field['var'] == 'FORM_TYPE':
            assertEquals('hidden', field['type'])
            assertEquals('urn:ytstenut:capabilities#org.gnome.Banshee',
                         field.children[0].children[0])
        elif field['var'] == 'type':
            assertEquals('application', field.children[0].children[0])
        elif field['var'] == 'name':
            names = [a.children[0] for a in field.children]
            assertLength(2, names)
            assertContains('en_GB/Banshee Media Player', names)
            assertContains('fr/Banshee Lecteur de Musique', names)
        elif field['var'] == 'capabilities':
            caps = [a.children[0] for a in field.children]
            assertLength(2, caps)
            assertContains('urn:ytstenut:capabilities:yts-caps-audio', caps)
            assertContains('urn:ytstenut:data:jingle:rtp', caps)
        else:
            assert False

    # now add another service
    forbidden = [EventPattern('dbus-signal', signal='ServiceRemoved')]
    q.forbid_events(forbidden)

    conn.ContactCapabilities.UpdateCapabilities([
        ('another.nice.gname', [],
         ['com.meego.xpmn.ytstenut.Channel/uid/org.gnome.Eog',
          'com.meego.xpmn.ytstenut.Channel/type/application',
          'com.meego.xpmn.ytstenut.Channel/name/en_GB/Eye Of Gnome',
          'com.meego.xpmn.ytstenut.Channel/name/it/Occhio Di uno Gnomo',
          'com.meego.xpmn.ytstenut.Channel/caps/urn:ytstenut:capabilities:yts-picz'])])

    e = q.expect('dbus-signal', signal='ServiceAdded')

    sync_dbus(bus, q, conn)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({'test@localhost':
                      {'org.gnome.Banshee': ('application',
                                             {'en_GB': 'Banshee Media Player',
                                              'fr': 'Banshee Lecteur de Musique'},
                                             ['urn:ytstenut:capabilities:yts-caps-audio',
                                              'urn:ytstenut:data:jingle:rtp']),
                       'org.gnome.Eog': ('application',
                                         {'en_GB': 'Eye Of Gnome',
                                          'it': 'Occhio Di uno Gnomo'},
                                         ['urn:ytstenut:capabilities:yts-picz'])}},
                 discovered)

    q.unforbid_events(forbidden)

    forbidden = [EventPattern('dbus-signal', signal='ServiceRemoved',
                              args=[self_handle_name, 'org.gnome.Eog'])]
    q.forbid_events(forbidden)

    conn.ContactCapabilities.UpdateCapabilities([
            ('well.gnome.name', [], [])])

    e = q.expect('dbus-signal', signal='ServiceRemoved',
                 args=[self_handle_name, 'org.gnome.Banshee'])

    sync_dbus(bus, q, conn)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({'test@localhost':
                      {'org.gnome.Eog': ('application',
                                         {'en_GB': 'Eye Of Gnome',
                                          'it': 'Occhio Di uno Gnomo'},
                                         ['urn:ytstenut:capabilities:yts-picz'])}},
                 discovered)

    q.unforbid_events(forbidden)

    conn.ContactCapabilities.UpdateCapabilities([
            ('another.nice.gname', [], [])])

    e = q.expect('dbus-signal', signal='ServiceRemoved',
                 args=[self_handle_name, 'org.gnome.Eog'])

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)
def incoming_fail(q, bus, conn, stream):
    chan, bare_jid, full_jid, self_handle_name = \
        setup_incoming_tests(q, bus, conn, stream)

    call_async(q, chan, 'Fail',
               ycs.ERROR_TYPE_AUTH, 'auth', 'omgwtfbbq',
               'I most certainly dont feel like dancing')

    _, e = q.expect_many(EventPattern('dbus-return', method='Fail'),
                         EventPattern('stream-message'))

    iq = e.stanza
    assertEquals('le-loldongs', iq['id'])
    assertEquals('error', iq['type'])
    assertEquals(self_handle_name, iq['from'])
    assertEquals(full_jid, iq['to'])
    assertEquals(2, len(iq.children))

    def check_message(message):
        assertEquals('message', message.name)
        assertEquals(ycs.MESSAGE_NS, message.uri)
        assertEquals('beautiful pea green boat', message['seacraft'])
        assertEquals('sea', message['destination'])
        assertEquals('the pussy cat', message['owl-companions'])
        assertEquals('the.from.service', message['from-service'])
        assertEquals('the.to.service', message['to-service'])
        assertEquals(1, len(message.children))

        lol = message.children[0]

        assertEquals('lol', lol.name)
        assertEquals('fill', lol['to'])
        assertEquals('time', lol['the'])
        assertEquals('stuff', lol['some'])
        assertEquals(1, len(lol.children))

        look = lol.children[0]

        assertEquals('look-into-my-eyes', look.name)
        assertEquals(1, len(look.children))
        assertEquals('and tell me how boring writing these tests is', look.children[0])

    def check_error(error):
        assertEquals('error', error.name)
        assertEquals('auth', error['type'])
        assertEquals(3, len(error.children))

        for c in error.children:
            if c.name == 'auth':
                assertEquals(ns.STANZA, c.uri)
            elif c.name == 'omgwtfbbq':
                assertEquals(ycs.MESSAGE_NS, c.uri)
            elif c.name == 'text':
                assertEquals(ns.STANZA, c.uri)
                assertEquals(1, len(c.children))
                assertEquals('I most certainly dont feel like dancing',
                             c.children[0])
            else:
                raise

    for child in iq.children:
        if child.name == 'message':
            check_message(child)
        elif child.name == 'error':
            check_error(child)
        else:
            raise

    # check we can't call anything any more
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol':'whut'}, '')
    q.expect('dbus-error', method='Reply')

    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')
    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    assertEquals(client + '#' + caps['ver'], event.query['node'])

    return event.stanza

def send_disco_reply(stream, stanza, identities, features, dataforms={}):
    stream.send(
        make_caps_disco_reply(stream, stanza, identities, features, dataforms))

if __name__ == '__main__':
    # example from XEP-0115
    assertEquals('QgayPKawpkPSDYmwT/WM94uAlu0=',
        compute_caps_hash(['client/pc//Exodus 0.9.1'],
            ["http://jabber.org/protocol/disco#info",
             "http://jabber.org/protocol/disco#items",
             "http://jabber.org/protocol/muc",
             "http://jabber.org/protocol/caps"],
            {}))

    # another example from XEP-0115
    identities = [u'client/pc/en/Psi 0.11', u'client/pc/el/Ψ 0.11']
    features = [
        u'http://jabber.org/protocol/caps',
        u'http://jabber.org/protocol/disco#info',
        u'http://jabber.org/protocol/disco#items',
        u'http://jabber.org/protocol/muc',
        ]
    dataforms = {
        u'urn:xmpp:dataforms:softwareinfo':
            { u'ip_version': [u'ipv4', u'ipv6'],
Beispiel #22
0
def incoming_reply(q, bus, conn, stream):
    chan, bare_jid, full_jid, self_handle_name = \
        setup_incoming_tests(q, bus, conn, stream)

    moar = Element((ycs.MESSAGE_NS, 'message'))
    moar['ninety-nine-problems'] = 'but a sauvignon blanc aint one'
    moar['also'] = 'my mum said hi'
    trollface = moar.addElement('trollface', content='problem?')

    call_async(
        q, chan, 'Reply', {
            'ninety-nine-problems': 'but a sauvignon blanc aint one',
            'also': 'my mum said hi'
        }, moar.toXml())

    _, e = q.expect_many(EventPattern('dbus-return', method='Reply'),
                         EventPattern('stream-message'))

    iq = e.stanza
    assertEquals('le-loldongs', iq['id'])
    assertEquals('result', iq['type'])
    assertEquals(self_handle_name, iq['from'])
    assertEquals(full_jid, iq['to'])
    assertEquals(1, len(iq.children))

    message = iq.children[0]

    assertEquals('message', message.name)
    assertEquals(ycs.MESSAGE_NS, message.uri)
    assertEquals('my mum said hi', message['also'])
    assertEquals('but a sauvignon blanc aint one',
                 message['ninety-nine-problems'])
    assertEquals('the.from.service', message['to-service'])
    assertEquals('the.to.service', message['from-service'])
    assertEquals(1, len(message.children))

    trollface = message.children[0]

    assertEquals('trollface', trollface.name)
    assertEquals(1, len(trollface.children))

    assertEquals('problem?', trollface.children[0])

    # check we can't call anything any more
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol': 'whut'}, '')
    q.expect('dbus-error', method='Reply')

    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')
Beispiel #23
0
    def check_message(message):
        assertEquals('message', message.name)
        assertEquals(ycs.MESSAGE_NS, message.uri)
        assertEquals('beautiful pea green boat', message['seacraft'])
        assertEquals('sea', message['destination'])
        assertEquals('the pussy cat', message['owl-companions'])
        assertEquals('the.from.service', message['from-service'])
        assertEquals('the.to.service', message['to-service'])
        assertEquals(1, len(message.children))

        lol = message.children[0]

        assertEquals('lol', lol.name)
        assertEquals('fill', lol['to'])
        assertEquals('time', lol['the'])
        assertEquals('stuff', lol['some'])
        assertEquals(1, len(lol.children))

        look = lol.children[0]

        assertEquals('look-into-my-eyes', look.name)
        assertEquals(1, len(look.children))
        assertEquals('and tell me how boring writing these tests is',
                     look.children[0])
    def check_message(message):
        assertEquals('message', message.name)
        assertEquals(ycs.MESSAGE_NS, message.uri)
        assertEquals('beautiful pea green boat', message['seacraft'])
        assertEquals('sea', message['destination'])
        assertEquals('the pussy cat', message['owl-companions'])
        assertEquals('the.from.service', message['from-service'])
        assertEquals('the.to.service', message['to-service'])
        assertEquals(1, len(message.children))

        lol = message.children[0]

        assertEquals('lol', lol.name)
        assertEquals('fill', lol['to'])
        assertEquals('time', lol['the'])
        assertEquals('stuff', lol['some'])
        assertEquals(1, len(lol.children))

        look = lol.children[0]

        assertEquals('look-into-my-eyes', look.name)
        assertEquals(1, len(look.children))
        assertEquals('and tell me how boring writing these tests is', look.children[0])
def expect_disco(q, contact, client, caps):
    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    assertEquals(client + '#' + caps['ver'], event.query['node'])

    return event.stanza
    def check_error(error):
        assertEquals('error', error.name)
        assertEquals('auth', error['type'])
        assertEquals(3, len(error.children))

        for c in error.children:
            if c.name == 'auth':
                assertEquals(ns.STANZA, c.uri)
            elif c.name == 'omgwtfbbq':
                assertEquals(ycs.MESSAGE_NS, c.uri)
            elif c.name == 'text':
                assertEquals(ns.STANZA, c.uri)
                assertEquals(1, len(c.children))
                assertEquals('I most certainly dont feel like dancing',
                             c.children[0])
            else:
                raise
def test(q, bus, conn, stream):
    call_async(q, conn.Future, 'EnsureSidecar', ycs.STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)

    # announce a contact with the right caps
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/NeeNawNeeNawIAmAnAmbulance"

    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [bare_jid])[0]

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, banshee, True, None)

    # this will be fired as text channel caps will be fired
    _, e = q.expect_many(EventPattern('dbus-signal', signal='ContactCapabilitiesChanged',
                                      predicate=lambda e: contact_handle in e.args[0]),
                         EventPattern('dbus-signal', signal='ServiceAdded'))

    contact_id, service_name, details = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals({'en_GB': 'Banshee Media Player',
                  'fr': 'Banshee Lecteur de Musique'}, name_map)
    assertSameSets(['urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'], caps)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp'])},
                }, discovered)

    # add evince
    tmp = banshee.copy()
    tmp.update(evince)
    client_caps['ver'] = compute_caps_hash(identity, features, tmp)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, tmp, False)

    e = q.expect('dbus-signal', signal='ServiceAdded')

    contact_id, service_name, details = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals({'en_GB': 'Evince Picture Viewer',
                  'fr': 'Evince uh, ow do you say'}, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp']),
                  'org.gnome.Evince':
                      ('application',
                       {'en_GB': 'Evince Picture Viewer',
                        'fr': 'Evince uh, ow do you say'},
                       ['urn:ytstenut:capabilities:pics'])}
                }, discovered)

    # remove evince
    forbidden = [EventPattern('dbus-signal', signal='stream-iq')]
    q.forbid_events(forbidden)

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    e = q.expect('dbus-signal', signal='ServiceRemoved')

    contact_id, service_name = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp'])},
                }, discovered)

    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # now just evince
    client_caps['ver'] = compute_caps_hash(identity, features, evince)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, evince, False)

    sa, sr = q.expect_many(EventPattern('dbus-signal', signal='ServiceAdded'),
                           EventPattern('dbus-signal', signal='ServiceRemoved'))

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals({'en_GB': 'Evince Picture Viewer',
                  'fr': 'Evince uh, ow do you say'}, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    contact_id, service_name = sr.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                  'org.gnome.Evince':
                      ('application',
                       {'en_GB': 'Evince Picture Viewer',
                        'fr': 'Evince uh, ow do you say'},
                       ['urn:ytstenut:capabilities:pics'])}
                }, discovered)

    # just banshee again
    forbidden = [EventPattern('dbus-signal', signal='stream-iq')]
    q.forbid_events(forbidden)

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    sr, sa = q.expect_many(EventPattern('dbus-signal', signal='ServiceRemoved'),
                           EventPattern('dbus-signal', signal='ServiceAdded'))

    contact_id, service_name = sr.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals({'en_GB': 'Banshee Media Player',
                  'fr': 'Banshee Lecteur de Musique'}, name_map)
    assertSameSets(['urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'], caps)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp'])}
                }, discovered)

    sync_stream(q, stream)

    # both again
    client_caps['ver'] = compute_caps_hash(identity, features, tmp)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    sa = q.expect('dbus-signal', signal='ServiceAdded')

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals({'en_GB': 'Evince Picture Viewer',
                  'fr': 'Evince uh, ow do you say'}, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp']),
                  'org.gnome.Evince':
                      ('application',
                       {'en_GB': 'Evince Picture Viewer',
                        'fr': 'Evince uh, ow do you say'},
                       ['urn:ytstenut:capabilities:pics'])}
                }, discovered)

    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # and finally, nothing
    client_caps['ver'] = compute_caps_hash(identity, features, {})
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, {}, False)

    q.expect_many(EventPattern('dbus-signal', signal='ServiceRemoved',
                               args=[bare_jid, 'org.gnome.Banshee']),
                  EventPattern('dbus-signal', signal='ServiceRemoved',
                               args=[bare_jid, 'org.gnome.Evince']))

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)
Beispiel #28
0
def test(q, bus, conn, stream):
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/NeeNawNeeNawIAmAnAmbulance"

    # we don't want these two signalled, ever.
    forbidden = [EventPattern('dbus-signal', signal='ServiceAdded'),
                 EventPattern('dbus-signal', signal='ServiceRemoved')]
    q.forbid_events(forbidden)

    conn.Connect()

    _, e = q.expect_many(EventPattern('dbus-signal', signal='StatusChanged',
                                      args=[0, 1]),
                         EventPattern('stream-iq', query_ns=ns.ROSTER,
                                      iq_type='get', query_name='query'))

    e.stanza['type'] = 'result'

    item = e.query.addElement('item')
    item['jid'] = bare_jid
    item['subscription'] = 'both'

    stream.send(e.stanza)

    q.expect('dbus-signal', signal='ContactListStateChanged',
            args=[cs.CONTACT_LIST_STATE_SUCCESS])

    # announce a contact with the right caps
    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [bare_jid])[0]

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, banshee, True, None)

    # this will be fired as text channel caps will be fired
    q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
             predicate=lambda e: contact_handle in e.args[0])

    # add evince
    tmp = banshee.copy()
    tmp.update(evince)
    client_caps['ver'] = compute_caps_hash(identity, features, tmp)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, tmp, False)

    sync_stream(q, stream)

    # now finally ensure the sidecar
    path, props = conn.Future.EnsureSidecar(ycs.STATUS_IFACE)
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({bare_jid: {
                'org.gnome.Banshee':
                    ('application',
                     {'en_GB': 'Banshee Media Player',
                      'fr': 'Banshee Lecteur de Musique'},
                     ['urn:ytstenut:capabilities:yts-caps-audio',
                      'urn:ytstenut:data:jingle:rtp']),
                  'org.gnome.Evince':
                      ('application',
                       {'en_GB': 'Evince Picture Viewer',
                        'fr': 'Evince uh, ow do you say'},
                       ['urn:ytstenut:capabilities:pics'])}
                }, discovered)
def expect_disco(q, contact, client, caps):
    # Gabble looks up our capabilities
    event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO)
    assertEquals(client + '#' + caps['ver'], event.query['node'])

    return event.stanza
Beispiel #30
0
def test(q, bus, conn, stream):
    # we won't be using any data forms, so these two shouldn't ever be
    # fired.
    q.forbid_events([
        EventPattern('dbus-signal', signal='ServiceAdded'),
        EventPattern('dbus-signal', signal='ServiceRemoved')
    ])

    call_async(q, conn.Future, 'EnsureSidecar', ycs.STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    # bad capability argument
    call_async(q, status, 'AdvertiseStatus', '', 'service.name', '')
    q.expect('dbus-error', method='AdvertiseStatus')

    # bad service name
    call_async(q, status, 'AdvertiseStatus', CAP_NAME, '', '')
    q.expect('dbus-error', method='AdvertiseStatus')

    # we can't test that the message type="headline" stanza is
    # actually received because it's thrown into the loopback stream
    # immediately.

    # announce a contact with the right caps
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/BIGGESTRESOURCEEVAAAAHHH"

    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [bare_jid])[0]

    presence_and_disco(q, conn, stream, full_jid, True, client, caps, features,
                       identity, {}, True, None)

    # this will be fired as text channel caps will be fired
    q.expect('dbus-signal',
             signal='ContactCapabilitiesChanged',
             predicate=lambda e: contact_handle in e.args[0])

    # okay now we know about the contact's caps, we can go ahead

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)

    el = Element(('urn:ytstenut:status', 'status'))
    el['activity'] = 'messing-with-your-stuff'
    desc = el.addElement('ytstenut:description',
                         content='Yeah sorry about that')
    desc['xml:lang'] = 'en-GB'

    call_async(q, status, 'AdvertiseStatus', CAP_NAME, 'ants.in.their.pants',
               el.toXml())

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('messing-with-your-stuff', status_el['activity'])
    assertEquals('ants.in.their.pants', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assertEquals('Yeah sorry about that', desc.children[0])

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal',
                   signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('ants.in.their.pants', service_name)
    assertNotEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {'test@localhost': {
            CAP_NAME: {
                'ants.in.their.pants': status_str
            }
        }}, discovered)

    # set another
    el = Element(('urn:ytstenut:status', 'status'))
    el['activity'] = 'rofling'
    desc = el.addElement('ytstenut:description', content='U MAD?')
    desc['xml:lang'] = 'en-GB'

    call_async(q, status, 'AdvertiseStatus', CAP_NAME, 'bananaman.on.holiday',
               el.toXml())

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('rofling', status_el['activity'])
    assertEquals('bananaman.on.holiday', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assertEquals('U MAD?', desc.children[0])

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal',
                   signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, bananaman_status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('bananaman.on.holiday', service_name)
    assertNotEquals('', bananaman_status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            'test@localhost': {
                CAP_NAME: {
                    'ants.in.their.pants': status_str,
                    'bananaman.on.holiday': bananaman_status_str
                }
            }
        }, discovered)

    # unset the status from one service
    call_async(q, status, 'AdvertiseStatus', CAP_NAME, 'ants.in.their.pants',
               '')

    e, _, = q.expect_many(
        EventPattern('stream-iq'),
        EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('ants.in.their.pants', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assert 'activity' not in status_el.attributes
    assertEquals([], status_el.children)

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal',
                   signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('ants.in.their.pants', service_name)
    assertEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            'test@localhost': {
                CAP_NAME: {
                    'bananaman.on.holiday': bananaman_status_str
                }
            }
        }, discovered)

    # unset the status from the other service
    call_async(q, status, 'AdvertiseStatus', CAP_NAME, 'bananaman.on.holiday',
               '')

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    # check message
    status_el, desc = check_pep_set(e.stanza)
    assertEquals('bananaman.on.holiday', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assert 'activity' not in status_el.attributes
    assertEquals([], status_el.children)

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal',
                   signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('bananaman.on.holiday', service_name)
    assertEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)
Beispiel #31
0
def setup_incoming_tests(q, bus, conn, stream):
    handle, bare_jid, full_jid = setup_tests(q, bus, conn, stream)

    self_handle = conn.GetSelfHandle()
    self_handle_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0]

    iq = IQ(None, 'get')
    iq['id'] = 'le-loldongs'
    iq['from'] = full_jid
    iq['to'] = self_handle_name
    msg = iq.addElement((ycs.MESSAGE_NS, 'message'))
    msg['from-service'] = 'the.from.service'
    msg['to-service'] = 'the.to.service'
    msg['owl-companions'] = 'the pussy cat'
    msg['destination'] = 'sea'
    msg['seacraft'] = 'beautiful pea green boat'

    lol = msg.addElement((None, 'lol'))
    lol['some'] = 'stuff'
    lol['to'] = 'fill'
    lol['the'] = 'time'
    lol.addElement((None, 'look-into-my-eyes'),
                   content='and tell me how boring writing these tests is')

    stream.send(iq)

    e = q.expect('dbus-signal',
                 signal='NewChannels',
                 predicate=lambda e: e.args[0][0][1][cs.CHANNEL_TYPE] == ycs.
                 CHANNEL_IFACE)
    path, props = e.args[0][0]

    assertEquals(handle, props[cs.INITIATOR_HANDLE])
    assertEquals(bare_jid, props[cs.INITIATOR_ID])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals(handle, props[cs.TARGET_HANDLE])
    assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE])
    assertEquals(bare_jid, props[cs.TARGET_ID])

    assertEquals('the.from.service', props[ycs.INITIATOR_SERVICE])
    assertEquals('the.to.service', props[ycs.TARGET_SERVICE])
    assertEquals(ycs.REQUEST_TYPE_GET, props[ycs.REQUEST_TYPE])
    assertEquals(
        {
            'destination': 'sea',
            'owl-companions': 'the pussy cat',
            'seacraft': 'beautiful pea green boat'
        }, props[ycs.REQUEST_ATTRIBUTES])

    assertEquals('<?xml version="1.0" encoding="UTF-8"?>\n' \
                     '<message seacraft="beautiful pea green boat" ' \
                     'from-service="the.from.service" destination="sea" ' \
                     'owl-companions="the pussy cat" to-service="the.to.service" ' \
                     'xmlns="urn:ytstenut:message">' \
                     '<lol to="fill" the="time" some="stuff">' \
                     '<look-into-my-eyes>and tell me how boring ' \
                     'writing these tests is</look-into-my-eyes>' \
                     '</lol></message>\n', props[ycs.REQUEST_BODY])

    # finally we have our channel
    chan = wrap_channel(bus, conn, path)

    # let's check we can't call Request()
    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')

    return chan, bare_jid, full_jid, self_handle_name
def check_pep_set(iq):
    pubsub = iq.children[0]
    publish = pubsub.children[0]
    item = publish.children[0]
    status_el = item.children[0]

    desc = None
    if status_el.children:
        desc = status_el.children[0]

    assertEquals('set', iq['type'])
    assertEquals(1, len(iq.children))

    assertEquals('pubsub', pubsub.name)
    assertEquals(ns.PUBSUB, pubsub.uri)
    assertEquals(1, len(pubsub.children))

    assertEquals('publish', publish.name)
    assertEquals(CAP_NAME, publish['node'])
    assertEquals(1, len(publish.children))

    assertEquals('item', item.name)
    assertEquals(1, len(item.children))

    assertEquals('status', status_el.name)

    if desc:
        assertEquals(1, len(status_el.children))

        assertEquals('description', desc.name)
        assertEquals(1, len(desc.children))

    return status_el, desc
Beispiel #33
0
def incoming_fail(q, bus, conn, stream):
    chan, bare_jid, full_jid, self_handle_name = \
        setup_incoming_tests(q, bus, conn, stream)

    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_AUTH, 'auth', 'omgwtfbbq',
               'I most certainly dont feel like dancing')

    _, e = q.expect_many(EventPattern('dbus-return', method='Fail'),
                         EventPattern('stream-message'))

    iq = e.stanza
    assertEquals('le-loldongs', iq['id'])
    assertEquals('error', iq['type'])
    assertEquals(self_handle_name, iq['from'])
    assertEquals(full_jid, iq['to'])
    assertEquals(2, len(iq.children))

    def check_message(message):
        assertEquals('message', message.name)
        assertEquals(ycs.MESSAGE_NS, message.uri)
        assertEquals('beautiful pea green boat', message['seacraft'])
        assertEquals('sea', message['destination'])
        assertEquals('the pussy cat', message['owl-companions'])
        assertEquals('the.from.service', message['from-service'])
        assertEquals('the.to.service', message['to-service'])
        assertEquals(1, len(message.children))

        lol = message.children[0]

        assertEquals('lol', lol.name)
        assertEquals('fill', lol['to'])
        assertEquals('time', lol['the'])
        assertEquals('stuff', lol['some'])
        assertEquals(1, len(lol.children))

        look = lol.children[0]

        assertEquals('look-into-my-eyes', look.name)
        assertEquals(1, len(look.children))
        assertEquals('and tell me how boring writing these tests is',
                     look.children[0])

    def check_error(error):
        assertEquals('error', error.name)
        assertEquals('auth', error['type'])
        assertEquals(3, len(error.children))

        for c in error.children:
            if c.name == 'auth':
                assertEquals(ns.STANZA, c.uri)
            elif c.name == 'omgwtfbbq':
                assertEquals(ycs.MESSAGE_NS, c.uri)
            elif c.name == 'text':
                assertEquals(ns.STANZA, c.uri)
                assertEquals(1, len(c.children))
                assertEquals('I most certainly dont feel like dancing',
                             c.children[0])
            else:
                raise

    for child in iq.children:
        if child.name == 'message':
            check_message(child)
        elif child.name == 'error':
            check_error(child)
        else:
            raise

    # check we can't call anything any more
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol': 'whut'}, '')
    q.expect('dbus-error', method='Reply')

    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')
def test(q, bus, conn, stream):
    # we won't be using any data forms, so these two shouldn't ever be
    # fired.
    q.forbid_events([EventPattern('dbus-signal', signal='ServiceAdded'),
                     EventPattern('dbus-signal', signal='ServiceRemoved')])

    call_async(q, conn.Future, 'EnsureSidecar', ycs.STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    # bad capability argument
    call_async(q, status, 'AdvertiseStatus', '', 'service.name', '')
    q.expect('dbus-error', method='AdvertiseStatus')

    # bad service name
    call_async(q, status, 'AdvertiseStatus', CAP_NAME, '', '')
    q.expect('dbus-error', method='AdvertiseStatus')

    # we can't test that the message type="headline" stanza is
    # actually received because it's thrown into the loopback stream
    # immediately.

    # announce a contact with the right caps
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/BIGGESTRESOURCEEVAAAAHHH"

    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [bare_jid])[0]

    presence_and_disco(q, conn, stream, full_jid, True, client, caps,
                       features, identity, {}, True, None)

    # this will be fired as text channel caps will be fired
    q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
             predicate=lambda e: contact_handle in e.args[0])

    # okay now we know about the contact's caps, we can go ahead

    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)

    el = Element(('urn:ytstenut:status', 'status'))
    el['activity'] = 'messing-with-your-stuff'
    desc = el.addElement('ytstenut:description', content='Yeah sorry about that')
    desc['xml:lang'] = 'en-GB'

    call_async(q, status, 'AdvertiseStatus', CAP_NAME,
               'ants.in.their.pants', el.toXml())

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('messing-with-your-stuff', status_el['activity'])
    assertEquals('ants.in.their.pants', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assertEquals('Yeah sorry about that', desc.children[0])

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal', signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('ants.in.their.pants', service_name)
    assertNotEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({'test@localhost': {CAP_NAME: {'ants.in.their.pants': status_str}}},
                 discovered)

    # set another
    el = Element(('urn:ytstenut:status', 'status'))
    el['activity'] = 'rofling'
    desc = el.addElement('ytstenut:description', content='U MAD?')
    desc['xml:lang'] = 'en-GB'

    call_async(q, status, 'AdvertiseStatus', CAP_NAME,
               'bananaman.on.holiday', el.toXml())

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('rofling', status_el['activity'])
    assertEquals('bananaman.on.holiday', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assertEquals('U MAD?', desc.children[0])

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal', signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, bananaman_status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('bananaman.on.holiday', service_name)
    assertNotEquals('', bananaman_status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({'test@localhost': {CAP_NAME: {
                    'ants.in.their.pants': status_str,
                    'bananaman.on.holiday': bananaman_status_str}}},
                 discovered)

    # unset the status from one service
    call_async(q, status, 'AdvertiseStatus', CAP_NAME,
               'ants.in.their.pants', '')

    e, _, = q.expect_many(EventPattern('stream-iq'),
                          EventPattern('dbus-return', method='AdvertiseStatus'))

    status_el, desc = check_pep_set(e.stanza)
    assertEquals('ants.in.their.pants', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assert 'activity' not in status_el.attributes
    assertEquals([], status_el.children)

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal', signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('ants.in.their.pants', service_name)
    assertEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({'test@localhost': {CAP_NAME: {
                    'bananaman.on.holiday': bananaman_status_str}}},
                 discovered)

    # unset the status from the other service
    call_async(q, status, 'AdvertiseStatus', CAP_NAME,
               'bananaman.on.holiday', '')

    e, _ = q.expect_many(EventPattern('stream-iq'),
                         EventPattern('dbus-return', method='AdvertiseStatus'))

    # check message
    status_el, desc = check_pep_set(e.stanza)
    assertEquals('bananaman.on.holiday', status_el['from-service'])
    assertEquals(CAP_NAME, status_el['capability'])
    assert 'activity' not in status_el.attributes
    assertEquals([], status_el.children)

    acknowledge_iq(stream, e.stanza)
    send_back_pep_event(stream, status_el)

    sig = q.expect('dbus-signal', signal='StatusChanged',
                   interface=ycs.STATUS_IFACE)

    # check signal
    contact_id, capability, service_name, status_str = sig.args
    assertEquals(CAP_NAME, capability)
    assertEquals('bananaman.on.holiday', service_name)
    assertEquals('', status_str)

    # check property
    discovered = status.Get(ycs.STATUS_IFACE, 'DiscoveredStatuses',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)
Beispiel #35
0
    def check_error(error):
        assertEquals('error', error.name)
        assertEquals('auth', error['type'])
        assertEquals(3, len(error.children))

        for c in error.children:
            if c.name == 'auth':
                assertEquals(ns.STANZA, c.uri)
            elif c.name == 'omgwtfbbq':
                assertEquals(ycs.MESSAGE_NS, c.uri)
            elif c.name == 'text':
                assertEquals(ns.STANZA, c.uri)
                assertEquals(1, len(c.children))
                assertEquals('I most certainly dont feel like dancing',
                             c.children[0])
            else:
                raise
def incoming_reply(q, bus, conn, stream):
    chan, bare_jid, full_jid, self_handle_name = \
        setup_incoming_tests(q, bus, conn, stream)

    moar = Element((ycs.MESSAGE_NS, 'message'))
    moar['ninety-nine-problems'] = 'but a sauvignon blanc aint one'
    moar['also'] = 'my mum said hi'
    trollface = moar.addElement('trollface', content='problem?')

    call_async(q, chan, 'Reply',
               {'ninety-nine-problems': 'but a sauvignon blanc aint one',
                'also': 'my mum said hi'},
               moar.toXml())

    _, e = q.expect_many(EventPattern('dbus-return', method='Reply'),
                         EventPattern('stream-message'))

    iq = e.stanza
    assertEquals('le-loldongs', iq['id'])
    assertEquals('result', iq['type'])
    assertEquals(self_handle_name, iq['from'])
    assertEquals(full_jid, iq['to'])
    assertEquals(1, len(iq.children))

    message = iq.children[0]

    assertEquals('message', message.name)
    assertEquals(ycs.MESSAGE_NS, message.uri)
    assertEquals('my mum said hi', message['also'])
    assertEquals('but a sauvignon blanc aint one', message['ninety-nine-problems'])
    assertEquals('the.from.service', message['to-service'])
    assertEquals('the.to.service', message['from-service'])
    assertEquals(1, len(message.children))

    trollface = message.children[0]

    assertEquals('trollface', trollface.name)
    assertEquals(1, len(trollface.children))

    assertEquals('problem?', trollface.children[0])

    # check we can't call anything any more
    call_async(q, chan, 'Fail', ycs.ERROR_TYPE_CANCEL, 'lol', 'whut', 'pear')
    q.expect('dbus-error', method='Fail')

    call_async(q, chan, 'Reply', {'lol':'whut'}, '')
    q.expect('dbus-error', method='Reply')

    call_async(q, chan, 'Request')
    q.expect('dbus-error', method='Request')
Beispiel #37
0
def test(q, bus, conn, stream):
    call_async(q, conn.Future, 'EnsureSidecar', ycs.STATUS_IFACE)

    conn.Connect()

    # Now we're connected, the call we made earlier should return.
    e = q.expect('dbus-return', method='EnsureSidecar')
    path, props = e.value
    assertEquals({}, props)

    status = ProxyWrapper(bus.get_object(conn.bus_name, path),
                          ycs.STATUS_IFACE, {})

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)

    # announce a contact with the right caps
    bare_jid = "*****@*****.**"
    full_jid = bare_jid + "/NeeNawNeeNawIAmAnAmbulance"

    contact_handle = conn.RequestHandles(cs.HT_CONTACT, [bare_jid])[0]

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, banshee, True, None)

    # this will be fired as text channel caps will be fired
    _, e = q.expect_many(
        EventPattern('dbus-signal',
                     signal='ContactCapabilitiesChanged',
                     predicate=lambda e: contact_handle in e.args[0]),
        EventPattern('dbus-signal', signal='ServiceAdded'))

    contact_id, service_name, details = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals(
        {
            'en_GB': 'Banshee Media Player',
            'fr': 'Banshee Lecteur de Musique'
        }, name_map)
    assertSameSets([
        'urn:ytstenut:capabilities:yts-caps-audio',
        'urn:ytstenut:data:jingle:rtp'
    ], caps)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Banshee': ('application', {
                    'en_GB': 'Banshee Media Player',
                    'fr': 'Banshee Lecteur de Musique'
                }, [
                    'urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'
                ])
            },
        }, discovered)

    # add evince
    tmp = banshee.copy()
    tmp.update(evince)
    client_caps['ver'] = compute_caps_hash(identity, features, tmp)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, tmp, False)

    e = q.expect('dbus-signal', signal='ServiceAdded')

    contact_id, service_name, details = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals(
        {
            'en_GB': 'Evince Picture Viewer',
            'fr': 'Evince uh, ow do you say'
        }, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Banshee': ('application', {
                    'en_GB': 'Banshee Media Player',
                    'fr': 'Banshee Lecteur de Musique'
                }, [
                    'urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'
                ]),
                'org.gnome.Evince': ('application', {
                    'en_GB': 'Evince Picture Viewer',
                    'fr': 'Evince uh, ow do you say'
                }, ['urn:ytstenut:capabilities:pics'])
            }
        }, discovered)

    # remove evince
    forbidden = [EventPattern('dbus-signal', signal='stream-iq')]
    q.forbid_events(forbidden)

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    e = q.expect('dbus-signal', signal='ServiceRemoved')

    contact_id, service_name = e.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Banshee': ('application', {
                    'en_GB': 'Banshee Media Player',
                    'fr': 'Banshee Lecteur de Musique'
                }, [
                    'urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'
                ])
            },
        }, discovered)

    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # now just evince
    client_caps['ver'] = compute_caps_hash(identity, features, evince)
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, evince, False)

    sa, sr = q.expect_many(
        EventPattern('dbus-signal', signal='ServiceAdded'),
        EventPattern('dbus-signal', signal='ServiceRemoved'))

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals(
        {
            'en_GB': 'Evince Picture Viewer',
            'fr': 'Evince uh, ow do you say'
        }, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    contact_id, service_name = sr.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Evince': ('application', {
                    'en_GB': 'Evince Picture Viewer',
                    'fr': 'Evince uh, ow do you say'
                }, ['urn:ytstenut:capabilities:pics'])
            }
        }, discovered)

    # just banshee again
    forbidden = [EventPattern('dbus-signal', signal='stream-iq')]
    q.forbid_events(forbidden)

    client_caps['ver'] = compute_caps_hash(identity, features, banshee)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    sr, sa = q.expect_many(
        EventPattern('dbus-signal', signal='ServiceRemoved'),
        EventPattern('dbus-signal', signal='ServiceAdded'))

    contact_id, service_name = sr.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Banshee', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals(
        {
            'en_GB': 'Banshee Media Player',
            'fr': 'Banshee Lecteur de Musique'
        }, name_map)
    assertSameSets([
        'urn:ytstenut:capabilities:yts-caps-audio',
        'urn:ytstenut:data:jingle:rtp'
    ], caps)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Banshee': ('application', {
                    'en_GB': 'Banshee Media Player',
                    'fr': 'Banshee Lecteur de Musique'
                }, [
                    'urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'
                ])
            }
        }, discovered)

    sync_stream(q, stream)

    # both again
    client_caps['ver'] = compute_caps_hash(identity, features, tmp)
    send_presence(q, conn, stream, full_jid, client_caps, initial=False)

    sa = q.expect('dbus-signal', signal='ServiceAdded')

    contact_id, service_name, details = sa.args
    assertEquals(bare_jid, contact_id)
    assertEquals('org.gnome.Evince', service_name)

    type, name_map, caps = details
    assertEquals('application', type)
    assertEquals(
        {
            'en_GB': 'Evince Picture Viewer',
            'fr': 'Evince uh, ow do you say'
        }, name_map)
    assertSameSets(['urn:ytstenut:capabilities:pics'], caps)

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(
        {
            bare_jid: {
                'org.gnome.Banshee': ('application', {
                    'en_GB': 'Banshee Media Player',
                    'fr': 'Banshee Lecteur de Musique'
                }, [
                    'urn:ytstenut:capabilities:yts-caps-audio',
                    'urn:ytstenut:data:jingle:rtp'
                ]),
                'org.gnome.Evince': ('application', {
                    'en_GB': 'Evince Picture Viewer',
                    'fr': 'Evince uh, ow do you say'
                }, ['urn:ytstenut:capabilities:pics'])
            }
        }, discovered)

    sync_stream(q, stream)

    q.unforbid_events(forbidden)

    # and finally, nothing
    client_caps['ver'] = compute_caps_hash(identity, features, {})
    presence_and_disco(q, conn, stream, full_jid, True, client, client_caps,
                       features, identity, {}, False)

    q.expect_many(
        EventPattern('dbus-signal',
                     signal='ServiceRemoved',
                     args=[bare_jid, 'org.gnome.Banshee']),
        EventPattern('dbus-signal',
                     signal='ServiceRemoved',
                     args=[bare_jid, 'org.gnome.Evince']))

    discovered = status.Get(ycs.STATUS_IFACE,
                            'DiscoveredServices',
                            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals({}, discovered)
    assertEquals(client + '#' + caps['ver'], event.query['node'])

    return event.stanza


def send_disco_reply(stream, stanza, identities, features, dataforms={}):
    stream.send(
        make_caps_disco_reply(stream, stanza, identities, features, dataforms))


if __name__ == '__main__':
    # example from XEP-0115
    assertEquals(
        'QgayPKawpkPSDYmwT/WM94uAlu0=',
        compute_caps_hash(['client/pc//Exodus 0.9.1'], [
            "http://jabber.org/protocol/disco#info",
            "http://jabber.org/protocol/disco#items",
            "http://jabber.org/protocol/muc", "http://jabber.org/protocol/caps"
        ], {}))

    # another example from XEP-0115
    identities = [u'client/pc/en/Psi 0.11', u'client/pc/el/Ψ 0.11']
    features = [
        u'http://jabber.org/protocol/caps',
        u'http://jabber.org/protocol/disco#info',
        u'http://jabber.org/protocol/disco#items',
        u'http://jabber.org/protocol/muc',
    ]
    dataforms = {
        u'urn:xmpp:dataforms:softwareinfo': {
            u'ip_version': [u'ipv4', u'ipv6'],