added helpers for storage
This commit is contained in:
Родитель
30ed120210
Коммит
37cdabb318
11
CHANGELOG
11
CHANGELOG
|
@ -1,3 +1,14 @@
|
|||
1.1.2 (2021-11-8)
|
||||
-----------------
|
||||
- added credentials cache serialize/deserialize methods
|
||||
- added "Property" model
|
||||
- added storage tests
|
||||
|
||||
1.1.1 (2021-06-25)
|
||||
-----------------
|
||||
- minor fixes for value wrapping
|
||||
|
||||
|
||||
1.1.0 (2021-02-05)
|
||||
-----------------
|
||||
- dropped Python 2.7 support (client should continue to work without tests)
|
||||
|
|
|
@ -5,6 +5,8 @@ import sys
|
|||
|
||||
from random import randint
|
||||
|
||||
from iotc.models import Property,Command
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__), "samples.ini"))
|
||||
|
||||
|
@ -29,11 +31,6 @@ key = config["DEVICE_M3"]["DeviceKey"]
|
|||
|
||||
class MemStorage(Storage):
|
||||
def retrieve(self):
|
||||
# return CredentialsCache(
|
||||
# hub_name,
|
||||
# device_id,
|
||||
# key,
|
||||
# )
|
||||
return None
|
||||
|
||||
def persist(self, credentials):
|
||||
|
@ -48,8 +45,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
async def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
async def on_props(prop:Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ from iotc import (
|
|||
IOTCConnectType,
|
||||
IOTCLogLevel,
|
||||
IOTCEvents,
|
||||
Command,
|
||||
CredentialsCache,
|
||||
Storage,
|
||||
)
|
||||
from iotc.models import Command, Property
|
||||
import os
|
||||
import asyncio
|
||||
import configparser
|
||||
|
@ -76,8 +76,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
async def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
async def on_props(prop: Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
from iotc.models import Command, Property, CredentialsCache, Storage
|
||||
from iotc.aio import IoTCClient
|
||||
from iotc import (
|
||||
IOTCConnectType,
|
||||
IOTCLogLevel,
|
||||
IOTCEvents,
|
||||
)
|
||||
import os
|
||||
import asyncio
|
||||
import configparser
|
||||
|
@ -12,22 +19,13 @@ config.read(os.path.join(os.path.dirname(__file__), "samples.ini"))
|
|||
if config["DEFAULT"].getboolean("Local"):
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from iotc import (
|
||||
IOTCConnectType,
|
||||
IOTCLogLevel,
|
||||
IOTCEvents,
|
||||
Command,
|
||||
CredentialsCache,
|
||||
Storage,
|
||||
)
|
||||
from iotc.aio import IoTCClient
|
||||
|
||||
class FileLogger:
|
||||
def __init__(self,logpath,logname="iotc_py_log"):
|
||||
self._logger=logging.getLogger(logname)
|
||||
def __init__(self, logpath, logname="iotc_py_log"):
|
||||
self._logger = logging.getLogger(logname)
|
||||
self._logger.setLevel(logging.DEBUG)
|
||||
handler= logging.handlers.RotatingFileHandler(
|
||||
os.path.join(logpath,logname), maxBytes=20, backupCount=5)
|
||||
handler = logging.handlers.RotatingFileHandler(
|
||||
os.path.join(logpath, logname), maxBytes=20, backupCount=5)
|
||||
self._logger.addHandler(handler)
|
||||
|
||||
async def _log(self, message):
|
||||
|
@ -46,7 +44,6 @@ class FileLogger:
|
|||
self._log_level = log_level
|
||||
|
||||
|
||||
|
||||
device_id = config["DEVICE_M3"]["DeviceId"]
|
||||
scope_id = config["DEVICE_M3"]["ScopeId"]
|
||||
key = config["DEVICE_M3"]["DeviceKey"]
|
||||
|
@ -54,7 +51,6 @@ hub_name = config["DEVICE_M3"]["HubName"]
|
|||
log_path = config['FileLog']['LogsPath']
|
||||
|
||||
|
||||
|
||||
class MemStorage(Storage):
|
||||
def retrieve(self):
|
||||
return CredentialsCache(
|
||||
|
@ -75,8 +71,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
async def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
async def on_props(prop: Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
@ -85,8 +81,9 @@ async def on_commands(command: Command):
|
|||
await command.reply()
|
||||
|
||||
|
||||
async def on_enqueued_commands(command:Command):
|
||||
print("Received offline command {} with value {}".format(command.name, command.value))
|
||||
async def on_enqueued_commands(command: Command):
|
||||
print("Received offline command {} with value {}".format(
|
||||
command.name, command.value))
|
||||
|
||||
|
||||
# change connect type to reflect the used key (device or group)
|
||||
|
@ -106,16 +103,17 @@ client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
|||
client.on(IOTCEvents.IOTC_COMMAND, on_commands)
|
||||
client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqueued_commands)
|
||||
|
||||
|
||||
async def main():
|
||||
await client.connect()
|
||||
await client.send_property({"writeableProp": 50})
|
||||
|
||||
|
||||
while not client.terminated():
|
||||
if client.is_connected():
|
||||
await client.send_telemetry(
|
||||
{
|
||||
"temperature": randint(20, 45)
|
||||
},{
|
||||
}, {
|
||||
"$.sub": "firstcomponent"
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from iotc.models import Storage, CredentialsCache, Command, Property
|
||||
from iotc.aio import IoTCClient
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents
|
||||
import os
|
||||
import asyncio
|
||||
import configparser
|
||||
|
@ -5,20 +8,19 @@ import sys
|
|||
from random import randint
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__),'samples.ini'))
|
||||
config.read(os.path.join(os.path.dirname(__file__), 'samples.ini'))
|
||||
|
||||
# Change config section name to reflect sample.ini
|
||||
device_id = config['DEVICE_A']['DeviceId']
|
||||
scope_id = config['DEVICE_A']['ScopeId']
|
||||
hub_name = config["DEVICE_A"]["HubName"]
|
||||
x509 = {'cert_file': config['DEVICE_A']['CertFilePath'],'key_file':config['DEVICE_A']['KeyFilePath'],'cert_phrase':config['DEVICE_A']['CertPassphrase']}
|
||||
x509 = {'cert_file': config['DEVICE_A']['CertFilePath'], 'key_file': config['DEVICE_A']
|
||||
['KeyFilePath'], 'cert_phrase': config['DEVICE_A']['CertPassphrase']}
|
||||
|
||||
|
||||
if config['DEFAULT'].getboolean('Local'):
|
||||
sys.path.insert(0, 'src')
|
||||
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents
|
||||
from iotc.aio import IoTCClient
|
||||
|
||||
class MemStorage(Storage):
|
||||
def retrieve(self):
|
||||
|
@ -40,8 +42,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
async def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
async def on_props(prop: Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
@ -50,8 +52,9 @@ async def on_commands(command: Command):
|
|||
await command.reply()
|
||||
|
||||
|
||||
async def on_enqueued_commands(command:Command):
|
||||
print("Received offline command {} with value {}".format(command.name, command.value))
|
||||
async def on_enqueued_commands(command: Command):
|
||||
print("Received offline command {} with value {}".format(
|
||||
command.name, command.value))
|
||||
|
||||
|
||||
# change connect type to reflect the used key (device or group)
|
||||
|
@ -70,16 +73,17 @@ client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
|||
client.on(IOTCEvents.IOTC_COMMAND, on_commands)
|
||||
client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqueued_commands)
|
||||
|
||||
|
||||
async def main():
|
||||
await client.connect()
|
||||
await client.send_property({"writeableProp": 50})
|
||||
|
||||
|
||||
while not client.terminated():
|
||||
if client.is_connected():
|
||||
await client.send_telemetry(
|
||||
{
|
||||
"temperature": randint(20, 45)
|
||||
},{
|
||||
}, {
|
||||
"$.sub": "firstcomponent"
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
from iotc.models import Command, Storage, CredentialsCache, Property
|
||||
from iotc import IoTCClient
|
||||
from iotc import (
|
||||
IOTCConnectType,
|
||||
IOTCLogLevel,
|
||||
IOTCEvents,
|
||||
)
|
||||
import os
|
||||
import configparser
|
||||
from re import M
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
@ -11,15 +19,6 @@ config.read(os.path.join(os.path.dirname(__file__), "samples.ini"))
|
|||
if config["DEFAULT"].getboolean("Local"):
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from iotc import (
|
||||
IOTCConnectType,
|
||||
IOTCLogLevel,
|
||||
IOTCEvents,
|
||||
Command,
|
||||
CredentialsCache,
|
||||
Storage,
|
||||
)
|
||||
from iotc import IoTCClient
|
||||
|
||||
device_id = config["DEVICE_M3"]["DeviceId"]
|
||||
scope_id = config["DEVICE_M3"]["ScopeId"]
|
||||
|
@ -47,8 +46,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
def on_props(prop: Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
@ -58,7 +57,8 @@ def on_commands(command):
|
|||
|
||||
|
||||
def on_enqueued_commands(command):
|
||||
print("Received offline command {} with value {}".format(command.name, command.value))
|
||||
print("Received offline command {} with value {}".format(
|
||||
command.name, command.value))
|
||||
|
||||
|
||||
# change connect type to reflect the used key (device or group)
|
||||
|
@ -81,7 +81,7 @@ client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqueued_commands)
|
|||
def main():
|
||||
client.connect()
|
||||
client.send_property({"writeableProp": 50})
|
||||
|
||||
|
||||
while not client.terminated():
|
||||
if client.is_connected():
|
||||
client.send_telemetry(
|
||||
|
@ -93,4 +93,5 @@ def main():
|
|||
)
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
main()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from iotc.models import CredentialsCache, Storage, Property, Command
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents, IoTCClient
|
||||
import os
|
||||
import configparser
|
||||
import sys
|
||||
|
@ -5,20 +7,19 @@ from random import randint
|
|||
import time
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__),'samples.ini'))
|
||||
config.read(os.path.join(os.path.dirname(__file__), 'samples.ini'))
|
||||
|
||||
# Change config section name to reflect sample.ini
|
||||
device_id = config['DEVICE_A']['DeviceId']
|
||||
scope_id = config['DEVICE_A']['ScopeId']
|
||||
hub_name = config["DEVICE_A"]["HubName"]
|
||||
x509 = {'cert_file': config['DEVICE_A']['CertFilePath'],'key_file':config['DEVICE_A']['KeyFilePath'],'cert_phrase':config['DEVICE_A']['CertPassphrase']}
|
||||
x509 = {'cert_file': config['DEVICE_A']['CertFilePath'], 'key_file': config['DEVICE_A']
|
||||
['KeyFilePath'], 'cert_phrase': config['DEVICE_A']['CertPassphrase']}
|
||||
|
||||
|
||||
if config['DEFAULT'].getboolean('Local'):
|
||||
sys.path.insert(0, 'src')
|
||||
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents,IoTCClient
|
||||
|
||||
|
||||
class MemStorage(Storage):
|
||||
def retrieve(self):
|
||||
|
@ -40,8 +41,8 @@ except:
|
|||
model_id = None
|
||||
|
||||
|
||||
def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
def on_props(prop: Property):
|
||||
print(f"Received {prop.name}:{prop.value}")
|
||||
return True
|
||||
|
||||
|
||||
|
@ -50,8 +51,9 @@ def on_commands(command: Command):
|
|||
command.reply()
|
||||
|
||||
|
||||
def on_enqueued_commands(command:Command):
|
||||
print("Received offline command {} with value {}".format(command.name, command.value))
|
||||
def on_enqueued_commands(command: Command):
|
||||
print("Received offline command {} with value {}".format(
|
||||
command.name, command.value))
|
||||
|
||||
|
||||
# change connect type to reflect the used key (device or group)
|
||||
|
@ -70,10 +72,11 @@ client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
|||
client.on(IOTCEvents.IOTC_COMMAND, on_commands)
|
||||
client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqueued_commands)
|
||||
|
||||
|
||||
def main():
|
||||
client.connect()
|
||||
client.send_property({"writeableProp": 50})
|
||||
|
||||
|
||||
while not client.terminated():
|
||||
if client.is_connected():
|
||||
client.send_telemetry(
|
||||
|
@ -85,4 +88,5 @@ def main():
|
|||
)
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
main()
|
||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ import sys
|
|||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
|
||||
setuptools.setup(
|
||||
name='iotc',
|
||||
|
|
|
@ -8,7 +8,7 @@ from azure.iot.device import IoTHubDeviceClient
|
|||
from azure.iot.device import ProvisioningDeviceClient
|
||||
from azure.iot.device import Message, MethodResponse
|
||||
from datetime import datetime
|
||||
from .models import Command, CredentialsCache, Storage, GracefulExit
|
||||
from .models import Command, CredentialsCache, Property, Storage, GracefulExit
|
||||
|
||||
try:
|
||||
__version__ = pkg_resources.get_distribution("iotc").version
|
||||
|
@ -266,7 +266,8 @@ class IoTCClient(AbstractClient):
|
|||
component_name=None,
|
||||
):
|
||||
if callback is not None:
|
||||
ret = callback(property_name, property_value, component_name)
|
||||
prop = Property(property_name, property_value, component_name)
|
||||
ret = callback(prop)
|
||||
else:
|
||||
ret = True
|
||||
if ret:
|
||||
|
@ -571,8 +572,8 @@ class IoTCClient(AbstractClient):
|
|||
self._device_client.on_method_request_received = self._on_commands
|
||||
self._device_client.on_message_received = self._on_enqueued_commands
|
||||
|
||||
self._conn_thread=threading.Thread(target=self._on_connection_state)
|
||||
self._conn_thread.daemon=True
|
||||
self._conn_thread = threading.Thread(target=self._on_connection_state)
|
||||
self._conn_thread.daemon = True
|
||||
self._conn_thread.start()
|
||||
|
||||
signal.signal(signal.SIGINT, self.disconnect)
|
||||
|
|
|
@ -2,6 +2,8 @@ import sys
|
|||
import signal
|
||||
import asyncio
|
||||
import pkg_resources
|
||||
|
||||
from iotc.models import Property
|
||||
from .. import (
|
||||
AbstractClient,
|
||||
IOTCLogLevel,
|
||||
|
@ -116,7 +118,8 @@ class IoTCClient(AbstractClient):
|
|||
component_name=None,
|
||||
):
|
||||
if callback is not None:
|
||||
ret = await callback(property_name, property_value, component_name)
|
||||
prop = Property(property_name, property_value, component_name)
|
||||
ret = await callback(prop)
|
||||
else:
|
||||
ret = True
|
||||
if ret:
|
||||
|
@ -362,6 +365,9 @@ class IoTCClient(AbstractClient):
|
|||
else None,
|
||||
)
|
||||
|
||||
if self._storage is not None:
|
||||
self._storage.persist(_credentials)
|
||||
|
||||
except Exception as e:
|
||||
await self._logger.info(
|
||||
"ERROR: Failed to get device provisioning information. {}".format(
|
||||
|
@ -409,7 +415,7 @@ class IoTCClient(AbstractClient):
|
|||
self._device_client.on_method_request_received = self._on_commands
|
||||
self._device_client.on_message_received = self._on_enqueued_commands
|
||||
|
||||
if hasattr(self,'_conn_thread') and self._conn_thread is not None:
|
||||
if hasattr(self, '_conn_thread') and self._conn_thread is not None:
|
||||
try:
|
||||
self._conn_thread.cancel()
|
||||
await self._conn_thread
|
||||
|
@ -432,7 +438,7 @@ class IoTCClient(AbstractClient):
|
|||
async def disconnect(self):
|
||||
await self._logger.info("Received shutdown signal")
|
||||
self._terminate = True
|
||||
if hasattr(self,'_conn_thread') and self._conn_thread is not None:
|
||||
if hasattr(self, '_conn_thread') and self._conn_thread is not None:
|
||||
tasks = asyncio.gather(
|
||||
self._conn_thread
|
||||
)
|
||||
|
|
|
@ -41,6 +41,18 @@ class CredentialsCache(object):
|
|||
self._hub_name, self._device_id
|
||||
)
|
||||
|
||||
def todict(self):
|
||||
return {
|
||||
"device_id": self.device_id,
|
||||
"hub_name": self.hub_name,
|
||||
"connection_string": self.connection_string,
|
||||
"device_key": self.device_key,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(classref, data: dict):
|
||||
return CredentialsCache(data["hub_name"], data["device_id"], data["device_key"])
|
||||
|
||||
|
||||
class Storage(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
@ -75,3 +87,31 @@ class Command(object):
|
|||
@property
|
||||
def component_name(self):
|
||||
return self._component_name
|
||||
|
||||
def __eq__(self, o: object) -> bool:
|
||||
return self.name == o.name and self.value == o.value and self.component_name == o.component_name
|
||||
|
||||
|
||||
class Property(object):
|
||||
def __init__(self, property_name, property_value, component_name=None):
|
||||
self._property_name = property_name
|
||||
self._property_value = property_value
|
||||
if component_name is not None:
|
||||
self._component_name = component_name
|
||||
else:
|
||||
self._component_name = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._property_name
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._property_value
|
||||
|
||||
@property
|
||||
def component_name(self):
|
||||
return self._component_name
|
||||
|
||||
def __eq__(self, o: object) -> bool:
|
||||
return self.name == o.name and self.value == o.value and self.component_name == o.component_name
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from iotc.models import Property
|
||||
from iotc.test import dummy_storage
|
||||
from iotc.aio import IoTCClient
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents, Command
|
||||
|
@ -80,7 +81,7 @@ async def test_on_properties_triggered(mocker, iotc_client):
|
|||
iotc_client.on(IOTCEvents.IOTC_PROPERTIES, prop_stub)
|
||||
await iotc_client.connect()
|
||||
await iotc_client._device_client.on_twin_desired_properties_patch_received(DEFAULT_COMPONENT_PROP)
|
||||
prop_stub.assert_called_with("prop1", "value1", None)
|
||||
prop_stub.assert_called_with(Property("prop1", "value1"))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -91,7 +92,7 @@ async def test_on_properties_triggered_with_component(mocker, iotc_client):
|
|||
iotc_client.on(IOTCEvents.IOTC_PROPERTIES, prop_stub)
|
||||
await iotc_client.connect()
|
||||
await iotc_client._device_client.on_twin_desired_properties_patch_received(COMPONENT_PROP)
|
||||
prop_stub.assert_called_with("prop1", "value1", "component1")
|
||||
prop_stub.assert_called_with(Property("prop1", "value1", "component1"))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -104,10 +105,10 @@ async def test_on_properties_triggered_with_complex_component(mocker, iotc_clien
|
|||
await iotc_client._device_client.on_twin_desired_properties_patch_received(COMPLEX_COMPONENT_PROP)
|
||||
prop_stub.assert_has_calls(
|
||||
[
|
||||
mocker.call("prop1", {"item1": "value1"}, "component1"),
|
||||
mocker.call("prop1", "value1", "component2"),
|
||||
mocker.call("prop2", 2, "component2"),
|
||||
mocker.call("prop2", {"item2": "value2"}, None),
|
||||
mocker.call(Property("prop1", {"item1": "value1"}, "component1")),
|
||||
mocker.call(Property("prop1", "value1", "component2")),
|
||||
mocker.call(Property("prop2", 2, "component2")),
|
||||
mocker.call(Property("prop2", {"item2": "value2"})),
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents, IoTCClient, Command
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents, IoTCClient
|
||||
from iotc.test import dummy_storage
|
||||
from iotc.models import Command, Property
|
||||
from azure.iot.device import MethodRequest, Message
|
||||
import pytest
|
||||
import configparser
|
||||
|
@ -76,8 +77,9 @@ def test_on_properties_triggered(mocker, iotc_client):
|
|||
prop_stub = mocker.MagicMock()
|
||||
iotc_client.on(IOTCEvents.IOTC_PROPERTIES, prop_stub)
|
||||
iotc_client.connect()
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(DEFAULT_COMPONENT_PROP)
|
||||
prop_stub.assert_called_with("prop1", {"value":"value1"}, None)
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(
|
||||
DEFAULT_COMPONENT_PROP)
|
||||
prop_stub.assert_called_with(Property("prop1", {"value": "value1"}))
|
||||
|
||||
|
||||
def test_on_properties_triggered_with_component(mocker, iotc_client):
|
||||
|
@ -86,8 +88,10 @@ def test_on_properties_triggered_with_component(mocker, iotc_client):
|
|||
prop_stub.return_value = True
|
||||
iotc_client.on(IOTCEvents.IOTC_PROPERTIES, prop_stub)
|
||||
iotc_client.connect()
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(COMPONENT_PROP)
|
||||
prop_stub.assert_called_with("prop1", {"value": "value1"}, "component1")
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(
|
||||
COMPONENT_PROP)
|
||||
prop_stub.assert_called_with(
|
||||
Property("prop1", {"value": "value1"}, "component1"))
|
||||
|
||||
|
||||
def test_on_properties_triggered_with_complex_component(mocker, iotc_client):
|
||||
|
@ -96,13 +100,14 @@ def test_on_properties_triggered_with_complex_component(mocker, iotc_client):
|
|||
prop_stub.return_value = True
|
||||
iotc_client.on(IOTCEvents.IOTC_PROPERTIES, prop_stub)
|
||||
iotc_client.connect()
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(COMPLEX_COMPONENT_PROP)
|
||||
iotc_client._device_client.on_twin_desired_properties_patch_received(
|
||||
COMPLEX_COMPONENT_PROP)
|
||||
prop_stub.assert_has_calls(
|
||||
[
|
||||
mocker.call("prop1", {"item1": "value1"}, "component1"),
|
||||
mocker.call("prop1", "value1", "component2"),
|
||||
mocker.call("prop2", 2, "component2"),
|
||||
mocker.call("prop2", {"item2": "value2"}, None),
|
||||
mocker.call(Property("prop1", {"item1": "value1"}, "component1")),
|
||||
mocker.call(Property("prop1", "value1", "component2")),
|
||||
mocker.call(Property("prop2", 2, "component2")),
|
||||
mocker.call(Property("prop2", {"item2": "value2"})),
|
||||
], any_order=True
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import pytest
|
||||
from iotc.models import CredentialsCache
|
||||
from iotc.models import Storage
|
||||
|
||||
|
||||
class MemStorage(Storage):
|
||||
def __init__(self, initial=None):
|
||||
if initial:
|
||||
self.creds = initial
|
||||
else:
|
||||
self.creds = {}
|
||||
|
||||
def persist(self, credentials: CredentialsCache):
|
||||
self.creds = credentials.todict()
|
||||
|
||||
def retrieve(self):
|
||||
return CredentialsCache.from_dict(self.creds)
|
||||
|
||||
|
||||
def test_storage_persist():
|
||||
creds = CredentialsCache('hub_name', 'device_id', 'device_key')
|
||||
storage = MemStorage()
|
||||
storage.persist(creds)
|
||||
assert storage.creds['hub_name'] == creds.hub_name
|
||||
assert storage.creds['device_id'] == creds.device_id
|
||||
assert storage.creds['device_key'] == creds.device_key
|
||||
|
||||
|
||||
def test_storage_retrieve():
|
||||
storage = MemStorage(
|
||||
{'hub_name': 'hub_name', 'device_id': 'device_id', 'device_key': 'device_key'})
|
||||
creds = storage.retrieve()
|
||||
assert creds.hub_name == 'hub_name'
|
||||
assert creds.device_id == 'device_id'
|
||||
assert creds.device_key == 'device_key'
|
||||
|
||||
|
||||
def test_connection_string():
|
||||
storage = MemStorage()
|
||||
creds = CredentialsCache('hub_name', 'device_id', 'device_key')
|
||||
storage.persist(creds)
|
||||
cstring = "HostName=hub_name;DeviceId=device_id;SharedAccessKey=device_key"
|
||||
assert cstring == creds.connection_string
|
||||
assert (storage.retrieve()).connection_string == cstring
|
Загрузка…
Ссылка в новой задаче