def test(q, bus, conn, stream):
    room = '*****@*****.**'

    chan, path, props, disco = join_muc(q,
                                        bus,
                                        conn,
                                        stream,
                                        room,
                                        also_capture=[
                                            EventPattern(
                                                'stream-iq',
                                                iq_type='get',
                                                query_name='query',
                                                query_ns=ns.DISCO_INFO,
                                                to=room)
                                        ])

    sync_dbus(bus, q, conn)

    # we call Close...
    call_async(q, chan, 'Close')
    q.expect('dbus-return', method='Close')

    # ...so gabble announces our unavailable presence to the MUC.
    event = q.expect('stream-presence', to=room + '/test')
    elem = event.stanza
    assertEquals('unavailable', elem['type'])

    # while we wait for the conference server to echo our unavailable
    # presence, we try and create the same channel again...
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: room
        })

    # ...which should fail because the channel hasn't closed yet.
    q.expect('dbus-error', method='CreateChannel', name=cs.NOT_AVAILABLE)

    # the conference server finally gets around to echoing our
    # unavailable presence...
    echo_muc_presence(q, stream, elem, 'none', 'participant')

    # ...and only now is the channel closed.
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    # now that the channel has finally closed, let's try and request
    # it again which should succeed!
    chan, _, _ = join_muc(q, bus, conn, stream, room)

    # let's clear up though.
    chan.Close()
    event = q.expect('stream-presence', to=room + '/test')
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream):
    room = '*****@*****.**'

    chan, path, props, disco = join_muc(q, bus, conn, stream,
            room,
            also_capture=[EventPattern('stream-iq', iq_type='get',
                query_name='query', query_ns=ns.DISCO_INFO, to=room)])

    sync_dbus(bus, q, conn)

    # we call Close...
    call_async(q, chan, 'Close')
    q.expect('dbus-return', method='Close')

    # ...so gabble announces our unavailable presence to the MUC.
    event = q.expect('stream-presence', to=room + '/test')
    elem = event.stanza
    assertEquals('unavailable', elem['type'])

    # while we wait for the conference server to echo our unavailable
    # presence, we try and create the same channel again...
    call_async(q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: room
            })

    # ...which should fail because the channel hasn't closed yet.
    q.expect('dbus-error', method='CreateChannel', name=cs.NOT_AVAILABLE)

    # the conference server finally gets around to echoing our
    # unavailable presence...
    echo_muc_presence(q, stream, elem, 'none', 'participant')

    # ...and only now is the channel closed.
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    # now that the channel has finally closed, let's try and request
    # it again which should succeed!
    chan, _, _ = join_muc(q, bus, conn, stream, room)

    # let's clear up though.
    chan.Close()
    event = q.expect('stream-presence', to=room + '/test')
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
示例#3
0
def create_muji_channel (q, conn, stream, muc, in_muc = False):
    call_async (q, conn.Requests, 'CreateChannel',
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
          cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
          cs.TARGET_ID: muc,
          cs.CALL_INITIAL_AUDIO: True,
          cs.CALL_INITIAL_AUDIO_NAME: "Audio",
         }, byte_arrays = True)

    if not in_muc:
        e = q.expect('stream-presence', to = muc + "/test")
        echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    e = q.expect ('dbus-return', method='CreateChannel')

    return e.value
def test_then_disconnect(q, bus, conn, stream):
    room = '*****@*****.**'

    chan, path, props, disco = join_muc(q,
                                        bus,
                                        conn,
                                        stream,
                                        room,
                                        also_capture=[
                                            EventPattern(
                                                'stream-iq',
                                                iq_type='get',
                                                query_name='query',
                                                query_ns=ns.DISCO_INFO,
                                                to=room)
                                        ])

    sync_dbus(bus, q, conn)

    # we call Close...
    call_async(q, chan, 'Close')
    q.expect('dbus-return', method='Close')

    # ...so gabble announces our unavailable presence to the MUC.
    event = q.expect('stream-presence', to=room + '/test')
    elem = event.stanza
    assertEquals('unavailable', elem['type'])

    # oh no, but now we want to disconnect.
    call_async(q, conn, 'Disconnect')

    # the muc factory is told to close everything, so it does so
    # without announcing it to the channel because it does it
    # forcibly, so the channels disappear.
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    # now echo the unavailable presence; this shouldn't be handled
    # because the channel has already closed.
    echo_muc_presence(q, stream, elem, 'none', 'participant')

    # send the stream footer so that the connection thinks it's
    # property disconnected now.
    stream.sendFooter()

    # finally, Disconnect returns
    q.expect('dbus-return', method='Disconnect')
