Merge pull request #4 from clemensv/master

Versioning support for 0.1 and 0.2
This commit is contained in:
Clemens Vasters 2018-11-28 14:06:24 +01:00 committed by GitHub
commit 51ea22ed49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 618 additions and 316 deletions

View File

@ -9,7 +9,6 @@ namespace CloudNative.CloudEvents.Amqp
using System.Dynamic;
using System.IO;
using System.Net.Mime;
using System.Threading.Tasks;
using global::Amqp;
using global::Amqp.Types;
@ -17,7 +16,9 @@ namespace CloudNative.CloudEvents.Amqp
{
const string AmqpHeaderPrefix = "cloudEvents:";
const string SpecVersionAmqpHeader = AmqpHeaderPrefix + "specversion";
const string SpecVersionAmqpHeader1 = AmqpHeaderPrefix + "cloudEventsVersion";
const string SpecVersionAmqpHeader2 = AmqpHeaderPrefix + "specversion";
static JsonEventFormatter jsonFormatter = new JsonEventFormatter();
@ -25,7 +26,8 @@ namespace CloudNative.CloudEvents.Amqp
{
return ((message.Properties.ContentType != null &&
message.Properties.ContentType.ToString().StartsWith(CloudEvent.MediaType)) ||
message.ApplicationProperties.Map.ContainsKey(SpecVersionAmqpHeader));
message.ApplicationProperties.Map.ContainsKey(SpecVersionAmqpHeader1) ||
message.ApplicationProperties.Map.ContainsKey(SpecVersionAmqpHeader2));
}
public static CloudEvent ToCloudEvent(this Message message,
@ -61,7 +63,14 @@ namespace CloudNative.CloudEvents.Amqp
}
else
{
var cloudEvent = new CloudEvent(extensions);
var cloudEvent = new CloudEvent(
message.ApplicationProperties.Map.ContainsKey(SpecVersionAmqpHeader1)
? CloudEventsSpecVersion.V0_1
: message.ApplicationProperties.Map.ContainsKey(SpecVersionAmqpHeader2)
? (message.ApplicationProperties.Map[SpecVersionAmqpHeader2] as string == "0.2"
? CloudEventsSpecVersion.V0_2
: CloudEventsSpecVersion.Default)
: CloudEventsSpecVersion.Default, extensions);
var attributes = cloudEvent.GetAttributes();
foreach (var prop in message.ApplicationProperties.Map)
{
@ -75,13 +84,14 @@ namespace CloudNative.CloudEvents.Amqp
{
exp[props.Key.ToString()] = props.Value;
}
attributes[((string)prop.Key).Substring(AmqpHeaderPrefix.Length).ToLowerInvariant()] =
exp;
exp;
}
else
{
attributes[((string)prop.Key).Substring(AmqpHeaderPrefix.Length).ToLowerInvariant()] =
prop.Value;
prop.Value;
}
}
}

View File

@ -5,7 +5,6 @@
namespace CloudNative.CloudEvents.Amqp
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using global::Amqp;
@ -19,7 +18,7 @@ namespace CloudNative.CloudEvents.Amqp
if (contentMode == ContentMode.Structured)
{
this.BodySection = new Data
{ Binary = formatter.EncodeStructuredEvent(cloudEvent, out var contentType) };
{ Binary = formatter.EncodeStructuredEvent(cloudEvent, out var contentType) };
this.Properties = new Properties() { ContentType = contentType.MediaType };
this.ApplicationProperties = new ApplicationProperties();
MapHeaders(cloudEvent);
@ -57,32 +56,28 @@ namespace CloudNative.CloudEvents.Amqp
{
foreach (var attribute in cloudEvent.GetAttributes())
{
switch (attribute.Key)
if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) &&
!attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion)))
{
case CloudEventAttributes.DataAttributeName:
case CloudEventAttributes.ContentTypeAttributeName:
break;
default:
if (attribute.Value is Uri)
if (attribute.Value is Uri)
{
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value.ToString());
}
else if (attribute.Value is DateTime || attribute.Value is DateTime || attribute.Value is string)
{
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value);
}
else
{
Map dict = new Map();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(attribute.Value))
{
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value.ToString());
dict.Add(descriptor.Name, descriptor.GetValue(attribute.Value));
}
else if (attribute.Value is DateTime || attribute.Value is DateTime || attribute.Value is string)
{
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value);
}
else
{
Map dict = new Map();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(attribute.Value))
{
dict.Add(descriptor.Name,descriptor.GetValue(attribute.Value));
}
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, dict);
}
break;
}
this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, dict);
}
}
}
}
}

View File

