[Telepathy-commits] [telepathy-gabble/master] new test for various content addition and removal scenarios

Senko Rasic senko at phyrexia.lan
Tue Dec 2 04:34:01 PST 2008


---
 tests/twisted/Makefile.am                          |    1 +
 tests/twisted/jingle/jingletest2.py                |    4 +-
 .../twisted/jingle/test-content-adding-removal.py  |    4 +-
 tests/twisted/jingle/test-content-complex.py       |  228 ++++++++++++++++++++
 4 files changed, 234 insertions(+), 3 deletions(-)
 create mode 100644 tests/twisted/jingle/test-content-complex.py

diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 27f4589..b602920 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -67,6 +67,7 @@ TWISTED_TESTS = \
 	jingle/test-outgoing-call-ensure.py \
 	jingle/test-dialects-incoming.py \
 	jingle/test-dialects-outgoing.py \
+	jingle/test-content-complex.py \
 	test-capabilities.py \
 	test-caps-cache.py \
 	test-caps-hash.py \
diff --git a/tests/twisted/jingle/jingletest2.py b/tests/twisted/jingle/jingletest2.py
index edc0d8c..9305f7f 100644
--- a/tests/twisted/jingle/jingletest2.py
+++ b/tests/twisted/jingle/jingletest2.py
@@ -205,8 +205,10 @@ class JingleProtocol015(JingleProtocol):
     def Description(self, type, children):
         if type == 'audio':
             ns = 'http://jabber.org/protocol/jingle/description/audio'
-        else:
+        elif type == 'video':
             ns = 'http://jabber.org/protocol/jingle/description/video'
+        else:
+            ns = 'unexistent-namespace'
         return ('description', ns, { 'type': type }, children)
 
 class JingleProtocol031(JingleProtocol):
diff --git a/tests/twisted/jingle/test-content-adding-removal.py b/tests/twisted/jingle/test-content-adding-removal.py
index edd2660..6a01939 100644
--- a/tests/twisted/jingle/test-content-adding-removal.py
+++ b/tests/twisted/jingle/test-content-adding-removal.py
@@ -144,12 +144,12 @@ def test(q, bus, conn, stream):
     assert e.query['action'] == 'content-remove'
     stream.send(gabbletest.make_result_iq(stream, e.stanza))
 
-    # Then we remove the second stream
+    # Then we remove the second stream, which terminates the session
     media_iface.RemoveStreams([stream2_id])
 
     e = q.expect('stream-iq')
     assert e.query.name == 'jingle'
-    assert e.query['action'] == 'content-remove'
+    assert e.query['action'] == 'session-terminate'
     stream.send(gabbletest.make_result_iq(stream, e.stanza))
 
     # Now the session should be terminated
