summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Laban <david.laban@collabora.co.uk>2010-12-06 18:49:40 +0000
committerDavid Laban <david.laban@collabora.co.uk>2011-01-26 17:16:33 +0000
commit76cba776cacd54b3994a590e572b1a51c2217761 (patch)
tree8b073df26a5aa28660fccb63307bd2e368eb4e08
parent364ff37b08cc76841312b04450cb8de9541f2ada (diff)
import incoming-basics from gabble
-rw-r--r--tests/twisted/voip/incoming-basics.py185
1 files changed, 185 insertions, 0 deletions
diff --git a/tests/twisted/voip/incoming-basics.py b/tests/twisted/voip/incoming-basics.py
new file mode 100644
index 0000000..beae04d
--- /dev/null
+++ b/tests/twisted/voip/incoming-basics.py
@@ -0,0 +1,185 @@
+"""
+Test incoming call handling.
+"""
+
+import dbus
+
+from gabbletest import make_result_iq
+from servicetest import (
+ make_channel_proxy, unwrap, EventPattern, assertEquals, assertLength)
+from jingletest2 import JingleTest2, test_all_dialects
+import constants as cs
+
+from twisted.words.xish import xpath
+
+def test(jp, q, bus, conn, stream, peer='foo@bar.com/Foo'):
+ jt = JingleTest2(jp, conn, q, stream, 'test@localhost', peer)
+ jt.prepare()
+
+ self_handle = conn.GetSelfHandle()
+ remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0]
+
+ # Remote end calls us
+ jt.incoming_call()
+
+ # If this is a Jingle dialect that supports it, Gabble should send a
+ # <ringing/> notification when it gets the session-initiate until Telepathy
+ # has a way for the UI to do this.
+ # https://bugs.freedesktop.org/show_bug.cgi?id=21964
+ ringing_event = jp.rtp_info_event_list("ringing")
+
+ if jp.dialect == 'gtalk-v0.4':
+ # With gtalk4, apparently we have to send transport-accept immediately,
+ # not even just before we send our transport-info. wjt tested this, and
+ # indeed if we don't send this for incoming calls, the call never
+ # connects.
+ ta_event = [
+ EventPattern('stream-iq', predicate=lambda x:
+ xpath.queryForNodes("/iq/session[@type='transport-accept']",
+ x.stanza)),
+ ]
+ else:
+ ta_event = []
+
+ nc, e = q.expect_many(
+ EventPattern('dbus-signal', signal='NewChannel',
+ predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args),
+ EventPattern('dbus-signal', signal='NewSessionHandler'),
+ *(ringing_event + ta_event)
+ )[0:2]
+ path, ct, ht, h, _ = nc.args
+
+ assert ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, ct
+ assert ht == cs.HT_CONTACT, ht
+ assert h == remote_handle, h
+
+ media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group')
+ media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia')
+
+ # S-E was notified about new session handler, and calls Ready on it
+ assert e.args[1] == 'rtp'
+ session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
+ session_handler.Ready()
+
+ nsh_event = q.expect('dbus-signal', signal='NewStreamHandler')
+
+ # S-E gets notified about a newly-created stream
+ stream_handler = make_channel_proxy(conn, nsh_event.args[0],
+ 'Media.StreamHandler')
+
+ streams = media_iface.ListStreams()
+ assertLength(1, streams)
+
+ stream_id, stream_handle, stream_type, _, stream_direction, pending_flags =\
+ streams[0]
+ assertEquals(remote_handle, stream_handle)
+ assertEquals(cs.MEDIA_STREAM_TYPE_AUDIO, stream_type)
+ assertEquals(cs.MEDIA_STREAM_DIRECTION_RECEIVE, stream_direction)
+ assertEquals(cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending_flags)
+
+ # Exercise channel properties
+ channel_props = media_chan.GetAll(
+ cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE)
+ assertEquals(remote_handle, channel_props['TargetHandle'])
+ assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType'])
+ assertEquals((cs.HT_CONTACT, remote_handle),
+ media_chan.GetHandle(dbus_interface=cs.CHANNEL))
+ assertEquals(jt.peer_bare_jid, channel_props['TargetID'])
+ assertEquals(jt.peer_bare_jid, channel_props['InitiatorID'])
+ assertEquals(remote_handle, channel_props['InitiatorHandle'])
+ assertEquals(False, channel_props['Requested'])
+
+ group_props = media_chan.GetAll(
+ cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE)
+
+ assert group_props['SelfHandle'] == self_handle, \
+ (group_props['SelfHandle'], self_handle)
+
+ flags = group_props['GroupFlags']
+ assert flags & cs.GF_PROPERTIES, flags
+ # Changing members in any way other than adding or removing yourself is
+ # meaningless for incoming calls, and the flags need not be sent to change
+ # your own membership.
+ assert not flags & cs.GF_CAN_ADD, flags
+ assert not flags & cs.GF_CAN_REMOVE, flags
+ assert not flags & cs.GF_CAN_RESCIND, flags
+
+ assert group_props['Members'] == [remote_handle], group_props['Members']
+ assert group_props['RemotePendingMembers'] == [], \
+ group_props['RemotePendingMembers']
+ # We're local pending because remote_handle invited us.
+ assert group_props['LocalPendingMembers'] == \
+ [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')], \
+ unwrap(group_props['LocalPendingMembers'])
+
+ streams = media_chan.ListStreams(
+ dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA)
+ assert len(streams) == 1, streams
+ assert len(streams[0]) == 6, streams[0]
+ # streams[0][0] is the stream identifier, which in principle we can't
+ # make any assertion about (although in practice it's probably 1)
+ assert streams[0][1] == remote_handle, (streams[0], remote_handle)
+ assert streams[0][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0]
+ # We haven't connected yet
+ assert streams[0][3] == cs.MEDIA_STREAM_STATE_DISCONNECTED, streams[0]
+ # In Gabble, incoming streams start off with remote send enabled, and
+ # local send requested
+ assert streams[0][4] == cs.MEDIA_STREAM_DIRECTION_RECEIVE, streams[0]
+ assert streams[0][5] == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, streams[0]
+
+ # Connectivity checks happen before we have accepted the call
+ stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus())
+ stream_handler.Ready(jt.get_audio_codecs_dbus())
+ stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED)
+ stream_handler.SupportedCodecs(jt.get_audio_codecs_dbus())
+
+ # peer gets the transport
+ e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info'))
+ assertEquals(jt.peer, e.query['initiator'])
+
+ if jp.dialect in ['jingle-v0.15', 'jingle-v0.31']:
+ content = xpath.queryForNodes('/iq/jingle/content', e.stanza)[0]
+ assertEquals('initiator', content['creator'])
+
+ stream.send(make_result_iq(stream, e.stanza))
+
+ # At last, accept the call
+ media_chan.AddMembers([self_handle], 'accepted')
+
+ # Call is accepted, we become a member, and the stream that was pending
+ # local send is now sending.
+ memb, acc, _, _, _ = q.expect_many(
+ EventPattern('dbus-signal', signal='MembersChanged',
+ args=[u'', [self_handle], [], [], [], self_handle,
+ cs.GC_REASON_NONE]),
+ EventPattern('stream-iq',
+ predicate=jp.action_predicate('session-accept')),
+ EventPattern('dbus-signal', signal='SetStreamSending', args=[True]),
+ EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]),
+ EventPattern('dbus-signal', signal='StreamDirectionChanged',
+ args=[stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]),
+ )
+
+ stream.send(make_result_iq(stream, acc.stanza))
+
+ # Also, if this is a Jingle dialect that supports it, Gabble should send an
+ # <active/> notification when the session-accept is acked (until the
+ # Telepathy spec lets the UI say it's not ringing any more).
+ active_event = jp.rtp_info_event("active")
+ if active_event is not None:
+ q.expect_many(active_event)
+
+ # we are now both in members
+ members = media_chan.GetMembers()
+ assert set(members) == set([self_handle, remote_handle]), members
+
+ # Connected! Blah, blah, ...
+
+ # 'Nuff said
+ jt.terminate()
+ q.expect('dbus-signal', signal='Closed', path=path)
+
+if __name__ == '__main__':
+ test_all_dialects(test)
+ test_all_dialects(lambda jp, q, bus, conn, stream:
+ test(jp, q, bus, conn, stream, 'foo@sip.bar.com'))