@ -15,7 +15,7 @@ namespace CloudNative.CloudEvents
{
public const string MediaType = "application/cloudevents";
readonly IDictionary<string, object> attributes;
readonly CloudEventAttributes attributes;
/// <summary>
/// Create a new CloudEvent instance.
@ -26,7 +26,21 @@ namespace CloudNative.CloudEvents
/// <param name="time">'time' of the CloudEvent</param>
/// <param name="extensions">Extensions to be added to this CloudEvents</param>
public CloudEvent(string type, Uri source, string id = null, DateTime? time = null,
params ICloudEventExtension[] extensions) : this(extensions)
params ICloudEventExtension[] extensions) : this(CloudEventsSpecVersion.V0_2, type, source, id, time, extensions)
{
}
/// <summary>
/// Create a new CloudEvent instance.
/// </summary>
/// <param name="specVersion">CloudEvents specification version</param>
/// <param name="type">'type' of the CloudEvent</param>
/// <param name="source">'source' of the CloudEvent</param>
/// <param name="id">'id' of the CloudEvent</param>
/// <param name="time">'time' of the CloudEvent</param>
/// <param name="extensions">Extensions to be added to this CloudEvents</param>
public CloudEvent(CloudEventsSpecVersion specVersion, string type, Uri source, string id = null, DateTime? time = null,
params ICloudEventExtension[] extensions) : this(specVersion, extensions)
{
Type = type;
Source = source;
@ -37,11 +51,11 @@ namespace CloudNative.CloudEvents
/// <summary>
/// Create a new CloudEvent instance
/// </summary>
/// <param name="specVersion">CloudEvents specification version</param>
/// <param name="extensions">Extensions to be added to this CloudEvents</param>
internal CloudEvent(IEnumerable<ICloudEventExtension> extensions)
internal CloudEvent(CloudEventsSpecVersion specVersion, IEnumerable<ICloudEventExtension> extensions)
{
attributes = new CloudEventAttributes(extensions);
SpecVersion = "0.2";
attributes = new CloudEventAttributes(specVersion, extensions);
this.Extensions = new Dictionary<Type, ICloudEventExtension>();
if (extensions != null)
{
@ -61,8 +75,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#contenttype"/>
public ContentType ContentType
{
get => attributes[CloudEventAttributes.ContentTypeAttributeName] as ContentType;
set => attributes[CloudEventAttributes.ContentTypeAttributeName] = value;
get => attributes[CloudEventAttributes.ContentTypeAttributeName(attributes.SpecVersion)] as ContentType;
set => attributes[CloudEventAttributes.ContentTypeAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -73,8 +87,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#data-1"/>
public object Data
{
get => attributes[CloudEventAttributes.DataAttributeName];
set => attributes[CloudEventAttributes.DataAttributeName] = value;
get => attributes[CloudEventAttributes.DataAttributeName(attributes.SpecVersion)];
set => attributes[CloudEventAttributes.DataAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -89,8 +103,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#id"/>
public string Id
{
get => attributes[CloudEventAttributes.IdAttributeName] as string;
set => attributes[CloudEventAttributes.IdAttributeName] = value;
get => attributes[CloudEventAttributes.IdAttributeName(attributes.SpecVersion)] as string;
set => attributes[CloudEventAttributes.IdAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -101,8 +115,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#schemaurl"/>
public Uri SchemaUrl
{
get => attributes[CloudEventAttributes.SchemaUrlAttributeName] as Uri;
set => attributes[CloudEventAttributes.SchemaUrlAttributeName] = value;
get => attributes[CloudEventAttributes.SchemaUrlAttributeName(attributes.SpecVersion)] as Uri;
set => attributes[CloudEventAttributes.SchemaUrlAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -114,8 +128,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#source"/>
public Uri Source
{
get => attributes[CloudEventAttributes.SourceAttributeName] as Uri;
set => attributes[CloudEventAttributes.SourceAttributeName] = value;
get => attributes[CloudEventAttributes.SourceAttributeName(attributes.SpecVersion)] as Uri;
set => attributes[CloudEventAttributes.SourceAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -123,10 +137,10 @@ namespace CloudNative.CloudEvents
/// specification which the event uses. This enables the interpretation of the context.
/// </summary>
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#specversion"/>
public string SpecVersion
public CloudEventsSpecVersion SpecVersion
{
get => attributes[CloudEventAttributes.SpecVersionAttributeName] as string;
set => attributes[CloudEventAttributes.SpecVersionAttributeName] = value;
get => attributes.SpecVersion;
set => attributes.SpecVersion = value;
}
/// <summary>
@ -135,8 +149,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#time"/>
public DateTime? Time
{
get => (DateTime?)attributes[CloudEventAttributes.TimeAttributeName];
set => attributes[CloudEventAttributes.TimeAttributeName] = value;
get => (DateTime?)attributes[CloudEventAttributes.TimeAttributeName(attributes.SpecVersion)];
set => attributes[CloudEventAttributes.TimeAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>
@ -146,8 +160,8 @@ namespace CloudNative.CloudEvents
/// <see cref="https://github.com/cloudevents/spec/blob/master/spec.md#type"/>
public string Type
{
get => attributes[CloudEventAttributes.TypeAttributeName] as string;
set => attributes[CloudEventAttributes.TypeAttributeName] = value;
get => attributes[CloudEventAttributes.TypeAttributeName(attributes.SpecVersion)] as string;
set => attributes[CloudEventAttributes.TypeAttributeName(attributes.SpecVersion)] = value;
}
/// <summary>

View File

@ -15,29 +15,17 @@ namespace CloudNative.CloudEvents
/// </summary>
public class CloudEventAttributes : IDictionary<string, object>
{
public const string ContentTypeAttributeName = "contenttype";
public const string DataAttributeName = "data";
public const string IdAttributeName = "id";
public const string SchemaUrlAttributeName = "schemaurl";
public const string SourceAttributeName = "source";
public const string SpecVersionAttributeName = "specversion";
public const string TimeAttributeName = "time";
public const string TypeAttributeName = "type";
readonly CloudEventsSpecVersion specVersion;
IDictionary<string, object> dict = new Dictionary<string, object>();
IEnumerable<ICloudEventExtension> extensions;
internal CloudEventAttributes(IEnumerable<ICloudEventExtension> extensions)
internal CloudEventAttributes(CloudEventsSpecVersion specVersion, IEnumerable<ICloudEventExtension> extensions)
{
this.extensions = extensions;
this.specVersion = specVersion;
dict[SpecVersionAttributeName(specVersion)] = specVersion == CloudEventsSpecVersion.V0_1 ? "0.1" : "0.2";
}
int ICollection<KeyValuePair<string, object>>.Count => dict.Count;
@ -48,7 +36,85 @@ namespace CloudNative.CloudEvents
ICollection<object> IDictionary<string, object>.Values => dict.Values;
object IDictionary<string, object>.this[string key]
public CloudEventsSpecVersion SpecVersion
{
get
{
object val;
if (dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), out val) ||
dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), out val))
{
return (val as string) == "0.1" ? CloudEventsSpecVersion.V0_1 : CloudEventsSpecVersion.V0_2;
}
return CloudEventsSpecVersion.V0_2;
}
set
{
var currentSpecVersion = SpecVersion;
object val;
if (dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), out val))
{
if (value == CloudEventsSpecVersion.V0_1 && (val as string) == "0.1")
{
return;
}
}
else if ( dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), out val))
{
if (value == CloudEventsSpecVersion.V0_2 && (val as string) == "0.2")
{
return;
}
}
// transform to new version
var copy = new Dictionary<string, object>(dict);
dict.Clear();
dict[SpecVersionAttributeName(value)] = value == CloudEventsSpecVersion.V0_1 ? "0.1" : "0.2";
foreach (var kv in copy)
{
if (SpecVersionAttributeName(currentSpecVersion).Equals(kv.Key))
{
continue;
}
if (ContentTypeAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[ContentTypeAttributeName(value)] = kv.Value;
}
else if (DataAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[DataAttributeName(value)] = kv.Value;
}
else if (IdAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[IdAttributeName(value)] = kv.Value;
}
else if (SchemaUrlAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[SchemaUrlAttributeName(value)] = kv.Value;
}
else if (SourceAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[SourceAttributeName(value)] = kv.Value;
}
else if (TimeAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[TimeAttributeName(value)] = kv.Value;
}
else if (TypeAttributeName(currentSpecVersion).Equals(kv.Key))
{
dict[TypeAttributeName(value)] = kv.Value;
}
else
{
dict[kv.Key] = kv.Value;
}
}
}
}
public object this[string key]
{
get => dict[key];
set
@ -58,6 +124,46 @@ namespace CloudNative.CloudEvents
}
}
public static string ContentTypeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "contentType" : "contenttype";
}
public static string DataAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return "data";
}
public static string IdAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "eventID" : "id";
}
public static string SchemaUrlAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "schemaUrl" : "schemaurl";
}
public static string SourceAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return "source";
}
public static string SpecVersionAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "cloudEventsVersion" : "specversion";
}
public static string TimeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "eventTime" : "time";
}
public static string TypeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default)
{
return version == CloudEventsSpecVersion.V0_1 ? "eventType" : "type";
}
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
object value = item.Value;
@ -118,114 +224,126 @@ namespace CloudNative.CloudEvents
internal virtual bool ValidateAndNormalize(string key, ref object value)
{
switch (key)
if (key.Equals(TypeAttributeName(this.SpecVersion)))
{
case TypeAttributeName:
if (value is string)
{
return true;
}
throw new InvalidOperationException(Strings.ErrorTypeValueIsNotAString);
case SpecVersionAttributeName:
if (value is string)
{
return true;
}
throw new InvalidOperationException(Strings.ErrorSpecVersionValueIsNotAString);
case IdAttributeName:
if (value is string)
{
return true;
}
throw new InvalidOperationException(Strings.ErrorIdValueIsNotAString);
case TimeAttributeName:
if (value is null || value is DateTime)
{
return true;
}
if (value is string)
{
if (DateTime.TryParseExact((string)value, "o", CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal, out var dateTimeVal))
{
value = dateTimeVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorTimeValueIsNotATimestamp);
case SourceAttributeName:
if (value is Uri)
{
return true;
}
if (value is string)
{
if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out var uriVal))
{
value = uriVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri);
case SchemaUrlAttributeName:
if (value is null || value is Uri)
{
return true;
}
if (value is string)
{
if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out var uriVal))
{
value = uriVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri);
case ContentTypeAttributeName:
if (value is null || value is ContentType)
{
return true;
}
if (value is string)
{
try
{
value = new ContentType((string)value);
return true;
}
catch (FormatException fe)
{
throw new InvalidOperationException(Strings.ErrorContentTypeIsNotRFC2046, fe);
}
}
throw new InvalidOperationException(Strings.ErrorContentTypeIsNotRFC2046);
case DataAttributeName:
if (value is string)
{
return true;
default:
if (extensions != null)
}
throw new InvalidOperationException(Strings.ErrorTypeValueIsNotAString);
}
else if (key.Equals(SpecVersionAttributeName(this.SpecVersion)))
{
if (value is string)
{
return true;
}
throw new InvalidOperationException(Strings.ErrorSpecVersionValueIsNotAString);
}
else if (key.Equals(IdAttributeName(this.SpecVersion)))
{
if (value is string)
{
return true;
}
throw new InvalidOperationException(Strings.ErrorIdValueIsNotAString);
}
else if (key.Equals(TimeAttributeName(this.SpecVersion)))
{
if (value is null || value is DateTime)
{
return true;
}
if (value is string)
{
if (DateTime.TryParseExact((string)value, "o", CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal, out var dateTimeVal))
{
foreach (var extension in extensions)
value = dateTimeVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorTimeValueIsNotATimestamp);
}
else if (key.Equals(SourceAttributeName(this.SpecVersion)))
{
if (value is Uri)
{
return true;
}
if (value is string)
{
if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out var uriVal))
{
value = uriVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri);
}
else if (key.Equals(SchemaUrlAttributeName(this.SpecVersion)))
{
if (value is null || value is Uri)
{
return true;
}
if (value is string)
{
if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out var uriVal))
{
value = uriVal;
return true;
}
}
throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri);
}
else if (key.Equals(ContentTypeAttributeName(this.SpecVersion)))
{
if (value is null || value is ContentType)
{
return true;
}
if (value is string)
{
try
{
value = new ContentType((string)value);
return true;
}
catch (FormatException fe)
{
throw new InvalidOperationException(Strings.ErrorContentTypeIsNotRFC2046, fe);
}
}
throw new InvalidOperationException(Strings.ErrorContentTypeIsNotRFC2046);
}
else if (key.Equals(DataAttributeName(this.SpecVersion)))
{
return true;
}
else
{
if (extensions != null)
{
foreach (var extension in extensions)
{
if (extension.ValidateAndNormalize(key, ref value))
{
if (extension.ValidateAndNormalize(key, ref value))
{
return true;
}
return true;
}
}
break;
}
}
return false;

