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