def expect_close(q, path, stream=None, jid=None):
    forbid_unavailable = [EventPattern('stream-presence',
                                       presence_type='unavailable',
                                       to='%s/test' % jid)]

    if jid is not None:
        e = q.expect_many(*forbid_unavailable)[0]
        echo_muc_presence(q, stream, e.stanza, 'none', 'participant')
    else:
        q.forbid_events(forbid_unavailable)

    q.expect_many(EventPattern('dbus-signal', signal='ChannelClosed',
                               args=[path]),
                  EventPattern('dbus-signal', signal='Closed',
                               path=path))

    if jid is not None:
        q.unforbid_events(forbid_unavailable)
def expect_close(q, path, stream=None, jid=None):
    forbid_unavailable = [
        EventPattern('stream-presence',
                     presence_type='unavailable',
                     to='%s/test' % jid)
    ]

    if jid is not None:
        e = q.expect_many(*forbid_unavailable)[0]
        echo_muc_presence(q, stream, e.stanza, 'none', 'participant')
    else:
        q.forbid_events(forbid_unavailable)

    q.expect_many(
        EventPattern('dbus-signal', signal='ChannelClosed', args=[path]),
        EventPattern('dbus-signal', signal='Closed', path=path))

    if jid is not None:
        q.unforbid_events(forbid_unavailable)
def create_muji_channel(q, conn, stream, muc, in_muc=False):
    call_async(q,
               conn.Requests,
               'CreateChannel', {
                   cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                   cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                   cs.TARGET_ID: muc,
                   cs.CALL_INITIAL_AUDIO: True,
                   cs.CALL_INITIAL_AUDIO_NAME: "Audio",
               },
               byte_arrays=True)

    if not in_muc:
        e = q.expect('stream-presence', to=muc + "/test")
        echo_muc_presence(q, stream, e.stanza, 'none', 'participant')

    e = q.expect('dbus-return', method='CreateChannel')

    return e.value
