Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: update content-encoding / content-type property names and other fixes #728

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
17 changes: 17 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
Release History
===============

0.26.0
+++++++++++++++

**General updates**

* We have dropped support for Python 3.8
* This extension now supports Python 3.12 as the CLI core is packaging newer releases with this python version,
* **[Breaking Change]** Older versions of `uamqp` (below `1.6.6`) are not compatible with Python 3.12
* If you update your packaged AZ CLI version (`2.66.0` or later) or otherwise change your environment's Python version to 3.12, you will need to update your `uamqp` dependency to `1.6.6` or above in order to use commands like `az iot hub monitor-events`
* You can repair this dependency at command runtime by utilizing the `--repair` / `-r` argument in `az iot hub monitor-events`

**IoT device updates**

* **[Breaking Change]** Device c2d messages (`az iot device c2d-message`) have been updated to support the following service-side changes:
* `ContentEncoding` system property is now `content-encoding`
* `ContentType` system property is now `content-type`


0.25.0
+++++++++++++++
Expand Down
3 changes: 2 additions & 1 deletion azext_iot/common/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,10 @@ def test_import_and_version(package, expected_version):
that are installed without metadata.
"""
from importlib import metadata
from packaging.version import parse

try:
return metadata.version(package) >= expected_version
return parse(metadata.version(package)) >= parse(expected_version)
except metadata.PackageNotFoundError:
return False

Expand Down
4 changes: 2 additions & 2 deletions azext_iot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"iothub-expiry",
"iothub-deliverycount",
"iothub-enqueuedtime",
"ContentType",
"ContentEncoding",
"content-type",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Against the same api-version? Interesting.

"content-encoding",
]
c-ryan-k marked this conversation as resolved.
Show resolved Hide resolved
METHOD_INVOKE_MAX_TIMEOUT_SEC = 300
METHOD_INVOKE_MIN_TIMEOUT_SEC = 10
Expand Down
4 changes: 2 additions & 2 deletions azext_iot/iothub/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@ def load_iothub_help():
to `application/octet-stream`.
Note: The command only works for symmetric key auth (SAS) based devices.
To enable querying on a message body in message routing, the contentType
system property must be application/JSON and the contentEncoding system
To enable querying on a message body in message routing, the content-type
system property must be application/JSON and the content-encoding system
property must be one of the UTF encoding values supported by that system
property(UTF-8, UTF-16 or UTF-32). If the content encoding isn't set when
Azure Storage is used as routing endpoint, then IoT Hub writes the messages
Expand Down
2 changes: 1 addition & 1 deletion azext_iot/iothub/providers/device_messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def _c2d_message_receive(self, lock_timeout: int = 60, ack: Optional[str] = None
payload["properties"]["system"] = sys_props

if result.content:
target_encoding = result.headers.get("ContentEncoding", "utf-8")
target_encoding = result.headers.get("content-encoding", "utf-8")
payload["data"] = NON_DECODABLE_PAYLOAD
if target_encoding in ["utf-8", "utf8", "utf-16", "utf16", "utf-32", "utf32"]:
logger.info(f"Decoding message data encoded with: {target_encoding}")
Expand Down
10 changes: 5 additions & 5 deletions azext_iot/tests/iothub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ def __init__(self, test_scenario, add_data_contributor=True):
)
sleep(ROLE_ASSIGNMENT_REFRESH_TIME)

target_hub = self.cmd(
"iot hub show -n {} -g {}".format(self.entity_name, self.entity_rg)
).get_output_in_json()
target_hub = self.cmd(
"iot hub show -n {} -g {}".format(self.entity_name, self.entity_rg)
).get_output_in_json()

if add_data_contributor:
self._add_data_contributor(target_hub)
if add_data_contributor:
self._add_data_contributor(target_hub)

self.host_name = target_hub["properties"]["hostName"]
self.region = self.get_region()
Expand Down
38 changes: 21 additions & 17 deletions azext_iot/tests/iothub/core/test_iot_messaging_int.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
# --------------------------------------------------------------------------------------------

import os
from azext_iot.iothub.common import NON_DECODABLE_PAYLOAD
from azext_iot.tests.conftest import get_context_path
import pytest
import json
from time import time, sleep

from time import time
from uuid import uuid4
from azext_iot.iothub.common import NON_DECODABLE_PAYLOAD
from azext_iot.tests.conftest import get_context_path
from azext_iot.tests.helpers import CERT_ENDING, KEY_ENDING
from azext_iot.tests.iothub import IoTLiveScenarioTest, PREFIX_DEVICE
from azext_iot.common.utility import (
Expand Down Expand Up @@ -101,8 +101,8 @@ def test_uamqp_device_messaging(self):
assert result["data"] == test_body

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == test_ce
assert system_props["ContentType"] == test_ct
assert system_props["content-encoding"] == test_ce
assert system_props["content-type"] == test_ct
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -157,8 +157,8 @@ def test_uamqp_device_messaging(self):
self._remove_newlines_spaces(payload=self.kwargs["messaging_data"])

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == test_ce
assert system_props["ContentType"] == 'application/json'
assert system_props["content-encoding"] == test_ce
assert system_props["content-type"] == 'application/json'
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -209,8 +209,8 @@ def test_uamqp_device_messaging(self):
assert result["data"] == self.kwargs["messaging_unicodable_data"]

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == test_ce
assert system_props["ContentType"] == 'application/octet-stream'
assert system_props["content-encoding"] == test_ce
assert system_props["content-type"] == 'application/octet-stream'
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -261,8 +261,8 @@ def test_uamqp_device_messaging(self):
assert result["data"] == self.kwargs["messaging_non_unicodable_data"]

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == test_ce
assert system_props["ContentType"] == 'application/octet-stream'
assert system_props["content-encoding"] == test_ce
assert system_props["content-type"] == 'application/octet-stream'
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -310,11 +310,12 @@ def test_uamqp_device_messaging(self):
)
).get_output_in_json()

assert result["data"] == self.kwargs["messaging_non_unicodable_data"]
# no data in this result
# assert result["data"] == self.kwargs["messaging_non_unicodable_data"]

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == 'gzip'
assert system_props["ContentType"] == 'application/octet-stream'
assert system_props["content-encoding"] == 'gzip'
assert system_props["content-type"] == 'application/octet-stream'
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -386,8 +387,8 @@ def test_uamqp_device_messaging(self):
assert result["data"] == self.kwargs["c2d_json_send_data"]

system_props = result["properties"]["system"]
assert system_props["ContentEncoding"] == test_ce
assert system_props["ContentType"] == test_ct
assert system_props["content-encoding"] == test_ce
assert system_props["content-type"] == test_ct
assert system_props["iothub-correlationid"] == test_cid
assert system_props["iothub-messageid"] == test_mid
assert system_props["iothub-expiry"]
Expand Down Expand Up @@ -771,8 +772,11 @@ def test_mqtt_device_simulation_x509(self):

# x509 CA device simulation and include model Id upon connection
model_id_simulate_x509ca = "dtmi:com:example:simulatex509ca;1"

# not sure why this needs a timer but it seems to help avoid unauthorized errors
sleep(60)
self.cmd(
"iot device simulate -d {} -n {} -g {} --da '{}' --mc 1 --mi 1 --cp {} --kp {} --pass {} --model-id {}".format(
"iot device simulate -d {} -n {} -g {} --da '{}' --mc 1 --mi 1 --cp {} --kp {} --pass {} --model-id '{}'".format(
device_ids[1], self.entity_name, self.entity_rg, simulate_msg,
f"{device_ids[1]}-cert.pem", f"{device_ids[1]}-key.pem", fake_pass, model_id_simulate_x509ca
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def test_iothub_c2d_messages(self):

# Assert system properties
received_system_props = c2d_receive_result["properties"]["system"]
assert received_system_props["ContentEncoding"] == test_ce
assert received_system_props["ContentType"] == test_ct
assert received_system_props["content-encoding"] == test_ce
assert received_system_props["content-type"] == test_ct
assert received_system_props["iothub-correlationid"] == test_cid
assert received_system_props["iothub-messageid"] == test_mid
assert received_system_props["iothub-expiry"]
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand All @@ -80,7 +79,7 @@
setup(
name=PACKAGE_NAME,
version=VERSION,
python_requires=">=3.8",
python_requires=">=3.9",
description=short_description,
long_description="{} Intended for power users and/or automation of IoT solutions at scale.".format(
short_description
Expand Down
Loading