View File

@ -51,7 +51,7 @@ namespace CloudNative.CloudEvents
}
else
{
inner = new InnerByteArrayContent(formatter.EncodeAttribute(CloudEventAttributes.DataAttributeName,
inner = new InnerByteArrayContent(formatter.EncodeAttribute(cloudEvent.SpecVersion, CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion),
cloudEvent.Data, cloudEvent.Extensions.Values));
}
@ -79,29 +79,27 @@ namespace CloudNative.CloudEvents
{
foreach (var attribute in cloudEvent.GetAttributes())
{
switch (attribute.Key)
if (!(attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) ||
attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion))))
{
case CloudEventAttributes.DataAttributeName:
case CloudEventAttributes.ContentTypeAttributeName:
break;
default:
if (attribute.Value is string)
{
Headers.Add("ce-" + attribute.Key, attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
Headers.Add("ce-" + attribute.Key, ((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
Headers.Add("ce-" + attribute.Key, attribute.Value.ToString());
}
else
{
Headers.Add("ce-" + attribute.Key, Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(attribute.Key, attribute.Value, cloudEvent.Extensions.Values)));
}
break;
if (attribute.Value is string)
{
Headers.Add("ce-" + attribute.Key, attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
Headers.Add("ce-" + attribute.Key, ((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
Headers.Add("ce-" + attribute.Key, attribute.Value.ToString());
}
else
{
Headers.Add("ce-" + attribute.Key,
Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(cloudEvent.SpecVersion, attribute.Key, attribute.Value,
cloudEvent.Extensions.Values)));
}
}
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Cloud Native Foundation.
// Licensed under the Apache 2.0 license.
// See LICENSE file in the project root for full license information.
namespace CloudNative.CloudEvents
{
public enum CloudEventsSpecVersion
{
V0_1,
V0_2,
Default = V0_2
}
}

View File

@ -9,7 +9,6 @@ namespace CloudNative.CloudEvents
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
@ -17,8 +16,12 @@ namespace CloudNative.CloudEvents
public static class HttpClientExtension
{
const string HttpHeaderPrefix = "ce-";
const string SpecVersionHttpHeader = HttpHeaderPrefix + "specversion";
const string HttpHeaderPrefix = "ce-";
const string SpecVersionHttpHeader1 = HttpHeaderPrefix + "cloudEventsVersion";
const string SpecVersionHttpHeader2 = HttpHeaderPrefix + "specversion";
static JsonEventFormatter jsonFormatter = new JsonEventFormatter();
/// <summary>
@ -81,9 +84,10 @@ namespace CloudNative.CloudEvents
/// <returns>true, if the response is a CloudEvent</returns>
public static bool IsCloudEvent(this HttpResponseMessage httpResponseMessage)
{
return ((httpResponseMessage.Content.Headers.ContentType != null &&
httpResponseMessage.Content.Headers.ContentType.MediaType.StartsWith(CloudEvent.MediaType)) ||
httpResponseMessage.Headers.Contains(SpecVersionHttpHeader));
return (httpResponseMessage.Content.Headers.ContentType != null &&
httpResponseMessage.Content.Headers.ContentType.MediaType.StartsWith(CloudEvent.MediaType)) ||
httpResponseMessage.Headers.Contains(SpecVersionHttpHeader1) ||
httpResponseMessage.Headers.Contains(SpecVersionHttpHeader2);
}
/// <summary>
@ -91,9 +95,10 @@ namespace CloudNative.CloudEvents
/// </summary>
public static bool IsCloudEvent(this HttpListenerRequest httpListenerRequest)
{
return ((httpListenerRequest.Headers["content-type"] != null &&
httpListenerRequest.Headers["content-type"].StartsWith(CloudEvent.MediaType)) ||
httpListenerRequest.Headers.AllKeys.Contains(SpecVersionHttpHeader));
return (httpListenerRequest.Headers["content-type"] != null &&
httpListenerRequest.Headers["content-type"].StartsWith(CloudEvent.MediaType)) ||
httpListenerRequest.Headers[SpecVersionHttpHeader1] != null ||
httpListenerRequest.Headers[SpecVersionHttpHeader2] != null;
}
/// <summary>
@ -169,22 +174,43 @@ namespace CloudNative.CloudEvents
}
else
{
var cloudEvent = new CloudEvent(extensions);
var attributes = cloudEvent.GetAttributes();
foreach (var httpResponseHeader in httpListenerRequest.Headers.AllKeys)
CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
if (httpListenerRequest.Headers[SpecVersionHttpHeader1] != null)
{
if (httpResponseHeader.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase))
version = CloudEventsSpecVersion.V0_1;
}
if (httpListenerRequest.Headers[SpecVersionHttpHeader2] != null)
{
version = httpListenerRequest.Headers[SpecVersionHttpHeader2] == "0.2"
? CloudEventsSpecVersion.V0_2
: CloudEventsSpecVersion.Default;
}
var cloudEvent = new CloudEvent(version, extensions);
var attributes = cloudEvent.GetAttributes();
foreach (var httpRequestHeaders in httpListenerRequest.Headers.AllKeys)
{
if (httpRequestHeaders.Equals(SpecVersionHttpHeader1,
StringComparison.InvariantCultureIgnoreCase) ||
httpRequestHeaders.Equals(SpecVersionHttpHeader2, StringComparison.InvariantCultureIgnoreCase))
{
string headerValue = httpListenerRequest.Headers[httpResponseHeader];
continue;
}
if (httpRequestHeaders.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase))
{
string headerValue = httpListenerRequest.Headers[httpRequestHeaders];
if (headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
headerValue.StartsWith("[") && headerValue.EndsWith("]"))
{
attributes[httpResponseHeader.Substring(3).ToLowerInvariant()] =
attributes[httpRequestHeaders.Substring(3).ToLowerInvariant()] =
JsonConvert.DeserializeObject(headerValue);
}
else
{
attributes[httpResponseHeader.Substring(3).ToLowerInvariant()] = headerValue;
attributes[httpRequestHeaders.Substring(3).ToLowerInvariant()] = headerValue;
attributes[httpRequestHeaders.Substring(3).ToLowerInvariant()] = headerValue;
}
}
}
@ -201,35 +227,31 @@ namespace CloudNative.CloudEvents
{
foreach (var attribute in cloudEvent.GetAttributes())
{
switch (attribute.Key)
if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) &&
!attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion)))
{
case CloudEventAttributes.DataAttributeName:
case CloudEventAttributes.ContentTypeAttributeName:
break;
default:
if (attribute.Value is string)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
attribute.Value.ToString());
}
else
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(attribute.Key, attribute.Value,
cloudEvent.Extensions.Values)));
}
break;
if (attribute.Value is string)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
attribute.Value.ToString());
}
else
{
httpListenerResponse.Headers.Add(HttpHeaderPrefix + attribute.Key,
Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(cloudEvent.SpecVersion, attribute.Key,
attribute.Value,
cloudEvent.Extensions.Values)));
}
}
}
}
@ -238,33 +260,29 @@ namespace CloudNative.CloudEvents
{
foreach (var attribute in cloudEvent.GetAttributes())
{
switch (attribute.Key)
if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) &&
!attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion)))
{
case CloudEventAttributes.DataAttributeName:
case CloudEventAttributes.ContentTypeAttributeName:
break;
default:
if (attribute.Value is string)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key, attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key,
((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key, attribute.Value.ToString());
}
else
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key,
Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(attribute.Key, attribute.Value,
cloudEvent.Extensions.Values)));
}
break;
if (attribute.Value is string)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key, attribute.Value.ToString());
}
else if (attribute.Value is DateTime)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key,
((DateTime)attribute.Value).ToString("o"));
}
else if (attribute.Value is Uri || attribute.Value is int)
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key, attribute.Value.ToString());
}
else
{
httpWebRequest.Headers.Add(HttpHeaderPrefix + attribute.Key,
Encoding.UTF8.GetString(jsonFormatter.EncodeAttribute(cloudEvent.SpecVersion, attribute.Key,
attribute.Value,
cloudEvent.Extensions.Values)));
}
}
}
}
@ -286,7 +304,8 @@ namespace CloudNative.CloudEvents
}
else
{
stream = new MemoryStream(formatter.EncodeAttribute(CloudEventAttributes.DataAttributeName,
stream = new MemoryStream(formatter.EncodeAttribute(cloudEvent.SpecVersion,
CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion),
cloudEvent.Data, cloudEvent.Extensions.Values));
}
@ -315,29 +334,55 @@ namespace CloudNative.CloudEvents
}
}
return formatter.DecodeStructuredEvent(httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(),
return formatter.DecodeStructuredEvent(
httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(),
extensions);
}
else
{
var cloudEvent = new CloudEvent(extensions);
CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
if (httpResponseMessage.Headers.Contains(SpecVersionHttpHeader1))
{
version = CloudEventsSpecVersion.V0_1;
}
if (httpResponseMessage.Headers.Contains(SpecVersionHttpHeader2))
{
version = httpResponseMessage.Headers.GetValues(SpecVersionHttpHeader2).First() == "0.2"
? CloudEventsSpecVersion.V0_2
: CloudEventsSpecVersion.Default;
}
var cloudEvent = new CloudEvent(version, extensions);
var attributes = cloudEvent.GetAttributes();
foreach (var httpResponseHeader in httpResponseMessage.Headers)
{
if (httpResponseHeader.Key.Equals(SpecVersionHttpHeader1,
StringComparison.InvariantCultureIgnoreCase) ||
httpResponseHeader.Key.Equals(SpecVersionHttpHeader2,
StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
if (httpResponseHeader.Key.StartsWith(HttpHeaderPrefix,
StringComparison.InvariantCultureIgnoreCase))
{
string headerValue = httpResponseHeader.Value.First();
if (headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
var name = httpResponseHeader.Key.Substring(3).ToLowerInvariant();
if (headerValue.StartsWith("\"") && headerValue.EndsWith("\"") ||
headerValue.StartsWith("'") && headerValue.EndsWith("'") ||
headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
headerValue.StartsWith("[") && headerValue.EndsWith("]"))
{
attributes[httpResponseHeader.Key.Substring(3).ToLowerInvariant()] =
JsonConvert.DeserializeObject(headerValue);
attributes[name] = jsonFormatter.DecodeAttribute(version, name,
Encoding.UTF8.GetBytes(headerValue), extensions);
}
else
{
attributes[httpResponseHeader.Key.Substring(3).ToLowerInvariant()] = headerValue;
}
attributes[name] = headerValue;
}
}
}

View File

@ -35,6 +35,7 @@ namespace CloudNative.CloudEvents
/// <param name="contentType"></param>
/// <returns></returns>
byte[] EncodeStructuredEvent(CloudEvent cloudEvent, out ContentType contentType);
/// <summary>
/// Decode an attribute from a byte array
/// </summary>
@ -42,7 +43,7 @@ namespace CloudNative.CloudEvents
/// <param name="data"></param>
/// <param name="extensions"></param>
/// <returns></returns>
object DecodeAttribute(string name, byte[] data, IEnumerable<ICloudEventExtension> extensions);
object DecodeAttribute(CloudEventsSpecVersion specVersion, string name, byte[] data, IEnumerable<ICloudEventExtension> extensions);
/// <summary>
/// Encode an attribute into a byte array
/// </summary>
@ -50,6 +51,6 @@ namespace CloudNative.CloudEvents
/// <param name="value"></param>
/// <param name="extensions"></param>
/// <returns></returns>
byte[] EncodeAttribute(string name, object value, IEnumerable<ICloudEventExtension> extensions);
byte[] EncodeAttribute(CloudEventsSpecVersion specVersion, string name, object value, IEnumerable<ICloudEventExtension> extensions);
}
}

View File

@ -46,11 +46,30 @@ namespace CloudNative.CloudEvents
public CloudEvent DecodeJObject(JObject jObject, IEnumerable<ICloudEventExtension> extensions = null)
{
var cloudEvent = new CloudEvent(extensions);
CloudEventsSpecVersion specVersion = CloudEventsSpecVersion.Default;
if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1)))
{
specVersion = CloudEventsSpecVersion.V0_1;
}
if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)))
{
specVersion =
((string)jObject[CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)] ==
"0.2")
? CloudEventsSpecVersion.V0_2
: CloudEventsSpecVersion.Default;
}
var cloudEvent = new CloudEvent(specVersion, extensions);
var attributes = cloudEvent.GetAttributes();
attributes.Clear();
foreach (var keyValuePair in jObject)
{
if (keyValuePair.Key.Equals(
CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1)) ||
keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)))
{
continue;
}
switch (keyValuePair.Value.Type)
{
case JTokenType.String:
@ -101,23 +120,30 @@ namespace CloudNative.CloudEvents
return Encoding.UTF8.GetBytes(jObject.ToString());
}
public object DecodeAttribute(string name, byte[] data, IEnumerable<ICloudEventExtension> extensions = null)
public object DecodeAttribute(CloudEventsSpecVersion specVersion, string name, byte[] data, IEnumerable<ICloudEventExtension> extensions = null)
{
switch (name)
if (name.Equals(CloudEventAttributes.IdAttributeName(specVersion)) ||
name.Equals(CloudEventAttributes.TypeAttributeName(specVersion)))
{
case CloudEventAttributes.SpecVersionAttributeName:
case CloudEventAttributes.IdAttributeName:
case CloudEventAttributes.TypeAttributeName:
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string));
case CloudEventAttributes.TimeAttributeName:
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(DateTime));
case CloudEventAttributes.SourceAttributeName:
case CloudEventAttributes.SchemaUrlAttributeName:
var uri = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string;
return new Uri(uri);
case CloudEventAttributes.ContentTypeAttributeName:
var s = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string;
return new ContentType(s);
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string));
}
if (name.Equals(CloudEventAttributes.TimeAttributeName(specVersion)))
{
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(DateTime));
}
if (name.Equals(CloudEventAttributes.SourceAttributeName(specVersion)) ||
name.Equals(CloudEventAttributes.SchemaUrlAttributeName(specVersion)))
{
var uri = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string;
return new Uri(uri);
}
if (name.Equals(CloudEventAttributes.ContentTypeAttributeName(specVersion)))
{
var s = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string;
return new ContentType(s);
}
if (extensions != null)
@ -131,13 +157,12 @@ namespace CloudNative.CloudEvents
}
}
}
return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data));
}
public byte[] EncodeAttribute(string name, object value, IEnumerable<ICloudEventExtension> extensions = null)
public byte[] EncodeAttribute(CloudEventsSpecVersion specVersion, string name, object value, IEnumerable<ICloudEventExtension> extensions = null)
{
if (name.Equals(CloudEventAttributes.DataAttributeName))
if (name.Equals(CloudEventAttributes.DataAttributeName(specVersion)))
{
if (value is Stream)
{

View File

@ -41,7 +41,7 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.True(message1.IsCloudEvent());
var receivedCloudEvent = message1.ToCloudEvent();
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);
@ -84,7 +84,7 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.True(message1.IsCloudEvent());
var receivedCloudEvent = message1.ToCloudEvent();
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);

View File

@ -26,7 +26,7 @@ namespace CloudNative.CloudEvents.UnitTests
attrs["comexampleextension1"] = "value";
attrs["comexampleextension2"] = new { othervalue = 5 };
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -57,7 +57,7 @@ namespace CloudNative.CloudEvents.UnitTests
attrs["comexampleextension1"] = "value";
attrs["comexampleextension2"] = new { othervalue = 5 };
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -71,6 +71,71 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue);
}
[Fact]
public void CreateV0_1()
{
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V0_1, "com.github.pull.create",
new Uri("https://github.com/cloudevents/spec/pull/123"))
{
Id = "A234-1234-1234",
Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc),
ContentType = new ContentType(MediaTypeNames.Text.Xml),
Data = "<much wow=\"xml\"/>"
};
var attrs = cloudEvent.GetAttributes();
attrs["comexampleextension1"] = "value";
attrs["comexampleextension2"] = new { othervalue = 5 };
Assert.Equal(CloudEventsSpecVersion.V0_1, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(),
cloudEvent.Time.Value.ToUniversalTime());
Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.ContentType);
Assert.Equal("<much wow=\"xml\"/>", cloudEvent.Data);
var attr = cloudEvent.GetAttributes();
Assert.Equal("value", (string)attr["comexampleextension1"]);
Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue);
}
[Fact]
public void CreateV0_1ConvertToV0_2()
{
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V0_1, "com.github.pull.create",
new Uri("https://github.com/cloudevents/spec/pull/123"))
{
Id = "A234-1234-1234",
Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc),
ContentType = new ContentType(MediaTypeNames.Text.Xml),
Data = "<much wow=\"xml\"/>"
};
var attrs = cloudEvent.GetAttributes();
attrs["comexampleextension1"] = "value";
attrs["comexampleextension2"] = new { othervalue = 5 };
cloudEvent.SpecVersion = CloudEventsSpecVersion.V0_2;
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(),
cloudEvent.Time.Value.ToUniversalTime());
Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.ContentType);
Assert.Equal("<much wow=\"xml\"/>", cloudEvent.Data);
var attr = cloudEvent.GetAttributes();
Assert.Equal("value", (string)attr["comexampleextension1"]);
Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue);
}
[Fact]
public void CreateEventWithExtensions()
{
@ -95,7 +160,7 @@ namespace CloudNative.CloudEvents.UnitTests
Data = "<much wow=\"xml\"/>"
};
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);

