1# -*- coding: utf-8 -*-
2"""
3    Slixmpp: The Slick XMPP Library
4    Implementation of xeps for Internet of Things
5    http://wiki.xmpp.org/web/Tech_pages/IoT_systems
6    Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se, bjorn.westrom@consoden.se
7    This file is part of Slixmpp.
8
9    See the file LICENSE for copying permission.
10"""
11
12import sys
13import datetime
14import time
15import threading
16
17from slixmpp.test import *
18from slixmpp.xmlstream import ElementBase
19from slixmpp.plugins.xep_0325.device import Device
20
21
22class TestStreamControl(SlixTest):
23
24    """
25    Test using the XEP-0325 plugin.
26    """
27    def setUp(self):
28        pass
29
30    def _time_now(self):
31        return datetime.datetime.now().replace(microsecond=0).isoformat()
32
33    def tearDown(self):
34        self.stream_close()
35
36    def testRequestSetOk(self):
37        self.stream_start(mode='component',
38                          plugins=['xep_0030',
39                                   'xep_0325'])
40
41        myDevice = Device("Device22")
42        myDevice._add_control_field(name="Temperature", typename="int", value="15")
43
44        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
45
46        self.recv("""
47            <iq type='set'
48                from='master@clayster.com/amr'
49                to='device@clayster.com'
50                id='1'>
51                <set xmlns='urn:xmpp:iot:control'>
52                    <int name="Temperature" value="17"/>
53                </set>
54            </iq>
55        """)
56
57        self.send("""
58            <iq type='result'
59                from='device@clayster.com'
60                to='master@clayster.com/amr'
61                id='1'>
62                <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
63            </iq>
64            """)
65
66        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
67
68    def testRequestSetMulti(self):
69        self.stream_start(mode='component',
70                          plugins=['xep_0030',
71                                   'xep_0325'])
72
73        myDevice = Device("Device22")
74        myDevice._add_control_field(name="Temperature", typename="int", value="15")
75        myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03")
76
77        myDevice2 = Device("Device23")
78        myDevice2._add_control_field(name="Temperature", typename="int", value="19")
79        myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09")
80
81        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
82        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5)
83
84        self.recv("""
85            <iq type='set'
86                from='master@clayster.com/amr'
87                to='device@clayster.com'
88                id='1'>
89                <set xmlns='urn:xmpp:iot:control'>
90                    <node nodeId='Device22' />
91                    <int name="Temperature" value="17"/>
92                </set>
93            </iq>
94        """)
95
96        self.send("""
97            <iq type='result'
98                from='device@clayster.com'
99                to='master@clayster.com/amr'
100                id='1'>
101                <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
102            </iq>
103            """)
104
105        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
106        self.assertEqual(myDevice2._get_field_value("Temperature"), "19")
107
108        self.recv("""
109            <iq type='set'
110                from='master@clayster.com/amr'
111                to='device@clayster.com'
112                id='2'>
113                <set xmlns='urn:xmpp:iot:control'>
114                    <node nodeId='Device23' />
115                    <node nodeId='Device22' />
116                    <date name="Startup" value="2013-02-01"/>
117                    <int name="Temperature" value="20"/>
118                </set>
119            </iq>
120        """)
121
122        self.send("""
123            <iq type='result'
124                from='device@clayster.com'
125                to='master@clayster.com/amr'
126                id='2'>
127                <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
128            </iq>
129            """)
130
131        self.assertEqual(myDevice._get_field_value("Temperature"), "20")
132        self.assertEqual(myDevice2._get_field_value("Temperature"), "20")
133        self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01")
134        self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01")
135
136    def testRequestSetFail(self):
137        self.stream_start(mode='component',
138                          plugins=['xep_0030',
139                                   'xep_0325'])
140
141        myDevice = Device("Device23")
142        myDevice._add_control_field(name="Temperature", typename="int", value="15")
143
144        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5)
145
146        self.recv("""
147            <iq type='set'
148                from='master@clayster.com/amr'
149                to='device@clayster.com'
150                id='9'>
151                <set xmlns='urn:xmpp:iot:control'>
152                    <int name="Voltage" value="17"/>
153                </set>
154            </iq>
155        """)
156
157        self.send("""
158            <iq type='error'
159                from='device@clayster.com'
160                to='master@clayster.com/amr'
161                id='9'>
162                <setResponse xmlns='urn:xmpp:iot:control' responseCode='NotFound'>
163                    <parameter name='Voltage' />
164                    <error var='Output'>Invalid field Voltage</error>
165                </setResponse>
166            </iq>
167            """)
168
169        self.assertEqual(myDevice._get_field_value("Temperature"), "15")
170        self.assertFalse(myDevice.has_control_field("Voltage", "int"))
171
172    def testDirectSetOk(self):
173        self.stream_start(mode='component',
174                          plugins=['xep_0030',
175                                   'xep_0325'])
176
177        myDevice = Device("Device22")
178        myDevice._add_control_field(name="Temperature", typename="int", value="15")
179
180        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
181
182        self.recv("""
183            <message
184                from='master@clayster.com/amr'
185                to='device@clayster.com'>
186                <set xmlns='urn:xmpp:iot:control'>
187                    <int name="Temperature" value="17"/>
188                </set>
189            </message>
190        """)
191
192        time.sleep(0.5)
193
194        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
195
196    def testDirectSetFail(self):
197        self.stream_start(mode='component',
198                          plugins=['xep_0030',
199                                   'xep_0325'])
200
201        myDevice = Device("Device22")
202        myDevice._add_control_field(name="Temperature", typename="int", value="15")
203
204        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
205
206        self.recv("""
207            <message
208                from='master@clayster.com/amr'
209                to='device@clayster.com'>
210                <set xmlns='urn:xmpp:iot:control'>
211                    <int name="Voltage" value="17"/>
212                </set>
213            </message>
214        """)
215
216        self.assertEqual(myDevice._get_field_value("Temperature"), "15");
217        self.assertFalse(myDevice.has_control_field("Voltage", "int"));
218
219
220    def testRequestSetOkAPI(self):
221
222        self.stream_start(mode='client',
223                          plugins=['xep_0030',
224                                   'xep_0325'])
225
226        results = []
227
228        def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
229            results.append(result)
230
231        fields = []
232        fields.append(("Temperature", "double", "20.5"))
233        fields.append(("TemperatureAlarmSetting", "string", "High"))
234
235        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
236
237        self.send("""
238            <iq type='set'
239                from='tester@localhost'
240                to='you@google.com'
241                id='1'>
242                <set xmlns='urn:xmpp:iot:control'>
243                    <node nodeId='Device33' />
244                    <node nodeId='Device22' />
245                    <double name="Temperature" value="20.5" />
246                    <string name="TemperatureAlarmSetting" value="High" />
247                </set>
248            </iq>
249            """)
250
251        self.recv("""
252            <iq type='result'
253                from='you@google.com'
254                to='tester@localhost'
255                id='1'>
256                <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
257            </iq>
258            """)
259
260        self.assertEqual(results, ["OK"]);
261
262    def testRequestSetErrorAPI(self):
263
264        self.stream_start(mode='client',
265                          plugins=['xep_0030',
266                                   'xep_0325'])
267
268        results = []
269
270        def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
271            results.append(result)
272
273        fields = []
274        fields.append(("Temperature", "double", "20.5"))
275        fields.append(("TemperatureAlarmSetting", "string", "High"))
276
277        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
278
279        self.send("""
280            <iq type='set'
281                from='tester@localhost'
282                to='you@google.com'
283                id='1'>
284                <set xmlns='urn:xmpp:iot:control'>
285                    <node nodeId='Device33' />
286                    <node nodeId='Device22' />
287                    <double name="Temperature" value="20.5" />
288                    <string name="TemperatureAlarmSetting" value="High" />
289                </set>
290            </iq>
291            """)
292
293        self.recv("""
294            <iq type='error'
295                from='you@google.com'
296                to='tester@localhost'
297                id='1'>
298                <setResponse xmlns='urn:xmpp:iot:control' responseCode="OtherError" >
299                    <error var='Temperature'>Sensor error</error>
300                </setResponse>
301            </iq>
302            """)
303
304        self.assertEqual(results, ["OtherError"])
305
306    def testServiceDiscoveryClient(self):
307        self.stream_start(mode='client',
308                          plugins=['xep_0030',
309                                   'xep_0325'])
310
311        self.recv("""
312        <iq type='get'
313                from='master@clayster.com/amr'
314                to='tester@localhost/resource'
315                id='disco1'>
316            <query xmlns='http://jabber.org/protocol/disco#info'/>
317        </iq>
318        """)
319
320        self.send("""
321        <iq type='result'
322            to='master@clayster.com/amr'
323            id='disco1'>
324            <query xmlns='http://jabber.org/protocol/disco#info'>
325                <identity category='client' type='bot'/>
326                <feature var='urn:xmpp:iot:control'/>
327            </query>
328        </iq>
329        """)
330
331    def testServiceDiscoveryComponent(self):
332        self.stream_start(mode='component',
333                          plugins=['xep_0030',
334                                   'xep_0325'])
335
336        self.recv("""
337        <iq type='get'
338                from='master@clayster.com/amr'
339                to='tester@localhost/resource'
340                id='disco1'>
341            <query xmlns='http://jabber.org/protocol/disco#info'/>
342        </iq>
343        """)
344
345        self.send("""
346        <iq type='result'
347            from='tester@localhost/resource'
348            to='master@clayster.com/amr'
349            id='disco1'>
350            <query xmlns='http://jabber.org/protocol/disco#info'>
351                <identity category='component' type='generic'/>
352                <feature var='urn:xmpp:iot:control'/>
353            </query>
354        </iq>
355        """)
356
357
358suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamControl)
359
360