V1.1.0 dev (#114)
* 100% test-coverage rule added to tox (#109) * version bump Signed-off-by: Curtis Mason <cumason@google.com> * adding tests for marshaller Signed-off-by: Curtis Mason <cumason@google.com> * marshaller 100% test-coverage Signed-off-by: Curtis Mason <cumason@bu.edu> * bricked some tests Signed-off-by: Curtis Mason <cumason@bu.edu> * additional error handling Signed-off-by: Curtis Mason <cumason@bu.edu> * 100% test-coverage Signed-off-by: Curtis Mason <cumason@bu.edu> * handles empty data and capitalized headers Signed-off-by: Curtis Mason <cumason@bu.edu> * 1.1.0 version bump Signed-off-by: Curtis Mason <cumason@bu.edu> * Removed _http suffix from http_methods (#108) * Removed _http suffix from http_methods to_binary_http renamed to_binary, and to_structured_http renamed to_structured. These functions are inside of cloudevents.http thus the _http part should be implicitly understood. Signed-off-by: Curtis Mason <cumason@google.com> * version bump Signed-off-by: Curtis Mason <cumason@google.com> * deprecated instead of removal Signed-off-by: Curtis Mason <cumason@bu.edu> * Update setup.py Co-authored-by: Dustin Ingram <di@users.noreply.github.com> Signed-off-by: Curtis Mason <cumason@bu.edu> * 1.1.0 version bump Signed-off-by: Curtis Mason <cumason@bu.edu> Co-authored-by: Dustin Ingram <di@users.noreply.github.com> * swapped args for from_http (#110) Signed-off-by: Curtis Mason <cumason@bu.edu> * exception names shortened (#111) * exception names shortened Signed-off-by: Curtis Mason <cumason@google.com> * to_structured documentation Signed-off-by: Curtis Mason <cumason@google.com> * adjusted readme and changelog (#113) * adjusted readme and changelog Signed-off-by: Curtis Mason <cumason@google.com> * readme adjustment Signed-off-by: Curtis Mason <cumason@google.com> * structured content mode Signed-off-by: Curtis Mason <cumason@google.com> Co-authored-by: Dustin Ingram <di@users.noreply.github.com>
This commit is contained in:
parent
d95b1303a9
commit
14c76188d1
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0]
|
||||
### Changed
|
||||
- Changed from_http to now expect headers argument before data ([#110])
|
||||
- Renamed exception names ([#111])
|
||||
|
||||
### Deprecated
|
||||
- Renamed to_binary_http and to_structured_http. ([#108])
|
||||
|
||||
## [1.0.1]
|
||||
### Added
|
||||
- CloudEvent exceptions and event type checking in http module ([#96])
|
||||
|
@ -93,4 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#71]: https://github.com/cloudevents/sdk-python/pull/71
|
||||
[#72]: https://github.com/cloudevents/sdk-python/pull/72
|
||||
[#96]: https://github.com/cloudevents/sdk-python/pull/96
|
||||
[#98]: https://github.com/cloudevents/sdk-python/pull/98
|
||||
[#98]: https://github.com/cloudevents/sdk-python/pull/98
|
||||
[#108]: https://github.com/cloudevents/sdk-python/pull/108
|
||||
[#110]: https://github.com/cloudevents/sdk-python/pull/110
|
||||
[#111]: https://github.com/cloudevents/sdk-python/pull/111
|
||||
|
|
23
README.md
23
README.md
|
@ -24,19 +24,20 @@ Below we will provide samples on how to send cloudevents using the popular
|
|||
### Binary HTTP CloudEvent
|
||||
|
||||
```python
|
||||
from cloudevents.http import CloudEvent, to_binary_http
|
||||
from cloudevents.http import CloudEvent, to_binary
|
||||
import requests
|
||||
|
||||
|
||||
# This data defines a binary cloudevent
|
||||
# Create a CloudEvent
|
||||
# - The CloudEvent "id" is generated if omitted. "specversion" defaults to "1.0".
|
||||
attributes = {
|
||||
"type": "com.example.sampletype1",
|
||||
"source": "https://example.com/event-producer",
|
||||
}
|
||||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_binary_http(event)
|
||||
|
||||
# Creates the HTTP request representation of the CloudEvent in binary content mode
|
||||
headers, body = to_binary(event)
|
||||
|
||||
# POST
|
||||
requests.post("<some-url>", data=body, headers=headers)
|
||||
|
@ -45,18 +46,20 @@ requests.post("<some-url>", data=body, headers=headers)
|
|||
### Structured HTTP CloudEvent
|
||||
|
||||
```python
|
||||
from cloudevents.http import CloudEvent, to_structured_http
|
||||
from cloudevents.http import CloudEvent, to_structured
|
||||
import requests
|
||||
|
||||
|
||||
# This data defines a structured cloudevent
|
||||
# Create a CloudEvent
|
||||
# - The CloudEvent "id" is generated if omitted. "specversion" defaults to "1.0".
|
||||
attributes = {
|
||||
"type": "com.example.sampletype2",
|
||||
"source": "https://example.com/event-producer",
|
||||
}
|
||||
data = {"message": "Hello World!"}
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_structured_http(event)
|
||||
|
||||
# Creates the HTTP request representation of the CloudEvent in structured content mode
|
||||
headers, body = to_structured(event)
|
||||
|
||||
# POST
|
||||
requests.post("<some-url>", data=body, headers=headers)
|
||||
|
@ -81,7 +84,7 @@ app = Flask(__name__)
|
|||
@app.route("/", methods=["POST"])
|
||||
def home():
|
||||
# create a CloudEvent
|
||||
event = from_http(request.get_data(), request.headers)
|
||||
event = from_http(request.headers, request.get_data())
|
||||
|
||||
# you can access cloudevent fields as seen below
|
||||
print(
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "1.0.1"
|
||||
__version__ = "1.1.0"
|
||||
|
|
|
@ -11,9 +11,17 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
class CloudEventMissingRequiredFields(Exception):
|
||||
class MissingRequiredFields(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CloudEventTypeErrorRequiredFields(Exception):
|
||||
class InvalidRequiredFields(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidStructuredJSON(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidHeadersFormat(Exception):
|
||||
pass
|
||||
|
|
|
@ -18,7 +18,9 @@ from cloudevents.http.event import CloudEvent
|
|||
from cloudevents.http.event_type import is_binary, is_structured
|
||||
from cloudevents.http.http_methods import (
|
||||
from_http,
|
||||
to_binary,
|
||||
to_binary_http,
|
||||
to_structured,
|
||||
to_structured_http,
|
||||
)
|
||||
from cloudevents.http.json_methods import from_json, to_json
|
||||
|
|
|
@ -58,15 +58,15 @@ class CloudEvent:
|
|||
).isoformat()
|
||||
|
||||
if self._attributes["specversion"] not in _required_by_version:
|
||||
raise cloud_exceptions.CloudEventMissingRequiredFields(
|
||||
f"Invalid specversion: {self._attributes['specversion']}"
|
||||
raise cloud_exceptions.MissingRequiredFields(
|
||||
f"Invalid specversion: {self._attributes['specversion']}. "
|
||||
)
|
||||
# There is no good way to default 'source' and 'type', so this
|
||||
# checks for those (or any new required attributes).
|
||||
required_set = _required_by_version[self._attributes["specversion"]]
|
||||
if not required_set <= self._attributes.keys():
|
||||
raise cloud_exceptions.CloudEventMissingRequiredFields(
|
||||
f"Missing required keys: {required_set - attributes.keys()}"
|
||||
raise cloud_exceptions.MissingRequiredFields(
|
||||
f"Missing required keys: {required_set - self._attributes.keys()}. "
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import json
|
||||
import typing
|
||||
|
||||
from deprecation import deprecated
|
||||
|
||||
import cloudevents.exceptions as cloud_exceptions
|
||||
from cloudevents.http.event import CloudEvent
|
||||
from cloudevents.http.event_type import is_binary, is_structured
|
||||
|
@ -10,20 +12,30 @@ from cloudevents.sdk import converters, marshaller, types
|
|||
|
||||
|
||||
def from_http(
|
||||
data: typing.Union[str, bytes],
|
||||
headers: typing.Dict[str, str],
|
||||
data: typing.Union[str, bytes, None],
|
||||
data_unmarshaller: types.UnmarshallerType = None,
|
||||
):
|
||||
"""
|
||||
Unwrap a CloudEvent (binary or structured) from an HTTP request.
|
||||
:param data: the HTTP request body
|
||||
:type data: typing.IO
|
||||
:param headers: the HTTP headers
|
||||
:type headers: typing.Dict[str, str]
|
||||
:param data: the HTTP request body
|
||||
:type data: typing.IO
|
||||
:param data_unmarshaller: Callable function to map data to a python object
|
||||
e.g. lambda x: x or lambda x: json.loads(x)
|
||||
:type data_unmarshaller: types.UnmarshallerType
|
||||
"""
|
||||
if data is None:
|
||||
data = ""
|
||||
|
||||
if not isinstance(data, (str, bytes, bytearray)):
|
||||
raise cloud_exceptions.InvalidStructuredJSON(
|
||||
"Expected json of type (str, bytes, bytearray), "
|
||||
f"but instead found {type(data)}. "
|
||||
)
|
||||
|
||||
headers = {key.lower(): value for key, value in headers.items()}
|
||||
if data_unmarshaller is None:
|
||||
data_unmarshaller = _json_or_string
|
||||
|
||||
|
@ -32,19 +44,25 @@ def from_http(
|
|||
if is_binary(headers):
|
||||
specversion = headers.get("ce-specversion", None)
|
||||
else:
|
||||
raw_ce = json.loads(data)
|
||||
try:
|
||||
raw_ce = json.loads(data)
|
||||
except json.decoder.JSONDecodeError:
|
||||
raise cloud_exceptions.InvalidStructuredJSON(
|
||||
"Failed to read fields from structured event. "
|
||||
f"The following can not be parsed as json: {data}. "
|
||||
)
|
||||
specversion = raw_ce.get("specversion", None)
|
||||
|
||||
if specversion is None:
|
||||
raise cloud_exceptions.CloudEventMissingRequiredFields(
|
||||
"could not find specversion in HTTP request"
|
||||
raise cloud_exceptions.MissingRequiredFields(
|
||||
"Failed to find specversion in HTTP request. "
|
||||
)
|
||||
|
||||
event_handler = _obj_by_version.get(specversion, None)
|
||||
|
||||
if event_handler is None:
|
||||
raise cloud_exceptions.CloudEventTypeErrorRequiredFields(
|
||||
f"found invalid specversion {specversion}"
|
||||
raise cloud_exceptions.InvalidRequiredFields(
|
||||
f"Found invalid specversion {specversion}. "
|
||||
)
|
||||
|
||||
event = marshall.FromRequest(
|
||||
|
@ -77,8 +95,8 @@ def _to_http(
|
|||
data_marshaller = _marshaller_by_format[format]
|
||||
|
||||
if event._attributes["specversion"] not in _obj_by_version:
|
||||
raise cloud_exceptions.CloudEventTypeErrorRequiredFields(
|
||||
f"Unsupported specversion: {event._attributes['specversion']}"
|
||||
raise cloud_exceptions.InvalidRequiredFields(
|
||||
f"Unsupported specversion: {event._attributes['specversion']}. "
|
||||
)
|
||||
|
||||
event_handler = _obj_by_version[event._attributes["specversion"]]()
|
||||
|
@ -91,11 +109,13 @@ def _to_http(
|
|||
)
|
||||
|
||||
|
||||
def to_structured_http(
|
||||
def to_structured(
|
||||
event: CloudEvent, data_marshaller: types.MarshallerType = None,
|
||||
) -> (dict, typing.Union[bytes, str]):
|
||||
"""
|
||||
Returns a tuple of HTTP headers/body dicts representing this cloudevent
|
||||
Returns a tuple of HTTP headers/body dicts representing this cloudevent. If
|
||||
event.data is a byte object, body will have a data_base64 field instead of
|
||||
data.
|
||||
|
||||
:param event: CloudEvent to cast into http data
|
||||
:type event: CloudEvent
|
||||
|
@ -107,7 +127,7 @@ def to_structured_http(
|
|||
return _to_http(event=event, data_marshaller=data_marshaller)
|
||||
|
||||
|
||||
def to_binary_http(
|
||||
def to_binary(
|
||||
event: CloudEvent, data_marshaller: types.MarshallerType = None,
|
||||
) -> (dict, typing.Union[bytes, str]):
|
||||
"""
|
||||
|
@ -125,3 +145,17 @@ def to_binary_http(
|
|||
format=converters.TypeBinary,
|
||||
data_marshaller=data_marshaller,
|
||||
)
|
||||
|
||||
|
||||
@deprecated(deprecated_in="1.0.2", details="Use to_binary function instead")
|
||||
def to_binary_http(
|
||||
event: CloudEvent, data_marshaller: types.MarshallerType = None,
|
||||
) -> (dict, typing.Union[bytes, str]):
|
||||
return to_binary(event, data_marshaller)
|
||||
|
||||
|
||||
@deprecated(deprecated_in="1.0.2", details="Use to_structured function instead")
|
||||
def to_structured_http(
|
||||
event: CloudEvent, data_marshaller: types.MarshallerType = None,
|
||||
) -> (dict, typing.Union[bytes, str]):
|
||||
return to_structured(event, data_marshaller)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import typing
|
||||
|
||||
from cloudevents.http.event import CloudEvent
|
||||
from cloudevents.http.http_methods import from_http, to_structured_http
|
||||
from cloudevents.http.http_methods import from_http, to_structured
|
||||
from cloudevents.sdk import types
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ def to_json(
|
|||
:type data_marshaller: typing.Callable
|
||||
:returns: json object representing the given event
|
||||
"""
|
||||
return to_structured_http(event, data_marshaller=data_marshaller)[1]
|
||||
return to_structured(event, data_marshaller=data_marshaller)[1]
|
||||
|
||||
|
||||
def from_json(
|
||||
|
@ -33,4 +33,4 @@ def from_json(
|
|||
:type data_unmarshaller: typing.Callable
|
||||
:returns: CloudEvent representing given cloudevent json object
|
||||
"""
|
||||
return from_http(data=data, headers={}, data_unmarshaller=data_unmarshaller)
|
||||
return from_http(headers={}, data=data, data_unmarshaller=data_unmarshaller)
|
||||
|
|
|
@ -12,7 +12,7 @@ def default_marshaller(content: any):
|
|||
|
||||
|
||||
def _json_or_string(content: typing.Union[str, bytes]):
|
||||
if len(content) == 0:
|
||||
if content is None or len(content) == 0:
|
||||
return None
|
||||
try:
|
||||
return json.loads(content)
|
||||
|
|
|
@ -22,7 +22,7 @@ from cloudevents.sdk import types
|
|||
# TODO(slinkydeveloper) is this really needed?
|
||||
|
||||
|
||||
class EventGetterSetter(object):
|
||||
class EventGetterSetter(object): # pragma: no cover
|
||||
|
||||
# ce-specversion
|
||||
def CloudEventVersion(self) -> str:
|
||||
|
@ -220,7 +220,7 @@ class BaseEvent(EventGetterSetter):
|
|||
|
||||
missing_fields = self._ce_required_fields - raw_ce.keys()
|
||||
if len(missing_fields) > 0:
|
||||
raise cloud_exceptions.CloudEventMissingRequiredFields(
|
||||
raise cloud_exceptions.MissingRequiredFields(
|
||||
f"Missing required attributes: {missing_fields}"
|
||||
)
|
||||
|
||||
|
@ -246,7 +246,7 @@ class BaseEvent(EventGetterSetter):
|
|||
missing_fields = required_binary_fields - headers.keys()
|
||||
|
||||
if len(missing_fields) > 0:
|
||||
raise cloud_exceptions.CloudEventMissingRequiredFields(
|
||||
raise cloud_exceptions.MissingRequiredFields(
|
||||
f"Missing required attributes: {missing_fields}"
|
||||
)
|
||||
|
||||
|
|
|
@ -75,10 +75,6 @@ class Event(base.BaseEvent):
|
|||
def ContentEncoding(self) -> str:
|
||||
return self.ce__datacontentencoding.get()
|
||||
|
||||
@property
|
||||
def datacontentencoding(self):
|
||||
return self.ContentEncoding()
|
||||
|
||||
def SetEventType(self, eventType: str) -> base.BaseEvent:
|
||||
self.Set("type", eventType)
|
||||
return self
|
||||
|
@ -119,6 +115,26 @@ class Event(base.BaseEvent):
|
|||
self.Set("datacontentencoding", contentEncoding)
|
||||
return self
|
||||
|
||||
@property
|
||||
def datacontentencoding(self):
|
||||
return self.ContentEncoding()
|
||||
|
||||
@datacontentencoding.setter
|
||||
def datacontentencoding(self, value: str):
|
||||
self.SetContentEncoding(value)
|
||||
|
||||
@property
|
||||
def subject(self) -> str:
|
||||
return self.Subject()
|
||||
|
||||
@subject.setter
|
||||
def subject(self, value: str):
|
||||
self.SetSubject(value)
|
||||
|
||||
@property
|
||||
def schema_url(self) -> str:
|
||||
return self.SchemaURL()
|
||||
|
||||
@schema_url.setter
|
||||
def schema_url(self, value: str):
|
||||
self.SetSchemaURL(value)
|
||||
|
|
|
@ -98,3 +98,19 @@ class Event(base.BaseEvent):
|
|||
def SetExtensions(self, extensions: dict) -> base.BaseEvent:
|
||||
self.Set("extensions", extensions)
|
||||
return self
|
||||
|
||||
@property
|
||||
def schema(self) -> str:
|
||||
return self.Schema()
|
||||
|
||||
@schema.setter
|
||||
def schema(self, value: str):
|
||||
self.SetSchema(value)
|
||||
|
||||
@property
|
||||
def subject(self) -> str:
|
||||
return self.Subject()
|
||||
|
||||
@subject.setter
|
||||
def subject(self, value: str):
|
||||
self.SetSubject(value)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import pytest
|
||||
|
||||
import cloudevents.exceptions as cloud_exceptions
|
||||
from cloudevents.sdk.event import v1, v03
|
||||
|
||||
|
||||
@pytest.mark.parametrize("event_class", [v1.Event, v03.Event])
|
||||
def test_unmarshall_binary_missing_fields(event_class):
|
||||
event = event_class()
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields) as e:
|
||||
event.UnmarshalBinary({}, "", lambda x: x)
|
||||
assert "Missing required attributes: " in str(e.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("event_class", [v1.Event, v03.Event])
|
||||
def test_get_nonexistent_optional(event_class):
|
||||
event = event_class()
|
||||
event.SetExtensions({"ext1": "val"})
|
||||
res = event.Get("ext1")
|
||||
assert res[0] == "val" and res[1] == True
|
|
@ -0,0 +1,41 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import pytest
|
||||
|
||||
from cloudevents.sdk import exceptions
|
||||
from cloudevents.sdk.converters import base, binary, structured
|
||||
|
||||
|
||||
def test_binary_converter_raise_unsupported():
|
||||
with pytest.raises(exceptions.UnsupportedEvent):
|
||||
cnvtr = binary.BinaryHTTPCloudEventConverter()
|
||||
cnvtr.read(None, {}, None, None)
|
||||
|
||||
|
||||
def test_base_converters_raise_exceptions():
|
||||
with pytest.raises(Exception):
|
||||
cnvtr = base.Converter()
|
||||
cnvtr.event_supported(None)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
cnvtr = base.Converter()
|
||||
cnvtr.can_read(None)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
cnvtr = base.Converter()
|
||||
cnvtr.write(None, None)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
cnvtr = base.Converter()
|
||||
cnvtr.read(None, None, None, None)
|
|
@ -92,7 +92,6 @@ def test_general_structured_properties(event_class):
|
|||
if key == "content-type":
|
||||
assert new_headers[key] == http_headers[key]
|
||||
continue
|
||||
assert key in copy_of_ce
|
||||
|
||||
# Test setters
|
||||
new_type = str(uuid4())
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import pytest
|
||||
|
||||
from cloudevents.http import (
|
||||
CloudEvent,
|
||||
to_binary,
|
||||
to_binary_http,
|
||||
to_structured,
|
||||
to_structured_http,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event():
|
||||
return CloudEvent({"source": "s", "type": "t"}, None)
|
||||
|
||||
|
||||
def test_to_binary_http_deprecated(event):
|
||||
with pytest.deprecated_call():
|
||||
assert to_binary(event) == to_binary_http(event)
|
||||
|
||||
|
||||
def test_to_structured_http_deprecated(event):
|
||||
with pytest.deprecated_call():
|
||||
assert to_structured(event) == to_structured_http(event)
|
|
@ -15,12 +15,7 @@ import json
|
|||
|
||||
import pytest
|
||||
|
||||
from cloudevents.http import (
|
||||
CloudEvent,
|
||||
from_http,
|
||||
to_binary_http,
|
||||
to_structured_http,
|
||||
)
|
||||
from cloudevents.http import CloudEvent, from_http, to_binary, to_structured
|
||||
|
||||
test_data = json.dumps({"data-key": "val"})
|
||||
test_attributes = {
|
||||
|
@ -39,7 +34,7 @@ def test_cloudevent_access_extensions(specversion):
|
|||
@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
|
||||
def test_to_binary_extensions(specversion):
|
||||
event = CloudEvent(test_attributes, test_data)
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
assert "ce-ext1" in headers
|
||||
assert headers.get("ce-ext1") == test_attributes["ext1"]
|
||||
|
@ -56,7 +51,7 @@ def test_from_binary_extensions(specversion):
|
|||
"ce-ext2": "test2",
|
||||
}
|
||||
body = json.dumps({"data-key": "val"})
|
||||
event = from_http(body, headers)
|
||||
event = from_http(headers, body)
|
||||
|
||||
assert headers["ce-ext1"] == event["ext1"]
|
||||
assert headers["ce-ext2"] == event["ext2"]
|
||||
|
@ -65,7 +60,7 @@ def test_from_binary_extensions(specversion):
|
|||
@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
|
||||
def test_to_structured_extensions(specversion):
|
||||
event = CloudEvent(test_attributes, test_data)
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
body = json.loads(body)
|
||||
|
||||
|
@ -86,7 +81,7 @@ def test_from_structured_extensions(specversion):
|
|||
}
|
||||
|
||||
data = json.dumps(body)
|
||||
event = from_http(data, headers)
|
||||
event = from_http(headers, data)
|
||||
|
||||
assert body["ext1"] == event["ext1"]
|
||||
assert body["ext2"] == event["ext2"]
|
||||
|
|
|
@ -61,4 +61,3 @@ def test_structured_event_to_request_upstream(event_class):
|
|||
if key == "content-type":
|
||||
assert new_headers[key] == http_headers[key]
|
||||
continue
|
||||
assert key in copy_of_ce
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import pytest
|
||||
|
||||
import cloudevents.exceptions as cloud_exceptions
|
||||
from cloudevents.http import CloudEvent
|
||||
|
||||
|
||||
|
@ -69,3 +70,47 @@ def test_http_cloudevent_mutates_equality(specversion):
|
|||
event3.data = '{"name":"paul"}'
|
||||
assert event2 == event3
|
||||
assert event1 != event2 and event3 != event1
|
||||
|
||||
|
||||
def test_cloudevent_missing_specversion():
|
||||
attributes = {"specversion": "0.2", "source": "s", "type": "t"}
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields) as e:
|
||||
event = CloudEvent(attributes, None)
|
||||
assert "Invalid specversion: 0.2" in str(e.value)
|
||||
|
||||
|
||||
def test_cloudevent_missing_minimal_required_fields():
|
||||
attributes = {"type": "t"}
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields) as e:
|
||||
event = CloudEvent(attributes, None)
|
||||
assert f"Missing required keys: {set(['source'])}" in str(e.value)
|
||||
|
||||
attributes = {"source": "s"}
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields) as e:
|
||||
event = CloudEvent(attributes, None)
|
||||
assert f"Missing required keys: {set(['type'])}" in str(e.value)
|
||||
|
||||
|
||||
def test_cloudevent_general_overrides():
|
||||
event = CloudEvent(
|
||||
{
|
||||
"source": "my-source",
|
||||
"type": "com.test.overrides",
|
||||
"subject": "my-subject",
|
||||
},
|
||||
None,
|
||||
)
|
||||
expected_attributes = [
|
||||
"time",
|
||||
"source",
|
||||
"id",
|
||||
"specversion",
|
||||
"type",
|
||||
"subject",
|
||||
]
|
||||
|
||||
assert len(event) == 6
|
||||
for attribute in expected_attributes:
|
||||
assert attribute in event
|
||||
del event[attribute]
|
||||
assert len(event) == 0
|
|
@ -25,7 +25,10 @@ from cloudevents.http import (
|
|||
CloudEvent,
|
||||
from_http,
|
||||
is_binary,
|
||||
is_structured,
|
||||
to_binary,
|
||||
to_binary_http,
|
||||
to_structured,
|
||||
to_structured_http,
|
||||
)
|
||||
from cloudevents.sdk import converters
|
||||
|
@ -69,17 +72,13 @@ test_data = {"payload-content": "Hello World!"}
|
|||
app = Sanic(__name__)
|
||||
|
||||
|
||||
def post(url, headers, data):
|
||||
return app.test_client.post(url, headers=headers, data=data)
|
||||
|
||||
|
||||
@app.route("/event", ["POST"])
|
||||
async def echo(request):
|
||||
decoder = None
|
||||
if "binary-payload" in request.headers:
|
||||
decoder = lambda x: x
|
||||
event = from_http(
|
||||
request.body, headers=dict(request.headers), data_unmarshaller=decoder
|
||||
dict(request.headers), request.body, data_unmarshaller=decoder
|
||||
)
|
||||
data = (
|
||||
event.data
|
||||
|
@ -91,25 +90,24 @@ async def echo(request):
|
|||
|
||||
@pytest.mark.parametrize("body", invalid_cloudevent_request_body)
|
||||
def test_missing_required_fields_structured(body):
|
||||
with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields):
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields):
|
||||
# CloudEvent constructor throws TypeError if missing required field
|
||||
# and NotImplementedError because structured calls aren't
|
||||
# implemented. In this instance one of the required keys should have
|
||||
# prefix e-id instead of ce-id therefore it should throw
|
||||
_ = from_http(
|
||||
json.dumps(body),
|
||||
headers={"Content-Type": "application/cloudevents+json"},
|
||||
{"Content-Type": "application/cloudevents+json"}, json.dumps(body),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("headers", invalid_test_headers)
|
||||
def test_missing_required_fields_binary(headers):
|
||||
with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields):
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields):
|
||||
# CloudEvent constructor throws TypeError if missing required field
|
||||
# and NotImplementedError because structured calls aren't
|
||||
# implemented. In this instance one of the required keys should have
|
||||
# prefix e-id instead of ce-id therefore it should throw
|
||||
_ = from_http(json.dumps(test_data), headers=headers)
|
||||
_ = from_http(headers, json.dumps(test_data))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("specversion", ["1.0", "0.3"])
|
||||
|
@ -177,9 +175,9 @@ def test_roundtrip_non_json_event(converter, specversion):
|
|||
event = CloudEvent(attrs, compressed_data)
|
||||
|
||||
if converter == converters.TypeStructured:
|
||||
headers, data = to_structured_http(event, data_marshaller=lambda x: x)
|
||||
headers, data = to_structured(event, data_marshaller=lambda x: x)
|
||||
elif converter == converters.TypeBinary:
|
||||
headers, data = to_binary_http(event, data_marshaller=lambda x: x)
|
||||
headers, data = to_binary(event, data_marshaller=lambda x: x)
|
||||
|
||||
headers["binary-payload"] = "true" # Decoding hint for server
|
||||
_, r = app.test_client.post("/event", headers=headers, data=data)
|
||||
|
@ -204,12 +202,12 @@ def test_missing_ce_prefix_binary_event(specversion):
|
|||
# breaking prefix e.g. e-id instead of ce-id
|
||||
prefixed_headers[key[1:]] = headers[key]
|
||||
|
||||
with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields):
|
||||
with pytest.raises(cloud_exceptions.MissingRequiredFields):
|
||||
# CloudEvent constructor throws TypeError if missing required field
|
||||
# and NotImplementedError because structured calls aren't
|
||||
# implemented. In this instance one of the required keys should have
|
||||
# prefix e-id instead of ce-id therefore it should throw
|
||||
_ = from_http(json.dumps(test_data), headers=prefixed_headers)
|
||||
_ = from_http(prefixed_headers, json.dumps(test_data))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("specversion", ["1.0", "0.3"])
|
||||
|
@ -226,7 +224,7 @@ def test_valid_binary_events(specversion):
|
|||
"ce-specversion": specversion,
|
||||
}
|
||||
data = {"payload": f"payload-{i}"}
|
||||
events_queue.append(from_http(json.dumps(data), headers=headers))
|
||||
events_queue.append(from_http(headers, json.dumps(data)))
|
||||
|
||||
for i, event in enumerate(events_queue):
|
||||
data = event.data
|
||||
|
@ -247,7 +245,7 @@ def test_structured_to_request(specversion):
|
|||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body_bytes = to_structured_http(event)
|
||||
headers, body_bytes = to_structured(event)
|
||||
assert isinstance(body_bytes, bytes)
|
||||
body = json.loads(body_bytes)
|
||||
|
||||
|
@ -267,7 +265,7 @@ def test_binary_to_request(specversion):
|
|||
}
|
||||
data = {"message": "Hello World!"}
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body_bytes = to_binary_http(event)
|
||||
headers, body_bytes = to_binary(event)
|
||||
body = json.loads(body_bytes)
|
||||
|
||||
for key in data:
|
||||
|
@ -289,7 +287,7 @@ def test_empty_data_structured_event(specversion):
|
|||
}
|
||||
|
||||
_ = from_http(
|
||||
json.dumps(attributes), {"content-type": "application/cloudevents+json"}
|
||||
{"content-type": "application/cloudevents+json"}, json.dumps(attributes)
|
||||
)
|
||||
|
||||
|
||||
|
@ -304,7 +302,7 @@ def test_empty_data_binary_event(specversion):
|
|||
"ce-time": "2018-10-23T12:28:22.4579346Z",
|
||||
"ce-source": "<source-url>",
|
||||
}
|
||||
_ = from_http("", headers)
|
||||
_ = from_http(headers, "")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("specversion", ["1.0", "0.3"])
|
||||
|
@ -322,8 +320,8 @@ def test_valid_structured_events(specversion):
|
|||
}
|
||||
events_queue.append(
|
||||
from_http(
|
||||
json.dumps(event),
|
||||
{"content-type": "application/cloudevents+json"},
|
||||
json.dumps(event),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -344,7 +342,7 @@ def test_structured_no_content_type(specversion):
|
|||
"specversion": specversion,
|
||||
"data": test_data,
|
||||
}
|
||||
event = from_http(json.dumps(data), {},)
|
||||
event = from_http({}, json.dumps(data))
|
||||
|
||||
assert event["id"] == "id"
|
||||
assert event["source"] == "source.com.test"
|
||||
|
@ -382,7 +380,7 @@ def test_cloudevent_repr(specversion):
|
|||
"ce-time": "2018-10-23T12:28:22.4579346Z",
|
||||
"ce-source": "<source-url>",
|
||||
}
|
||||
event = from_http("", headers)
|
||||
event = from_http(headers, "")
|
||||
# Testing to make sure event is printable. I could runevent. __repr__() but
|
||||
# we had issues in the past where event.__repr__() could run but
|
||||
# print(event) would fail.
|
||||
|
@ -398,5 +396,79 @@ def test_none_data_cloudevent(specversion):
|
|||
"specversion": specversion,
|
||||
}
|
||||
)
|
||||
to_binary_http(event)
|
||||
to_structured_http(event)
|
||||
to_binary(event)
|
||||
to_structured(event)
|
||||
|
||||
|
||||
def test_wrong_specversion():
|
||||
headers = {"Content-Type": "application/cloudevents+json"}
|
||||
data = json.dumps(
|
||||
{
|
||||
"specversion": "0.2",
|
||||
"type": "word.found.name",
|
||||
"id": "96fb5f0b-001e-0108-6dfe-da6e2806f124",
|
||||
"source": "<my-source>",
|
||||
}
|
||||
)
|
||||
with pytest.raises(cloud_exceptions.InvalidRequiredFields) as e:
|
||||
from_http(headers, data)
|
||||
assert "Found invalid specversion 0.2" in str(e.value)
|
||||
|
||||
|
||||
def test_invalid_data_format_structured_from_http():
|
||||
headers = {"Content-Type": "application/cloudevents+json"}
|
||||
data = 20
|
||||
with pytest.raises(cloud_exceptions.InvalidStructuredJSON) as e:
|
||||
from_http(headers, data)
|
||||
assert "Expected json of type (str, bytes, bytearray)" in str(e.value)
|
||||
|
||||
|
||||
def test_wrong_specversion_to_request():
|
||||
event = CloudEvent({"source": "s", "type": "t"}, None)
|
||||
with pytest.raises(cloud_exceptions.InvalidRequiredFields) as e:
|
||||
event["specversion"] = "0.2"
|
||||
to_binary(event)
|
||||
assert "Unsupported specversion: 0.2" in str(e.value)
|
||||
|
||||
|
||||
def test_is_structured():
|
||||
headers = {
|
||||
"Content-Type": "application/cloudevents+json",
|
||||
}
|
||||
assert is_structured(headers)
|
||||
|
||||
headers = {
|
||||
"ce-id": "my-id",
|
||||
"ce-source": "<event-source>",
|
||||
"ce-type": "cloudevent.event.type",
|
||||
"ce-specversion": "1.0",
|
||||
"Content-Type": "text/plain",
|
||||
}
|
||||
assert not is_structured(headers)
|
||||
|
||||
|
||||
def test_empty_json_structured():
|
||||
headers = {"Content-Type": "application/cloudevents+json"}
|
||||
data = ""
|
||||
with pytest.raises(cloud_exceptions.InvalidStructuredJSON) as e:
|
||||
from_http(
|
||||
headers, data,
|
||||
)
|
||||
assert "Failed to read fields from structured event. " in str(e.value)
|
||||
|
||||
|
||||
def test_uppercase_headers_with_none_data_binary():
|
||||
headers = {
|
||||
"Ce-Id": "my-id",
|
||||
"Ce-Source": "<event-source>",
|
||||
"Ce-Type": "cloudevent.event.type",
|
||||
"Ce-Specversion": "1.0",
|
||||
}
|
||||
event = from_http(headers, None)
|
||||
|
||||
for key in headers:
|
||||
assert event[key.lower()[3:]] == headers[key]
|
||||
assert event.data == None
|
||||
|
||||
_, new_data = to_binary(event)
|
||||
assert new_data == None
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pytest
|
||||
|
||||
from cloudevents.sdk import converters, exceptions, marshaller
|
||||
from cloudevents.sdk.converters import binary, structured
|
||||
from cloudevents.sdk.event import v1
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def headers():
|
||||
return {
|
||||
"ce-specversion": "1.0",
|
||||
"ce-source": "1.0",
|
||||
"ce-type": "com.marshaller.test",
|
||||
"ce-id": "1234-1234-1234",
|
||||
}
|
||||
|
||||
|
||||
def test_from_request_wrong_unmarshaller():
|
||||
with pytest.raises(exceptions.InvalidDataUnmarshaller):
|
||||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
_ = m.FromRequest(v1.Event(), {}, "", None)
|
||||
|
||||
|
||||
def test_to_request_wrong_marshaller():
|
||||
with pytest.raises(exceptions.InvalidDataMarshaller):
|
||||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
_ = m.ToRequest(v1.Event(), data_marshaller="")
|
||||
|
||||
|
||||
def test_from_request_cannot_read(headers):
|
||||
with pytest.raises(exceptions.UnsupportedEventConverter):
|
||||
m = marshaller.HTTPMarshaller(
|
||||
[binary.NewBinaryHTTPCloudEventConverter(),]
|
||||
)
|
||||
m.FromRequest(v1.Event(), {}, "")
|
||||
|
||||
with pytest.raises(exceptions.UnsupportedEventConverter):
|
||||
m = marshaller.HTTPMarshaller(
|
||||
[structured.NewJSONHTTPCloudEventConverter()]
|
||||
)
|
||||
m.FromRequest(v1.Event(), headers, "")
|
||||
|
||||
|
||||
def test_to_request_invalid_converter():
|
||||
with pytest.raises(exceptions.NoSuchConverter):
|
||||
m = marshaller.HTTPMarshaller(
|
||||
[structured.NewJSONHTTPCloudEventConverter()]
|
||||
)
|
||||
m.ToRequest(v1.Event(), "")
|
|
@ -0,0 +1,36 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pytest
|
||||
|
||||
from cloudevents.sdk.event.opt import Option
|
||||
|
||||
|
||||
def test_set_raise_error():
|
||||
with pytest.raises(ValueError):
|
||||
o = Option("test", "value", True)
|
||||
o.set(None)
|
||||
|
||||
|
||||
def test_options_eq_override():
|
||||
o = Option("test", "value", True)
|
||||
assert o.required()
|
||||
|
||||
o2 = Option("test", "value", True)
|
||||
assert o2.required()
|
||||
|
||||
assert o == o2
|
||||
o.set("setting to new value")
|
||||
|
||||
assert o != o2
|
|
@ -0,0 +1,64 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import pytest
|
||||
|
||||
from cloudevents.sdk.event import v03
|
||||
|
||||
|
||||
def test_v03_time_property():
|
||||
event = v03.Event()
|
||||
|
||||
time1 = "1234"
|
||||
event.time = time1
|
||||
assert event.EventTime() == time1
|
||||
|
||||
time2 = "4321"
|
||||
event.SetEventTime(time2)
|
||||
assert event.time == time2
|
||||
|
||||
|
||||
def test_v03_subject_property():
|
||||
event = v03.Event()
|
||||
|
||||
subject1 = "<my-subject>"
|
||||
event.subject = subject1
|
||||
assert event.Subject() == subject1
|
||||
|
||||
subject2 = "<my-subject2>"
|
||||
event.SetSubject(subject2)
|
||||
assert event.subject == subject2
|
||||
|
||||
|
||||
def test_v03_schema_url_property():
|
||||
event = v03.Event()
|
||||
|
||||
schema_url1 = "<my-schema>"
|
||||
event.schema_url = schema_url1
|
||||
assert event.SchemaURL() == schema_url1
|
||||
|
||||
schema_url2 = "<my-schema2>"
|
||||
event.SetSchemaURL(schema_url2)
|
||||
assert event.schema_url == schema_url2
|
||||
|
||||
|
||||
def test_v03_datacontentencoding_property():
|
||||
event = v03.Event()
|
||||
|
||||
datacontentencoding1 = "<my-datacontentencoding>"
|
||||
event.datacontentencoding = datacontentencoding1
|
||||
assert event.ContentEncoding() == datacontentencoding1
|
||||
|
||||
datacontentencoding2 = "<my-datacontentencoding2>"
|
||||
event.SetContentEncoding(datacontentencoding2)
|
||||
assert event.datacontentencoding == datacontentencoding2
|
|
@ -0,0 +1,53 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pytest
|
||||
|
||||
from cloudevents.sdk.event import v1
|
||||
|
||||
|
||||
def test_v1_time_property():
|
||||
event = v1.Event()
|
||||
|
||||
time1 = "1234"
|
||||
event.time = time1
|
||||
assert event.EventTime() == time1
|
||||
|
||||
time2 = "4321"
|
||||
event.SetEventTime(time2)
|
||||
assert event.time == time2
|
||||
|
||||
|
||||
def test_v1_subject_property():
|
||||
event = v1.Event()
|
||||
|
||||
subject1 = "<my-subject>"
|
||||
event.subject = subject1
|
||||
assert event.Subject() == subject1
|
||||
|
||||
subject2 = "<my-subject2>"
|
||||
event.SetSubject(subject2)
|
||||
assert event.subject == subject2
|
||||
|
||||
|
||||
def test_v1_schema_property():
|
||||
event = v1.Event()
|
||||
|
||||
schema1 = "<my-schema>"
|
||||
event.schema = schema1
|
||||
assert event.Schema() == schema1
|
||||
|
||||
schema2 = "<my-schema2>"
|
||||
event.SetSchema(schema2)
|
||||
assert event.schema == schema2
|
|
@ -15,7 +15,7 @@ import sys
|
|||
|
||||
import requests
|
||||
|
||||
from cloudevents.http import CloudEvent, to_binary_http, to_structured_http
|
||||
from cloudevents.http import CloudEvent, to_binary, to_structured
|
||||
|
||||
resp = requests.get(
|
||||
"https://raw.githubusercontent.com/cncf/artwork/master/projects/cloudevents/horizontal/color/cloudevents-horizontal-color.png"
|
||||
|
@ -33,7 +33,7 @@ def send_binary_cloud_event(url: str):
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create cloudevent HTTP headers and content
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
# Send cloudevent
|
||||
requests.post(url, headers=headers, data=body)
|
||||
|
@ -50,10 +50,10 @@ def send_structured_cloud_event(url: str):
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create cloudevent HTTP headers and content
|
||||
# Note that to_structured_http will create a data_base64 data field in
|
||||
# Note that to_structured will create a data_base64 data field in
|
||||
# specversion 1.0 (default specversion) if given
|
||||
# an event whose data field is of type bytes.
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
# Send cloudevent
|
||||
requests.post(url, headers=headers, data=body)
|
||||
|
|
|
@ -26,8 +26,8 @@ def home():
|
|||
# Create a CloudEvent.
|
||||
# data_unmarshaller will cast event.data into an io.BytesIO object
|
||||
event = from_http(
|
||||
request.get_data(),
|
||||
request.headers,
|
||||
request.get_data(),
|
||||
data_unmarshaller=lambda x: io.BytesIO(x),
|
||||
)
|
||||
|
||||
|
|
|
@ -7,12 +7,7 @@ from client import image_bytes
|
|||
from image_sample_server import app
|
||||
from PIL import Image
|
||||
|
||||
from cloudevents.http import (
|
||||
CloudEvent,
|
||||
from_http,
|
||||
to_binary_http,
|
||||
to_structured_http,
|
||||
)
|
||||
from cloudevents.http import CloudEvent, from_http, to_binary, to_structured
|
||||
|
||||
image_fileobj = io.BytesIO(image_bytes)
|
||||
image_expected_shape = (1880, 363)
|
||||
|
@ -35,11 +30,11 @@ def test_create_binary_image():
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create http headers/body content
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
# Unmarshall CloudEvent and re-create image
|
||||
reconstruct_event = from_http(
|
||||
body, headers, data_unmarshaller=lambda x: io.BytesIO(x)
|
||||
headers, body, data_unmarshaller=lambda x: io.BytesIO(x)
|
||||
)
|
||||
|
||||
# reconstruct_event.data is an io.BytesIO object due to data_unmarshaller
|
||||
|
@ -62,7 +57,7 @@ def test_create_structured_image():
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create http headers/body content
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
# Structured has cloudevent attributes marshalled inside the body. For this
|
||||
# reason we must load the byte object to create the python dict containing
|
||||
|
@ -75,7 +70,7 @@ def test_create_structured_image():
|
|||
|
||||
# Unmarshall CloudEvent and re-create image
|
||||
reconstruct_event = from_http(
|
||||
body, headers, data_unmarshaller=lambda x: io.BytesIO(x)
|
||||
headers, body, data_unmarshaller=lambda x: io.BytesIO(x)
|
||||
)
|
||||
|
||||
# reconstruct_event.data is an io.BytesIO object due to data_unmarshaller
|
||||
|
@ -92,10 +87,10 @@ def test_server_structured(client):
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create cloudevent HTTP headers and content
|
||||
# Note that to_structured_http will create a data_base64 data field in
|
||||
# Note that to_structured will create a data_base64 data field in
|
||||
# specversion 1.0 (default specversion) if given
|
||||
# an event whose data field is of type bytes.
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
# Send cloudevent
|
||||
r = client.post("/", headers=headers, data=body)
|
||||
|
@ -113,7 +108,7 @@ def test_server_binary(client):
|
|||
event = CloudEvent(attributes, image_bytes)
|
||||
|
||||
# Create cloudevent HTTP headers and content
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
# Send cloudevent
|
||||
r = client.post("/", headers=headers, data=body)
|
||||
|
|
|
@ -16,7 +16,7 @@ import sys
|
|||
|
||||
import requests
|
||||
|
||||
from cloudevents.http import CloudEvent, to_binary_http, to_structured_http
|
||||
from cloudevents.http import CloudEvent, to_binary, to_structured
|
||||
|
||||
|
||||
def send_binary_cloud_event(url):
|
||||
|
@ -28,7 +28,7 @@ def send_binary_cloud_event(url):
|
|||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
# send and print event
|
||||
requests.post(url, headers=headers, data=body)
|
||||
|
@ -44,7 +44,7 @@ def send_structured_cloud_event(url):
|
|||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
# send and print event
|
||||
requests.post(url, headers=headers, data=body)
|
||||
|
|
|
@ -22,7 +22,7 @@ app = Flask(__name__)
|
|||
@app.route("/", methods=["POST"])
|
||||
def home():
|
||||
# create a CloudEvent
|
||||
event = from_http(request.get_data(), request.headers)
|
||||
event = from_http(request.headers, request.get_data())
|
||||
|
||||
# you can access cloudevent fields as seen below
|
||||
print(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import pytest
|
||||
from json_sample_server import app
|
||||
|
||||
from cloudevents.http import CloudEvent, to_binary_http, to_structured_http
|
||||
from cloudevents.http import CloudEvent, to_binary, to_structured
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -19,7 +19,7 @@ def test_binary_request(client):
|
|||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_binary_http(event)
|
||||
headers, body = to_binary(event)
|
||||
|
||||
r = client.post("/", headers=headers, data=body)
|
||||
assert r.status_code == 204
|
||||
|
@ -34,7 +34,7 @@ def test_structured_request(client):
|
|||
data = {"message": "Hello World!"}
|
||||
|
||||
event = CloudEvent(attributes, data)
|
||||
headers, body = to_structured_http(event)
|
||||
headers, body = to_structured(event)
|
||||
|
||||
r = client.post("/", headers=headers, data=body)
|
||||
assert r.status_code == 204
|
||||
|
|
1
setup.py
1
setup.py
|
@ -41,4 +41,5 @@ setup(
|
|||
],
|
||||
packages=find_packages(exclude=["cloudevents.tests"]),
|
||||
version=pypi_config["version_target"],
|
||||
install_requires=["deprecation>=2.0,<3.0"],
|
||||
)
|
||||
|
|
2
tox.ini
2
tox.ini
|
@ -9,7 +9,7 @@ deps =
|
|||
-r{toxinidir}/requirements/docs.txt
|
||||
-r{toxinidir}/requirements/publish.txt
|
||||
setenv =
|
||||
PYTESTARGS = -v -s --tb=long --cov=cloudevents
|
||||
PYTESTARGS = -v -s --tb=long --cov=cloudevents --cov-report term-missing --cov-fail-under=100
|
||||
commands = pytest {env:PYTESTARGS} {posargs}
|
||||
|
||||
[testenv:reformat]
|
||||
|
|
Loading…
Reference in New Issue