2017-11-10 09:44:02 +00:00
|
|
|
import json
|
|
|
|
import boto3
|
2020-10-06 05:54:49 +00:00
|
|
|
import pytest
|
2017-11-10 09:44:02 +00:00
|
|
|
from botocore.exceptions import ClientError
|
2022-02-10 09:02:40 +00:00
|
|
|
|
|
|
|
import moto.iotdata.models
|
|
|
|
from moto import mock_iotdata, mock_iot, settings
|
2022-08-13 09:49:43 +00:00
|
|
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_iot
|
|
|
|
@mock_iotdata
|
|
|
|
def test_basic():
|
|
|
|
iot_client = boto3.client("iot", region_name="ap-northeast-1")
|
|
|
|
client = boto3.client("iot-data", region_name="ap-northeast-1")
|
|
|
|
name = "my-thing"
|
|
|
|
raw_payload = b'{"state": {"desired": {"led": "on"}}}'
|
|
|
|
iot_client.create_thing(thingName=name)
|
|
|
|
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError):
|
2017-11-10 09:44:02 +00:00
|
|
|
client.get_thing_shadow(thingName=name)
|
|
|
|
|
|
|
|
res = client.update_thing_shadow(thingName=name, payload=raw_payload)
|
|
|
|
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = '{"desired": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["desired"]
|
|
|
|
assert payload["version"] == 1
|
|
|
|
assert "timestamp" in payload
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
res = client.get_thing_shadow(thingName=name)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = b'{"desired": {"led": "on"}, "delta": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["desired"]
|
|
|
|
assert payload["version"] == 1
|
|
|
|
assert "timestamp" in payload
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
client.delete_thing_shadow(thingName=name)
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError):
|
2017-11-10 09:44:02 +00:00
|
|
|
client.get_thing_shadow(thingName=name)
|
|
|
|
|
|
|
|
|
|
|
|
@mock_iot
|
|
|
|
@mock_iotdata
|
|
|
|
def test_update():
|
|
|
|
iot_client = boto3.client("iot", region_name="ap-northeast-1")
|
|
|
|
client = boto3.client("iot-data", region_name="ap-northeast-1")
|
|
|
|
name = "my-thing"
|
|
|
|
raw_payload = b'{"state": {"desired": {"led": "on"}}}'
|
|
|
|
iot_client.create_thing(thingName=name)
|
|
|
|
|
|
|
|
# first update
|
|
|
|
res = client.update_thing_shadow(thingName=name, payload=raw_payload)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = '{"desired": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["desired"]
|
|
|
|
assert payload["version"] == 1
|
|
|
|
assert "timestamp" in payload
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
res = client.get_thing_shadow(thingName=name)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = b'{"desired": {"led": "on"}, "delta": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["desired"]
|
|
|
|
assert payload["version"] == 1
|
|
|
|
assert "timestamp" in payload
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
# reporting new state
|
|
|
|
new_payload = b'{"state": {"reported": {"led": "on"}}}'
|
|
|
|
res = client.update_thing_shadow(thingName=name, payload=new_payload)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = '{"reported": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["reported"]
|
|
|
|
assert payload["version"] == 2
|
|
|
|
assert "timestamp" in payload
|
2017-11-10 09:44:02 +00:00
|
|
|
|
|
|
|
res = client.get_thing_shadow(thingName=name)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
expected_state = b'{"desired": {"led": "on"}, "reported": {"led": "on"}}'
|
2023-08-09 07:37:49 +00:00
|
|
|
assert payload["state"] == json.loads(expected_state)
|
|
|
|
assert "led" in payload["metadata"]["desired"]
|
|
|
|
assert payload["version"] == 2
|
|
|
|
assert "timestamp" in payload
|
2017-11-24 17:22:53 +00:00
|
|
|
|
2019-08-26 04:28:56 +00:00
|
|
|
raw_payload = b'{"state": {"desired": {"led": "on"}}, "version": 1}'
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError) as ex:
|
2019-08-26 04:28:56 +00:00
|
|
|
client.update_thing_shadow(thingName=name, payload=raw_payload)
|
2023-08-09 07:37:49 +00:00
|
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 409
|
|
|
|
assert ex.value.response["Error"]["Message"] == "Version conflict"
|
2019-08-26 04:28:56 +00:00
|
|
|
|
2017-11-24 17:22:53 +00:00
|
|
|
|
2023-08-11 07:20:44 +00:00
|
|
|
@mock_iot
|
|
|
|
@mock_iotdata
|
|
|
|
def test_create_named_shadows():
|
|
|
|
iot_client = boto3.client("iot", region_name="ap-northeast-1")
|
|
|
|
client = boto3.client("iot-data", region_name="ap-northeast-1")
|
|
|
|
thing_name = "my-thing"
|
|
|
|
iot_client.create_thing(thingName=thing_name)
|
|
|
|
|
|
|
|
# default shadow
|
|
|
|
default_payload = json.dumps({"state": {"desired": {"name": "default"}}})
|
|
|
|
res = client.update_thing_shadow(thingName=thing_name, payload=default_payload)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
assert payload["state"] == {"desired": {"name": "default"}}
|
|
|
|
|
|
|
|
# Create named shadows
|
|
|
|
for name in ["shadow1", "shadow2"]:
|
|
|
|
named_payload = json.dumps({"state": {"reported": {"name": name}}}).encode(
|
|
|
|
"utf-8"
|
|
|
|
)
|
|
|
|
client.update_thing_shadow(
|
|
|
|
thingName=thing_name, payload=named_payload, shadowName=name
|
|
|
|
)
|
|
|
|
|
|
|
|
res = client.get_thing_shadow(thingName=thing_name, shadowName=name)
|
|
|
|
payload = json.loads(res["payload"].read())
|
|
|
|
assert payload["state"]["reported"] == {"name": name}
|
|
|
|
|
|
|
|
# List named shadows
|
|
|
|
shadows = client.list_named_shadows_for_thing(thingName=thing_name)["results"]
|
|
|
|
assert len(shadows) == 2
|
|
|
|
|
|
|
|
for shadow in shadows:
|
|
|
|
shadow.pop("metadata")
|
|
|
|
shadow.pop("timestamp")
|
|
|
|
shadow.pop("version")
|
|
|
|
|
|
|
|
# Verify both named shadows are present
|
|
|
|
for name in ["shadow1", "shadow2"]:
|
|
|
|
assert {
|
|
|
|
"state": {"reported": {"name": name}, "delta": {"name": name}}
|
|
|
|
} in shadows
|
|
|
|
|
|
|
|
# Verify we can delete a named shadow
|
|
|
|
client.delete_thing_shadow(thingName=thing_name, shadowName="shadow2")
|
|
|
|
|
|
|
|
with pytest.raises(ClientError):
|
|
|
|
client.get_thing_shadow(thingName="shadow1")
|
|
|
|
|
|
|
|
# The default and other named shadow are still there
|
|
|
|
assert "payload" in client.get_thing_shadow(thingName=thing_name)
|
|
|
|
assert "payload" in client.get_thing_shadow(
|
|
|
|
thingName=thing_name, shadowName="shadow1"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2017-11-24 17:22:53 +00:00
|
|
|
@mock_iotdata
|
|
|
|
def test_publish():
|
2022-02-10 09:02:40 +00:00
|
|
|
region_name = "ap-northeast-1"
|
|
|
|
client = boto3.client("iot-data", region_name=region_name)
|
2023-01-03 21:21:52 +00:00
|
|
|
client.publish(topic="test/topic1", qos=1, payload=b"pl1")
|
|
|
|
client.publish(topic="test/topic2", qos=1, payload=b"pl2")
|
2023-07-11 09:31:44 +00:00
|
|
|
client.publish(topic="test/topic3", qos=1, payload=b"\xbf")
|
2022-02-10 09:02:40 +00:00
|
|
|
|
|
|
|
if not settings.TEST_SERVER_MODE:
|
2022-08-13 09:49:43 +00:00
|
|
|
mock_backend = moto.iotdata.models.iotdata_backends[ACCOUNT_ID][region_name]
|
2023-08-09 07:37:49 +00:00
|
|
|
assert len(mock_backend.published_payloads) == 3
|
|
|
|
assert ("test/topic1", b"pl1") in mock_backend.published_payloads
|
|
|
|
assert ("test/topic2", b"pl2") in mock_backend.published_payloads
|
|
|
|
assert ("test/topic3", b"\xbf") in mock_backend.published_payloads
|
2021-06-30 07:15:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_iot
|
|
|
|
@mock_iotdata
|
|
|
|
def test_delete_field_from_device_shadow():
|
|
|
|
test_thing_name = "TestThing"
|
|
|
|
|
|
|
|
iot_raw_client = boto3.client("iot", region_name="eu-central-1")
|
|
|
|
iot_raw_client.create_thing(thingName=test_thing_name)
|
|
|
|
iot = boto3.client("iot-data", region_name="eu-central-1")
|
|
|
|
|
|
|
|
iot.update_thing_shadow(
|
|
|
|
thingName=test_thing_name,
|
|
|
|
payload=json.dumps({"state": {"desired": {"state1": 1, "state2": 2}}}),
|
|
|
|
)
|
|
|
|
response = json.loads(
|
|
|
|
iot.get_thing_shadow(thingName=test_thing_name)["payload"].read()
|
|
|
|
)
|
|
|
|
assert len(response["state"]["desired"]) == 2
|
|
|
|
|
|
|
|
iot.update_thing_shadow(
|
|
|
|
thingName=test_thing_name,
|
|
|
|
payload=json.dumps({"state": {"desired": {"state1": None}}}),
|
|
|
|
)
|
|
|
|
response = json.loads(
|
|
|
|
iot.get_thing_shadow(thingName=test_thing_name)["payload"].read()
|
|
|
|
)
|
|
|
|
assert len(response["state"]["desired"]) == 1
|
|
|
|
assert "state2" in response["state"]["desired"]
|
|
|
|
|
|
|
|
iot.update_thing_shadow(
|
|
|
|
thingName=test_thing_name,
|
|
|
|
payload=json.dumps({"state": {"desired": {"state2": None}}}),
|
|
|
|
)
|
|
|
|
response = json.loads(
|
|
|
|
iot.get_thing_shadow(thingName=test_thing_name)["payload"].read()
|
|
|
|
)
|
|
|
|
assert "desired" not in response["state"]
|