def test_then_disconnect(q, bus, conn, stream):
    room = '*****@*****.**'

    chan, path, props, disco = join_muc(q, bus, conn, stream,
            room,
            also_capture=[EventPattern('stream-iq', iq_type='get',
                query_name='query', query_ns=ns.DISCO_INFO, to=room)])

    sync_dbus(bus, q, conn)

    # we call Close...
    call_async(q, chan, 'Close')
    q.expect('dbus-return', method='Close')

    # ...so gabble announces our unavailable presence to the MUC.
    event = q.expect('stream-presence', to=room + '/test')
    elem = event.stanza
    assertEquals('unavailable', elem['type'])

    # oh no, but now we want to disconnect.
    call_async(q, conn, 'Disconnect')

    # the muc factory is told to close everything, so it does so
    # without announcing it to the channel because it does it
    # forcibly, so the channels disappear.
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))

    # now echo the unavailable presence; this shouldn't be handled
    # because the channel has already closed.
    echo_muc_presence(q, stream, elem, 'none', 'participant')

    # send the stream footer so that the connection thinks it's
    # property disconnected now.
    stream.sendFooter()

    # finally, Disconnect returns
    q.expect('dbus-return', method='Disconnect')
    assert removed == [bob_handle]

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name}

    tube_chan.Channel.Close()
    _, _, event = q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        EventPattern('stream-presence', to='[email protected]/test',
                     presence_type='unavailable'))

    # we must echo the MUC presence so the room will actually close
    # and we should wait to make sure gabble has actually parsed our
    # echo before trying to rejoin
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    sync_stream(q, stream)

    # rejoin the room
    call_async(q, conn.Requests, 'CreateChannel',
        { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
          cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
          cs.TARGET_ID: '*****@*****.**' })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    act_prop_iface = dbus.Interface(conn,
                                    'org.laptop.Telepathy.ActivityProperties')
    bob_handle = conn.get_contact_handle_sync('bob@localhost')

    # Bob invites us to a chatroom, pre-seeding properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('From the invitation')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('1')

    stream.send(message)

    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement((ns.MUC_USER, 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannel')

    assert event.args[1] == cs.CHANNEL_TYPE_TEXT

    assert event.args[2] == 2  # handle type
    assert event.args[3] == 1  # handle
    room_handle = 1

    text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]),
                             'Text')
    group_iface = text_chan.Group

    members = group_iface.GetAllMembers()[0]
    local_pending = group_iface.GetAllMembers()[1]
    remote_pending = group_iface.GetAllMembers()[2]

    assert len(members) == 1
    assert conn.inspect_contact_sync(members[0]) == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.inspect_contact_sync(local_pending[0]) == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                "SelfHandle")
    assert room_self_handle == local_pending[0]

    # by now, we should have picked up the extra activity properties
    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    call_async(q, buddy_iface, 'GetActivities', bob_handle)

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob still has no (public) activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')

    assert event.value == ([('foo_id', room_handle)], )

    props = act_prop_iface.GetProperties(room_handle)
    assert len(props) == 2
    assert props['title'] == 'From the invitation'
    assert props['private'] == True

    # Now Bob changes the properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Mushroom, mushroom')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')

    assert event.args == [
        room_handle, {
            'title': 'Mushroom, mushroom',
            'private': False
        }
    ]
    assert act_prop_iface.GetProperties(room_handle) == \
            event.args[1]

    # OK, now accept the invitation
    call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then')

    q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal',
                     signal='MembersChanged',
                     args=[
                         '', [], [bob_handle], [], [room_self_handle], 0,
                         cs.GC_REASON_INVITED
                     ]),
        EventPattern('dbus-return', method='AddMembers'),
    )

    # Send presence for own membership of room.
    stream.send(
        make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChanged')
    assert event.args == ['', [room_self_handle], [], [], [], 0, 0]

    call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)])

    event = q.expect('stream-iq', iq_type='set')
    # Now that it's not private, it'll go in my PEP
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    q.expect('dbus-return', method='SetActivities')

    # Bob changes the properties and tells the room he's done so
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = '[email protected]/bob'
    message['to'] = '*****@*****.**'
    properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Badger badger badger')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('stream-iq', iq_type='set')
    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'Badger badger badger'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    act_prop_iface = dbus.Interface(conn,
                                    'org.laptop.Telepathy.ActivityProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties', room_handle, {
        'title': 'I can set the properties too',
        'private': True
    })

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    q.expect('dbus-return', method='SetProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties', room_handle, {
        'title': 'I can set the properties too',
        'private': False
    })

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert (activity is not None and len(activity) == 1), repr(activity)
    assert activity[0]['room'] == '*****@*****.**'
    assert activity[0]['type'] == 'foo_id'  # sic

    q.expect('dbus-return', method='SetProperties')

    text_chan.Close()

    # we must echo the MUC presence so the room will actually close
    event = q.expect('stream-presence',
                     to='[email protected]/test',
                     presence_type='unavailable')
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
                                     message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)
                          'DBusNames',
                          dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name}

    tube_chan.Channel.Close()
    _, _, event = q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     presence_type='unavailable'))

    # we must echo the MUC presence so the room will actually close
    # and we should wait to make sure gabble has actually parsed our
    # echo before trying to rejoin
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    sync_stream(q, stream)

    # rejoin the room
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()
示例#12
0
    assert removed == [bob_handle]

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, "DBusNames", dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name}

    chan_iface.Close()
    q.expect_many(EventPattern("dbus-signal", signal="Closed"), EventPattern("dbus-signal", signal="ChannelClosed"))

    # leave the room
    text_chan.Close()

    # we must echo the MUC presence so the room will actually close
    # and we should wait to make sure gabble has actually parsed our
    # echo before trying to rejoin
    event = q.expect("stream-presence", to="[email protected]/test", presence_type="unavailable")
    echo_muc_presence(q, stream, event.stanza, "none", "participant")
    sync_stream(q, stream)

    q.expect_many(EventPattern("dbus-signal", signal="Closed"), EventPattern("dbus-signal", signal="ChannelClosed"))

    # rejoin the room
    call_async(
        q,
        conn.Requests,
        "CreateChannel",
        {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: "*****@*****.**",
        },
    )