diff --git a/tests/twisted/jingle/test-content-complex.py b/tests/twisted/jingle/test-content-complex.py
new file mode 100644
index 0000000..50a387a
--- /dev/null
+++ b/tests/twisted/jingle/test-content-complex.py
@@ -0,0 +1,228 @@
+"""
+Test everything related to contents
+"""
+
+from gabbletest import exec_test, make_result_iq, sync_stream, exec_tests
+from servicetest import make_channel_proxy, unwrap, tp_path_prefix, \
+        EventPattern
+import gabbletest
+import dbus
+import time
+from twisted.words.xish import xpath
+
+from jingletest2 import *
+
+def worker(jp, q, bus, conn, stream):
+
+    def make_stream_request(stream_type):
+        media_iface.RequestStreams(remote_handle, [stream_type])
+
+        e = q.expect('dbus-signal', signal='NewStreamHandler')
+        stream_id = e.args[1]
+
+        stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')
+
+        stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus())
+        stream_handler.Ready(jt2.get_audio_codecs_dbus())
+        stream_handler.StreamState(2)
+        return (stream_handler, stream_id)
+
+
+    jt2 = JingleTest2(jp, conn, q, stream, 'test at localhost', 'foo at bar.com/Foo')
+    jt2.prepare()
+
+    remote_handle = conn.RequestHandles(1, ["foo at bar.com/Foo"])[0]
+
+    # Remote end calls us
+    # jt.incoming_call()
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'session-initiate', [
+            jp.Content('stream1', 'initiator', 'both', [
+                jp.Description('audio', [
+                    jp.PayloadType(name, str(rate), str(id)) for
+                        (name, id, rate) in jt2.audio_codecs ]),
+            jp.TransportGoogleP2P() ]) ]) ])
+    stream.send(jp.xml(node))
+
+    # we don't even need this here, because we've provided a very strict
+    # predicate to expect_racy() so it won't get the wrong event
+    # q.flush_past_events()
+
+    # The caller is in members
+    e = q.expect('dbus-signal', signal='MembersChanged',
+             args=[u'', [remote_handle], [], [], [], 0, 0])
+
+    # We're pending because of remote_handle
+    e = q.expect('dbus-signal', signal='MembersChanged',
+             args=[u'', [], [], [1L], [], remote_handle, 0])
+
+    media_chan = make_channel_proxy(conn, tp_path_prefix + e.path, 'Channel.Interface.Group')
+    signalling_iface = make_channel_proxy(conn, tp_path_prefix + e.path, 'Channel.Interface.MediaSignalling')
+    media_iface = make_channel_proxy(conn, tp_path_prefix + e.path, 'Channel.Type.StreamedMedia')
+
+    # S-E gets notified about new session handler, and calls Ready on it
+    e = q.expect('dbus-signal', signal='NewSessionHandler')
+    assert e.args[1] == 'rtp'
+
+    session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler')
+    session_handler.Ready()
+
+    media_chan.AddMembers([dbus.UInt32(1)], 'accepted')
+
+    # S-E gets notified about a newly-created stream
+    e = q.expect('dbus-signal', signal='NewStreamHandler')
+    id1 = e.args[1]
+
+    stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')
+
+    # We are now in members too
+    e = q.expect('dbus-signal', signal='MembersChanged',
+             args=[u'', [1L], [], [], [], 0, 0])
+
+    # we are now both in members
+    members = media_chan.GetMembers()
+    assert set(members) == set([1L, remote_handle]), members
+
+    stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus())
+    stream_handler.Ready(jt2.get_audio_codecs_dbus())
+    stream_handler.StreamState(2)
+
+    # First one is transport-info
+    e = q.expect('stream-iq')
+    assert jp.match_jingle_action(e.query, 'transport-info')
+    assert e.query['initiator'] == 'foo at bar.com/Foo'
+
+    # stream.send(gabbletest.make_result_iq(stream, e.stanza))
+    stream.send(jp.xml(jp.ResultIq('test at localhost', e.stanza, [])))
+
+    # Second one is session-accept
+    e = q.expect('stream-iq')
+    assert jp.match_jingle_action(e.query, 'session-accept')
+
+    # stream.send(gabbletest.make_result_iq(stream, e.stanza))
+    stream.send(jp.xml(jp.ResultIq('test at localhost', e.stanza, [])))
+
+    # Here starts the interesting part of this test
+    # Remote end tries to create a content we can't handle
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'content-add', [
+            jp.Content('bogus', 'initiator', 'both', [
+                jp.Description('hologram', [
+                    jp.PayloadType(name, str(rate), str(id)) for
+                        (name, id, rate) in jt2.audio_codecs ]),
+            jp.TransportGoogleP2P() ]) ]) ])
+    stream.send(jp.xml(node))
+
+    # In older Jingle, this is a separate namespace, which isn't
+    # recognized, but it's a valid request, so it gets ackd and rejected
+    if jp.dialect == 'jingle-v0.15':
+        # Gabble should acknowledge content-add
+        q.expect('stream-iq', iq_type='result')
+
+        # .. and then send content-reject for the bogus content
+        e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
+            xpath.queryForNodes("/iq/jingle[@action='content-reject']/content[@name='bogus']",
+                x.stanza))
+
+    # In new Jingle, this is a bogus subtype of recognized namespace,
+    # so Gabble returns a bad request error
+    else:
+        q.expect('stream-iq', iq_type='error')
+
+
+    # Remote end then tries to create content which we already have
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'content-add', [
+            jp.Content('stream1', 'initiator', 'both', [
+                jp.Description('audio', [
+                    jp.PayloadType(name, str(rate), str(id)) for
+                        (name, id, rate) in jt2.audio_codecs ]),
+            jp.TransportGoogleP2P() ]) ]) ])
+    stream.send(jp.xml(node))
+
+    # Gabble should return error (content already exists)
+    q.expect('stream-iq', iq_type='error')
+
+    (stream_handler2, id2) = make_stream_request(1) # 1 == MEDIA_STREAM_TYPE_VIDEO
+
+    # Gabble should now send content-add
+    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
+        xpath.queryForNodes("/iq/jingle[@action='content-add']",
+            x.stanza))
+    stream.send(jp.xml(jp.ResultIq('test at localhost', e.stanza, [])))
+
+    c = e.query.firstChildElement()
+
+    # Remote end rejects it
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'content-reject', [
+            jp.Content(c['name'], c['creator'], c['senders'], []) ]) ])
+    stream.send(jp.xml(node))
+
+    # Gabble removes the stream
+    q.expect('dbus-signal', signal='StreamRemoved',
+        interface='org.freedesktop.Telepathy.Channel.Type.StreamedMedia')
+
+
+    # We try to make the request again, and succeed
+    (stream_handler3, id3) = make_stream_request(1) # 1 == MEDIA_STREAM_TYPE_VIDEO
+
+    # Gabble should again send content-add
+    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
+        xpath.queryForNodes("/iq/jingle[@action='content-add']",
+            x.stanza))
+    stream.send(jp.xml(jp.ResultIq('test at localhost', e.stanza, [])))
+    c = e.query.firstChildElement()
+
+    # Remote end finally accepts
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'content-accept', [
+            jp.Content(c['name'], c['creator'], c['senders'], [
+                jp.Description('video', [
+                    jp.PayloadType(name, str(rate), str(id)) for
+                        (name, id, rate) in jt2.audio_codecs ]),
+            jp.TransportGoogleP2P() ]) ]) ])
+    stream.send(jp.xml(node))
+
+    # We get remote codecs
+    e = q.expect('dbus-signal', signal='SetRemoteCodecs')
+
+    # Now, both we and remote peer try to remove the content simultaneously
+    media_iface.RemoveStreams([id3])
+    node = jp.SetIq(jt2.peer, jt2.jid, [
+        jp.Jingle(jt2.sid, jt2.peer, 'content-remove', [
+            jp.Content(c['name'], c['creator'], c['senders'], []) ]) ])
+    stream.send(jp.xml(node))
+
+    # Gabble should ignore our content-remove and send it's own
+    # (fixme: this could be racy)
+    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
+        xpath.queryForNodes("/iq/jingle[@action='content-remove']",
+            x.stanza))
+
+    # Now we want to remove the first stream
+    media_iface.RemoveStreams([id1])
+
+    # The remote peer still hasn't ackd the first stream removal, but since
+    # gabble knows no streams will be left after the removal completes,
+    # it will just terminate the session.
+
+    e = q.expect('stream-iq', iq_type='set', predicate=lambda x:
+        xpath.queryForNodes("/iq/jingle[@action='session-terminate']",
+            x.stanza))
+
+    conn.Disconnect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
+
+    return True
+
+
+def test015(q, bus, conn, stream):
+    return worker(JingleProtocol015(), q, bus, conn, stream)
+
+def test031(q, bus, conn, stream):
+    return worker(JingleProtocol031(),q, bus, conn, stream)
+
+if __name__ == '__main__':
+    exec_tests([test015, test031] * 10)
+
-- 
1.5.6.5




More information about the Telepathy-commits mailing list