diff --git a/backport-IOTData-Fix-bug-where-publish-could-only-be-called-once.patch b/backport-IOTData-Fix-bug-where-publish-could-only-be-called-once.patch new file mode 100644 index 0000000000000000000000000000000000000000..81607cdcfd5fa426e366e73e618a8f29fc252950 --- /dev/null +++ b/backport-IOTData-Fix-bug-where-publish-could-only-be-called-once.patch @@ -0,0 +1,100 @@ +From d68fb04ee1fdf33c485b00fb40500406ac32d857 Mon Sep 17 00:00:00 2001 +From: Bert Blommers +Date: Tue, 3 Jan 2023 21:21:52 +0000 +Subject: [PATCH] IOTData: Fix bug where publish() could only be called once + (#5812) + +--- + moto/iotdata/responses.py | 20 ++++++++------------ + moto/iotdata/urls.py | 9 --------- + tests/test_iotdata/test_iotdata.py | 10 +++++++--- + 3 files changed, 15 insertions(+), 24 deletions(-) + +diff --git a/moto/iotdata/responses.py b/moto/iotdata/responses.py +index 6aa157327..ca31eb811 100644 +--- a/moto/iotdata/responses.py ++++ b/moto/iotdata/responses.py +@@ -8,6 +8,12 @@ class IoTDataPlaneResponse(BaseResponse): + def __init__(self): + super().__init__(service_name="iot-data") + ++ def _get_action(self) -> str: ++ if self.path and self.path.startswith("/topics/"): ++ # Special usecase - there is no way identify this action, besides the URL ++ return "publish" ++ return super()._get_action() ++ + @property + def iotdata_backend(self): + return iotdata_backends[self.current_account][self.region] +@@ -30,18 +36,8 @@ class IoTDataPlaneResponse(BaseResponse): + payload = self.iotdata_backend.delete_thing_shadow(thing_name=thing_name) + return json.dumps(payload.to_dict()) + +- def dispatch_publish(self, request, full_url, headers): +- # This endpoint requires specialized handling because it has +- # a uri parameter containing forward slashes that is not +- # correctly url encoded when we're running in server mode. +- # https://github.com/pallets/flask/issues/900 +- self.setup_class(request, full_url, headers) +- self.querystring["Action"] = ["Publish"] +- topic = self.path.partition("/topics/")[-1] +- self.querystring["target"] = [unquote(topic)] if "%" in topic else [topic] +- return self.call_action() +- + def publish(self): +- topic = self._get_param("target") ++ topic = self.path.split("/topics/")[-1] ++ topic = unquote(topic) if "%" in topic else topic + self.iotdata_backend.publish(topic=topic, payload=self.body) + return json.dumps(dict()) +diff --git a/moto/iotdata/urls.py b/moto/iotdata/urls.py +index 6e1adbbb9..44f9cffde 100644 +--- a/moto/iotdata/urls.py ++++ b/moto/iotdata/urls.py +@@ -10,18 +10,9 @@ response = IoTDataPlaneResponse() + + + url_paths = { +- # +- # Paths for :class:`moto.core.models.MockAWS` +- # +- # This route requires special handling. +- "{0}/topics/(?P.*)$": response.dispatch_publish, +- # The remaining routes can be handled by the default dispatcher. + "{0}/.*$": response.dispatch, + # + # (Flask) Paths for :class:`moto.core.models.ServerModeMockAWS` + # +- # This route requires special handling. +- "{0}/topics/$": response.dispatch_publish, +- # The remaining routes can be handled by the default dispatcher. + "{0}/$": response.dispatch, + } +diff --git a/tests/test_iotdata/test_iotdata.py b/tests/test_iotdata/test_iotdata.py +index 0a0b7a350..59df5c06d 100644 +--- a/tests/test_iotdata/test_iotdata.py ++++ b/tests/test_iotdata/test_iotdata.py +@@ -110,12 +110,16 @@ def test_update(): + def test_publish(): + region_name = "ap-northeast-1" + client = boto3.client("iot-data", region_name=region_name) +- client.publish(topic="test/topic", qos=1, payload=b"pl") ++ client.publish(topic="test/topic1", qos=1, payload=b"pl1") ++ client.publish(topic="test/topic2", qos=1, payload=b"pl2") ++ client.publish(topic="test/topic3", qos=1, payload=b"pl3") + + if not settings.TEST_SERVER_MODE: + mock_backend = moto.iotdata.models.iotdata_backends[ACCOUNT_ID][region_name] +- mock_backend.published_payloads.should.have.length_of(1) +- mock_backend.published_payloads.should.contain(("test/topic", "pl")) ++ mock_backend.published_payloads.should.have.length_of(3) ++ mock_backend.published_payloads.should.contain(("test/topic1", "pl1")) ++ mock_backend.published_payloads.should.contain(("test/topic2", "pl2")) ++ mock_backend.published_payloads.should.contain(("test/topic3", "pl3")) + + + @mock_iot +-- +2.27.0 + diff --git a/python-moto.spec b/python-moto.spec index 327eacdb4e14cb900ca5375a1aa34371d6b9c626..3b77b174e137501c5ecd0761d1f965cf13405221 100644 --- a/python-moto.spec +++ b/python-moto.spec @@ -1,11 +1,12 @@ %global _empty_manifest_terminate_build 0 Name: python-moto Version: 4.0.12 -Release: 1 +Release: 2 Summary: A library that allows your python tests to easily mock out the boto library License: Apache-2.0 URL: https://github.com/spulec/moto Source0: https://files.pythonhosted.org/packages/51/36/0e2f4b73b638563ce1a342b6d32f9cace043e1bfc2f763a8b8a5a10d29a2/moto-4.0.12.tar.gz +Patch0: backport-IOTData-Fix-bug-where-publish-could-only-be-called-once.patch BuildArch: noarch %description @@ -60,7 +61,7 @@ Provides: python3-moto-doc Moto is a library that allows your tests to easily mock out AWS Services. %prep -%autosetup -n moto-%{version} +%autosetup -n moto-%{version} -p1 %build %py3_build @@ -103,6 +104,9 @@ mv %{buildroot}/doclist.lst . %{_docdir}/* %changelog +* Wed May 22 2024 lilu - 4.0.12-2 +- IOTData: Fix bug where publish could only be called once + * Wed Dec 21 2022 wangjunqi - 4.0.12-1 - Update package to version 4.0.12