Rename to slixmpp
[slixmpp.git] / tests / test_stream_xep_0050.py
blob222e997e3214e68b177c89c96b1f868e328f4efb
1 import time
2 import logging
4 import unittest
5 from slixmpp.test import SlixTest
6 from slixmpp.xmlstream import ElementBase, register_stanza_plugin
9 class TestAdHocCommands(SlixTest):
11 def setUp(self):
12 self.stream_start(mode='client',
13 plugins=['xep_0030', 'xep_0004', 'xep_0050'])
15 # Real session IDs don't make for nice tests, so use
16 # a dummy value.
17 self.xmpp['xep_0050'].new_session = lambda: '_sessionid_'
19 def tearDown(self):
20 self.stream_close()
22 def testInitialPayloadCommand(self):
23 """Test a command with an initial payload."""
25 class TestPayload(ElementBase):
26 name = 'foo'
27 namespace = 'test'
28 interfaces = set(['bar'])
29 plugin_attrib = name
31 Command = self.xmpp['xep_0050'].stanza.Command
32 register_stanza_plugin(Command, TestPayload, iterable=True)
34 def handle_command(iq, session):
35 initial = session['payload']
36 logging.debug(initial)
37 new_payload = TestPayload()
38 if initial:
39 new_payload['bar'] = 'Received: %s' % initial['bar']
40 else:
41 new_payload['bar'] = 'Failed'
43 logging.debug(initial)
45 session['payload'] = new_payload
46 session['next'] = None
47 session['has_next'] = False
49 return session
51 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
52 'Do Foo', handle_command)
54 self.recv("""
55 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
56 <command xmlns="http://jabber.org/protocol/commands"
57 node="foo"
58 action="execute">
59 <foo xmlns="test" bar="baz" />
60 </command>
61 </iq>
62 """)
64 self.send("""
65 <iq id="11" type="result" to="foo@bar">
66 <command xmlns="http://jabber.org/protocol/commands"
67 node="foo"
68 status="completed"
69 sessionid="_sessionid_">
70 <foo xmlns="test" bar="Received: baz" />
71 </command>
72 </iq>
73 """)
75 def testZeroStepCommand(self):
76 """Test running a command with no steps."""
78 def handle_command(iq, session):
79 form = self.xmpp['xep_0004'].makeForm(ftype='result')
80 form.addField(var='foo', ftype='text-single',
81 label='Foo', value='bar')
83 session['payload'] = form
84 session['next'] = None
85 session['has_next'] = False
87 return session
89 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
90 'Do Foo', handle_command)
92 self.recv("""
93 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
94 <command xmlns="http://jabber.org/protocol/commands"
95 node="foo"
96 action="execute" />
97 </iq>
98 """)
100 self.send("""
101 <iq id="11" type="result" to="foo@bar">
102 <command xmlns="http://jabber.org/protocol/commands"
103 node="foo"
104 status="completed"
105 sessionid="_sessionid_">
106 <x xmlns="jabber:x:data" type="result">
107 <field var="foo" label="Foo" type="text-single">
108 <value>bar</value>
109 </field>
110 </x>
111 </command>
112 </iq>
113 """)
115 def testOneStepCommand(self):
116 """Test running a single step command."""
117 results = []
119 def handle_command(iq, session):
121 def handle_form(form, session):
122 results.append(form['values']['foo'])
124 form = self.xmpp['xep_0004'].makeForm('form')
125 form.addField(var='foo', ftype='text-single', label='Foo')
127 session['payload'] = form
128 session['next'] = handle_form
129 session['has_next'] = False
131 return session
133 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
134 'Do Foo', handle_command)
136 self.recv("""
137 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
138 <command xmlns="http://jabber.org/protocol/commands"
139 node="foo"
140 action="execute" />
141 </iq>
142 """)
144 self.send("""
145 <iq id="11" type="result" to="foo@bar">
146 <command xmlns="http://jabber.org/protocol/commands"
147 node="foo"
148 status="executing"
149 sessionid="_sessionid_">
150 <actions>
151 <complete />
152 </actions>
153 <x xmlns="jabber:x:data" type="form">
154 <field var="foo" label="Foo" type="text-single" />
155 </x>
156 </command>
157 </iq>
158 """)
160 self.recv("""
161 <iq id="12" type="set" to="tester@localhost" from="foo@bar">
162 <command xmlns="http://jabber.org/protocol/commands"
163 node="foo"
164 action="complete"
165 sessionid="_sessionid_">
166 <x xmlns="jabber:x:data" type="submit">
167 <field var="foo" label="Foo" type="text-single">
168 <value>blah</value>
169 </field>
170 </x>
171 </command>
172 </iq>
173 """)
175 self.send("""
176 <iq id="12" type="result" to="foo@bar">
177 <command xmlns="http://jabber.org/protocol/commands"
178 node="foo"
179 status="completed"
180 sessionid="_sessionid_" />
181 </iq>
182 """)
184 self.assertEqual(results, ['blah'],
185 "Command handler was not executed: %s" % results)
187 def testTwoStepCommand(self):
188 """Test using a two-stage command."""
189 results = []
191 def handle_command(iq, session):
193 def handle_step2(form, session):
194 results.append(form['values']['bar'])
196 def handle_step1(form, session):
197 results.append(form['values']['foo'])
199 form = self.xmpp['xep_0004'].makeForm('form')
200 form.addField(var='bar', ftype='text-single', label='Bar')
202 session['payload'] = form
203 session['next'] = handle_step2
204 session['has_next'] = False
206 return session
208 form = self.xmpp['xep_0004'].makeForm('form')
209 form.addField(var='foo', ftype='text-single', label='Foo')
211 session['payload'] = form
212 session['next'] = handle_step1
213 session['has_next'] = True
215 return session
217 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
218 'Do Foo', handle_command)
220 self.recv("""
221 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
222 <command xmlns="http://jabber.org/protocol/commands"
223 node="foo"
224 action="execute" />
225 </iq>
226 """)
228 self.send("""
229 <iq id="11" type="result" to="foo@bar">
230 <command xmlns="http://jabber.org/protocol/commands"
231 node="foo"
232 status="executing"
233 sessionid="_sessionid_">
234 <actions>
235 <next />
236 </actions>
237 <x xmlns="jabber:x:data" type="form">
238 <field var="foo" label="Foo" type="text-single" />
239 </x>
240 </command>
241 </iq>
242 """)
244 self.recv("""
245 <iq id="12" type="set" to="tester@localhost" from="foo@bar">
246 <command xmlns="http://jabber.org/protocol/commands"
247 node="foo"
248 action="next"
249 sessionid="_sessionid_">
250 <x xmlns="jabber:x:data" type="submit">
251 <field var="foo" label="Foo" type="text-single">
252 <value>blah</value>
253 </field>
254 </x>
255 </command>
256 </iq>
257 """)
259 self.send("""
260 <iq id="12" type="result" to="foo@bar">
261 <command xmlns="http://jabber.org/protocol/commands"
262 node="foo"
263 status="executing"
264 sessionid="_sessionid_">
265 <actions>
266 <complete />
267 </actions>
268 <x xmlns="jabber:x:data" type="form">
269 <field var="bar" label="Bar" type="text-single" />
270 </x>
271 </command>
272 </iq>
273 """)
275 self.recv("""
276 <iq id="13" type="set" to="tester@localhost" from="foo@bar">
277 <command xmlns="http://jabber.org/protocol/commands"
278 node="foo"
279 action="complete"
280 sessionid="_sessionid_">
281 <x xmlns="jabber:x:data" type="submit">
282 <field var="bar" label="Bar" type="text-single">
283 <value>meh</value>
284 </field>
285 </x>
286 </command>
287 </iq>
288 """)
289 self.send("""
290 <iq id="13" type="result" to="foo@bar">
291 <command xmlns="http://jabber.org/protocol/commands"
292 node="foo"
293 status="completed"
294 sessionid="_sessionid_" />
295 </iq>
296 """)
298 self.assertEqual(results, ['blah', 'meh'],
299 "Command handler was not executed: %s" % results)
301 def testCancelCommand(self):
302 """Test canceling command."""
303 results = []
305 def handle_command(iq, session):
307 def handle_form(form, session):
308 results.append(form['values']['foo'])
310 def handle_cancel(iq, session):
311 results.append('canceled')
313 form = self.xmpp['xep_0004'].makeForm('form')
314 form.addField(var='foo', ftype='text-single', label='Foo')
316 session['payload'] = form
317 session['next'] = handle_form
318 session['cancel'] = handle_cancel
319 session['has_next'] = False
321 return session
323 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
324 'Do Foo', handle_command)
326 self.recv("""
327 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
328 <command xmlns="http://jabber.org/protocol/commands"
329 node="foo"
330 action="execute" />
331 </iq>
332 """)
334 self.send("""
335 <iq id="11" type="result" to="foo@bar">
336 <command xmlns="http://jabber.org/protocol/commands"
337 node="foo"
338 status="executing"
339 sessionid="_sessionid_">
340 <actions>
341 <complete />
342 </actions>
343 <x xmlns="jabber:x:data" type="form">
344 <field var="foo" label="Foo" type="text-single" />
345 </x>
346 </command>
347 </iq>
348 """)
350 self.recv("""
351 <iq id="12" type="set" to="tester@localhost" from="foo@bar">
352 <command xmlns="http://jabber.org/protocol/commands"
353 node="foo"
354 action="cancel"
355 sessionid="_sessionid_">
356 <x xmlns="jabber:x:data" type="submit">
357 <field var="foo" label="Foo" type="text-single">
358 <value>blah</value>
359 </field>
360 </x>
361 </command>
362 </iq>
363 """)
365 self.send("""
366 <iq id="12" type="result" to="foo@bar">
367 <command xmlns="http://jabber.org/protocol/commands"
368 node="foo"
369 status="canceled"
370 sessionid="_sessionid_" />
371 </iq>
372 """)
374 self.assertEqual(results, ['canceled'],
375 "Cancelation handler not executed: %s" % results)
377 def testCommandNote(self):
378 """Test adding notes to commands."""
380 def handle_command(iq, session):
381 form = self.xmpp['xep_0004'].makeForm(ftype='result')
382 form.addField(var='foo', ftype='text-single',
383 label='Foo', value='bar')
385 session['payload'] = form
386 session['next'] = None
387 session['has_next'] = False
388 session['notes'] = [('info', 'testing notes')]
390 return session
392 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
393 'Do Foo', handle_command)
395 self.recv("""
396 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
397 <command xmlns="http://jabber.org/protocol/commands"
398 node="foo"
399 action="execute" />
400 </iq>
401 """)
403 self.send("""
404 <iq id="11" type="result" to="foo@bar">
405 <command xmlns="http://jabber.org/protocol/commands"
406 node="foo"
407 status="completed"
408 sessionid="_sessionid_">
409 <note type="info">testing notes</note>
410 <x xmlns="jabber:x:data" type="result">
411 <field var="foo" label="Foo" type="text-single">
412 <value>bar</value>
413 </field>
414 </x>
415 </command>
416 </iq>
417 """)
421 def testMultiPayloads(self):
422 """Test using commands with multiple payloads."""
423 results = []
425 def handle_command(iq, session):
427 def handle_form(forms, session):
428 for form in forms:
429 results.append(form['values']['FORM_TYPE'])
431 form1 = self.xmpp['xep_0004'].makeForm('form')
432 form1.addField(var='FORM_TYPE', ftype='hidden', value='form_1')
433 form1.addField(var='foo', ftype='text-single', label='Foo')
435 form2 = self.xmpp['xep_0004'].makeForm('form')
436 form2.addField(var='FORM_TYPE', ftype='hidden', value='form_2')
437 form2.addField(var='foo', ftype='text-single', label='Foo')
439 session['payload'] = [form1, form2]
440 session['next'] = handle_form
441 session['has_next'] = False
443 return session
445 self.xmpp['xep_0050'].add_command('tester@localhost', 'foo',
446 'Do Foo', handle_command)
448 self.recv("""
449 <iq id="11" type="set" to="tester@localhost" from="foo@bar">
450 <command xmlns="http://jabber.org/protocol/commands"
451 node="foo"
452 action="execute" />
453 </iq>
454 """)
456 self.send("""
457 <iq id="11" type="result" to="foo@bar">
458 <command xmlns="http://jabber.org/protocol/commands"
459 node="foo"
460 status="executing"
461 sessionid="_sessionid_">
462 <actions>
463 <complete />
464 </actions>
465 <x xmlns="jabber:x:data" type="form">
466 <field var="FORM_TYPE" type="hidden">
467 <value>form_1</value>
468 </field>
469 <field var="foo" label="Foo" type="text-single" />
470 </x>
471 <x xmlns="jabber:x:data" type="form">
472 <field var="FORM_TYPE" type="hidden">
473 <value>form_2</value>
474 </field>
475 <field var="foo" label="Foo" type="text-single" />
476 </x>
477 </command>
478 </iq>
479 """)
481 self.recv("""
482 <iq id="12" type="set" to="tester@localhost" from="foo@bar">
483 <command xmlns="http://jabber.org/protocol/commands"
484 node="foo"
485 action="complete"
486 sessionid="_sessionid_">
487 <x xmlns="jabber:x:data" type="submit">
488 <field var="FORM_TYPE" type="hidden">
489 <value>form_1</value>
490 </field>
491 <field var="foo" type="text-single">
492 <value>bar</value>
493 </field>
494 </x>
495 <x xmlns="jabber:x:data" type="submit">
496 <field var="FORM_TYPE" type="hidden">
497 <value>form_2</value>
498 </field>
499 <field var="foo" type="text-single">
500 <value>bar</value>
501 </field>
502 </x>
503 </command>
504 </iq>
505 """)
507 self.send("""
508 <iq id="12" type="result" to="foo@bar">
509 <command xmlns="http://jabber.org/protocol/commands"
510 node="foo"
511 status="completed"
512 sessionid="_sessionid_" />
513 </iq>
514 """)
516 self.assertEqual(results, [['form_1'], ['form_2']],
517 "Command handler was not executed: %s" % results)
519 def testClientAPI(self):
520 """Test using client-side API for commands."""
521 results = []
523 def handle_complete(iq, session):
524 for item in session['custom_data']:
525 results.append(item)
527 def handle_step2(iq, session):
528 form = self.xmpp['xep_0004'].makeForm(ftype='submit')
529 form.addField(var='bar', value='123')
531 session['custom_data'].append('baz')
532 session['payload'] = form
533 session['next'] = handle_complete
534 self.xmpp['xep_0050'].complete_command(session)
536 def handle_step1(iq, session):
537 form = self.xmpp['xep_0004'].makeForm(ftype='submit')
538 form.addField(var='foo', value='42')
540 session['custom_data'].append('bar')
541 session['payload'] = form
542 session['next'] = handle_step2
543 self.xmpp['xep_0050'].continue_command(session)
545 session = {'custom_data': ['foo'],
546 'next': handle_step1}
548 self.xmpp['xep_0050'].start_command(
549 'foo@example.com',
550 'test_client',
551 session)
553 self.send("""
554 <iq id="1" to="foo@example.com" type="set">
555 <command xmlns="http://jabber.org/protocol/commands"
556 node="test_client"
557 action="execute" />
558 </iq>
559 """)
561 self.recv("""
562 <iq id="1" from="foo@example.com" type="result">
563 <command xmlns="http://jabber.org/protocol/commands"
564 node="test_client"
565 sessionid="_sessionid_"
566 status="executing">
567 <x xmlns="jabber:x:data" type="form">
568 <field var="foo" type="text-single" />
569 </x>
570 </command>
571 </iq>
572 """)
574 self.send("""
575 <iq id="2" to="foo@example.com" type="set">
576 <command xmlns="http://jabber.org/protocol/commands"
577 node="test_client"
578 sessionid="_sessionid_"
579 action="next">
580 <x xmlns="jabber:x:data" type="submit">
581 <field var="foo">
582 <value>42</value>
583 </field>
584 </x>
585 </command>
586 </iq>
587 """)
589 self.recv("""
590 <iq id="2" from="foo@example.com" type="result">
591 <command xmlns="http://jabber.org/protocol/commands"
592 node="test_client"
593 sessionid="_sessionid_"
594 status="executing">
595 <x xmlns="jabber:x:data" type="form">
596 <field var="bar" type="text-single" />
597 </x>
598 </command>
599 </iq>
600 """)
602 self.send("""
603 <iq id="3" to="foo@example.com" type="set">
604 <command xmlns="http://jabber.org/protocol/commands"
605 node="test_client"
606 sessionid="_sessionid_"
607 action="complete">
608 <x xmlns="jabber:x:data" type="submit">
609 <field var="bar">
610 <value>123</value>
611 </field>
612 </x>
613 </command>
614 </iq>
615 """)
617 self.recv("""
618 <iq id="3" from="foo@example.com" type="result">
619 <command xmlns="http://jabber.org/protocol/commands"
620 node="test_client"
621 sessionid="_sessionid_"
622 status="completed" />
623 </iq>
624 """)
626 # Give the event queue time to process
627 time.sleep(0.3)
629 self.failUnless(results == ['foo', 'bar', 'baz'],
630 'Incomplete command workflow: %s' % results)
632 def testClientAPICancel(self):
633 """Test using client-side cancel API for commands."""
634 results = []
636 def handle_canceled(iq, session):
637 for item in session['custom_data']:
638 results.append(item)
640 def handle_step1(iq, session):
641 session['custom_data'].append('bar')
642 session['next'] = handle_canceled
643 self.xmpp['xep_0050'].cancel_command(session)
645 session = {'custom_data': ['foo'],
646 'next': handle_step1}
648 self.xmpp['xep_0050'].start_command(
649 'foo@example.com',
650 'test_client',
651 session)
653 self.send("""
654 <iq id="1" to="foo@example.com" type="set">
655 <command xmlns="http://jabber.org/protocol/commands"
656 node="test_client"
657 action="execute" />
658 </iq>
659 """)
661 self.recv("""
662 <iq id="1" to="foo@example.com" type="result">
663 <command xmlns="http://jabber.org/protocol/commands"
664 node="test_client"
665 sessionid="_sessionid_"
666 status="executing">
667 <x xmlns="jabber:x:data" type="form">
668 <field var="foo" type="text-single" />
669 </x>
670 </command>
671 </iq>
672 """)
674 self.send("""
675 <iq id="2" to="foo@example.com" type="set">
676 <command xmlns="http://jabber.org/protocol/commands"
677 node="test_client"
678 sessionid="_sessionid_"
679 action="cancel" />
680 </iq>
681 """)
683 self.recv("""
684 <iq id="2" to="foo@example.com" type="result">
685 <command xmlns="http://jabber.org/protocol/commands"
686 node="test_client"
687 sessionid="_sessionid_"
688 status="canceled" />
689 </iq>
690 """)
692 # Give the event queue time to process
693 time.sleep(0.3)
695 self.failUnless(results == ['foo', 'bar'],
696 'Incomplete command workflow: %s' % results)
698 def testClientAPIError(self):
699 """Test using client-side error API for commands."""
700 results = []
702 def handle_error(iq, session):
703 for item in session['custom_data']:
704 results.append(item)
706 session = {'custom_data': ['foo'],
707 'error': handle_error}
709 self.xmpp['xep_0050'].start_command(
710 'foo@example.com',
711 'test_client',
712 session)
714 self.send("""
715 <iq id="1" to="foo@example.com" type="set">
716 <command xmlns="http://jabber.org/protocol/commands"
717 node="test_client"
718 action="execute" />
719 </iq>
720 """)
722 self.recv("""
723 <iq id="1" to="foo@example.com" type="error">
724 <command xmlns="http://jabber.org/protocol/commands"
725 node="test_client"
726 action="execute" />
727 <error type='cancel'>
728 <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
729 </error>
730 </iq>
731 """)
733 # Give the event queue time to process
734 time.sleep(0.3)
736 self.failUnless(results == ['foo'],
737 'Incomplete command workflow: %s' % results)
739 def testClientAPIErrorStrippedResponse(self):
740 """Test errors that don't include the command substanza."""
741 results = []
743 def handle_error(iq, session):
744 for item in session['custom_data']:
745 results.append(item)
747 session = {'custom_data': ['foo'],
748 'error': handle_error}
750 self.xmpp['xep_0050'].start_command(
751 'foo@example.com',
752 'test_client',
753 session)
755 self.send("""
756 <iq id="1" to="foo@example.com" type="set">
757 <command xmlns="http://jabber.org/protocol/commands"
758 node="test_client"
759 action="execute" />
760 </iq>
761 """)
763 self.recv("""
764 <iq id="1" to="foo@example.com" type="error">
765 <error type='cancel'>
766 <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' />
767 </error>
768 </iq>
769 """)
771 # Give the event queue time to process
772 time.sleep(0.3)
774 self.failUnless(results == ['foo'],
775 'Incomplete command workflow: %s' % results)
781 suite = unittest.TestLoader().loadTestsFromTestCase(TestAdHocCommands)