View File

@ -55,7 +55,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonDistTrace), new DistributedTracingExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -74,7 +74,7 @@ namespace CloudNative.CloudEvents.UnitTests
var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent1, out var contentType);
var cloudEvent = jsonFormatter.DecodeStructuredEvent(jsonData, new DistributedTracingExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -90,7 +90,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonSequence), new SequenceExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -109,7 +109,7 @@ namespace CloudNative.CloudEvents.UnitTests
var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent1, out var contentType);
var cloudEvent = jsonFormatter.DecodeStructuredEvent(jsonData, new SequenceExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -125,7 +125,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonSequence), new IntegerSequenceExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -143,7 +143,7 @@ namespace CloudNative.CloudEvents.UnitTests
var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent1, out var contentType);
var cloudEvent = jsonFormatter.DecodeStructuredEvent(jsonData, new IntegerSequenceExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -158,7 +158,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonSampledRate), new SamplingExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -176,7 +176,7 @@ namespace CloudNative.CloudEvents.UnitTests
var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent1, out var contentType);
var cloudEvent = jsonFormatter.DecodeStructuredEvent(jsonData, new SamplingExtension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);

View File

@ -107,7 +107,7 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
var receivedCloudEvent = result.ToCloudEvent();
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);
@ -152,7 +152,7 @@ namespace CloudNative.CloudEvents.UnitTests
var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter());
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);
@ -234,7 +234,7 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.True(result.IsCloudEvent());
var receivedCloudEvent = result.ToCloudEvent();
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);
@ -274,7 +274,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter());
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);
@ -336,7 +336,7 @@ namespace CloudNative.CloudEvents.UnitTests
{
var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter());
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);