示例#13
0
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)

    # check if we can request muc D-Bus tube
    t.check_conn_properties(q, conn)

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_name = conn.inspect_contact_sync(self_handle)

    # offer a D-Bus tube to another room using new API
    muc = '*****@*****.**'
    request = {
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE,
        cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
        cs.TARGET_ID: '*****@*****.**',
        cs.DBUS_TUBE_SERVICE_NAME: 'com.example.TestCase',
    }
    join_muc(q, bus, conn, stream, muc, request=request)

    exv = q.expect('dbus-signal', signal='NewChannels')

    channels = exv.args[0]
    assert len(channels) == 1
    path, prop = channels[0]
    assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE
    assert prop[cs.INITIATOR_ID] == '[email protected]/test'
    assert prop[cs.REQUESTED] == True
    assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM
    assert prop[cs.TARGET_ID] == '*****@*****.**'
    assert prop[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase'
    assert prop[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ]

    # check that the tube channel is in the channels list
    all_channels = conn.Get(cs.CONN_IFACE_REQUESTS,
                            'Channels',
                            dbus_interface=cs.PROPERTIES_IFACE,
                            byte_arrays=True)
    assertContains((path, prop), all_channels)

    tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube')
    tube_props = tube_chan.Properties.GetAll(cs.CHANNEL_IFACE_TUBE,
                                             byte_arrays=True)

    assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED

    # try to offer using a wrong access control
    try:
        tube_chan.DBusTube.Offer(sample_parameters,
                                 cs.SOCKET_ACCESS_CONTROL_PORT)
    except dbus.DBusException as e:
        assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT)
    else:
        assert False

    # offer the tube
    call_async(q, tube_chan.DBusTube, 'Offer', sample_parameters,
               access_control)

    presence_event, return_event, status_event, dbus_changed_event = q.expect_many(
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     predicate=lambda e: t.presence_contains_tube(e)),
        EventPattern('dbus-return', method='Offer'),
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     args=[cs.TUBE_CHANNEL_STATE_OPEN]),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE))

    tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                'SelfHandle')
    assert tube_self_handle != 0

    # handle presence_event
    # We announce our newly created tube in our muc presence
    presence = presence_event.stanza
    dbus_stream_id, my_bus_name, dbus_tube_id = check_tube_in_presence(
        presence, '[email protected]/test')

    # handle dbus_changed_event
    added, removed = dbus_changed_event.args
    assert added == {tube_self_handle: my_bus_name}
    assert removed == []

    dbus_tube_adr = return_event.value[0]

    bob_bus_name = ':2.Ym9i'
    bob_handle = conn.get_contact_handle_sync('[email protected]/bob')

    def bob_in_tube():
        presence = elem('presence',
                        from_='[email protected]/bob',
                        to='*****@*****.**')(
                            elem('x', xmlns=ns.MUC_USER),
                            elem('tubes', xmlns=ns.TUBES)(
                                elem('tube',
                                     type='dbus',
                                     initiator='[email protected]/test',
                                     service='com.example.TestCase',
                                     id=str(dbus_tube_id))(elem('parameters')(
                                         elem('parameter',
                                              name='ay',
                                              type='bytes')(u'aGVsbG8='),
                                         elem('parameter',
                                              name='s',
                                              type='str')(u'hello'),
                                         elem('parameter',
                                              name='i',
                                              type='int')(u'-123'),
                                         elem('parameter',
                                              name='u',
                                              type='uint')(u'123')))))

        # have to add stream-id and dbus-name attributes manually as we can't use
        # keyword with '-'...
        tube_node = xpath.queryForNodes('/presence/tubes/tube', presence)[0]
        tube_node['stream-id'] = dbus_stream_id
        tube_node['dbus-name'] = bob_bus_name
        stream.send(presence)

    # Bob joins the tube
    bob_in_tube()

    dbus_changed_event = q.expect('dbus-signal',
                                  signal='DBusNamesChanged',
                                  interface=cs.CHANNEL_TYPE_DBUS_TUBE)

    added, removed = dbus_changed_event.args
    assert added == {bob_handle: bob_bus_name}
    assert removed == []

    tube = Connection(dbus_tube_adr)
    fire_signal_on_tube(q, tube, '*****@*****.**', dbus_stream_id,
                        my_bus_name)

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                          'DBusNames',
                          dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name, bob_handle: bob_bus_name}

    # Bob leave the tube
    presence = elem('presence',
                    from_='[email protected]/bob',
                    to='*****@*****.**')(elem('x', xmlns=ns.MUC_USER),
                                               elem('tubes', xmlns=ns.TUBES))
    stream.send(presence)

    dbus_changed_event = q.expect('dbus-signal',
                                  signal='DBusNamesChanged',
                                  interface=cs.CHANNEL_TYPE_DBUS_TUBE)

    added, removed = dbus_changed_event.args
    assert added == {}
    assert removed == [bob_handle]

    names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                          'DBusNames',
                          dbus_interface=cs.PROPERTIES_IFACE)
    assert names == {tube_self_handle: my_bus_name}

    tube_chan.Channel.Close()
    _, _, event = q.expect_many(
        EventPattern('dbus-signal', signal='Closed'),
        EventPattern('dbus-signal', signal='ChannelClosed'),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     presence_type='unavailable'))

    # we must echo the MUC presence so the room will actually close
    # and we should wait to make sure gabble has actually parsed our
    # echo before trying to rejoin
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')
    sync_stream(q, stream)

    # rejoin the room
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
            cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
            cs.TARGET_ID: '*****@*****.**'
        })

    q.expect('stream-presence', to='[email protected]/test')

    # Bob is in the room and in the tube
    bob_in_tube()

    # Send presence for own membership of room.
    stream.send(make_muc_presence('none', 'participant', muc, 'test'))

    def new_tube(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    def new_text(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT

    # tube and text is created
    text_event, tube_event = q.expect_many(
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_text),
        EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube))

    channels = exv.args[0]
    tube_path, props = tube_event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/test', props[cs.INITIATOR_ID])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE])
    assertEquals('com.example.TestCase', props[cs.DBUS_TUBE_SERVICE_NAME])

    _, props = text_event.args[0][0]
    assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE])
    assertEquals(True, props[cs.REQUESTED])

    # tube is local-pending
    tube_chan = bus.get_object(conn.bus_name, tube_path)
    state = tube_chan.Get(cs.CHANNEL_IFACE_TUBE,
                          'State',
                          dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(cs.TUBE_STATE_LOCAL_PENDING, state)
def test(q, bus, conn, stream):
    iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties')
    bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0]

    # Bob invites us to a chatroom, pre-seeding properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('From the invitation')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('1')

    stream.send(message)

    message = domish.Element((None, 'message'))
    message['from'] = '*****@*****.**'
    message['to'] = 'test@localhost'
    x = message.addElement((ns.MUC_USER, 'x'))
    invite = x.addElement((None, 'invite'))
    invite['from'] = 'bob@localhost'
    reason = invite.addElement((None, 'reason'))
    reason.addContent('No good reason')

    stream.send(message)

    event = q.expect('dbus-signal', signal='NewChannel')

    assert event.args[1] == cs.CHANNEL_TYPE_TEXT

    assert event.args[2] == 2   # handle type
    assert event.args[3] == 1   # handle
    room_handle = 1

    text_chan = bus.get_object(conn.bus_name, event.args[0])
    chan_iface = dbus.Interface(text_chan, cs.CHANNEL)
    group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP)

    members = group_iface.GetAllMembers()[0]
    local_pending = group_iface.GetAllMembers()[1]
    remote_pending = group_iface.GetAllMembers()[2]

    assert len(members) == 1
    assert conn.InspectHandles(1, members)[0] == 'bob@localhost'
    bob_handle = members[0]
    assert len(local_pending) == 1
    # FIXME: the username-part-is-nickname assumption
    assert conn.InspectHandles(1, local_pending)[0] == \
            '[email protected]/test'
    assert len(remote_pending) == 0

    room_self_handle = group_iface.GetSelfHandle()
    assert room_self_handle == local_pending[0]

    # by now, we should have picked up the extra activity properties
    buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
    call_async(q, buddy_iface, 'GetActivities', bob_handle)

    event = q.expect('stream-iq', iq_type='get', to='bob@localhost')
    # Bob still has no (public) activities
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'bob@localhost'
    stream.send(event.stanza)

    event = q.expect('dbus-return', method='GetActivities')

    assert event.value == ([('foo_id', room_handle)],)

    props = act_prop_iface.GetProperties(room_handle)
    assert len(props) == 2
    assert props['title'] == 'From the invitation'
    assert props['private'] == True

    # Now Bob changes the properties
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = 'bob@localhost'
    message['to'] = 'test@localhost'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['room'] = '*****@*****.**'
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Mushroom, mushroom')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')

    assert event.args == [room_handle, {'title': 'Mushroom, mushroom',
        'private': False }]
    assert act_prop_iface.GetProperties(room_handle) == \
            event.args[1]

    # OK, now accept the invitation
    call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then')

    q.expect_many(
        EventPattern('stream-presence', to='[email protected]/test'),
        EventPattern('dbus-signal', signal='MembersChanged',
            args=['', [], [bob_handle], [], [room_self_handle],
                0, cs.GC_REASON_INVITED]),
        EventPattern('dbus-return', method='AddMembers'),
        )

    # Send presence for own membership of room.
    stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'test'))

    event = q.expect('dbus-signal', signal='MembersChanged')
    assert event.args == ['', [room_self_handle], [], [], [], 0, 0]

    call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)])

    event = q.expect('stream-iq', iq_type='set')
    # Now that it's not private, it'll go in my PEP
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    q.expect('dbus-return', method='SetActivities')

    # Bob changes the properties and tells the room he's done so
    message = domish.Element(('jabber:client', 'message'))
    message['from'] = '[email protected]/bob'
    message['to'] = '*****@*****.**'
    properties = message.addElement(
        (ns.OLPC_ACTIVITY_PROPS, 'properties'))
    properties['activity'] = 'foo_id'
    property = properties.addElement((None, 'property'))
    property['type'] = 'str'
    property['name'] = 'title'
    property.addContent('Badger badger badger')
    property = properties.addElement((None, 'property'))
    property['type'] = 'bool'
    property['name'] = 'private'
    property.addContent('0')

    stream.send(message)

    event = q.expect('stream-iq', iq_type='set')
    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'Badger badger badger'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties',
            room_handle, {'title': 'I can set the properties too', 'private': True})

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '1'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen


    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    q.expect('dbus-return', method='SetProperties')

    # test sets the title and sets private back to True
    call_async(q, act_prop_iface, 'SetProperties',
        room_handle, {'title': 'I can set the properties too',
                              'private': False})

    event = q.expect('stream-message', to='*****@*****.**')
    message = event.stanza

    properties = xpath.queryForNodes('/message/properties', message)
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert (properties is not None and len(properties) == 1), repr(properties)
    assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS
    assert properties[0]['room'] == '*****@*****.**'
    assert properties[0]['activity'] == 'foo_id'

    property = xpath.queryForNodes('/properties/property', properties[0])
    assert (property is not None and len(property) == 2), repr(property)
    seen = set()
    for p in property:
        seen.add(p['name'])
        if p['name'] == 'title':
            assert p['type'] == 'str'
            assert str(p) == 'I can set the properties too'
        elif p['name'] == 'private':
            assert p['type'] == 'bool'
            assert str(p) == '0'
        else:
            assert False, 'Unexpected property %s' % p['name']
    assert 'title' in seen, seen
    assert 'private' in seen, seen

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert (activity is not None and len(activity) == 1), repr(activity)
    assert activity[0]['room'] == '*****@*****.**'
    assert activity[0]['type'] == 'foo_id'                  # sic

    q.expect('dbus-return', method='SetProperties')

    chan_iface.Close()

    # we must echo the MUC presence so the room will actually close
    event = q.expect('stream-presence', to='[email protected]/test',
                     presence_type='unavailable')
    echo_muc_presence(q, stream, event.stanza, 'none', 'participant')

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITIES

    activity = xpath.queryForNodes('/activities/activity', activities[0])
    assert activity is None, repr(activity)

    event = q.expect('stream-iq', iq_type='set')
    event.stanza['type'] = 'result'
    event.stanza['to'] = 'test@localhost'
    event.stanza['from'] = 'test@localhost'
    stream.send(event.stanza)

    message = event.stanza

    activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities',
            message)
    assert (activities is not None and len(activities) == 1), repr(activities)
    assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS

    properties = xpath.queryForNodes('/activities/properties', activities[0])
    assert properties is None, repr(properties)