Can't update the connection callback if it is already gone.
[thrasher.git] / perl / tests / xmpp_stream_in.pl
blobbd1b7da2f3231196d88545462401c2b2f6cf9f87
1 #!/usr/bin/perl
3 # Test that Thrasher::XMPPStreams works as expected.
4 use Test::More 'no_plan';
5 use Test::Deep;
7 use strict;
8 use warnings;
10 use Data::Dumper;
11 use XML::SAX;
13 BEGIN {
14 use_ok 'Thrasher::XMPPStreamIn', qw(:all);
15 use_ok 'Thrasher::Constants', qw(:all);
16 use_ok 'Thrasher::Log', qw(:all);
17 use_ok 'Thrasher::Test', qw(:all);
18 use_ok 'Thrasher::XML', qw(:all);
21 # Verify the support code is working correctly
22 SUPPORT_CODE: {
23 cmp_deeply(normalize_name("x"),
24 [$NS_CLIENT, 'x'],
25 'normalizing works as expected');
26 cmp_deeply(normalize_name(['', 'x']),
27 [$NS_CLIENT, 'x']);
28 cmp_deeply(normalize_name(['stream', 'x']),
29 [$NS_STREAM, 'x']);
30 cmp_deeply(normalize_name([$NS_STREAM, 'x']),
31 [$NS_STREAM, 'x']);
33 my $tag1 = normalize_name('x');
34 my $tag2 = 'x';
35 my $tag3 = ['stream', 'x'];
36 my $tag4 = [$NS_STREAM, 'x'];
37 is(same_name($tag1, $tag2), 1, 'same names correctly compares names');
38 is(same_name($tag1, $tag1), 1);
39 is(same_name($tag2, $tag2), 1);
40 is(same_name($tag3, $tag3), 1);
41 is(same_name($tag3, $tag4), 1);
42 is(same_name($tag4, $tag4), 1);
43 is(same_name($tag1, $tag3), '');
44 is(same_name($tag2, $tag3), '');
47 # Verify that XML is handled in the expected manner
48 XML_TESTING: {
49 my $s = get_parser();
50 is(ref($s), 'Thrasher::XMPPStreamIn', 'obj constructed');
52 my $messages = $s->parse(<<STREAM);
53 <stream:stream
54 to='example.com'
55 xmlns='jabber:client'
56 xmlns:stream='http://etherx.jabber.org/streams'
57 stream:moo="test"
58 moo="test2"
59 version='1.0'><stream:stream xmlns:stream="test" /></stream:stream>
61 STREAM
63 cmp_deeply($messages,
66 [$NS_STREAM, 'stream'],
67 {'{}version' => '1.0',
68 "{$NS_STREAM}moo" => 'test',
69 '{}to' => 'example.com',
70 '{}moo' => 'test2'},
75 ['test', 'stream'],
76 {},
79 ]);
81 $s = get_parser();
82 $messages = $s->parse(<<'STREAM');
83 <stream:stream
84 to='example.com'
85 xmlns='jabber:client'
86 xmlns:stream='http://etherx.jabber.org/streams'>
88 <iq type="set" to="moo">
89 <forbidden xmlns="stream-not-totally-awesome">
90 <yo>queiro taco bell?</yo>
91 </forbidden>
92 </iq>
94 <message to="moo@moo.com/Moo" from="baa@baa.com/Baa">
95 <body>You &gt; make me smooth.</body>
96 <xhtml xmlns="oh.some.xhtml.ns.thingy">You &gt; m<i>a</i>ke me smooth.</xhtml>
97 <stream:special xmlns:stream="specially.for.you">
98 <stream:termination />
99 </stream:special>
100 </message>
102 STREAM
104 cmp_deeply($messages,
105 [[[$NS_STREAM, 'stream'],
106 {'{}to' => 'example.com'},
107 []],
108 [[$NS_CLIENT, 'iq'],
109 {'{}type' => 'set',
110 '{}to' => 'moo'},
113 [['stream-not-totally-awesome',
114 'forbidden'],
118 [['stream-not-totally-awesome', 'yo'],
120 ['queiro taco bell?']
123 ']],
125 ']],
126 [[$NS_CLIENT, 'message'],
127 {'{}from' => 'baa@baa.com/Baa',
128 '{}to' => 'moo@moo.com/Moo'},
131 [[$NS_CLIENT, 'body'],
133 ['You > make me smooth.']],
136 [['oh.some.xhtml.ns.thingy', 'xhtml'],
138 ['You > m',
139 [['oh.some.xhtml.ns.thingy', 'i'],
141 ['a']
143 'ke me smooth.'
147 [['specially.for.you', 'special'],
152 [['specially.for.you', 'termination'],
161 ]]],
162 'xml message parsing works as designed.');
166 EXTRACTING: {
167 my $test_element = [$NS_CLIENT, 'message'];
169 # degenerate case
170 cmp_deeply(extract(undef, []), [],
171 'degenerate extraction case works');
173 # element match fail
174 dies {
175 extract([[$NS_CLIENT, 'message'], undef, undef],
176 [[$NS_STREAM, 'message'], undef, undef]);
177 } 'namespace mismatch detected';
178 dies {
179 extract([[$NS_CLIENT, 'message'], undef, undef],
180 [[$NS_CLIENT, 'iq'], undef, undef]);
181 } 'element name mismatch detected';
183 # attribute match fail
184 dies {
185 extract([$test_element, { a => 'b' }, undef],
186 [[$NS_CLIENT, 'test'], {'{}a' => 'c'}, undef]);
187 } 'attribute mismatch detected.';
189 # Attribute matching works when the pattern just gives
190 # a straight attribute name with no preceding {} when
191 # the attribute is in the default namespace.
192 ok(extract([$test_element, { a => 'b' }, undef],
193 [$test_element, { '{}a' => 'b' }, undef]),
194 "don't have to provide default namespace specs for atts");
196 # children mismatch fail
197 dies {
198 extract([$test_element, undef, ['x']],
199 [$test_element, undef, []]);
201 # children match succeed
202 cmp_deeply(extract([$test_element, undef, 'x'],
203 [$test_element, undef, ['y', 'x', []]]),
204 {}, 'simple children match works');
206 # test placeholder
207 cmp_deeply(extract([save("element"), undef, undef],
208 [[$NS_CLIENT, 'message'],
210 []]),
211 {element => [$NS_CLIENT, 'message']},
212 'non-recursive placeholder works');
214 # test sub placeholder
215 cmp_deeply(extract([save_sub('element',
216 sub { my $x = shift; $x->[0] .=
217 'eee'; return $x; }),
218 undef, undef],
219 [[$NS_CLIENT, 'message'], {}, []]),
220 {element => [$NS_CLIENT.'eee', 'message']},
221 'extracting with sub processing works.');
223 # test match placeholder
224 cmp_deeply(extract([[$NS_CLIENT, 'message'],
225 undef, save_match([[$NS_CLIENT, 'body'],
226 undef, save('body')])],
227 [[$NS_CLIENT, 'message'],
228 {}, [' ',
229 [[$NS_CLIENT, 'body'], {},
230 ['hizzle']],
231 'schmoo']
233 {body => 'hizzle'},
234 'extracting submatches works as expected');
236 # test take
237 # simply doesn't die
238 extract([take('element'), undef, undef],
239 [[$NS_CLIENT, 'message'], {}, []],
240 {element => [$NS_CLIENT, 'message']});
242 extract([[$NS_COMPONENT, 'handshake'], {}, []],
243 [[$NS_COMPONENT, 'handshake'], {}, []]);
245 dies {
246 extract([take('element'), undef, undef],
247 [[$NS_CLIENT, 'notamessage'], {}, []],
248 {element => [$NS_CLIENT, 'message']});
249 } 'Can pass in stuff to fill in placeholders.';
251 extract([undef, {test => save('x', 1)}, undef],
252 [[$NS_COMPONENT, 'test'], {}, []]);
253 pass("Saving can be optional.");
255 extract([undef, undef, save_match('x', [undef, {x => 1}, []], 1)],
256 [[$NS_COMPONENT, 'test'], {}, []]);
257 pass("save_matching can be optional");
259 # Recursive extracting: test that recursive extraction works as
260 # intended
261 my $XML = [[$NS_COMPONENT, 'top'], {},
262 [[[$NS_COMPONENT, 'middle'], {'{}x' => 1},
263 [[[$NS_COMPONENT, 'bottom'], {}, []]]]]];
264 my $results = recursive_extract
265 ($XML,
266 [[undef, 'top'], undef, save_match('rec', [[undef, 'middle']])],
267 [undef, {x => save('moo')}, save_match('rec', [[undef, 'bottom']])]
269 is($results->{moo}, 1, 'found the attribute');
270 is($results->{rec}->[0]->[1], 'bottom',
271 'recurses as expected');
274 # These are packets that we encountered during testing that
275 # weren't handled correctly
276 REAL_WORLD_TESTS: {
277 # This is a message with typing notifications before the body,
278 # where the body is the word "menu", along with the XHTML.
279 my $message_with_typing = [
280 ['jabber:component:accept', 'message'],
282 '{}type' => 'chat',
283 '{}id' => 'purplea511de5f',
284 '{}from' => 'jbowers@barracudanetworks.com/Kopete',
285 '{}to' => 'gossipingabby@aim.transport'
288 [['jabber:x:event', 'x'],
291 [['jabber:x:event', 'composing'],
298 ['jabber:component:accept', 'body'],
300 ['menu']
303 ['http://jabber.org/protocol/xhtml-im', 'html'],
306 [['http://www.w3.org/1999/xhtml', 'body'],
308 ['menu']
315 my $match = [[$NS_COMPONENT, 'message'],
316 {to => save("to"),
317 from => save("from"),
318 type => save("type")},
319 save_match('body',
320 [[undef, 'body'], undef, undef])];
322 my $result = extract($match, $message_with_typing);
323 cmp_deeply($result->{body},
324 [['jabber:component:accept', 'body'],
325 {}, ['menu']],
326 "body can be extracted even when not first");
328 my $file_tag =
331 'http://jabber.org/protocol/si/profile/file-transfer',
332 'file'
335 '{}size' => '3684376',
336 '{}name' => 'aim.capture.pkts'
339 ' ',
342 'http://jabber.org/protocol/si/profile/file-transfer',
343 'desc'
347 'oeioei'
350 ' ',
353 'http://jabber.org/protocol/si/profile/file-transfer',
354 'range'
363 $result = recursive_extract
364 ($file_tag,
365 [undef, undef,
366 save_match('rec', [[undef, 'desc'], undef, undef])],
368 [undef, undef, save_sub('desc', \&text_extractor)]);
370 cmp_deeply($result->{desc}, ['oeioei']);