1
2"""
3Test handling of Error() call on stream handler.
4
5This tests a regression in which MembersChanged was emitted with reason other
6than GC_REASON_ERROR.
7"""
8
9from servicetest import EventPattern, assertEquals, make_channel_proxy
10from jingletest2 import JingleTest2, test_all_dialects
11import constants as cs
12
13from twisted.words.xish import xpath
14
15from config import VOIP_ENABLED
16
17if not VOIP_ENABLED:
18    print "NOTE: built with --disable-voip"
19    raise SystemExit(77)
20
21def _session_terminate_predicate(event, reason, msg, jp):
22    matches = jp.match_jingle_action(event.query, 'session-terminate')
23
24    if matches and jp.is_modern_jingle():
25        reason = xpath.queryForNodes("/iq"
26                                     "/jingle[@action='session-terminate']"
27                                     "/reason/%s" % reason,
28                                     event.stanza)
29        reason_text = xpath.queryForString("/iq/jingle/reason/text",
30                                           event.stanza)
31
32        return bool(reason) and reason_text == msg
33
34    return matches
35
36def _test(jp, q, bus, conn, stream,
37          jingle_reason, group_change_reason, stream_error):
38    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo')
39    jt.prepare()
40    self_handle = conn.GetSelfHandle()
41    remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0]
42
43    # Ring ring!
44    jt.incoming_call()
45    new_channel, new_session_handler = q.expect_many(
46        EventPattern('dbus-signal', signal='NewChannel',
47            predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args),
48        EventPattern('dbus-signal', signal='NewSessionHandler'))
49    assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, new_channel.args[1])
50    assertEquals(cs.HT_CONTACT, new_channel.args[2])
51    assertEquals(remote_handle, new_channel.args[3])
52    assertEquals('rtp', new_session_handler.args[1])
53
54    channel_path = new_channel.args[0]
55
56    # Client calls Ready on new session handler.
57    session_handler = make_channel_proxy(
58        conn, new_session_handler.args[0], 'Media.SessionHandler')
59    session_handler.Ready()
60
61    # Client gets notified about a newly created stream...
62    new_stream_handler = q.expect('dbus-signal', signal='NewStreamHandler')
63    stream_id = new_stream_handler.args[1]
64    stream_handler = make_channel_proxy(
65        conn, new_stream_handler.args[0], 'Media.StreamHandler')
66    stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus())
67    stream_handler.Ready(jt.dbusify_codecs([("FOO", 5, 8000, {})]))
68
69    q.expect('dbus-signal', signal='SetRemoteCodecs')
70
71    msg = u"o noes"
72
73    # ...but something goes wrong.
74    stream_handler.Error(stream_error, msg)
75
76    q.expect("stream-iq", iq_type="set",
77             predicate=lambda x: _session_terminate_predicate(x, jingle_reason,
78                                                              msg, jp))
79    # Bye bye members.
80    mc = q.expect('dbus-signal', signal='MembersChanged',
81                  interface=cs.CHANNEL_IFACE_GROUP, path=channel_path,
82                  args=[msg, [], [self_handle, remote_handle], [],
83                        [], self_handle, group_change_reason])
84
85    q.expect('dbus-signal', signal='StreamError',
86             interface=cs.CHANNEL_TYPE_STREAMED_MEDIA,
87             args=[stream_id, stream_error, msg])
88
89    # Bye bye stream
90    q.expect('dbus-signal', signal='Close')
91    q.expect('dbus-signal', signal='StreamRemoved')
92
93    # Bye bye channel.
94    q.expect('dbus-signal', signal='Closed')
95    q.expect('dbus-signal', signal='ChannelClosed')
96
97def test_connection_error(jp, q, bus, conn, stream):
98    _test(jp, q, bus, conn, stream, "connectivity-error", cs.GC_REASON_ERROR,
99          cs.MEDIA_STREAM_ERROR_NETWORK_ERROR)
100
101def test_codec_negotiation_fail(jp, q, bus, conn, stream):
102    _test(jp, q, bus, conn, stream, "failed-application", cs.GC_REASON_ERROR,
103          cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED)
104
105if __name__ == '__main__':
106    test_all_dialects(test_connection_error)
107    test_all_dialects(test_codec_negotiation_fail)
108