Adding web app tests (#13)
* Adding web app tests Signed-off-by: Denis Makogon <denys.makogon@oracle.com> * addressing review comments Signed-off-by: Denis Makogon <denys.makogon@oracle.com>
This commit is contained in:
parent
5cd67e4122
commit
7070e5124a
|
@ -21,8 +21,13 @@ class Converter(object):
|
|||
|
||||
TYPE = None
|
||||
|
||||
def read(self, event, headers: dict, body: typing.IO,
|
||||
data_unmarshaller: typing.Callable) -> base.BaseEvent:
|
||||
def read(
|
||||
self,
|
||||
event,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable
|
||||
) -> base.BaseEvent:
|
||||
raise Exception("not implemented")
|
||||
|
||||
def event_supported(self, event: object) -> bool:
|
||||
|
@ -31,6 +36,9 @@ class Converter(object):
|
|||
def can_read(self, content_type: str) -> bool:
|
||||
raise Exception("not implemented")
|
||||
|
||||
def write(self, event: base.BaseEvent,
|
||||
data_marshaller: typing.Callable) -> (dict, typing.IO):
|
||||
def write(
|
||||
self,
|
||||
event: base.BaseEvent,
|
||||
data_marshaller: typing.Callable
|
||||
) -> (dict, object):
|
||||
raise Exception("not implemented")
|
||||
|
|
|
@ -23,7 +23,7 @@ from cloudevents.sdk.event import v02
|
|||
class BinaryHTTPCloudEventConverter(base.Converter):
|
||||
|
||||
TYPE = "binary"
|
||||
SUPPORTED_VERSIONS = [v02.Event, ]
|
||||
SUPPORTED_VERSIONS = [v02.Event]
|
||||
|
||||
def can_read(self, content_type: str) -> bool:
|
||||
return True
|
||||
|
@ -31,17 +31,21 @@ class BinaryHTTPCloudEventConverter(base.Converter):
|
|||
def event_supported(self, event: object) -> bool:
|
||||
return type(event) in self.SUPPORTED_VERSIONS
|
||||
|
||||
def read(self,
|
||||
event: event_base.BaseEvent,
|
||||
headers: dict, body: typing.IO,
|
||||
data_unmarshaller: typing.Callable) -> event_base.BaseEvent:
|
||||
def read(
|
||||
self,
|
||||
event: event_base.BaseEvent,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable,
|
||||
) -> event_base.BaseEvent:
|
||||
if type(event) not in self.SUPPORTED_VERSIONS:
|
||||
raise exceptions.UnsupportedEvent(type(event))
|
||||
event.UnmarshalBinary(headers, body, data_unmarshaller)
|
||||
return event
|
||||
|
||||
def write(self, event: event_base.BaseEvent,
|
||||
data_marshaller: typing.Callable) -> (dict, typing.IO):
|
||||
def write(
|
||||
self, event: event_base.BaseEvent, data_marshaller: typing.Callable
|
||||
) -> (dict, typing.IO):
|
||||
return event.MarshalBinary(data_marshaller)
|
||||
|
||||
|
||||
|
|
|
@ -30,17 +30,20 @@ class JSONHTTPCloudEventConverter(base.Converter):
|
|||
# structured format supported by both spec 0.1 and 0.2
|
||||
return True
|
||||
|
||||
def read(self, event: event_base.BaseEvent,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable) -> event_base.BaseEvent:
|
||||
def read(
|
||||
self,
|
||||
event: event_base.BaseEvent,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable,
|
||||
) -> event_base.BaseEvent:
|
||||
event.UnmarshalJSON(body, data_unmarshaller)
|
||||
return event
|
||||
|
||||
def write(self,
|
||||
event: event_base.BaseEvent,
|
||||
data_marshaller: typing.Callable) -> (dict, typing.IO):
|
||||
http_headers = {'content-type': self.MIME_TYPE}
|
||||
def write(
|
||||
self, event: event_base.BaseEvent, data_marshaller: typing.Callable
|
||||
) -> (dict, typing.IO):
|
||||
http_headers = {"content-type": self.MIME_TYPE}
|
||||
return http_headers, event.MarshalJSON(data_marshaller)
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import typing
|
|||
|
||||
|
||||
class EventGetterSetter(object):
|
||||
|
||||
def CloudEventVersion(self) -> str:
|
||||
raise Exception("not implemented")
|
||||
|
||||
|
@ -76,18 +75,13 @@ class EventGetterSetter(object):
|
|||
|
||||
|
||||
class BaseEvent(EventGetterSetter):
|
||||
|
||||
def Properties(self, with_nullable=False) -> dict:
|
||||
props = dict()
|
||||
for name, value in self.__dict__.items():
|
||||
if str(name).startswith("ce__"):
|
||||
v = value.get()
|
||||
if v is not None or with_nullable:
|
||||
props.update(
|
||||
{
|
||||
str(name).replace("ce__", ""): value.get()
|
||||
}
|
||||
)
|
||||
props.update({str(name).replace("ce__", ""): value.get()})
|
||||
|
||||
return props
|
||||
|
||||
|
@ -119,33 +113,38 @@ class BaseEvent(EventGetterSetter):
|
|||
props["data"] = data_marshaller(props.get("data"))
|
||||
return io.BytesIO(json.dumps(props).encode("utf-8"))
|
||||
|
||||
def UnmarshalJSON(self, b: typing.IO,
|
||||
data_unmarshaller: typing.Callable):
|
||||
def UnmarshalJSON(self, b: typing.IO, data_unmarshaller: typing.Callable):
|
||||
raw_ce = json.load(b)
|
||||
for name, value in raw_ce.items():
|
||||
if name == "data":
|
||||
value = data_unmarshaller(value)
|
||||
self.Set(name, value)
|
||||
|
||||
def UnmarshalBinary(self, headers: dict, body: typing.IO,
|
||||
data_unmarshaller: typing.Callable):
|
||||
BINARY_MAPPING = {
|
||||
'content-type': 'contenttype',
|
||||
def UnmarshalBinary(
|
||||
self,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable
|
||||
):
|
||||
binary_mapping = {
|
||||
"content-type": "contenttype",
|
||||
# TODO(someone): add Distributed Tracing. It's not clear
|
||||
# if this is one extension or two.
|
||||
# https://github.com/cloudevents/spec/blob/master/extensions/distributed-tracing.md
|
||||
}
|
||||
for header, value in headers.items():
|
||||
header = header.lower()
|
||||
if header in BINARY_MAPPING:
|
||||
self.Set(BINARY_MAPPING[header], value)
|
||||
if header in binary_mapping:
|
||||
self.Set(binary_mapping[header], value)
|
||||
elif header.startswith("ce-"):
|
||||
self.Set(header[3:], value)
|
||||
|
||||
self.Set("data", data_unmarshaller(body))
|
||||
|
||||
def MarshalBinary(
|
||||
self, data_marshaller: typing.Callable) -> (dict, object):
|
||||
self,
|
||||
data_marshaller: typing.Callable
|
||||
) -> (dict, object):
|
||||
headers = {}
|
||||
if self.ContentType():
|
||||
headers["content-type"] = self.ContentType()
|
||||
|
@ -159,5 +158,4 @@ class BaseEvent(EventGetterSetter):
|
|||
headers["ce-{0}".format(key)] = value
|
||||
|
||||
data, _ = self.Get("data")
|
||||
return headers, io.BytesIO(
|
||||
str(data_marshaller(data)).encode("utf-8"))
|
||||
return headers, data_marshaller(data)
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
|
||||
class Option(object):
|
||||
|
||||
def __init__(self, name, value, is_required):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
@ -25,7 +24,9 @@ class Option(object):
|
|||
if self.is_required and is_none:
|
||||
raise ValueError(
|
||||
"Attribute value error: '{0}', "
|
||||
"invalid new value.".format(self.name))
|
||||
"" "invalid new value."
|
||||
.format(self.name)
|
||||
)
|
||||
|
||||
self.value = new_value
|
||||
|
||||
|
|
|
@ -12,25 +12,62 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from cloudevents.sdk.event import opt
|
||||
from cloudevents.sdk.event import base
|
||||
from cloudevents.sdk.event import opt
|
||||
|
||||
|
||||
class Event(base.BaseEvent):
|
||||
|
||||
def __init__(self):
|
||||
self.ce__cloudEventsVersion = opt.Option(
|
||||
"cloudEventsVersion", "0.1", True)
|
||||
self.ce__eventType = opt.Option("eventType", None, True)
|
||||
"cloudEventsVersion",
|
||||
"0.1",
|
||||
True
|
||||
)
|
||||
self.ce__eventType = opt.Option(
|
||||
"eventType",
|
||||
None,
|
||||
True
|
||||
)
|
||||
self.ce__eventTypeVersion = opt.Option(
|
||||
"eventTypeVersion", None, False)
|
||||
self.ce__source = opt.Option("source", None, True)
|
||||
self.ce__eventID = opt.Option("eventID", None, True)
|
||||
self.ce__eventTime = opt.Option("eventTime", None, True)
|
||||
self.ce__schemaURL = opt.Option("schemaURL", None, False)
|
||||
self.ce__contentType = opt.Option("contentType", None, False)
|
||||
self.ce__data = opt.Option("data", None, False)
|
||||
self.ce__extensions = opt.Option("extensions", dict(), False)
|
||||
"eventTypeVersion",
|
||||
None,
|
||||
False
|
||||
)
|
||||
self.ce__source = opt.Option(
|
||||
"source",
|
||||
None,
|
||||
True
|
||||
)
|
||||
self.ce__eventID = opt.Option(
|
||||
"eventID",
|
||||
None,
|
||||
True
|
||||
)
|
||||
self.ce__eventTime = opt.Option(
|
||||
"eventTime",
|
||||
None,
|
||||
True
|
||||
)
|
||||
self.ce__schemaURL = opt.Option(
|
||||
"schemaURL",
|
||||
None,
|
||||
False
|
||||
)
|
||||
self.ce__contentType = opt.Option(
|
||||
"contentType",
|
||||
None,
|
||||
False
|
||||
)
|
||||
self.ce__data = opt.Option(
|
||||
"data",
|
||||
None,
|
||||
False
|
||||
)
|
||||
self.ce__extensions = opt.Option(
|
||||
"extensions",
|
||||
dict(),
|
||||
False
|
||||
)
|
||||
|
||||
def CloudEventVersion(self) -> str:
|
||||
return self.ce__cloudEventsVersion.get()
|
||||
|
|
|
@ -12,12 +12,11 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from cloudevents.sdk.event import opt
|
||||
from cloudevents.sdk.event import base
|
||||
from cloudevents.sdk.event import opt
|
||||
|
||||
|
||||
class Event(base.BaseEvent):
|
||||
|
||||
def __init__(self):
|
||||
self.ce__specversion = opt.Option("specversion", "0.2", True)
|
||||
self.ce__type = opt.Option("type", None, True)
|
||||
|
|
|
@ -14,34 +14,34 @@
|
|||
|
||||
|
||||
class UnsupportedEvent(Exception):
|
||||
|
||||
def __init__(self, event_class):
|
||||
super().__init__("Invalid CloudEvent class: "
|
||||
"'{0}'".format(event_class))
|
||||
super().__init__(
|
||||
"Invalid CloudEvent class: '{0}'".format(event_class)
|
||||
)
|
||||
|
||||
|
||||
class InvalidDataUnmarshaller(Exception):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
"Invalid data unmarshaller, is not a callable")
|
||||
super().__init__("Invalid data unmarshaller, is not a callable")
|
||||
|
||||
|
||||
class InvalidDataMarshaller(Exception):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
"Invalid data marshaller, is not a callable")
|
||||
"Invalid data marshaller, is not a callable"
|
||||
)
|
||||
|
||||
|
||||
class NoSuchConverter(Exception):
|
||||
def __init__(self, converter_type):
|
||||
super().__init__(
|
||||
"No such converter {0}".format(converter_type))
|
||||
"No such converter {0}".format(converter_type)
|
||||
)
|
||||
|
||||
|
||||
class UnsupportedEventConverter(Exception):
|
||||
def __init__(self, content_type):
|
||||
super().__init__(
|
||||
"Unable to identify valid event converter "
|
||||
"for content-type: '{0}'".format(content_type))
|
||||
"for content-type: '{0}'".format(content_type)
|
||||
)
|
||||
|
|
|
@ -35,14 +35,16 @@ class HTTPMarshaller(object):
|
|||
:param converters: a list of HTTP-to-CloudEvent-to-HTTP constructors
|
||||
:type converters: typing.List[base.Converter]
|
||||
"""
|
||||
self.__converters = (c for c in converters)
|
||||
self.__converters = [c for c in converters]
|
||||
self.__converters_by_type = {c.TYPE: c for c in converters}
|
||||
|
||||
def FromRequest(self, event: event_base.BaseEvent,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller:
|
||||
typing.Callable) -> event_base.BaseEvent:
|
||||
def FromRequest(
|
||||
self,
|
||||
event: event_base.BaseEvent,
|
||||
headers: dict,
|
||||
body: typing.IO,
|
||||
data_unmarshaller: typing.Callable,
|
||||
) -> event_base.BaseEvent:
|
||||
"""
|
||||
Reads a CloudEvent from an HTTP headers and request body
|
||||
:param event: CloudEvent placeholder
|
||||
|
@ -59,8 +61,7 @@ class HTTPMarshaller(object):
|
|||
if not isinstance(data_unmarshaller, typing.Callable):
|
||||
raise exceptions.InvalidDataUnmarshaller()
|
||||
|
||||
content_type = headers.get(
|
||||
"content-type", headers.get("Content-Type"))
|
||||
content_type = headers.get("content-type", headers.get("Content-Type"))
|
||||
|
||||
for cnvrtr in self.__converters:
|
||||
if cnvrtr.can_read(content_type) and cnvrtr.event_supported(event):
|
||||
|
@ -68,11 +69,16 @@ class HTTPMarshaller(object):
|
|||
|
||||
raise exceptions.UnsupportedEventConverter(
|
||||
"No registered marshaller for {0} in {1}".format(
|
||||
content_type, self.__converters))
|
||||
content_type, self.__converters
|
||||
)
|
||||
)
|
||||
|
||||
def ToRequest(self, event: event_base.BaseEvent,
|
||||
converter_type: str,
|
||||
data_marshaller: typing.Callable) -> (dict, typing.IO):
|
||||
def ToRequest(
|
||||
self,
|
||||
event: event_base.BaseEvent,
|
||||
converter_type: str,
|
||||
data_marshaller: typing.Callable,
|
||||
) -> (dict, typing.IO):
|
||||
"""
|
||||
Writes a CloudEvent into a HTTP-ready form of headers and request body
|
||||
:param event: CloudEvent
|
||||
|
@ -101,14 +107,17 @@ def NewDefaultHTTPMarshaller() -> HTTPMarshaller:
|
|||
:return: an instance of HTTP marshaller
|
||||
:rtype: cloudevents.sdk.marshaller.HTTPMarshaller
|
||||
"""
|
||||
return HTTPMarshaller([
|
||||
structured.NewJSONHTTPCloudEventConverter(),
|
||||
binary.NewBinaryHTTPCloudEventConverter(),
|
||||
])
|
||||
return HTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter(),
|
||||
binary.NewBinaryHTTPCloudEventConverter(),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def NewHTTPMarshaller(
|
||||
converters: typing.List[base.Converter]) -> HTTPMarshaller:
|
||||
converters: typing.List[base.Converter]
|
||||
) -> HTTPMarshaller:
|
||||
"""
|
||||
Creates the default HTTP marshaller with both
|
||||
structured and binary converters
|
||||
|
|
|
@ -25,7 +25,7 @@ headers = {
|
|||
"ce-id": ce_id,
|
||||
"ce-time": eventTime,
|
||||
"ce-source": source,
|
||||
"Content-Type": contentType
|
||||
"Content-Type": contentType,
|
||||
}
|
||||
ce = {
|
||||
"specversion": specversion,
|
||||
|
@ -33,5 +33,5 @@ ce = {
|
|||
"id": ce_id,
|
||||
"time": eventTime,
|
||||
"source": source,
|
||||
"contenttype": contentType
|
||||
"contenttype": contentType,
|
||||
}
|
||||
|
|
|
@ -30,10 +30,7 @@ from cloudevents.tests import data
|
|||
|
||||
def test_binary_converter_upstream():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
binary.NewBinaryHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[binary.NewBinaryHTTPCloudEventConverter()])
|
||||
event = m.FromRequest(v02.Event(), data.headers, None, lambda x: x)
|
||||
assert event is not None
|
||||
assert event.Get("type") == (data.ce_type, True)
|
||||
|
@ -42,15 +39,12 @@ def test_binary_converter_upstream():
|
|||
|
||||
def test_structured_converter_upstream():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[structured.NewJSONHTTPCloudEventConverter()])
|
||||
event = m.FromRequest(
|
||||
v02.Event(),
|
||||
{"Content-Type": "application/cloudevents+json"},
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
lambda x: x.read(),
|
||||
)
|
||||
|
||||
assert event is not None
|
||||
|
@ -60,41 +54,40 @@ def test_structured_converter_upstream():
|
|||
|
||||
def test_binary_converter_v01():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
binary.NewBinaryHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[binary.NewBinaryHTTPCloudEventConverter()])
|
||||
|
||||
pytest.raises(
|
||||
exceptions.UnsupportedEventConverter,
|
||||
m.FromRequest,
|
||||
v01.Event, {}, None, lambda x: x)
|
||||
v01.Event,
|
||||
{},
|
||||
None,
|
||||
lambda x: x,
|
||||
)
|
||||
|
||||
|
||||
def test_unsupported_converter_v01():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[structured.NewJSONHTTPCloudEventConverter()])
|
||||
|
||||
pytest.raises(
|
||||
exceptions.UnsupportedEventConverter,
|
||||
m.FromRequest,
|
||||
v01.Event, {}, None, lambda x: x)
|
||||
v01.Event,
|
||||
{},
|
||||
None,
|
||||
lambda x: x,
|
||||
)
|
||||
|
||||
|
||||
def test_structured_converter_v01():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[structured.NewJSONHTTPCloudEventConverter()])
|
||||
event = m.FromRequest(
|
||||
v01.Event(),
|
||||
{"Content-Type": "application/cloudevents+json"},
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
lambda x: x.read(),
|
||||
)
|
||||
|
||||
assert event is not None
|
||||
|
@ -109,7 +102,7 @@ def test_default_http_marshaller_with_structured():
|
|||
v02.Event(),
|
||||
{"Content-Type": "application/cloudevents+json"},
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
lambda x: x.read(),
|
||||
)
|
||||
assert event is not None
|
||||
assert event.Get("type") == (data.ce_type, True)
|
||||
|
@ -120,8 +113,7 @@ def test_default_http_marshaller_with_binary():
|
|||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
|
||||
event = m.FromRequest(
|
||||
v02.Event(),
|
||||
data.headers,
|
||||
v02.Event(), data.headers,
|
||||
io.StringIO(json.dumps(data.body)),
|
||||
json.load
|
||||
)
|
||||
|
@ -133,17 +125,14 @@ def test_default_http_marshaller_with_binary():
|
|||
|
||||
def test_unsupported_event_configuration():
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
binary.NewBinaryHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
[binary.NewBinaryHTTPCloudEventConverter()])
|
||||
pytest.raises(
|
||||
exceptions.UnsupportedEventConverter,
|
||||
m.FromRequest,
|
||||
v01.Event(),
|
||||
{"Content-Type": "application/cloudevents+json"},
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
lambda x: x.read(),
|
||||
)
|
||||
|
||||
|
||||
|
@ -152,12 +141,12 @@ def test_invalid_data_unmarshaller():
|
|||
pytest.raises(
|
||||
exceptions.InvalidDataUnmarshaller,
|
||||
m.FromRequest,
|
||||
v01.Event(), {}, None, None)
|
||||
v01.Event(), {}, None, None
|
||||
)
|
||||
|
||||
|
||||
def test_invalid_data_marshaller():
|
||||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
pytest.raises(
|
||||
exceptions.InvalidDataMarshaller,
|
||||
m.ToRequest,
|
||||
v01.Event(), "blah", None)
|
||||
exceptions.InvalidDataMarshaller, m.ToRequest, v01.Event(), "blah", None
|
||||
)
|
||||
|
|
|
@ -27,13 +27,13 @@ from cloudevents.tests import data
|
|||
|
||||
def test_event_pipeline_upstream():
|
||||
event = (
|
||||
v02.Event().
|
||||
SetContentType(data.contentType).
|
||||
SetData(data.body).
|
||||
SetEventID(data.ce_id).
|
||||
SetSource(data.source).
|
||||
SetEventTime(data.eventTime).
|
||||
SetEventType(data.ce_type)
|
||||
v02.Event()
|
||||
.SetContentType(data.contentType)
|
||||
.SetData(data.body)
|
||||
.SetEventID(data.ce_id)
|
||||
.SetSource(data.source)
|
||||
.SetEventTime(data.eventTime)
|
||||
.SetEventType(data.ce_type)
|
||||
)
|
||||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
new_headers, body = m.ToRequest(event, converters.TypeBinary, lambda x: x)
|
||||
|
@ -44,29 +44,25 @@ def test_event_pipeline_upstream():
|
|||
assert "ce-id" in new_headers
|
||||
assert "ce-time" in new_headers
|
||||
assert "content-type" in new_headers
|
||||
assert isinstance(body, io.BytesIO)
|
||||
assert data.body == body.read().decode("utf-8")
|
||||
assert isinstance(body, str)
|
||||
assert data.body == body
|
||||
|
||||
|
||||
def test_event_pipeline_v01():
|
||||
event = (
|
||||
v01.Event().
|
||||
SetContentType(data.contentType).
|
||||
SetData(data.body).
|
||||
SetEventID(data.ce_id).
|
||||
SetSource(data.source).
|
||||
SetEventTime(data.eventTime).
|
||||
SetEventType(data.ce_type)
|
||||
)
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter()
|
||||
]
|
||||
v01.Event()
|
||||
.SetContentType(data.contentType)
|
||||
.SetData(data.body)
|
||||
.SetEventID(data.ce_id)
|
||||
.SetSource(data.source)
|
||||
.SetEventTime(data.eventTime)
|
||||
.SetEventType(data.ce_type)
|
||||
)
|
||||
m = marshaller.NewHTTPMarshaller([structured.NewJSONHTTPCloudEventConverter()])
|
||||
|
||||
_, body = m.ToRequest(event, converters.TypeStructured, lambda x: x)
|
||||
assert isinstance(body, io.BytesIO)
|
||||
new_headers = json.load(io.TextIOWrapper(body, encoding='utf-8'))
|
||||
new_headers = json.load(io.TextIOWrapper(body, encoding="utf-8"))
|
||||
assert new_headers is not None
|
||||
assert "cloudEventsVersion" in new_headers
|
||||
assert "eventType" in new_headers
|
||||
|
|
|
@ -33,7 +33,7 @@ def test_binary_event_to_request_upstream():
|
|||
v02.Event(),
|
||||
{"Content-Type": "application/cloudevents+json"},
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
lambda x: x.read(),
|
||||
)
|
||||
|
||||
assert event is not None
|
||||
|
@ -50,10 +50,7 @@ def test_structured_event_to_request_upstream():
|
|||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
http_headers = {"content-type": "application/cloudevents+json"}
|
||||
event = m.FromRequest(
|
||||
v02.Event(),
|
||||
http_headers,
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
v02.Event(), http_headers, io.StringIO(json.dumps(data.ce)), lambda x: x.read()
|
||||
)
|
||||
assert event is not None
|
||||
assert event.Get("type") == (data.ce_type, True)
|
||||
|
@ -69,17 +66,10 @@ def test_structured_event_to_request_upstream():
|
|||
|
||||
def test_structured_event_to_request_v01():
|
||||
copy_of_ce = copy.deepcopy(data.ce)
|
||||
m = marshaller.NewHTTPMarshaller(
|
||||
[
|
||||
structured.NewJSONHTTPCloudEventConverter()
|
||||
]
|
||||
)
|
||||
m = marshaller.NewHTTPMarshaller([structured.NewJSONHTTPCloudEventConverter()])
|
||||
http_headers = {"content-type": "application/cloudevents+json"}
|
||||
event = m.FromRequest(
|
||||
v01.Event(),
|
||||
http_headers,
|
||||
io.StringIO(json.dumps(data.ce)),
|
||||
lambda x: x.read()
|
||||
v01.Event(), http_headers, io.StringIO(json.dumps(data.ce)), lambda x: x.read()
|
||||
)
|
||||
assert event is not None
|
||||
assert event.Get("type") == (data.ce_type, True)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# 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.
|
||||
|
||||
from cloudevents.sdk import marshaller
|
||||
from cloudevents.sdk import converters
|
||||
from cloudevents.sdk.event import v02
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic import response
|
||||
|
||||
from cloudevents.tests import data as test_data
|
||||
|
||||
|
||||
m = marshaller.NewDefaultHTTPMarshaller()
|
||||
app = Sanic(__name__)
|
||||
|
||||
|
||||
@app.route("/is-ok", ["POST"])
|
||||
async def is_ok(request):
|
||||
m.FromRequest(
|
||||
v02.Event(),
|
||||
dict(request.headers),
|
||||
request.body,
|
||||
lambda x: x
|
||||
)
|
||||
return response.text("OK")
|
||||
|
||||
|
||||
@app.route("/echo", ["POST"])
|
||||
async def echo(request):
|
||||
event = m.FromRequest(
|
||||
v02.Event(),
|
||||
dict(request.headers),
|
||||
request.body,
|
||||
lambda x: x
|
||||
)
|
||||
hs, body = m.ToRequest(event, converters.TypeBinary, lambda x: x)
|
||||
return response.text(body, headers=hs)
|
||||
|
||||
|
||||
def test_reusable_marshaller():
|
||||
for i in range(10):
|
||||
_, r = app.test_client.post(
|
||||
"/is-ok", headers=test_data.headers, data=test_data.body
|
||||
)
|
||||
assert r.status == 200
|
||||
|
||||
|
||||
def test_web_app_integration():
|
||||
_, r = app.test_client.post(
|
||||
"/is-ok", headers=test_data.headers, data=test_data.body
|
||||
)
|
||||
assert r.status == 200
|
||||
|
||||
|
||||
def test_web_app_echo():
|
||||
_, r = app.test_client.post("/echo", headers=test_data.headers, data=test_data.body)
|
||||
assert r.status == 200
|
||||
event = m.FromRequest(v02.Event(), dict(r.headers), r.body, lambda x: x)
|
||||
assert event is not None
|
||||
props = event.Properties()
|
||||
for key in test_data.headers.keys():
|
||||
if key == "Content-Type":
|
||||
assert "contenttype" in props
|
||||
else:
|
||||
assert key.lstrip("ce-") in props
|
|
@ -1,4 +1,10 @@
|
|||
flake8<2.7.0,>=2.6.0
|
||||
hacking==1.1.0
|
||||
flake8
|
||||
pep8-naming==0.5.0
|
||||
flake8-import-order
|
||||
flake8-print
|
||||
flake8-strict
|
||||
pytest==4.0.0
|
||||
pytest-cov==2.4.0
|
||||
# web app tests
|
||||
sanic
|
||||
aiohttp
|
7
tox.ini
7
tox.ini
|
@ -18,7 +18,8 @@ whitelist_externals = find
|
|||
go
|
||||
docker
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
commands =
|
||||
flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
@ -30,6 +31,6 @@ commands = pytest -v -s --tb=long --cov=cloudevents {toxinidir}/cloudevents/test
|
|||
commands = pytest -v -s --tb=long --cov=cloudevents {toxinidir}/cloudevents/tests
|
||||
|
||||
[flake8]
|
||||
ignore = H405,H404,H403,H401,H306
|
||||
ignore = H405,H404,H403,H401,H306,S101,N802,N803,N806,I202,I201
|
||||
show-source = True
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,docs,venv,.venv,docs,etc
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,docs,venv,.venv,docs,etc,samples,tests
|
||||
|
|
Loading…
Reference in New Issue