1# -*- coding: utf-8 -*-
2
3import sys
4import datetime
5import time
6import threading
7import unittest
8import re
9
10from slixmpp.test import *
11from slixmpp.xmlstream import ElementBase
12from slixmpp.plugins.xep_0323.device import Device
13
14
15@unittest.skip('')
16class TestStreamSensorData(SlixTest):
17
18    """
19    Test using the XEP-0323 plugin.
20    """
21    def setUp(self):
22        pass
23
24    def _time_now(self):
25        return datetime.datetime.now().replace(microsecond=0).isoformat()
26
27    def tearDown(self):
28        self.stream_close()
29
30    def testRequestAccept(self):
31        self.stream_start(mode='component',
32                          plugins=['xep_0030',
33                                   'xep_0323'])
34
35        myDevice = Device("Device22")
36        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
37        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
38        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
39
40        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
41
42        self.recv("""
43            <iq type='get'
44                from='master@clayster.com/amr'
45                to='device@clayster.com'
46                id='1'>
47                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'/>
48            </iq>
49        """)
50
51        self.send("""
52            <iq type='result'
53                from='device@clayster.com'
54                to='master@clayster.com/amr'
55                id='1'>
56                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
57            </iq>
58            """)
59
60        self.send("""
61            <message from='device@clayster.com'
62                     to='master@clayster.com/amr'>
63                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
64                    <node nodeId='Device22'>
65                        <timestamp value='2013-03-07T16:24:30'>
66                            <numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
67                        </timestamp>
68                    </node>
69                </fields>
70            </message>
71            """)
72
73    def testRequestRejectAuth(self):
74
75        self.stream_start(mode='component',
76                          plugins=['xep_0030',
77                                   'xep_0323'])
78
79        self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com")
80
81        self.recv("""
82            <iq type='get'
83                from='master@clayster.com/amr'
84                to='device@clayster.com'
85                id='4'>
86                <req xmlns='urn:xmpp:iot:sensordata' seqnr='5' momentary='true'/>
87            </iq>
88        """)
89
90        self.send("""
91            <iq type='error'
92                from='device@clayster.com'
93                to='master@clayster.com/amr'
94                id='4'>
95                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='5'>
96                    <error>Access denied</error>
97                </rejected>
98            </iq>
99            """)
100
101    def testRequestNode(self):
102
103        self.stream_start(mode='component',
104                          plugins=['xep_0030',
105                                   'xep_0323'])
106
107        myDevice = Device("Device44")
108        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
109
110        print("."),
111
112        self.recv("""
113            <iq type='get'
114                from='master@clayster.com/amr'
115                to='device@clayster.com'
116                id='77'>
117                <req xmlns='urn:xmpp:iot:sensordata' seqnr='66' momentary='true'>
118                    <node nodeId='Device33'/>
119                </req>
120            </iq>
121        """)
122
123        self.send("""
124            <iq type='error'
125                from='device@clayster.com'
126                to='master@clayster.com/amr'
127                id='77'>
128                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='66'>
129                    <error>Invalid nodeId Device33</error>
130                </rejected>
131            </iq>
132            """)
133
134        print("."),
135
136        self.recv("""
137            <iq type='get'
138                from='master@clayster.com/amr'
139                to='device@clayster.com'
140                id='8'>
141                <req xmlns='urn:xmpp:iot:sensordata' seqnr='7' momentary='true'>
142                    <node nodeId='Device44'/>
143                </req>
144            </iq>
145        """)
146
147        self.send("""
148            <iq type='result'
149                from='device@clayster.com'
150                to='master@clayster.com/amr'
151                id='8'>
152                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
153            </iq>
154            """)
155
156
157    def testRequestField(self):
158
159        self.stream_start(mode='component',
160                          plugins=['xep_0030',
161                                   'xep_0323'])
162
163        myDevice = Device("Device44")
164        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
165        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
166
167        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
168
169        print("."),
170
171        self.recv("""
172            <iq type='get'
173                from='master@clayster.com/amr'
174                to='device@clayster.com'
175                id='7'>
176                <req xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
177                    <field name='Current'/>
178                </req>
179            </iq>
180        """)
181
182        self.send("""
183            <iq type='error'
184                from='device@clayster.com'
185                to='master@clayster.com/amr'
186                id='7'>
187                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
188                    <error>Invalid field Current</error>
189                </rejected>
190            </iq>
191            """)
192
193        print("."),
194
195        self.recv("""
196            <iq type='get'
197                from='master@clayster.com/amr'
198                to='device@clayster.com'
199                id='8'>
200                <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
201                    <field name='Voltage'/>
202                </req>
203            </iq>
204        """)
205
206        self.send("""
207            <iq type='result'
208                from='device@clayster.com'
209                to='master@clayster.com/amr'
210                id='8'>
211                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
212            </iq>
213            """)
214
215        self.send("""
216            <message from='device@clayster.com'
217                     to='master@clayster.com/amr'>
218                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
219                    <node nodeId='Device44'>
220                        <timestamp value='2000-01-01T00:01:02'>
221                            <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
222                        </timestamp>
223                    </node>
224                </fields>
225            </message>
226            """)
227
228        self.send("""
229            <message from='device@clayster.com'
230                     to='master@clayster.com/amr'>
231                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
232                </fields>
233            </message>
234            """)
235
236    def testRequestMultiTimestampSingleField(self):
237
238        self.stream_start(mode='component',
239                          plugins=['xep_0030',
240                                   'xep_0323'])
241
242        myDevice = Device("Device44")
243        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
244        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
245        myDevice._add_field(name='Current', typename="numeric", unit="A")
246        myDevice._add_field(name='Height', typename="string")
247        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
248        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
249
250        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
251
252        print("."),
253
254        self.recv("""
255            <iq type='get'
256                from='master@clayster.com/amr'
257                to='device@clayster.com'
258                id='8'>
259                <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
260                    <field name='Voltage'/>
261                </req>
262            </iq>
263        """)
264
265        self.send("""
266            <iq type='result'
267                from='device@clayster.com'
268                to='master@clayster.com/amr'
269                id='8'>
270                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
271            </iq>
272            """)
273
274        self.send("""
275            <message from='device@clayster.com'
276                     to='master@clayster.com/amr'>
277                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
278                    <node nodeId='Device44'>
279                        <timestamp value='2000-01-01T00:01:02'>
280                            <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
281                        </timestamp>
282                    </node>
283                </fields>
284            </message>
285            """)
286
287        self.send("""
288            <message from='device@clayster.com'
289                     to='master@clayster.com/amr'>
290                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
291                    <node nodeId='Device44'>
292                        <timestamp value='2000-01-01T01:01:02'>
293                            <numeric name='Voltage' value='230.6' unit='V'/>
294                        </timestamp>
295                    </node>
296                </fields>
297            </message>
298            """)
299
300        self.send("""
301            <message from='device@clayster.com'
302                     to='master@clayster.com/amr'>
303                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
304                </fields>
305            </message>
306            """)
307
308    def testRequestMultiTimestampAllFields(self):
309
310        self.stream_start(mode='component',
311                          plugins=['xep_0030',
312                                   'xep_0323'])
313
314        myDevice = Device("Device44")
315        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
316        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
317        myDevice._add_field(name='Current', typename="numeric", unit="A")
318        myDevice._add_field(name='Height', typename="string")
319        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
320        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
321
322        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
323
324        print("."),
325
326        self.recv("""
327            <iq type='get'
328                from='master@clayster.com/amr'
329                to='device@clayster.com'
330                id='8'>
331                <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
332            </iq>
333        """)
334
335        self.send("""
336            <iq type='result'
337                from='device@clayster.com'
338                to='master@clayster.com/amr'
339                id='8'>
340                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
341            </iq>
342            """)
343
344        self.send("""
345            <message from='device@clayster.com'
346                     to='master@clayster.com/amr'>
347                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
348                    <node nodeId='Device44'>
349                        <timestamp value='2000-01-01T00:01:02'>
350                            <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
351                        </timestamp>
352                    </node>
353                </fields>
354            </message>
355            """)
356
357        self.send("""
358            <message from='device@clayster.com'
359                     to='master@clayster.com/amr'>
360                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
361                    <node nodeId='Device44'>
362                        <timestamp value='2000-01-01T01:01:02'>
363                            <numeric name='Voltage' value='230.6' unit='V'/>
364                            <string name='Height' invoiced='true' value='115 m'/>
365                        </timestamp>
366                    </node>
367                </fields>
368            </message>
369            """)
370
371        self.send("""
372            <message from='device@clayster.com'
373                     to='master@clayster.com/amr'>
374                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
375                </fields>
376            </message>
377            """)
378
379    def testRequestAPI(self):
380
381        self.stream_start(mode='client',
382                          plugins=['xep_0030',
383                                   'xep_0323'])
384
385        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None)
386
387        self.send("""
388            <iq type='get'
389                from='tester@localhost'
390                to='you@google.com'
391                id='1'>
392                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
393            </iq>
394            """)
395
396        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None)
397
398        self.send("""
399            <iq type='get'
400                from='tester@localhost'
401                to='you@google.com'
402                id='2'>
403                <req xmlns='urn:xmpp:iot:sensordata' seqnr='2'>
404                    <node nodeId="Device33"/>
405                    <node nodeId="Device22"/>
406                </req>
407            </iq>
408            """)
409
410        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None)
411
412        self.send("""
413            <iq type='get'
414                from='tester@localhost'
415                to='you@google.com'
416                id='3'>
417                <req xmlns='urn:xmpp:iot:sensordata' seqnr='3'>
418                    <field name="Temperature"/>
419                    <field name="Voltage"/>
420                </req>
421            </iq>
422            """)
423
424    def testRequestRejectAPI(self):
425
426        self.stream_start(mode='client',
427                          plugins=['xep_0030',
428                                   'xep_0323'])
429
430        results = []
431
432        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
433            if (result == "rejected") and (error_msg == "Invalid device Device22"):
434                results.append("rejected")
435
436        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
437
438        self.send("""
439            <iq type='get'
440                from='tester@localhost'
441                to='you@google.com'
442                id='1'>
443                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
444                    <node nodeId="Device33"/>
445                    <node nodeId="Device22"/>
446                </req>
447            </iq>
448            """)
449
450        self.recv("""
451            <iq type='error'
452                from='you@google.com'
453                to='tester@localhost'
454                id='1'>
455                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
456                    <error>Invalid device Device22</error>
457                </rejected>
458            </iq>
459            """)
460
461        self.assertTrue(results == ["rejected"],
462                "Rejected callback was not properly executed")
463
464    def testRequestAcceptedAPI(self):
465
466        self.stream_start(mode='client',
467                          plugins=['xep_0030',
468                                   'xep_0323'])
469
470        results = []
471
472        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
473            results.append(result)
474
475        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
476
477        self.send("""
478            <iq type='get'
479                from='tester@localhost'
480                to='you@google.com'
481                id='1'>
482                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
483                    <node nodeId="Device33"/>
484                    <node nodeId="Device22"/>
485                </req>
486            </iq>
487            """)
488
489        self.recv("""
490            <iq type='result'
491                from='you@google.com'
492                to='tester@localhost'
493                id='1'>
494                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
495            </iq>
496            """)
497
498        self.assertTrue(results == ["accepted"],
499                "Accepted callback was not properly executed")
500
501    def testRequestFieldsAPI(self):
502
503        self.stream_start(mode='client',
504                          plugins=['xep_0030',
505                                   'xep_0323'])
506
507        results = []
508        callback_data = {}
509
510        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
511            results.append(result)
512            if result == "fields":
513                callback_data["nodeId"] = nodeId
514                callback_data["timestamp"] = timestamp
515                callback_data["error_msg"] = error_msg
516                for f in fields:
517                    callback_data["field_" + f['name']] = f
518
519        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
520                                            to_jid="you@google.com",
521                                            nodeIds=['Device33'],
522                                            callback=my_callback)
523        #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
524
525        self.send("""
526            <iq type='get'
527                from='tester@localhost'
528                to='you@google.com'
529                id='1'>
530                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
531                    <node nodeId="Device33"/>
532                </req>
533            </iq>
534            """)
535
536        self.recv("""
537            <iq type='result'
538                from='you@google.com'
539                to='tester@localhost'
540                id='1'>
541                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
542            </iq>
543            """)
544
545        self.recv("""
546            <message from='you@google.com'
547                     to='tester@localhost'>
548                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
549                    <node nodeId='Device33'>
550                        <timestamp value='2000-01-01T00:01:02'>
551                            <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
552                            <boolean name='TestBool' value='true'/>
553                        </timestamp>
554                    </node>
555                </fields>
556            </message>
557            """)
558
559        self.recv("""
560            <message from='you@google.com'
561                     to='tester@localhost'>
562                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
563            </message>
564            """)
565
566        self.assertEqual(results, ["accepted","fields","done"])
567        # self.assertIn("nodeId", callback_data);
568        self.assertTrue("nodeId" in callback_data)
569        self.assertEqual(callback_data["nodeId"], "Device33")
570        # self.assertIn("timestamp", callback_data);
571        self.assertTrue("timestamp" in callback_data)
572        self.assertEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
573        #self.assertIn("field_Voltage", callback_data);
574        self.assertTrue("field_Voltage" in callback_data)
575        self.assertEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
576        #self.assertIn("field_TestBool", callback_data);
577        self.assertTrue("field_TestBool" in callback_data)
578        self.assertEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
579
580    def testServiceDiscoveryClient(self):
581        self.stream_start(mode='client',
582                          plugins=['xep_0030',
583                                   'xep_0323'])
584
585        self.recv("""
586        <iq type='get'
587                from='master@clayster.com/amr'
588                to='tester@localhost/resource'
589                id='disco1'>
590            <query xmlns='http://jabber.org/protocol/disco#info'/>
591        </iq>
592        """)
593
594        self.send("""
595        <iq type='result'
596            to='master@clayster.com/amr'
597            id='disco1'>
598            <query xmlns='http://jabber.org/protocol/disco#info'>
599                <identity category='client' type='bot'/>
600                <feature var='urn:xmpp:iot:sensordata'/>
601            </query>
602        </iq>
603        """)
604
605    def testServiceDiscoveryComponent(self):
606        self.stream_start(mode='component',
607                          plugins=['xep_0030',
608                                   'xep_0323'])
609
610        self.recv("""
611        <iq type='get'
612                from='master@clayster.com/amr'
613                to='tester@localhost/resource'
614                id='disco1'>
615            <query xmlns='http://jabber.org/protocol/disco#info'/>
616        </iq>
617        """)
618
619        self.send("""
620        <iq type='result'
621            from='tester@localhost/resource'
622            to='master@clayster.com/amr'
623            id='disco1'>
624            <query xmlns='http://jabber.org/protocol/disco#info'>
625                <identity category='component' type='generic'/>
626                <feature var='urn:xmpp:iot:sensordata'/>
627            </query>
628        </iq>
629        """)
630
631    def testRequestTimeout(self):
632
633        self.stream_start(mode='client',
634                          plugins=['xep_0030',
635                                   'xep_0323'])
636
637        results = []
638        callback_data = {}
639
640        def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
641            results.append(result)
642            if result == "failure":
643                callback_data["nodeId"] = nodeId
644                callback_data["timestamp"] = timestamp
645                callback_data["error_msg"] = error_msg
646
647        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
648                                           to_jid="you@google.com",
649                                           nodeIds=['Device33'],
650                                           callback=my_callback)
651        self.send("""
652            <iq type='get'
653                from='tester@localhost'
654                to='you@google.com'
655                id='1'>
656                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
657                    <node nodeId="Device33"/>
658                </req>
659            </iq>
660            """)
661
662        self.recv("""
663            <iq type='result'
664                from='you@google.com'
665                to='tester@localhost'
666                id='1'>
667                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
668            </iq>
669            """)
670
671        self.recv("""
672            <message from='you@google.com'
673                to='tester@localhost'>
674                <failure xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
675                    <error nodeId='Device33' timestamp='2013-03-07T17:13:30'>Timeout.</error>
676                </failure>
677            </message>
678            """)
679
680        self.assertEqual(results, ["accepted","failure"]);
681        # self.assertIn("nodeId", callback_data);
682        self.assertTrue("nodeId" in callback_data)
683        self.assertEqual(callback_data["nodeId"], "Device33")
684        # self.assertIn("timestamp", callback_data);
685        self.assertTrue("timestamp" in callback_data)
686        self.assertEqual(callback_data["timestamp"], "2013-03-07T17:13:30")
687        # self.assertIn("error_msg", callback_data);
688        self.assertTrue("error_msg" in callback_data)
689        self.assertEqual(callback_data["error_msg"], "Timeout.")
690
691    def testDelayedRequest(self):
692        self.stream_start(mode='component',
693                          plugins=['xep_0030',
694                                   'xep_0323'])
695
696        myDevice = Device("Device22")
697        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
698        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
699        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
700
701        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
702
703        dtnow = datetime.datetime.now()
704        ts_2sec = datetime.timedelta(0,2)
705        dtnow_plus_2sec = dtnow + ts_2sec
706        when_flag = dtnow_plus_2sec.replace(microsecond=0).isoformat()
707
708        self.recv("""
709            <iq type='get'
710                from='master@clayster.com/amr'
711                to='device@clayster.com'
712                id='1'>
713                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
714            </iq>
715        """)
716
717        self.send("""
718            <iq type='result'
719                from='device@clayster.com'
720                to='master@clayster.com/amr'
721                id='1'>
722                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true' />
723            </iq>
724            """)
725
726        time.sleep(1)
727
728        self.send("""
729            <message from='device@clayster.com'
730                     to='master@clayster.com/amr'>
731                <started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
732            </message>
733            """)
734
735        self.send("""
736            <message from='device@clayster.com'
737                     to='master@clayster.com/amr'>
738                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
739                    <node nodeId='Device22'>
740                        <timestamp value='2013-03-07T16:24:30'>
741                            <numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
742                        </timestamp>
743                    </node>
744                </fields>
745            </message>
746            """)
747
748    def testDelayedRequestFail(self):
749        self.stream_start(mode='component',
750                          plugins=['xep_0030',
751                                   'xep_0323'])
752
753        myDevice = Device("Device22")
754        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
755        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
756        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
757
758        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
759
760        dtnow = datetime.datetime.now()
761        ts_2sec = datetime.timedelta(0,2)
762        dtnow_minus_2sec = dtnow - ts_2sec
763        when_flag = dtnow_minus_2sec.replace(microsecond=0).isoformat()
764
765        self.recv("""
766            <iq type='get'
767                from='master@clayster.com/amr'
768                to='device@clayster.com'
769                id='1'>
770                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
771            </iq>
772        """)
773
774        # Remove the returned datetime to allow predictable test
775        xml_stanza = self._filtered_stanza_prepare()
776        error_text = xml_stanza['rejected']['error'] #['text']
777        error_text = re.sub(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-]\d{2}:\d{2})?', '…', error_text)
778        xml_stanza['rejected']['error'] = error_text
779
780        self._filtered_stanza_check("""
781            <iq type='error'
782                from='device@clayster.com'
783                to='master@clayster.com/amr'
784                id='1'>
785                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
786                    <error>Invalid datetime in 'when' flag, cannot set a time in the past (…). Current time: …</error>
787                </rejected>
788            </iq>
789            """, xml_stanza)
790
791
792    def _filtered_stanza_prepare(self, timeout=.5):
793        sent = self.xmpp.socket.next_sent(timeout)
794        if sent is None:
795            self.fail("No stanza was sent.")
796
797        xml = self.parse_xml(sent)
798        self.fix_namespaces(xml, 'jabber:client')
799        sent = self.xmpp._build_stanza(xml, 'jabber:client')
800        return sent
801
802    def _filtered_stanza_check(self, data, filtered, defaults=None, use_values=True, method='exact'):
803        self.check(filtered, data,
804                   method=method,
805                   defaults=defaults,
806                   use_values=use_values)
807
808    def testRequestFieldFrom(self):
809
810        self.stream_start(mode='component',
811                          plugins=['xep_0030',
812                                   'xep_0323'])
813
814        myDevice = Device("Device44")
815        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
816        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
817        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
818        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
819
820        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
821
822        print("."),
823
824        self.recv("""
825            <iq type='get'
826                from='master@clayster.com/amr'
827                to='device@clayster.com'
828                id='6'>
829                <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' from='2000-01-02T00:00:01'>
830                    <field name='Voltage'/>
831                </req>
832            </iq>
833        """)
834
835        self.send("""
836            <iq type='result'
837                from='device@clayster.com'
838                to='master@clayster.com/amr'
839                id='6'>
840                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
841            </iq>
842            """)
843
844        self.send("""
845            <message from='device@clayster.com'
846                     to='master@clayster.com/amr'>
847                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
848                    <node nodeId='Device44'>
849                        <timestamp value='2000-02-01T00:01:02'>
850                            <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
851                        </timestamp>
852                    </node>
853                </fields>
854            </message>
855            """)
856
857        self.send("""
858            <message from='device@clayster.com'
859                     to='master@clayster.com/amr'>
860                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
861                    <node nodeId='Device44'>
862                        <timestamp value='2000-03-01T00:01:02'>
863                            <numeric name='Voltage' invoiced='true' value='230.3' unit='V'/>
864                        </timestamp>
865                    </node>
866                </fields>
867            </message>
868            """)
869
870        self.send("""
871            <message from='device@clayster.com'
872                     to='master@clayster.com/amr'>
873                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
874                </fields>
875            </message>
876            """)
877
878    def testRequestFieldTo(self):
879
880        self.stream_start(mode='component',
881                          plugins=['xep_0030',
882                                   'xep_0323'])
883
884        myDevice = Device("Device44")
885        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
886        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
887        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
888        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
889
890        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
891
892        print("."),
893
894        self.recv("""
895            <iq type='get'
896                from='master@clayster.com/amr'
897                to='device@clayster.com'
898                id='6'>
899                <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' to='2000-02-02T00:00:01'>
900                    <field name='Voltage'/>
901                </req>
902            </iq>
903        """)
904
905        self.send("""
906            <iq type='result'
907                from='device@clayster.com'
908                to='master@clayster.com/amr'
909                id='6'>
910                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
911            </iq>
912            """)
913
914        self.send("""
915            <message from='device@clayster.com'
916                     to='master@clayster.com/amr'>
917                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
918                    <node nodeId='Device44'>
919                        <timestamp value='2000-01-01T00:01:02'>
920                            <numeric name='Voltage' invoiced='true' value='230.1' unit='V'/>
921                        </timestamp>
922                    </node>
923                </fields>
924            </message>
925            """)
926
927        self.send("""
928            <message from='device@clayster.com'
929                     to='master@clayster.com/amr'>
930                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
931                    <node nodeId='Device44'>
932                        <timestamp value='2000-02-01T00:01:02'>
933                            <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
934                        </timestamp>
935                    </node>
936                </fields>
937            </message>
938            """)
939
940        self.send("""
941            <message from='device@clayster.com'
942                     to='master@clayster.com/amr'>
943                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
944                </fields>
945            </message>
946            """)
947
948    def testRequestFieldFromTo(self):
949
950        self.stream_start(mode='component',
951                          plugins=['xep_0030',
952                                   'xep_0323'])
953
954        myDevice = Device("Device44")
955        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
956        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
957        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
958        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
959
960        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
961
962        print("."),
963
964        self.recv("""
965            <iq type='get'
966                from='master@clayster.com/amr'
967                to='device@clayster.com'
968                id='6'>
969                <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' from='2000-01-01T00:01:03' to='2000-02-02T00:00:01'>
970                    <field name='Voltage'/>
971                </req>
972            </iq>
973        """)
974
975        self.send("""
976            <iq type='result'
977                from='device@clayster.com'
978                to='master@clayster.com/amr'
979                id='6'>
980                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
981            </iq>
982            """)
983
984        self.send("""
985            <message from='device@clayster.com'
986                     to='master@clayster.com/amr'>
987                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
988                    <node nodeId='Device44'>
989                        <timestamp value='2000-02-01T00:01:02'>
990                            <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
991                        </timestamp>
992                    </node>
993                </fields>
994            </message>
995            """)
996
997        self.send("""
998            <message from='device@clayster.com'
999                     to='master@clayster.com/amr'>
1000                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
1001                </fields>
1002            </message>
1003            """)
1004
1005    def testDelayedRequestClient(self):
1006        self.stream_start(mode='client',
1007                          plugins=['xep_0030',
1008                                   'xep_0323'])
1009
1010        results = []
1011        callback_data = {}
1012
1013        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
1014            results.append(result)
1015            if result == "fields":
1016                callback_data["nodeId"] = nodeId
1017                callback_data["timestamp"] = timestamp
1018                callback_data["error_msg"] = error_msg
1019                for f in fields:
1020                    callback_data["field_" + f['name']] = f
1021
1022        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
1023                                           to_jid="you@google.com",
1024                                           nodeIds=['Device33'],
1025                                           callback=my_callback)
1026        #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
1027
1028        self.send("""
1029            <iq type='get'
1030                from='tester@localhost'
1031                to='you@google.com'
1032                id='1'>
1033                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
1034                    <node nodeId="Device33"/>
1035                </req>
1036            </iq>
1037            """)
1038
1039        self.recv("""
1040            <iq type='result'
1041                from='you@google.com'
1042                to='tester@localhost'
1043                id='1'>
1044                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'  queued='true'/>
1045            </iq>
1046            """)
1047
1048        self.recv("""
1049            <message from='device@clayster.com'
1050                     to='master@clayster.com/amr'>
1051                <started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1052            </message>
1053            """)
1054
1055        self.recv("""
1056            <message from='you@google.com'
1057                     to='tester@localhost'>
1058                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
1059                    <node nodeId='Device33'>
1060                        <timestamp value='2000-01-01T00:01:02'>
1061                            <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
1062                            <boolean name='TestBool' value='true'/>
1063                        </timestamp>
1064                    </node>
1065                </fields>
1066            </message>
1067            """)
1068
1069        self.recv("""
1070            <message from='you@google.com'
1071                     to='tester@localhost'>
1072                <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
1073            </message>
1074            """)
1075
1076        self.assertEqual(results, ["queued","started","fields","done"]);
1077        # self.assertIn("nodeId", callback_data);
1078        self.assertTrue("nodeId" in callback_data)
1079        self.assertEqual(callback_data["nodeId"], "Device33")
1080        # self.assertIn("timestamp", callback_data);
1081        self.assertTrue("timestamp" in callback_data)
1082        self.assertEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
1083        # self.assertIn("field_Voltage", callback_data);
1084        self.assertTrue("field_Voltage" in callback_data)
1085        self.assertEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
1086        # self.assertIn("field_TestBool", callback_data);
1087        self.assertTrue("field_TestBool" in callback_data)
1088        self.assertEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
1089
1090
1091    def testRequestFieldsCancelAPI(self):
1092
1093        self.stream_start(mode='client',
1094                          plugins=['xep_0030',
1095                                   'xep_0323'])
1096
1097        results = []
1098
1099        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
1100            results.append(result)
1101
1102        session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback)
1103
1104        self.send("""
1105            <iq type='get'
1106                from='tester@localhost'
1107                to='you@google.com'
1108                id='1'>
1109                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
1110                    <node nodeId="Device33"/>
1111                </req>
1112            </iq>
1113            """)
1114
1115        self.recv("""
1116            <iq type='result'
1117                from='you@google.com'
1118                to='tester@localhost'
1119                id='1'>
1120                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
1121            </iq>
1122            """)
1123
1124        self.xmpp['xep_0323'].cancel_request(session=session)
1125
1126        self.send("""
1127            <iq type='get'
1128                from='tester@localhost'
1129                to='you@google.com'
1130                id='1'>
1131                <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1132            </iq>
1133            """)
1134
1135        self.recv("""
1136            <iq type='result'
1137                from='tester@localhost'
1138                to='you@google.com'
1139                id='1'>
1140                <cancelled xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1141            </iq>
1142            """)
1143
1144        self.assertEqual(results, ["accepted","cancelled"])
1145
1146    def testDelayedRequestCancel(self):
1147        self.stream_start(mode='component',
1148                          plugins=['xep_0030',
1149                                   'xep_0323'])
1150
1151        myDevice = Device("Device22")
1152        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
1153        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
1154        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
1155
1156        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
1157
1158        dtnow = datetime.datetime.now()
1159        ts_2sec = datetime.timedelta(0,2)
1160        dtnow_plus_2sec = dtnow + ts_2sec
1161        when_flag = dtnow_plus_2sec.replace(microsecond=0).isoformat()
1162
1163        self.recv("""
1164            <iq type='get'
1165                from='master@clayster.com/amr'
1166                to='device@clayster.com'
1167                id='1'>
1168                <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
1169            </iq>
1170        """)
1171
1172        self.send("""
1173            <iq type='result'
1174                from='device@clayster.com'
1175                to='master@clayster.com/amr'
1176                id='1'>
1177                <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true' />
1178            </iq>
1179            """)
1180
1181        self.recv("""
1182            <iq type='get'
1183                from='master@clayster.com/amr'
1184                to='device@clayster.com'
1185                id='1'>
1186                <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1187            </iq>
1188            """)
1189
1190        self.send("""
1191            <iq type='result'
1192                from='device@clayster.com'
1193                to='master@clayster.com/amr'
1194                id='1'>
1195                <cancelled xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1196            </iq>
1197            """)
1198
1199        # Test cancel of non-existing request
1200        self.recv("""
1201            <iq type='get'
1202                from='tester@localhost'
1203                to='you@google.com'
1204                id='1'>
1205                <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
1206            </iq>
1207            """)
1208
1209        self.send("""
1210            <iq type='error'
1211                from='you@google.com'
1212                to='tester@localhost'
1213                id='1'>
1214                <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
1215                    <error>Cancel request received, no matching request is active.</error>
1216                </rejected>
1217            </iq>
1218            """)
1219
1220        # Ensure we don't get anything after cancellation
1221        self.send(None)
1222
1223
1224
1225suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamSensorData)
1226
1227