View File

@ -43,12 +43,30 @@ namespace CloudNative.CloudEvents.UnitTests
Assert.Equal(cloudEvent2.Data, cloudEvent.Data);
}
[Fact]
public void ReserializeTestV0_2toV0_1()
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json));
cloudEvent.SpecVersion = CloudEventsSpecVersion.V0_1;
var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent, out var contentType);
var cloudEvent2 = jsonFormatter.DecodeStructuredEvent(jsonData);
Assert.Equal(cloudEvent2.SpecVersion, cloudEvent.SpecVersion);
Assert.Equal(cloudEvent2.Type, cloudEvent.Type);
Assert.Equal(cloudEvent2.Source, cloudEvent.Source);
Assert.Equal(cloudEvent2.Id, cloudEvent.Id);
Assert.Equal(cloudEvent2.Time.Value.ToUniversalTime(), cloudEvent.Time.Value.ToUniversalTime());
Assert.Equal(cloudEvent2.ContentType, cloudEvent.ContentType);
Assert.Equal(cloudEvent2.Data, cloudEvent.Data);
}
[Fact]
public void StructuredParseSuccess()
{
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json));
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);
@ -68,7 +86,7 @@ namespace CloudNative.CloudEvents.UnitTests
var jsonFormatter = new JsonEventFormatter();
var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json), new ComExampleExtension1Extension(),
new ComExampleExtension2Extension());
Assert.Equal("0.2", cloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", cloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), cloudEvent.Source);
Assert.Equal("A234-1234-1234", cloudEvent.Id);

View File

@ -74,7 +74,7 @@ namespace CloudNative.CloudEvents.UnitTests
await client.PublishAsync(new MqttCloudEventMessage(cloudEvent, new JsonEventFormatter()) { Topic = "abc" });
var receivedCloudEvent = await tcs.Task;
Assert.Equal("0.2", receivedCloudEvent.SpecVersion);
Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion);
Assert.Equal("com.github.pull.create", receivedCloudEvent.Type);
Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull/123"), receivedCloudEvent.Source);
Assert.Equal("A234-1234-1234", receivedCloudEvent.Id);