summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_stanza_xep_0323.py364
-rw-r--r--tests/test_stanza_xep_0325.py248
-rw-r--r--tests/test_stream_xep_0323.py1250
-rw-r--r--tests/test_stream_xep_0325.py365
4 files changed, 2213 insertions, 14 deletions
diff --git a/tests/test_stanza_xep_0323.py b/tests/test_stanza_xep_0323.py
index a052fced..67e0daf0 100644
--- a/tests/test_stanza_xep_0323.py
+++ b/tests/test_stanza_xep_0323.py
@@ -1,15 +1,24 @@
+# -*- coding: utf-8 -*-
+
from sleekxmpp.test import *
import sleekxmpp.plugins.xep_0323 as xep_0323
namespace='sn'
-class TestChatStates(SleekTest):
+class TestSensorDataStanzas(SleekTest):
def setUp(self):
- register_stanza_plugin(Message, xep_0323.stanza.Request)
- register_stanza_plugin(Message, xep_0323.stanza.Accepted)
- register_stanza_plugin(Message, xep_0323.stanza.Failure)
+ pass
+ #register_stanza_plugin(Iq, xep_0323.stanza.Request)
+ #register_stanza_plugin(Iq, xep_0323.stanza.Accepted)
+ #register_stanza_plugin(Message, xep_0323.stanza.Failure)
+ #register_stanza_plugin(xep_0323.stanza.Failure, xep_0323.stanza.Error)
+ #register_stanza_plugin(Iq, xep_0323.stanza.Rejected)
+ #register_stanza_plugin(Message, xep_0323.stanza.Fields)
+ #register_stanza_plugin(Message, xep_0323.stanza.Request)
+ #register_stanza_plugin(Message, xep_0323.stanza.Accepted)
+ #register_stanza_plugin(Message, xep_0323.stanza.Failure)
# register_stanza_plugin(Message, xep_0323.stanza.Result)
# register_stanza_plugin(Message, xep_0323.stanza.Gone)
# register_stanza_plugin(Message, xep_0323.stanza.Inactive)
@@ -21,37 +30,364 @@ class TestChatStates(SleekTest):
"""
iq = self.Iq()
iq['type'] = 'get'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '1'
+ iq['req']['seqnr'] = '1'
+ iq['req']['momentary'] = 'true'
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'/>
+ </iq>
+ """
+ )
+
+ def testRequestNodes(self):
+ """
+ test of request nodes stanza
+ """
+ iq = self.Iq()
+ iq['type'] = 'get'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '1'
+ iq['req']['seqnr'] = '1'
+ iq['req']['momentary'] = 'true'
+
+
+ iq['req'].add_node("Device02", "Source02", "CacheType");
+ iq['req'].add_node("Device44");
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ <node nodeId='Device02' sourceId='Source02' cacheType='CacheType'/>
+ <node nodeId='Device44'/>
+ </req>
+ </iq>
+ """
+ )
+
+ iq['req'].del_node("Device02");
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ <node nodeId='Device44'/>
+ </req>
+ </iq>
+ """
+ )
+
+ iq['req'].del_nodes();
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ </req>
+ </iq>
+ """
+ )
+
+ def testRequestField(self):
+ """
+ test of request field stanza
+ """
+ iq = self.Iq()
+ iq['type'] = 'get'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
iq['id'] = '1'
- iq['sensordata']['req']['seqnr'] = '1'
- iq['sensordata']['req']['momentary'] = 'true'
+ iq['req']['seqnr'] = '1'
+ iq['req']['momentary'] = 'true'
+
+
+ iq['req'].add_field("Top temperature");
+ iq['req'].add_field("Bottom temperature");
self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ <field name='Top temperature'/>
+ <field name='Bottom temperature'/>
+ </req>
+ </iq>
"""
)
+ iq['req'].del_field("Top temperature")
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ <field name='Bottom temperature'/>
+ </req>
+ </iq>
+ """
+ )
+
+ iq['req'].del_fields()
+
+ self.check(iq,"""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'>
+ </req>
+ </iq>
+ """
+ )
+
+
def testAccepted(self):
"""
test of request stanza
"""
iq = self.Iq()
iq['type'] = 'result'
+ iq['from'] = 'device@clayster.com'
+ iq['to'] = 'master@clayster.com/amr'
iq['id'] = '2'
- iq['sensordata']['accepted']['seqnr'] = '2'
+ iq['accepted']['seqnr'] = '2'
- print(str(iq))
self.check(iq,"""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='2'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='2'/>
+ </iq>
"""
)
-
- def testReadOutMomentary_multiple(self):
+
+ def testRejected(self):
"""
- test of reading momentary value from a nde with multiple responses
+ test of request stanza
"""
- iq = self.Iq()
- print(str(iq))
+ iq = self.Iq()
+ iq['type'] = 'error'
+ iq['from'] = 'device@clayster.com'
+ iq['to'] = 'master@clayster.com/amr'
+ iq['id'] = '4'
+ iq['rejected']['seqnr'] = '4'
+ iq['rejected']['error'] = 'Access denied.'
self.check(iq,"""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='4'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='4'>
+ <error>Access denied.</error>
+ </rejected>
+ </iq>
+ """
+ )
+
+ def testFailure(self):
+ """
+ test of failure stanza
+ """
+ msg = self.Message()
+ msg['from'] = 'device@clayster.com'
+ msg['to'] = 'master@clayster.com/amr'
+ msg['failure']['seqnr'] = '3'
+ msg['failure']['done'] = 'true'
+ msg['failure']['error']['nodeId'] = 'Device01'
+ msg['failure']['error']['timestamp'] = '2013-03-07T17:13:30'
+ msg['failure']['error']['text'] = 'Timeout.'
+
+ self.check(msg,"""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <failure xmlns='urn:xmpp:iot:sensordata' seqnr='3' done='true'>
+ <error nodeId='Device01' timestamp='2013-03-07T17:13:30'>
+ Timeout.</error>
+ </failure>
+ </message>
"""
)
+
+ def testFields(self):
+ """
+ test of fields stanza
+ """
+ msg = self.Message()
+ msg['from'] = 'device@clayster.com'
+ msg['to'] = 'master@clayster.com/amr'
+ msg['fields']['seqnr'] = '1'
+
+ node = msg['fields'].add_node("Device02");
+ ts = node.add_timestamp("2013-03-07T16:24:30");
+
+ data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K');
+ data['momentary'] = 'true';
+ data['automaticReadout'] = 'true';
+
+ self.check(msg,"""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device02'>
+ <timestamp value='2013-03-07T16:24:30'>
+ <numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """
+ )
+
+ node = msg['fields'].add_node("EmptyDevice");
+ node = msg['fields'].add_node("Device04");
+ ts = node.add_timestamp("EmptyTimestamp");
+
+
+ self.check(msg,"""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device02'>
+ <timestamp value='2013-03-07T16:24:30'>
+ <numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
+ </timestamp>
+ </node>
+ <node nodeId='EmptyDevice'/>
+ <node nodeId='Device04'>
+ <timestamp value='EmptyTimestamp'/>
+ </node>
+ </fields>
+ </message>
+ """
+ )
+
+ node = msg['fields'].add_node("Device77");
+ ts = node.add_timestamp("2013-05-03T12:00:01");
+ data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K');
+ data['historicalDay'] = 'true';
+ data = ts.add_data(typename="numeric", name="Speed", value="312.42", unit='km/h');
+ data['historicalWeek'] = 'false';
+ data = ts.add_data(typename="string", name="Temperature name", value="Bottom oil");
+ data['historicalMonth'] = 'true';
+ data = ts.add_data(typename="string", name="Speed name", value="Top speed");
+ data['historicalQuarter'] = 'false';
+ data = ts.add_data(typename="dateTime", name="T1", value="1979-01-01T00:00:00");
+ data['historicalYear'] = 'true';
+ data = ts.add_data(typename="dateTime", name="T2", value="2000-01-01T01:02:03");
+ data['historicalOther'] = 'false';
+ data = ts.add_data(typename="timeSpan", name="TS1", value="P5Y");
+ data['missing'] = 'true';
+ data = ts.add_data(typename="timeSpan", name="TS2", value="PT2M1S");
+ data['manualEstimate'] = 'false';
+ data = ts.add_data(typename="enum", name="top color", value="red", dataType="string");
+ data['invoiced'] = 'true';
+ data = ts.add_data(typename="enum", name="bottom color", value="black", dataType="string");
+ data['powerFailure'] = 'false';
+ data = ts.add_data(typename="boolean", name="Temperature real", value="false");
+ data['historicalDay'] = 'true';
+ data = ts.add_data(typename="boolean", name="Speed real", value="true");
+ data['historicalWeek'] = 'false';
+
+ self.check(msg,"""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device02'>
+ <timestamp value='2013-03-07T16:24:30'>
+ <numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
+ </timestamp>
+ </node>
+ <node nodeId='EmptyDevice'/>
+ <node nodeId='Device04'>
+ <timestamp value='EmptyTimestamp'/>
+ </node>
+ <node nodeId='Device77'>
+ <timestamp value='2013-05-03T12:00:01'>
+ <numeric name='Temperature' historicalDay='true' value='-12.42' unit='K'/>
+ <numeric name='Speed' historicalWeek='false' value='312.42' unit='km/h'/>
+ <string name='Temperature name' historicalMonth='true' value='Bottom oil'/>
+ <string name='Speed name' historicalQuarter='false' value='Top speed'/>
+ <dateTime name='T1' historicalYear='true' value='1979-01-01T00:00:00'/>
+ <dateTime name='T2' historicalOther='false' value='2000-01-01T01:02:03'/>
+ <timeSpan name='TS1' missing='true' value='P5Y'/>
+ <timeSpan name='TS2' manualEstimate='false' value='PT2M1S'/>
+ <enum name='top color' invoiced='true' value='red' dataType='string'/>
+ <enum name='bottom color' powerFailure='false' value='black' dataType='string'/>
+ <boolean name='Temperature real' historicalDay='true' value='false'/>
+ <boolean name='Speed real' historicalWeek='false' value='true'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """
+ )
+
+
+ def testTimestamp(self):
+ msg = self.Message();
+
+ msg['from'] = 'device@clayster.com'
+ msg['to'] = 'master@clayster.com/amr'
+ msg['fields']['seqnr'] = '1'
+
+ node = msg['fields'].add_node("Device02");
+ node = msg['fields'].add_node("Device03");
+
+ ts = node.add_timestamp("2013-03-07T16:24:30");
+ ts = node.add_timestamp("2013-03-07T16:24:31");
+
+
+
+ self.check(msg,"""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device02'/>
+ <node nodeId='Device03'>
+ <timestamp value='2013-03-07T16:24:30'/>
+ <timestamp value='2013-03-07T16:24:31'/>
+ </node>
+ </fields>
+ </message>
+ """
+ )
+
+
+ def testStringIdsMatcher(self):
+ """
+ test of StringIds follow spec
+ """
+ emptyStringIdXML='<message xmlns="jabber:client"><fields xmlns="urn:xmpp:iot:sensordata" /></message>'
+
+ msg = self.Message()
+ msg['fields']['stringIds'] = "Nisse"
+ self.check(msg,emptyStringIdXML)
+ msg['fields']['stringIds'] = "Nisse___nje#"
+ self.check(msg,emptyStringIdXML)
+ msg['fields']['stringIds'] = "1"
+ self.check(msg,emptyStringIdXML)
+
+
+
-suite = unittest.TestLoader().loadTestsFromTestCase(TestChatStates)
+suite = unittest.TestLoader().loadTestsFromTestCase(TestSensorDataStanzas)
diff --git a/tests/test_stanza_xep_0325.py b/tests/test_stanza_xep_0325.py
new file mode 100644
index 00000000..b15b764c
--- /dev/null
+++ b/tests/test_stanza_xep_0325.py
@@ -0,0 +1,248 @@
+# -*- coding: utf-8 -*-
+"""
+ SleekXMPP: The Sleek XMPP Library
+ Implementation of xeps for Internet of Things
+ http://wiki.xmpp.org/web/Tech_pages/IoT_systems
+ Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se, bjorn.westrom@consoden.se
+ This file is part of SleekXMPP.
+
+ See the file LICENSE for copying permission.
+"""
+
+from sleekxmpp.test import *
+import sleekxmpp.plugins.xep_0325 as xep_0325
+
+namespace='sn'
+
+class TestControlStanzas(SleekTest):
+
+
+ def setUp(self):
+ pass
+
+ def testSetRequest(self):
+ """
+ test of set request stanza
+ """
+ iq = self.Iq()
+ iq['type'] = 'set'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '1'
+ iq['set'].add_node("Device02", "Source02", "MyCacheType");
+ iq['set'].add_node("Device15");
+ iq['set'].add_data("Tjohej", "boolean", "true")
+
+ self.check(iq,"""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device02' sourceId='Source02' cacheType='MyCacheType'/>
+ <node nodeId='Device15'/>
+ <boolean name='Tjohej' value='true'/>
+ </set>
+ </iq>
+ """
+ )
+
+ iq['set'].del_node("Device02");
+
+ self.check(iq,"""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device15'/>
+ <boolean name='Tjohej' value='true'/>
+ </set>
+ </iq>
+ """
+ )
+
+ iq['set'].del_nodes();
+
+ self.check(iq,"""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <boolean name='Tjohej' value='true'/>
+ </set>
+ </iq>
+ """
+ )
+
+
+ def testDirectSet(self):
+ """
+ test of direct set stanza
+ """
+ msg = self.Message()
+ msg['from'] = 'master@clayster.com/amr'
+ msg['to'] = 'device@clayster.com'
+ msg['set'].add_node("Device02");
+ msg['set'].add_node("Device15");
+ msg['set'].add_data("Tjohej", "boolean", "true")
+
+ self.check(msg,"""
+ <message
+ from='master@clayster.com/amr'
+ to='device@clayster.com'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device02'/>
+ <node nodeId='Device15'/>
+ <boolean name='Tjohej' value='true'/>
+ </set>
+ </message>
+ """
+ )
+
+
+ def testSetResponse(self):
+ """
+ test of set response stanza
+ """
+ iq = self.Iq()
+ iq['type'] = 'result'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '8'
+ iq['setResponse']['responseCode'] = "OK";
+
+ self.check(iq,"""
+ <iq type='result'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='8'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode='OK' />
+ </iq>
+ """
+ )
+
+ iq = self.Iq()
+ iq['type'] = 'error'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '9'
+ iq['setResponse']['responseCode'] = "OtherError";
+ iq['setResponse']['error']['var'] = "Output";
+ iq['setResponse']['error']['text'] = "Test of other error.!";
+
+
+ self.check(iq,"""
+ <iq type='error'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='9'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode='OtherError'>
+ <error var='Output'>Test of other error.!</error>
+ </setResponse>
+ </iq>
+ """
+ )
+
+ iq = self.Iq()
+ iq['type'] = 'error'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '9'
+ iq['setResponse']['responseCode'] = "NotFound";
+ iq['setResponse'].add_node("Device17", "Source09");
+ iq['setResponse'].add_node("Device18", "Source09");
+ iq['setResponse'].add_data("Tjohopp");
+
+
+ self.check(iq,"""
+ <iq type='error'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='9'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode='NotFound'>
+ <node nodeId='Device17' sourceId='Source09'/>
+ <node nodeId='Device18' sourceId='Source09'/>
+ <parameter name='Tjohopp' />
+ </setResponse>
+ </iq>
+ """
+ )
+
+ def testSetRequestDatas(self):
+ """
+ test of set request data stanzas
+ """
+ iq = self.Iq()
+ iq['type'] = 'set'
+ iq['from'] = 'master@clayster.com/amr'
+ iq['to'] = 'device@clayster.com'
+ iq['id'] = '1'
+ iq['set'].add_node("Device02", "Source02", "MyCacheType");
+ iq['set'].add_node("Device15");
+
+ iq['set'].add_data("Tjohej", "boolean", "true");
+ iq['set'].add_data("Tjohej2", "boolean", "false");
+
+ iq['set'].add_data("TjohejC", "color", "FF00FF");
+ iq['set'].add_data("TjohejC2", "color", "00FF00");
+
+ iq['set'].add_data("TjohejS", "string", "String1");
+ iq['set'].add_data("TjohejS2", "string", "String2");
+
+ iq['set'].add_data("TjohejDate", "date", "2012-01-01");
+ iq['set'].add_data("TjohejDate2", "date", "1900-12-03");
+
+ iq['set'].add_data("TjohejDateT4", "dateTime", "1900-12-03 12:30");
+ iq['set'].add_data("TjohejDateT2", "dateTime", "1900-12-03 11:22");
+
+ iq['set'].add_data("TjohejDouble2", "double", "200.22");
+ iq['set'].add_data("TjohejDouble3", "double", "-12232131.3333");
+
+ iq['set'].add_data("TjohejDur", "duration", "P5Y");
+ iq['set'].add_data("TjohejDur2", "duration", "PT2M1S");
+
+ iq['set'].add_data("TjohejInt", "int", "1");
+ iq['set'].add_data("TjohejInt2", "int", "-42");
+
+ iq['set'].add_data("TjohejLong", "long", "123456789098");
+ iq['set'].add_data("TjohejLong2", "long", "-90983243827489374");
+
+ iq['set'].add_data("TjohejTime", "time", "23:59");
+ iq['set'].add_data("TjohejTime2", "time", "12:00");
+
+ self.check(iq,"""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device02' sourceId='Source02' cacheType='MyCacheType'/>
+ <node nodeId='Device15'/>
+ <boolean name='Tjohej' value='true'/>
+ <boolean name='Tjohej2' value='false'/>
+ <color name='TjohejC' value='FF00FF'/>
+ <color name='TjohejC2' value='00FF00'/>
+ <string name='TjohejS' value='String1'/>
+ <string name='TjohejS2' value='String2'/>
+ <date name='TjohejDate' value='2012-01-01'/>
+ <date name='TjohejDate2' value='1900-12-03'/>
+ <dateTime name='TjohejDateT4' value='1900-12-03 12:30'/>
+ <dateTime name='TjohejDateT2' value='1900-12-03 11:22'/>
+ <double name='TjohejDouble2' value='200.22'/>
+ <double name='TjohejDouble3' value='-12232131.3333'/>
+ <duration name='TjohejDur' value='P5Y'/>
+ <duration name='TjohejDur2' value='PT2M1S'/>
+ <int name='TjohejInt' value='1'/>
+ <int name='TjohejInt2' value='-42'/>
+ <long name='TjohejLong' value='123456789098'/>
+ <long name='TjohejLong2' value='-90983243827489374'/>
+ <time name='TjohejTime' value='23:59'/>
+ <time name='TjohejTime2' value='12:00'/>
+ </set>
+ </iq>
+ """
+ )
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestControlStanzas)
diff --git a/tests/test_stream_xep_0323.py b/tests/test_stream_xep_0323.py
new file mode 100644
index 00000000..b10f0b0d
--- /dev/null
+++ b/tests/test_stream_xep_0323.py
@@ -0,0 +1,1250 @@
+# -*- coding: utf-8 -*-
+
+import sys
+import datetime
+import time
+import threading
+
+from sleekxmpp.test import *
+from sleekxmpp.xmlstream import ElementBase
+from sleekxmpp.plugins.xep_0323.device import Device
+
+
+class TestStreamSensorData(SleekTest):
+
+ """
+ Test using the XEP-0323 plugin.
+ """
+ def setUp(self):
+ pass
+
+ def _time_now(self):
+ return datetime.datetime.now().replace(microsecond=0).isoformat();
+
+ def tearDown(self):
+ self.stream_close()
+
+ def testRequestAccept(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device22");
+ myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
+ myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
+ myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
+
+ self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
+ <node nodeId='Device22'>
+ <timestamp value='2013-03-07T16:24:30'>
+ <numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ def testRequestRejectAuth(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com");
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='4'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='5' momentary='true'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='4'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='5'>
+ <error>Access denied</error>
+ </rejected>
+ </iq>
+ """)
+
+ def testRequestNode(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='77'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='66' momentary='true'>
+ <node nodeId='Device33'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='77'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='66'>
+ <error>Invalid nodeId Device33</error>
+ </rejected>
+ </iq>
+ """)
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='8'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='7' momentary='true'>
+ <node nodeId='Device44'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='8'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
+ </iq>
+ """)
+
+
+ def testRequestField(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='7'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <field name='Current'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='7'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <error>Invalid field Current</error>
+ </rejected>
+ </iq>
+ """)
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='8'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <field name='Voltage'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='8'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testRequestMultiTimestampSingleField(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field(name='Current', typename="numeric", unit="A");
+ myDevice._add_field(name='Height', typename="string");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02");
+ myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='8'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <field name='Voltage'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='8'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T01:01:02'>
+ <numeric name='Voltage' value='230.6' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testRequestMultiTimestampAllFields(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field(name='Current', typename="numeric", unit="A");
+ myDevice._add_field(name='Height', typename="string");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02");
+ myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='8'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='8'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='7'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T01:01:02'>
+ <numeric name='Voltage' value='230.6' unit='V'/>
+ <string name='Height' invoiced='true' value='115 m'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testRequestAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='2'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='2'>
+ <node nodeId="Device33"/>
+ <node nodeId="Device22"/>
+ </req>
+ </iq>
+ """)
+
+ self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='3'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='3'>
+ <field name="Temperature"/>
+ <field name="Voltage"/>
+ </req>
+ </iq>
+ """)
+
+ def testRequestRejectAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
+ if (result == "rejected") and (error_msg == "Invalid device Device22"):
+ results.append("rejected");
+
+ self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ <node nodeId="Device22"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='error'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <error>Invalid device Device22</error>
+ </rejected>
+ </iq>
+ """)
+
+ time.sleep(.1)
+
+ self.failUnless(results == ["rejected"],
+ "Rejected callback was not properly executed");
+
+ def testRequestAcceptedAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
+ results.append(result);
+
+ self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ <node nodeId="Device22"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ time.sleep(.1)
+
+ self.failUnless(results == ["accepted"],
+ "Accepted callback was not properly executed");
+
+ def testRequestFieldsAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+ callback_data = {};
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
+ results.append(result);
+ if result == "fields":
+ callback_data["nodeId"] = nodeId;
+ callback_data["timestamp"] = timestamp;
+ callback_data["error_msg"] = error_msg;
+ for f in fields:
+ callback_data["field_" + f['name']] = f;
+
+ t1= threading.Thread(name="request_data",
+ target=self.xmpp['xep_0323'].request_data,
+ kwargs={"from_jid": "tester@localhost",
+ "to_jid": "you@google.com",
+ "nodeIds": ['Device33'],
+ "callback": my_callback});
+ t1.start();
+ #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ self.recv("""
+ <message from='you@google.com'
+ to='tester@localhost'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device33'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
+ <boolean name='TestBool' value='true'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.recv("""
+ <message from='you@google.com'
+ to='tester@localhost'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
+ </message>
+ """)
+
+ t1.join();
+ time.sleep(.5)
+
+ self.failUnlessEqual(results, ["accepted","fields","done"]);
+ # self.assertIn("nodeId", callback_data);
+ self.assertTrue(callback_data.has_key("nodeId"));
+ self.failUnlessEqual(callback_data["nodeId"], "Device33");
+ # self.assertIn("timestamp", callback_data);
+ self.assertTrue(callback_data.has_key("timestamp"));
+ self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02");
+ #self.assertIn("field_Voltage", callback_data);
+ self.assertTrue(callback_data.has_key("field_Voltage"));
+ self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}});
+ #self.assertIn("field_TestBool", callback_data);
+ self.assertTrue(callback_data.has_key("field_TestBool"));
+ self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" });
+
+ def testServiceDiscoveryClient(self):
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323']);
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='tester@localhost'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ to='master@clayster.com/amr'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'>
+ <identity category='client' type='bot'/>
+ <feature var='urn:xmpp:iot:sensordata'/>
+ </query>
+ </iq>
+ """)
+
+ def testServiceDiscoveryComponent(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323']);
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='tester@localhost'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='tester@localhost'
+ to='master@clayster.com/amr'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'>
+ <identity category='component' type='generic'/>
+ <feature var='urn:xmpp:iot:sensordata'/>
+ </query>
+ </iq>
+ """)
+
+ def testRequestTimeout(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+ callback_data = {};
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
+ results.append(result);
+ if result == "failure":
+ callback_data["nodeId"] = nodeId;
+ callback_data["timestamp"] = timestamp;
+ callback_data["error_msg"] = error_msg;
+
+ t1= threading.Thread(name="request_data",
+ target=self.xmpp['xep_0323'].request_data,
+ kwargs={"from_jid": "tester@localhost",
+ "to_jid": "you@google.com",
+ "nodeIds": ['Device33'],
+ "callback": my_callback});
+ t1.start();
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ self.recv("""
+ <message from='you@google.com'
+ to='tester@localhost'>
+ <failure xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
+ <error nodeId='Device33' timestamp='2013-03-07T17:13:30'>Timeout.</error>
+ </failure>
+ </message>
+ """)
+
+ t1.join();
+ time.sleep(.5)
+
+ self.failUnlessEqual(results, ["accepted","failure"]);
+ # self.assertIn("nodeId", callback_data);
+ self.assertTrue(callback_data.has_key("nodeId"));
+ self.failUnlessEqual(callback_data["nodeId"], "Device33");
+ # self.assertIn("timestamp", callback_data);
+ self.assertTrue(callback_data.has_key("timestamp"));
+ self.failUnlessEqual(callback_data["timestamp"], "2013-03-07T17:13:30");
+ # self.assertIn("error_msg", callback_data);
+ self.assertTrue(callback_data.has_key("error_msg"));
+ self.failUnlessEqual(callback_data["error_msg"], "Timeout.");
+
+ def testDelayedRequest(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device22");
+ myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
+ myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
+ myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
+
+ self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ dtnow = datetime.datetime.now()
+ ts_2sec = datetime.timedelta(0,2)
+ dtnow_plus_2sec = dtnow + ts_2sec
+ when_flag = dtnow_plus_2sec.replace(microsecond=0).isoformat()
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true' />
+ </iq>
+ """)
+
+ time.sleep(2)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
+ <node nodeId='Device22'>
+ <timestamp value='2013-03-07T16:24:30'>
+ <numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ def testDelayedRequestFail(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device22");
+ myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
+ myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
+ myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
+
+ self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ dtnow = datetime.datetime.now()
+ ts_2sec = datetime.timedelta(0,2)
+ dtnow_minus_2sec = dtnow - ts_2sec
+ when_flag = dtnow_minus_2sec.replace(microsecond=0).isoformat()
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
+ </iq>
+ """)
+
+ # Remove the returned datetime to allow predictable test
+ xml_stanza = self._filtered_stanza_prepare()
+ error_text = xml_stanza['rejected']['error'] #['text']
+ error_text = error_text[:error_text.find(':')]
+ xml_stanza['rejected']['error'] = error_text
+
+ self._filtered_stanza_check("""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <error>Invalid datetime in 'when' flag, cannot set a time in the past. Current time</error>
+ </rejected>
+ </iq>
+ """, xml_stanza)
+
+
+ def _filtered_stanza_prepare(self, timeout=.5):
+ sent = self.xmpp.socket.next_sent(timeout)
+ if sent is None:
+ self.fail("No stanza was sent.")
+
+ xml = self.parse_xml(sent)
+ self.fix_namespaces(xml, 'jabber:client')
+ sent = self.xmpp._build_stanza(xml, 'jabber:client')
+ return sent
+
+ def _filtered_stanza_check(self, data, filtered, defaults=None, use_values=True, method='exact'):
+ self.check(filtered, data,
+ method=method,
+ defaults=defaults,
+ use_values=use_values)
+
+ def testRequestFieldFrom(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='6'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' from='2000-01-02T00:00:01'>
+ <field name='Voltage'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='6'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-02-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-03-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.3' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testRequestFieldTo(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='6'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' to='2000-02-02T00:00:01'>
+ <field name='Voltage'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='6'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.1' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-02-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testRequestFieldFromTo(self):
+
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device44");
+ myDevice._add_field(name='Voltage', typename="numeric", unit="V");
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
+ myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
+
+ self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
+
+ print("."),
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='6'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='6' from='2000-01-01T00:01:03' to='2000-02-02T00:00:01'>
+ <field name='Voltage'/>
+ </req>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='6'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='6'/>
+ </iq>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
+ <node nodeId='Device44'>
+ <timestamp value='2000-02-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.send("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
+ </fields>
+ </message>
+ """)
+
+ def testDelayedRequestClient(self):
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+ callback_data = {};
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
+ results.append(result);
+ if result == "fields":
+ callback_data["nodeId"] = nodeId;
+ callback_data["timestamp"] = timestamp;
+ callback_data["error_msg"] = error_msg;
+ for f in fields:
+ callback_data["field_" + f['name']] = f;
+
+ t1= threading.Thread(name="request_data",
+ target=self.xmpp['xep_0323'].request_data,
+ kwargs={"from_jid": "tester@localhost",
+ "to_jid": "you@google.com",
+ "nodeIds": ['Device33'],
+ "callback": my_callback});
+ t1.start();
+ #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true'/>
+ </iq>
+ """)
+
+ self.recv("""
+ <message from='device@clayster.com'
+ to='master@clayster.com/amr'>
+ <started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </message>
+ """)
+
+ self.recv("""
+ <message from='you@google.com'
+ to='tester@localhost'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId='Device33'>
+ <timestamp value='2000-01-01T00:01:02'>
+ <numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
+ <boolean name='TestBool' value='true'/>
+ </timestamp>
+ </node>
+ </fields>
+ </message>
+ """)
+
+ self.recv("""
+ <message from='you@google.com'
+ to='tester@localhost'>
+ <fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
+ </message>
+ """)
+
+ t1.join();
+ time.sleep(.5)
+
+ self.failUnlessEqual(results, ["queued","started","fields","done"]);
+ # self.assertIn("nodeId", callback_data);
+ self.assertTrue(callback_data.has_key("nodeId"));
+ self.failUnlessEqual(callback_data["nodeId"], "Device33");
+ # self.assertIn("timestamp", callback_data);
+ self.assertTrue(callback_data.has_key("timestamp"));
+ self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02");
+ # self.assertIn("field_Voltage", callback_data);
+ self.assertTrue(callback_data.has_key("field_Voltage"));
+ self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}});
+ # self.assertIn("field_TestBool", callback_data);
+ self.assertTrue(callback_data.has_key("field_TestBool"));
+ self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" });
+
+
+ def testRequestFieldsCancelAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ results = [];
+
+ def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
+ results.append(result);
+
+ session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <node nodeId="Device33"/>
+ </req>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
+ </iq>
+ """)
+
+ self.xmpp['xep_0323'].cancel_request(session=session);
+
+ self.send("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <cancelled xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </iq>
+ """)
+
+ time.sleep(.5)
+
+ self.failUnlessEqual(results, ["accepted","cancelled"]);
+
+ def testDelayedRequestCancel(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0323'])
+
+ myDevice = Device("Device22");
+ myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
+ myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
+ myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
+
+ self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ dtnow = datetime.datetime.now()
+ ts_2sec = datetime.timedelta(0,2)
+ dtnow_plus_2sec = dtnow + ts_2sec
+ when_flag = dtnow_plus_2sec.replace(microsecond=0).isoformat()
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <req xmlns='urn:xmpp:iot:sensordata' seqnr='1' momentary='true' when='""" + when_flag + """'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true' />
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <cancelled xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </iq>
+ """)
+
+ # Test cancel of non-existing request
+ self.recv("""
+ <iq type='get'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <cancel xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='error'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
+ <error>Cancel request received, no matching request is active.</error>
+ </rejected>
+ </iq>
+ """)
+
+ time.sleep(2)
+
+ # Ensure we don't get anything after cancellation
+ self.send(None)
+
+
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamSensorData)
+
diff --git a/tests/test_stream_xep_0325.py b/tests/test_stream_xep_0325.py
new file mode 100644
index 00000000..4b3250fc
--- /dev/null
+++ b/tests/test_stream_xep_0325.py
@@ -0,0 +1,365 @@
+# -*- coding: utf-8 -*-
+"""
+ SleekXMPP: The Sleek XMPP Library
+ Implementation of xeps for Internet of Things
+ http://wiki.xmpp.org/web/Tech_pages/IoT_systems
+ Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se, bjorn.westrom@consoden.se
+ This file is part of SleekXMPP.
+
+ See the file LICENSE for copying permission.
+"""
+
+import sys
+import datetime
+import time
+import threading
+
+from sleekxmpp.test import *
+from sleekxmpp.xmlstream import ElementBase
+from sleekxmpp.plugins.xep_0325.device import Device
+
+
+class TestStreamControl(SleekTest):
+
+ """
+ Test using the XEP-0325 plugin.
+ """
+ def setUp(self):
+ pass
+
+ def _time_now(self):
+ return datetime.datetime.now().replace(microsecond=0).isoformat();
+
+ def tearDown(self):
+ self.stream_close()
+
+ def testRequestSetOk(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ myDevice = Device("Device22");
+ myDevice._add_control_field(name="Temperature", typename="int", value="15");
+
+ self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ self.recv("""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <int name="Temperature" value="17"/>
+ </set>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
+ </iq>
+ """)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "17");
+
+ def testRequestSetMulti(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ myDevice = Device("Device22");
+ myDevice._add_control_field(name="Temperature", typename="int", value="15");
+ myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03");
+
+ myDevice2 = Device("Device23");
+ myDevice2._add_control_field(name="Temperature", typename="int", value="19");
+ myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09");
+
+ self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+ self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5);
+
+ self.recv("""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device22' />
+ <int name="Temperature" value="17"/>
+ </set>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='1'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
+ </iq>
+ """)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "17");
+ self.assertEqual(myDevice2._get_field_value("Temperature"), "19");
+
+ self.recv("""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='2'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device23' />
+ <node nodeId='Device22' />
+ <date name="Startup" value="2013-02-01"/>
+ <int name="Temperature" value="20"/>
+ </set>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='2'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
+ </iq>
+ """)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "20");
+ self.assertEqual(myDevice2._get_field_value("Temperature"), "20");
+ self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01");
+ self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01");
+
+ def testRequestSetFail(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ myDevice = Device("Device23");
+ myDevice._add_control_field(name="Temperature", typename="int", value="15");
+
+ self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5);
+
+ self.recv("""
+ <iq type='set'
+ from='master@clayster.com/amr'
+ to='device@clayster.com'
+ id='9'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <int name="Voltage" value="17"/>
+ </set>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='error'
+ from='device@clayster.com'
+ to='master@clayster.com/amr'
+ id='9'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode='NotFound'>
+ <parameter name='Voltage' />
+ <error var='Output'>Invalid field Voltage</error>
+ </setResponse>
+ </iq>
+ """)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "15");
+ self.assertFalse(myDevice.has_control_field("Voltage", "int"));
+
+ def testDirectSetOk(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ myDevice = Device("Device22");
+ myDevice._add_control_field(name="Temperature", typename="int", value="15");
+
+ self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ self.recv("""
+ <message
+ from='master@clayster.com/amr'
+ to='device@clayster.com'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <int name="Temperature" value="17"/>
+ </set>
+ </message>
+ """)
+
+ time.sleep(.5)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "17");
+
+ def testDirectSetFail(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ myDevice = Device("Device22");
+ myDevice._add_control_field(name="Temperature", typename="int", value="15");
+
+ self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
+
+ self.recv("""
+ <message
+ from='master@clayster.com/amr'
+ to='device@clayster.com'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <int name="Voltage" value="17"/>
+ </set>
+ </message>
+ """)
+
+ time.sleep(.5)
+
+ self.assertEqual(myDevice._get_field_value("Temperature"), "15");
+ self.assertFalse(myDevice.has_control_field("Voltage", "int"));
+
+
+ def testRequestSetOkAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ results = [];
+
+ def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
+ results.append(result);
+
+ fields = []
+ fields.append(("Temperature", "double", "20.5"))
+ fields.append(("TemperatureAlarmSetting", "string", "High"))
+
+ self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback);
+
+ self.send("""
+ <iq type='set'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device33' />
+ <node nodeId='Device22' />
+ <double name="Temperature" value="20.5" />
+ <string name="TemperatureAlarmSetting" value="High" />
+ </set>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='result'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
+ </iq>
+ """)
+
+ time.sleep(.5)
+
+ self.assertEqual(results, ["OK"]);
+
+ def testRequestSetErrorAPI(self):
+
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0325'])
+
+ results = [];
+
+ def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
+ results.append(result);
+
+ fields = []
+ fields.append(("Temperature", "double", "20.5"))
+ fields.append(("TemperatureAlarmSetting", "string", "High"))
+
+ self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback);
+
+ self.send("""
+ <iq type='set'
+ from='tester@localhost'
+ to='you@google.com'
+ id='1'>
+ <set xmlns='urn:xmpp:iot:control'>
+ <node nodeId='Device33' />
+ <node nodeId='Device22' />
+ <double name="Temperature" value="20.5" />
+ <string name="TemperatureAlarmSetting" value="High" />
+ </set>
+ </iq>
+ """)
+
+ self.recv("""
+ <iq type='error'
+ from='you@google.com'
+ to='tester@localhost'
+ id='1'>
+ <setResponse xmlns='urn:xmpp:iot:control' responseCode="OtherError" >
+ <error var='Temperature'>Sensor error</error>
+ </setResponse>
+ </iq>
+ """)
+
+ time.sleep(.5)
+
+ self.assertEqual(results, ["OtherError"]);
+
+ def testServiceDiscoveryClient(self):
+ self.stream_start(mode='client',
+ plugins=['xep_0030',
+ 'xep_0325']);
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='tester@localhost'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ to='master@clayster.com/amr'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'>
+ <identity category='client' type='bot'/>
+ <feature var='urn:xmpp:iot:control'/>
+ </query>
+ </iq>
+ """)
+
+ def testServiceDiscoveryComponent(self):
+ self.stream_start(mode='component',
+ plugins=['xep_0030',
+ 'xep_0325']);
+
+ self.recv("""
+ <iq type='get'
+ from='master@clayster.com/amr'
+ to='tester@localhost'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'/>
+ </iq>
+ """)
+
+ self.send("""
+ <iq type='result'
+ from='tester@localhost'
+ to='master@clayster.com/amr'
+ id='disco1'>
+ <query xmlns='http://jabber.org/protocol/disco#info'>
+ <identity category='component' type='generic'/>
+ <feature var='urn:xmpp:iot:control'/>
+ </query>
+ </iq>
+ """)
+
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamControl)
+