From 8483e8e3106ac41556e1cfa3b16ff644a350566f Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Sun, 10 Jul 2022 12:44:52 +0300 Subject: [PATCH] feat: event attribute get operation support (#165) * feat: get operation support Signed-off-by: Alexander Tkachev * docs: event get operation Signed-off-by: Alexander Tkachev * test: extract dummy attributes into a fixture Signed-off-by: Alexander Tkachev * test: extract common dummy data into consts Signed-off-by: Alexander Tkachev * test: event get operation Signed-off-by: Alexander Tkachev * docs: return value Signed-off-by: Alexander Tkachev * test: remove assertion Signed-off-by: Alexander Tkachev * test: move dummy data into fixtures Signed-off-by: Alexander Tkachev * style: black formatting Signed-off-by: Alexander Tkachev * style: black formatting Signed-off-by: Alexander Tkachev * docs: fix bad grammar Signed-off-by: Alexander Tkachev * test: style fix line too long Signed-off-by: Alexander Tkachev * style: fix line too long Signed-off-by: Alexander Tkachev --- cloudevents/http/event.py | 16 +++ cloudevents/tests/test_http_cloudevent.py | 120 ++++++++++++++++------ 2 files changed, 105 insertions(+), 31 deletions(-) diff --git a/cloudevents/http/event.py b/cloudevents/http/event.py index 7cf10fa..f39124f 100644 --- a/cloudevents/http/event.py +++ b/cloudevents/http/event.py @@ -77,6 +77,22 @@ class CloudEvent: def __getitem__(self, key): return self._attributes[key] + def get( + self, key: str, default: typing.Optional[typing.Any] = None + ) -> typing.Optional[typing.Any]: + """ + Retrieves an event attribute value for the given key. + Returns the default value if not attribute for the given key exists. + + MUST NOT throw an exception when the key does not exist. + + :param key: The event attribute name. + :param default: The default value to be returned when + no attribute with the given key exists. + :returns: The event attribute value if exists, default value otherwise. + """ + return self._attributes.get(key, default) + def __setitem__(self, key, value): self._attributes[key] = value diff --git a/cloudevents/tests/test_http_cloudevent.py b/cloudevents/tests/test_http_cloudevent.py index 0568aa9..52ffdfb 100644 --- a/cloudevents/tests/test_http_cloudevent.py +++ b/cloudevents/tests/test_http_cloudevent.py @@ -5,9 +5,14 @@ from cloudevents.http import CloudEvent from cloudevents.http.util import _json_or_string -@pytest.mark.parametrize("specversion", ["0.3", "1.0"]) -def test_http_cloudevent_equality(specversion): - attributes = { +@pytest.fixture(params=["0.3", "1.0"]) +def specversion(request): + return request.param + + +@pytest.fixture() +def dummy_attributes(specversion): + return { "source": "", "specversion": specversion, "id": "my-id", @@ -16,48 +21,55 @@ def test_http_cloudevent_equality(specversion): "datacontenttype": "application/json", "subject": "my-subject", } - data = '{"name":"john"}' - event1 = CloudEvent(attributes, data) - event2 = CloudEvent(attributes, data) + + +@pytest.fixture() +def my_dummy_data(): + return '{"name":"john"}' + + +@pytest.fixture() +def your_dummy_data(): + return '{"name":"paul"}' + + +def test_http_cloudevent_equality( + dummy_attributes, my_dummy_data, your_dummy_data +): + data = my_dummy_data + event1 = CloudEvent(dummy_attributes, data) + event2 = CloudEvent(dummy_attributes, data) assert event1 == event2 # Test different attributes - for key in attributes: + for key in dummy_attributes: if key == "specversion": continue else: - attributes[key] = f"noise-{key}" - event3 = CloudEvent(attributes, data) - event2 = CloudEvent(attributes, data) + dummy_attributes[key] = f"noise-{key}" + event3 = CloudEvent(dummy_attributes, data) + event2 = CloudEvent(dummy_attributes, data) assert event2 == event3 assert event1 != event2 and event3 != event1 # Test different data - data = '{"name":"paul"}' - event3 = CloudEvent(attributes, data) - event2 = CloudEvent(attributes, data) + data = your_dummy_data + event3 = CloudEvent(dummy_attributes, data) + event2 = CloudEvent(dummy_attributes, data) assert event2 == event3 assert event1 != event2 and event3 != event1 -@pytest.mark.parametrize("specversion", ["0.3", "1.0"]) -def test_http_cloudevent_mutates_equality(specversion): - attributes = { - "source": "", - "specversion": specversion, - "id": "my-id", - "time": "tomorrow", - "type": "tests.cloudevents.override", - "datacontenttype": "application/json", - "subject": "my-subject", - } - data = '{"name":"john"}' - event1 = CloudEvent(attributes, data) - event2 = CloudEvent(attributes, data) - event3 = CloudEvent(attributes, data) +def test_http_cloudevent_mutates_equality( + dummy_attributes, my_dummy_data, your_dummy_data +): + data = my_dummy_data + event1 = CloudEvent(dummy_attributes, data) + event2 = CloudEvent(dummy_attributes, data) + event3 = CloudEvent(dummy_attributes, data) assert event1 == event2 # Test different attributes - for key in attributes: + for key in dummy_attributes: if key == "specversion": continue else: @@ -67,8 +79,8 @@ def test_http_cloudevent_mutates_equality(specversion): assert event1 != event2 and event3 != event1 # Test different data - event2.data = '{"name":"paul"}' - event3.data = '{"name":"paul"}' + event2.data = your_dummy_data + event3.data = your_dummy_data assert event2 == event3 assert event1 != event2 and event3 != event1 @@ -119,3 +131,49 @@ def test_cloudevent_general_overrides(): def test_none_json_or_string(): assert _json_or_string(None) is None + + +@pytest.fixture() +def dummy_event(dummy_attributes, my_dummy_data): + return CloudEvent(attributes=dummy_attributes, data=my_dummy_data) + + +@pytest.fixture() +def non_exiting_attribute_name(dummy_event): + result = "nonexisting" + assert result not in dummy_event + return result + + +def test_get_operation_on_non_existing_attribute_must_not_raise_exception( + dummy_event, non_exiting_attribute_name +): + dummy_event.get(non_exiting_attribute_name) + + +def test_get_must_return_attribute_value_if_exists(dummy_event): + assert dummy_event.get("source") == dummy_event["source"] + + +def test_get_operation_on_non_existing_attribute_must_return_none_by_default( + dummy_event, non_exiting_attribute_name +): + assert dummy_event.get(non_exiting_attribute_name) is None + + +def test_get_operation_on_non_existing_attribute_must_return_default_value_if_given( + dummy_event, non_exiting_attribute_name +): + dummy_value = "Hello World" + assert ( + dummy_event.get(non_exiting_attribute_name, dummy_value) == dummy_value + ) + + +def test_get_operation_on_non_existing_attribute_should_not_copy_default_value( + dummy_event, non_exiting_attribute_name +): + dummy_value = object() + assert ( + dummy_event.get(non_exiting_attribute_name, dummy_value) is dummy_value + )