From a940228cc5e0ca61a1166f4d729af6dd803cb61b Mon Sep 17 00:00:00 2001 From: clemensv Date: Tue, 17 Sep 2019 12:48:40 +0200 Subject: [PATCH] Updated to support 1.0-rc Signed-off-by: clemensv --- appveyor.yml | 2 +- samples/HttpSend/Program.cs | 2 +- .../AmqpClientExtensions.cs | 4 +- .../AmqpCloudEventMessage.cs | 4 +- src/CloudNative.CloudEvents/CloudEvent.cs | 28 +++-- .../CloudEventAttributes.cs | 67 ++++++++--- .../CloudEventContent.cs | 4 +- .../CloudEventsSpecVersion.cs | 3 +- .../HttpClientExtension.cs | 35 +++--- .../JsonEventFormatter.cs | 46 +++++++- .../Strings.Designer.cs | 9 ++ src/CloudNative.CloudEvents/Strings.resx | 3 + .../AmqpTest.cs | 21 ++-- .../ConstructorTest.cs | 65 +++++++---- .../ExtensionsTest.cs | 22 ++-- .../HttpTest.cs | 50 ++++----- .../JsonTest.cs | 106 ++++++++++++++++-- .../MqttTests.cs | 8 +- 18 files changed, 332 insertions(+), 147 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2b624da..4932f95 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ # main branch -version: 0.1.{build} +version: 0.9.{build} clone_depth: 15 branches: diff --git a/samples/HttpSend/Program.cs b/samples/HttpSend/Program.cs index 904c494..59d56f4 100644 --- a/samples/HttpSend/Program.cs +++ b/samples/HttpSend/Program.cs @@ -32,7 +32,7 @@ namespace HttpSend { var cloudEvent = new CloudEvent(this.Type, new Uri(this.Source)) { - ContentType = new ContentType(MediaTypeNames.Application.Json), + DataContentType = new ContentType(MediaTypeNames.Application.Json), Data = JsonConvert.SerializeObject("hey there!") }; diff --git a/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs b/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs index 3b60275..6f80484 100644 --- a/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs +++ b/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs @@ -77,7 +77,7 @@ namespace CloudNative.CloudEvents.Amqp if (prop.Key is string && ((string)prop.Key).StartsWith(AmqpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase)) { - if (prop.Value is Map) + if (cloudEvent.SpecVersion != CloudEventsSpecVersion.V1_0 && prop.Value is Map) { IDictionary exp = new ExpandoObject(); foreach (var props in (Map)prop.Value) @@ -96,7 +96,7 @@ namespace CloudNative.CloudEvents.Amqp } } - cloudEvent.ContentType = message.Properties.ContentType != null + cloudEvent.DataContentType = message.Properties.ContentType != null ? new ContentType(message.Properties.ContentType) : null; cloudEvent.Data = message.Body; diff --git a/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs b/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs index 0d71070..4aa5080 100644 --- a/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs +++ b/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs @@ -47,7 +47,7 @@ namespace CloudNative.CloudEvents.Amqp this.BodySection = new AmqpValue() { Value = cloudEvent.Data }; } - this.Properties = new Properties() { ContentType = cloudEvent.ContentType?.MediaType }; + this.Properties = new Properties() { ContentType = cloudEvent.DataContentType?.MediaType }; this.ApplicationProperties = new ApplicationProperties(); MapHeaders(cloudEvent); } @@ -57,7 +57,7 @@ namespace CloudNative.CloudEvents.Amqp foreach (var attribute in cloudEvent.GetAttributes()) { if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) && - !attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion))) + !attribute.Key.Equals(CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion))) { if (attribute.Value is Uri) { diff --git a/src/CloudNative.CloudEvents/CloudEvent.cs b/src/CloudNative.CloudEvents/CloudEvent.cs index b010e54..77f2bad 100644 --- a/src/CloudNative.CloudEvents/CloudEvent.cs +++ b/src/CloudNative.CloudEvents/CloudEvent.cs @@ -26,7 +26,7 @@ namespace CloudNative.CloudEvents /// 'time' of the CloudEvent /// Extensions to be added to this CloudEvents public CloudEvent(string type, Uri source, string id = null, DateTime? time = null, - params ICloudEventExtension[] extensions) : this(CloudEventsSpecVersion.V0_2, type, source, id, time, extensions) + params ICloudEventExtension[] extensions) : this(CloudEventsSpecVersion.Default, type, source, id, time, extensions) { } @@ -73,10 +73,10 @@ namespace CloudNative.CloudEvents /// format and encoding might differ from that of the chosen event format. /// /// - public ContentType ContentType + public ContentType DataContentType { - get => attributes[CloudEventAttributes.ContentTypeAttributeName(attributes.SpecVersion)] as ContentType; - set => attributes[CloudEventAttributes.ContentTypeAttributeName(attributes.SpecVersion)] = value; + get => attributes[CloudEventAttributes.DataContentTypeAttributeName(attributes.SpecVersion)] as ContentType; + set => attributes[CloudEventAttributes.DataContentTypeAttributeName(attributes.SpecVersion)] = value; } /// @@ -113,10 +113,10 @@ namespace CloudNative.CloudEvents /// different URL. /// /// - public Uri SchemaUrl + public Uri DataSchema { - get => attributes[CloudEventAttributes.SchemaUrlAttributeName(attributes.SpecVersion)] as Uri; - set => attributes[CloudEventAttributes.SchemaUrlAttributeName(attributes.SpecVersion)] = value; + get => attributes[CloudEventAttributes.DataSchemaAttributeName(attributes.SpecVersion)] as Uri; + set => attributes[CloudEventAttributes.DataSchemaAttributeName(attributes.SpecVersion)] = value; } /// @@ -143,6 +143,20 @@ namespace CloudNative.CloudEvents set => attributes.SpecVersion = value; } + /// + /// CloudEvents 'subject' attribute. This describes the subject of the event in the context + /// of the event producer (identified by source). In publish-subscribe scenarios, a subscriber + /// will typically subscribe to events emitted by a source, but the source identifier alone + /// might not be sufficient as a qualifier for any specific event if the source context has + /// internal sub-structure. + /// + /// + public string Subject + { + get => attributes[CloudEventAttributes.SubjectAttributeName(attributes.SpecVersion)] as string; + set => attributes[CloudEventAttributes.SubjectAttributeName(attributes.SpecVersion)] = value; + } + /// /// CloudEvents 'time' attribute. Timestamp of when the event happened. /// diff --git a/src/CloudNative.CloudEvents/CloudEventAttributes.cs b/src/CloudNative.CloudEvents/CloudEventAttributes.cs index 5e4584c..f6959bd 100644 --- a/src/CloudNative.CloudEvents/CloudEventAttributes.cs +++ b/src/CloudNative.CloudEvents/CloudEventAttributes.cs @@ -26,7 +26,8 @@ namespace CloudNative.CloudEvents { this.extensions = extensions; this.specVersion = specVersion; - dict[SpecVersionAttributeName(specVersion)] = specVersion == CloudEventsSpecVersion.V0_1 ? "0.1" : "0.2"; + dict[SpecVersionAttributeName(specVersion)] = (specVersion == CloudEventsSpecVersion.V0_1 ? "0.1" : + (specVersion == CloudEventsSpecVersion.V0_2 ? "0.2" : "1.0")); } int ICollection>.Count => dict.Count; @@ -43,15 +44,22 @@ namespace CloudNative.CloudEvents { object val; if (dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), out val) || - dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), out val)) + dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), out val) || + dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V1_0), out val)) { - return (val as string) == "0.1" ? CloudEventsSpecVersion.V0_1 : CloudEventsSpecVersion.V0_2; + return (val as string) == "0.1" ? CloudEventsSpecVersion.V0_1 : + (val as string) == "0.2" ? CloudEventsSpecVersion.V0_2 : CloudEventsSpecVersion.V1_0; + } return CloudEventsSpecVersion.Default; } set { + // this setter sets the version and initiates a transform to the new target version if + // required. The transformation may fail under some circumstances where CloudEvents + // versions are in mutual conflict + var currentSpecVersion = SpecVersion; object val; if (dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), out val)) @@ -61,28 +69,33 @@ namespace CloudNative.CloudEvents return; } } - else if ( dict.TryGetValue(SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), out val)) + else if ( dict.TryGetValue(SpecVersionAttributeName(), out val)) // 0.2 and 1.0 are the same { if (value == CloudEventsSpecVersion.V0_2 && (val as string) == "0.2") { return; } - } + if (value == CloudEventsSpecVersion.V1_0 && (val as string) == "1.0") + { + return; + } + } // transform to new version var copy = new Dictionary(dict); dict.Clear(); - this[SpecVersionAttributeName(value)] = value == CloudEventsSpecVersion.V0_1 ? "0.1" : "0.2"; + this[SpecVersionAttributeName(value)] = value == CloudEventsSpecVersion.V0_1 ? "0.1" : (value == CloudEventsSpecVersion.V0_2 ? "0.2" : "1.0"); foreach (var kv in copy) { if (SpecVersionAttributeName(CloudEventsSpecVersion.V0_2).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase) || - SpecVersionAttributeName(CloudEventsSpecVersion.V0_1).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) + SpecVersionAttributeName(CloudEventsSpecVersion.V0_1).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase) || + SpecVersionAttributeName(CloudEventsSpecVersion.V1_0).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { continue; } - if (ContentTypeAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) + if (DataContentTypeAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { - this[ContentTypeAttributeName(value)] = kv.Value; + this[DataContentTypeAttributeName(value)] = kv.Value; } else if (DataAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { @@ -92,14 +105,18 @@ namespace CloudNative.CloudEvents { this[IdAttributeName(value)] = kv.Value; } - else if (SchemaUrlAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) + else if (DataSchemaAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { - this[SchemaUrlAttributeName(value)] = kv.Value; + this[DataSchemaAttributeName(value)] = kv.Value; } else if (SourceAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { this[SourceAttributeName(value)] = kv.Value; } + else if (SubjectAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) + { + this[SubjectAttributeName(value)] = kv.Value; + } else if (TimeAttributeName(currentSpecVersion).Equals(kv.Key, StringComparison.InvariantCultureIgnoreCase)) { this[TimeAttributeName(value)] = kv.Value; @@ -133,9 +150,10 @@ namespace CloudNative.CloudEvents } } - public static string ContentTypeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) + public static string DataContentTypeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) { - return version == CloudEventsSpecVersion.V0_1 ? "contentType" : "contenttype"; + return version == CloudEventsSpecVersion.V0_1 ? "contentType" : + (version == CloudEventsSpecVersion.V0_2 ? "contenttype" : "datacontenttype"); } public static string DataAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) @@ -148,9 +166,10 @@ namespace CloudNative.CloudEvents return version == CloudEventsSpecVersion.V0_1 ? "eventID" : "id"; } - public static string SchemaUrlAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) + public static string DataSchemaAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) { - return version == CloudEventsSpecVersion.V0_1 ? "schemaUrl" : "schemaurl"; + return version == CloudEventsSpecVersion.V0_1 ? "schemaUrl" : + (version == CloudEventsSpecVersion.V0_2 ? "schemaurl" : "dataschema"); } public static string SourceAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) @@ -163,6 +182,11 @@ namespace CloudNative.CloudEvents return version == CloudEventsSpecVersion.V0_1 ? "cloudEventsVersion" : "specversion"; } + public static string SubjectAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) + { + return "subject"; + } + public static string TimeAttributeName(CloudEventsSpecVersion version = CloudEventsSpecVersion.Default) { return version == CloudEventsSpecVersion.V0_1 ? "eventTime" : "time"; @@ -297,7 +321,16 @@ namespace CloudNative.CloudEvents throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri); } - else if (key.Equals(SchemaUrlAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) + else if (key.Equals(SubjectAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) + { + if (value is string) + { + return true; + } + + throw new InvalidOperationException(Strings.ErrorSubjectValueIsNotAString); + } + else if (key.Equals(DataSchemaAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { if (value is null || value is Uri) { @@ -315,7 +348,7 @@ namespace CloudNative.CloudEvents throw new InvalidOperationException(Strings.ErrorSchemaUrlIsNotAUri); } - else if (key.Equals(ContentTypeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) + else if (key.Equals(DataContentTypeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { if (value is null || value is ContentType) { diff --git a/src/CloudNative.CloudEvents/CloudEventContent.cs b/src/CloudNative.CloudEvents/CloudEventContent.cs index 3683885..bc5061f 100644 --- a/src/CloudNative.CloudEvents/CloudEventContent.cs +++ b/src/CloudNative.CloudEvents/CloudEventContent.cs @@ -55,7 +55,7 @@ namespace CloudNative.CloudEvents cloudEvent.Data, cloudEvent.Extensions.Values)); } - Headers.ContentType = new MediaTypeHeaderValue(cloudEvent.ContentType?.MediaType); + Headers.ContentType = new MediaTypeHeaderValue(cloudEvent.DataContentType?.MediaType); MapHeaders(cloudEvent); } @@ -80,7 +80,7 @@ namespace CloudNative.CloudEvents foreach (var attribute in cloudEvent.GetAttributes()) { if (!(attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) || - attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion)))) + attribute.Key.Equals(CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion)))) { if (attribute.Value is string) { diff --git a/src/CloudNative.CloudEvents/CloudEventsSpecVersion.cs b/src/CloudNative.CloudEvents/CloudEventsSpecVersion.cs index 26cc189..c37a108 100644 --- a/src/CloudNative.CloudEvents/CloudEventsSpecVersion.cs +++ b/src/CloudNative.CloudEvents/CloudEventsSpecVersion.cs @@ -8,6 +8,7 @@ namespace CloudNative.CloudEvents { V0_1, V0_2, - Default = V0_2 + V1_0, + Default = V1_0 } } \ No newline at end of file diff --git a/src/CloudNative.CloudEvents/HttpClientExtension.cs b/src/CloudNative.CloudEvents/HttpClientExtension.cs index cb17c76..3023872 100644 --- a/src/CloudNative.CloudEvents/HttpClientExtension.cs +++ b/src/CloudNative.CloudEvents/HttpClientExtension.cs @@ -45,7 +45,7 @@ namespace CloudNative.CloudEvents } Stream stream = MapDataAttributeToStream(cloudEvent, formatter); - httpListenerResponse.ContentType = cloudEvent.ContentType.ToString(); + httpListenerResponse.ContentType = cloudEvent.DataContentType.ToString(); MapAttributesToListenerResponse(cloudEvent, httpListenerResponse); return stream.CopyToAsync(httpListenerResponse.OutputStream); } @@ -72,7 +72,7 @@ namespace CloudNative.CloudEvents } Stream stream = MapDataAttributeToStream(cloudEvent, formatter); - httpWebRequest.ContentType = cloudEvent.ContentType.ToString(); + httpWebRequest.ContentType = cloudEvent.DataContentType.ToString(); MapAttributesToWebRequest(cloudEvent, httpWebRequest); await stream.CopyToAsync(httpWebRequest.GetRequestStream()); } @@ -340,8 +340,10 @@ namespace CloudNative.CloudEvents if (httpRequestHeaders.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase)) { string headerValue = httpListenerRequest.Headers[httpRequestHeaders]; - if (headerValue.StartsWith("{") && headerValue.EndsWith("}") || - headerValue.StartsWith("[") && headerValue.EndsWith("]")) + // maps in headers have been abolished in 1.0 + if (version != CloudEventsSpecVersion.V1_0 && + (headerValue.StartsWith("{") && headerValue.EndsWith("}") || + headerValue.StartsWith("[") && headerValue.EndsWith("]"))) { attributes[httpRequestHeaders.Substring(3)] = JsonConvert.DeserializeObject(headerValue); @@ -349,12 +351,11 @@ namespace CloudNative.CloudEvents else { attributes[httpRequestHeaders.Substring(3)] = headerValue; - attributes[httpRequestHeaders.Substring(3)] = headerValue; } } } - cloudEvent.ContentType = httpListenerRequest.ContentType != null + cloudEvent.DataContentType = httpListenerRequest.ContentType != null ? new ContentType(httpListenerRequest.ContentType) : null; cloudEvent.Data = httpListenerRequest.InputStream; @@ -429,21 +430,22 @@ namespace CloudNative.CloudEvents StringComparison.InvariantCultureIgnoreCase)) { string headerValue = httpListenerRequest.Headers.GetValues(httpRequestHeaders.Key).First(); - if (headerValue.StartsWith("{") && headerValue.EndsWith("}") || - headerValue.StartsWith("[") && headerValue.EndsWith("]")) + // maps in headers have been abolished in version 1.0 + if (version != CloudEventsSpecVersion.V1_0 && + (headerValue.StartsWith("{") && headerValue.EndsWith("}") || + headerValue.StartsWith("[") && headerValue.EndsWith("]"))) { attributes[httpRequestHeaders.Key.Substring(3)] = JsonConvert.DeserializeObject(headerValue); } else { - attributes[httpRequestHeaders.Key.Substring(3)] = headerValue; - attributes[httpRequestHeaders.Key.Substring(3)] = headerValue; + attributes[httpRequestHeaders.Key.Substring(3)] = headerValue; } } } - cloudEvent.ContentType = httpListenerRequest.Content?.Headers.ContentType != null + cloudEvent.DataContentType = httpListenerRequest.Content?.Headers.ContentType != null ? new ContentType(httpListenerRequest.Content.Headers.ContentType.MediaType) : null; cloudEvent.Data = httpListenerRequest.Content?.ReadAsStreamAsync().GetAwaiter().GetResult(); @@ -456,7 +458,7 @@ namespace CloudNative.CloudEvents foreach (var attribute in cloudEvent.GetAttributes()) { if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) && - !attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion))) + !attribute.Key.Equals(CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion))) { if (attribute.Value is string) { @@ -489,7 +491,7 @@ namespace CloudNative.CloudEvents foreach (var attribute in cloudEvent.GetAttributes()) { if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) && - !attribute.Key.Equals(CloudEventAttributes.ContentTypeAttributeName(cloudEvent.SpecVersion))) + !attribute.Key.Equals(CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion))) { if (attribute.Value is string) { @@ -599,10 +601,11 @@ namespace CloudNative.CloudEvents string headerValue = httpResponseHeader.Value.First(); var name = httpResponseHeader.Key.Substring(3); - if (headerValue.StartsWith("\"") && headerValue.EndsWith("\"") || + // abolished structures in headers in 1.0 + if (version != CloudEventsSpecVersion.V1_0 && (headerValue.StartsWith("\"") && headerValue.EndsWith("\"") || headerValue.StartsWith("'") && headerValue.EndsWith("'") || headerValue.StartsWith("{") && headerValue.EndsWith("}") || - headerValue.StartsWith("[") && headerValue.EndsWith("]")) + headerValue.StartsWith("[") && headerValue.EndsWith("]"))) { attributes[name] = jsonFormatter.DecodeAttribute(version, name, Encoding.UTF8.GetBytes(headerValue), extensions); @@ -614,7 +617,7 @@ namespace CloudNative.CloudEvents } } - cloudEvent.ContentType = httpResponseMessage.Content?.Headers.ContentType != null + cloudEvent.DataContentType = httpResponseMessage.Content?.Headers.ContentType != null ? new ContentType(httpResponseMessage.Content.Headers.ContentType.ToString()) : null; cloudEvent.Data = httpResponseMessage.Content?.ReadAsStreamAsync().GetAwaiter().GetResult(); diff --git a/src/CloudNative.CloudEvents/JsonEventFormatter.cs b/src/CloudNative.CloudEvents/JsonEventFormatter.cs index 0777c66..f305d3e 100644 --- a/src/CloudNative.CloudEvents/JsonEventFormatter.cs +++ b/src/CloudNative.CloudEvents/JsonEventFormatter.cs @@ -5,8 +5,10 @@ namespace CloudNative.CloudEvents { using System; + using System.Collections; using System.Collections.Generic; using System.IO; + using System.Linq; using System.Net.Mime; using System.Text; using Newtonsoft.Json; @@ -65,13 +67,24 @@ namespace CloudNative.CloudEvents var attributes = cloudEvent.GetAttributes(); foreach (var keyValuePair in jObject) { - if (keyValuePair.Key.Equals( - CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), StringComparison.InvariantCultureIgnoreCase) || - keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), StringComparison.InvariantCultureIgnoreCase)) + // skip the version since we set that above + if (keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), StringComparison.InvariantCultureIgnoreCase) || + keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), StringComparison.InvariantCultureIgnoreCase) || + keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V1_0), StringComparison.InvariantCultureIgnoreCase)) { continue; } + if (specVersion == CloudEventsSpecVersion.V1_0) + { + // handle base64 encoded binaries + if (keyValuePair.Key.Equals("data_base64")) + { + attributes["data"] = Convert.FromBase64String(keyValuePair.Value.ToString()); + continue; + } + } + switch (keyValuePair.Value.Type) { case JTokenType.String: @@ -113,6 +126,26 @@ namespace CloudNative.CloudEvents { jObject[keyValuePair.Key] = JToken.FromObject(((ContentType)keyValuePair.Value).ToString()); } + else if (cloudEvent.SpecVersion == CloudEventsSpecVersion.V1_0 && + keyValuePair.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion))) + { + if (keyValuePair.Value is Stream) + { + using (var sr = new BinaryReader((Stream)keyValuePair.Value)) + { + jObject["data_base64"] = Convert.ToBase64String(sr.ReadBytes((int)sr.BaseStream.Length)); + } + } + else if (keyValuePair.Value is IEnumerable) + { + jObject["data_base64"] = + Convert.ToBase64String(((IEnumerable)keyValuePair.Value).ToArray()); + } + else + { + jObject["data"] = JToken.FromObject(keyValuePair.Value); + } + } else { jObject[keyValuePair.Key] = JToken.FromObject(keyValuePair.Value); @@ -125,7 +158,8 @@ namespace CloudNative.CloudEvents public object DecodeAttribute(CloudEventsSpecVersion specVersion, string name, byte[] data, IEnumerable extensions = null) { if (name.Equals(CloudEventAttributes.IdAttributeName(specVersion)) || - name.Equals(CloudEventAttributes.TypeAttributeName(specVersion))) + name.Equals(CloudEventAttributes.TypeAttributeName(specVersion)) || + name.Equals(CloudEventAttributes.SubjectAttributeName(specVersion))) { return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)); } @@ -136,13 +170,13 @@ namespace CloudNative.CloudEvents } if (name.Equals(CloudEventAttributes.SourceAttributeName(specVersion)) || - name.Equals(CloudEventAttributes.SchemaUrlAttributeName(specVersion))) + name.Equals(CloudEventAttributes.DataSchemaAttributeName(specVersion))) { var uri = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string; return new Uri(uri); } - if (name.Equals(CloudEventAttributes.ContentTypeAttributeName(specVersion))) + if (name.Equals(CloudEventAttributes.DataContentTypeAttributeName(specVersion))) { var s = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(string)) as string; return new ContentType(s); diff --git a/src/CloudNative.CloudEvents/Strings.Designer.cs b/src/CloudNative.CloudEvents/Strings.Designer.cs index 5e9976c..ccd5bda 100644 --- a/src/CloudNative.CloudEvents/Strings.Designer.cs +++ b/src/CloudNative.CloudEvents/Strings.Designer.cs @@ -132,6 +132,15 @@ namespace CloudNative.CloudEvents { } } + /// + /// Looks up a localized string similar to The 'subject' attribute value must be a string. + /// + internal static string ErrorSubjectValueIsNotAString { + get { + return ResourceManager.GetString("ErrorSubjectValueIsNotAString", resourceCulture); + } + } + /// /// Looks up a localized string similar to The 'time' attribute value must be a valid ISO8601 timestamp expression. /// diff --git a/src/CloudNative.CloudEvents/Strings.resx b/src/CloudNative.CloudEvents/Strings.resx index 7b4f758..5498596 100644 --- a/src/CloudNative.CloudEvents/Strings.resx +++ b/src/CloudNative.CloudEvents/Strings.resx @@ -141,6 +141,9 @@ The 'specversion' attribute value must be a string + + The 'subject' attribute value must be a string + The 'time' attribute value must be a valid ISO8601 timestamp expression diff --git a/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs b/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs index 52a1980..3edca1b 100644 --- a/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs @@ -25,14 +25,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + var message = new AmqpCloudEventMessage(cloudEvent, ContentMode.Structured, new JsonEventFormatter()); Assert.True(message.IsCloudEvent()); var encodedAmqpMessage = message.Encode(); @@ -41,18 +40,17 @@ namespace CloudNative.CloudEvents.UnitTests Assert.True(message1.IsCloudEvent()); var receivedCloudEvent = message1.ToCloudEvent(); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); } [Fact] @@ -68,14 +66,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + var message = new AmqpCloudEventMessage(cloudEvent, ContentMode.Binary, new JsonEventFormatter()); Assert.True(message.IsCloudEvent()); var encodedAmqpMessage = message.Encode(); @@ -84,18 +81,18 @@ namespace CloudNative.CloudEvents.UnitTests Assert.True(message1.IsCloudEvent()); var receivedCloudEvent = message1.ToCloudEvent(); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); + } } } \ No newline at end of file diff --git a/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs b/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs index 492ae13..f1c6688 100644 --- a/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs @@ -18,7 +18,7 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -26,13 +26,13 @@ namespace CloudNative.CloudEvents.UnitTests attrs["comexampleextension1"] = "value"; attrs["comexampleextension2"] = new { othervalue = 5 }; - Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); var attr = cloudEvent.GetAttributes(); @@ -49,7 +49,7 @@ namespace CloudNative.CloudEvents.UnitTests "A234-1234-1234", new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc)) { - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -57,13 +57,13 @@ namespace CloudNative.CloudEvents.UnitTests attrs["comexampleextension1"] = "value"; attrs["comexampleextension2"] = new { othervalue = 5 }; - Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); var attr = cloudEvent.GetAttributes(); @@ -80,7 +80,7 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -94,7 +94,7 @@ namespace CloudNative.CloudEvents.UnitTests 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); var attr = cloudEvent.GetAttributes(); @@ -110,7 +110,7 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -126,7 +126,7 @@ namespace CloudNative.CloudEvents.UnitTests 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); var attr = cloudEvent.GetAttributes(); @@ -135,6 +135,35 @@ namespace CloudNative.CloudEvents.UnitTests } + [Fact] + public void CreateV0_2ConvertToV1_0() + { + var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V0_2, "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), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), + Data = "" + }; + + var attrs = cloudEvent.GetAttributes(); + attrs["comexampleextension1"] = "value"; + + cloudEvent.SpecVersion = CloudEventsSpecVersion.V1_0; + + Assert.Equal(CloudEventsSpecVersion.V1_0, 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.DataContentType); + Assert.Equal("", cloudEvent.Data); + + var attr = cloudEvent.GetAttributes(); + Assert.Equal("value", (string)attr["comexampleextension1"]); + } [Fact] public void CreateEventWithExtensions() @@ -147,30 +176,22 @@ namespace CloudNative.CloudEvents.UnitTests new ComExampleExtension1Extension() { ComExampleExtension1 = "value" - }, - new ComExampleExtension2Extension() - { - ComExampleExtension2 = new ComExampleExtension2Data() - { - OtherValue = 5 - } }) { - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; - Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); Assert.Equal("value", cloudEvent.Extension().ComExampleExtension1); - Assert.Equal(5, cloudEvent.Extension().ComExampleExtension2.OtherValue); - } + } } } \ No newline at end of file diff --git a/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs b/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs index 1111c07..1d8c824 100644 --- a/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs @@ -14,7 +14,7 @@ namespace CloudNative.CloudEvents.UnitTests { const string jsonDistTrace = "{\n" + - " \"specversion\" : \"0.2\",\n" + + " \"specversion\" : \"1.0\",\n" + " \"type\" : \"com.github.pull.create\",\n" + " \"source\" : \"https://github.com/cloudevents/spec/pull/123\",\n" + " \"id\" : \"A234-1234-1234\",\n" + @@ -27,7 +27,7 @@ namespace CloudNative.CloudEvents.UnitTests const string jsonSequence = "{\n" + - " \"specversion\" : \"0.2\",\n" + + " \"specversion\" : \"1.0\",\n" + " \"type\" : \"com.github.pull.create\",\n" + " \"source\" : \"https://github.com/cloudevents/spec/pull/123\",\n" + " \"id\" : \"A234-1234-1234\",\n" + @@ -40,7 +40,7 @@ namespace CloudNative.CloudEvents.UnitTests const string jsonSampledRate = "{\n" + - " \"specversion\" : \"0.2\",\n" + + " \"specversion\" : \"1.0\",\n" + " \"type\" : \"com.github.pull.create\",\n" + " \"source\" : \"https://github.com/cloudevents/spec/pull/123\",\n" + " \"id\" : \"A234-1234-1234\",\n" + @@ -55,7 +55,7 @@ namespace CloudNative.CloudEvents.UnitTests { var jsonFormatter = new JsonEventFormatter(); var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonDistTrace), new DistributedTracingExtension()); - Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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); diff --git a/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs b/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs index d20cde6..e0f7e2b 100644 --- a/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs @@ -97,14 +97,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + await context.Response.CopyFromAsync(cloudEvent, ContentMode.Binary, new JsonEventFormatter()); context.Response.StatusCode = (int)HttpStatusCode.OK; } @@ -127,13 +126,13 @@ namespace CloudNative.CloudEvents.UnitTests Assert.Equal(HttpStatusCode.OK, result.StatusCode); var receivedCloudEvent = result.ToCloudEvent(); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); using (var sr = new StreamReader((Stream)receivedCloudEvent.Data)) { Assert.Equal("", sr.ReadToEnd()); @@ -141,7 +140,6 @@ namespace CloudNative.CloudEvents.UnitTests var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); } [Fact] @@ -152,14 +150,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + string ctx = Guid.NewGuid().ToString(); var content = new CloudEventContent(cloudEvent, ContentMode.Binary, new JsonEventFormatter()); content.Headers.Add(testContextHeader, ctx); @@ -172,13 +169,13 @@ namespace CloudNative.CloudEvents.UnitTests var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter()); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); using (var sr = new StreamReader((Stream)receivedCloudEvent.Data)) { @@ -187,7 +184,6 @@ namespace CloudNative.CloudEvents.UnitTests var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); context.Response.StatusCode = (int)HttpStatusCode.NoContent; } catch (Exception e) @@ -223,14 +219,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + await context.Response.CopyFromAsync(cloudEvent, ContentMode.Structured, new JsonEventFormatter()); context.Response.StatusCode = (int)HttpStatusCode.OK; } @@ -254,18 +249,17 @@ namespace CloudNative.CloudEvents.UnitTests Assert.True(result.IsCloudEvent()); var receivedCloudEvent = result.ToCloudEvent(); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); } [Fact] @@ -276,14 +270,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + string ctx = Guid.NewGuid().ToString(); var content = new CloudEventContent(cloudEvent, ContentMode.Structured, new JsonEventFormatter()); content.Headers.Add(testContextHeader, ctx); @@ -294,18 +287,17 @@ namespace CloudNative.CloudEvents.UnitTests { var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter()); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); context.Response.StatusCode = (int)HttpStatusCode.NoContent; } catch (Exception e) @@ -336,14 +328,13 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; - + string ctx = Guid.NewGuid().ToString(); HttpWebRequest httpWebRequest = WebRequest.CreateHttp(listenerAddress + "ep"); httpWebRequest.Method = "POST"; @@ -356,18 +347,17 @@ namespace CloudNative.CloudEvents.UnitTests { var receivedCloudEvent = context.Request.ToCloudEvent(new JsonEventFormatter()); - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue); context.Response.StatusCode = (int)HttpStatusCode.NoContent; } catch (Exception e) diff --git a/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs b/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs index cf27290..1a6b4f4 100644 --- a/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs @@ -11,7 +11,7 @@ namespace CloudNative.CloudEvents.UnitTests public class JsonTest { - const string json = + const string jsonv02 = "{\n" + " \"specversion\" : \"0.2\",\n" + " \"type\" : \"com.github.pull.create\",\n" + @@ -26,11 +26,23 @@ namespace CloudNative.CloudEvents.UnitTests " \"data\" : \"\"\n" + "}"; + const string jsonv10 = + "{\n" + + " \"specversion\" : \"1.0\",\n" + + " \"type\" : \"com.github.pull.create\",\n" + + " \"source\" : \"https://github.com/cloudevents/spec/pull/123\",\n" + + " \"id\" : \"A234-1234-1234\",\n" + + " \"time\" : \"2018-04-05T17:31:00Z\",\n" + + " \"comexampleextension1\" : \"value\",\n" + + " \"datacontenttype\" : \"text/xml\",\n" + + " \"data\" : \"\"\n" + + "}"; + [Fact] - public void ReserializeTest() + public void ReserializeTest02() { var jsonFormatter = new JsonEventFormatter(); - var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json)); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv02)); var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent, out var contentType); var cloudEvent2 = jsonFormatter.DecodeStructuredEvent(jsonData); @@ -39,7 +51,24 @@ namespace CloudNative.CloudEvents.UnitTests 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.DataContentType, cloudEvent.DataContentType); + Assert.Equal(cloudEvent2.Data, cloudEvent.Data); + } + + [Fact] + public void ReserializeTest10() + { + var jsonFormatter = new JsonEventFormatter(); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv10)); + 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.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -47,7 +76,7 @@ namespace CloudNative.CloudEvents.UnitTests public void ReserializeTestV0_2toV0_1() { var jsonFormatter = new JsonEventFormatter(); - var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json)); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv02)); cloudEvent.SpecVersion = CloudEventsSpecVersion.V0_1; var jsonData = jsonFormatter.EncodeStructuredEvent(cloudEvent, out var contentType); var cloudEvent2 = jsonFormatter.DecodeStructuredEvent(jsonData); @@ -57,22 +86,40 @@ namespace CloudNative.CloudEvents.UnitTests 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.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } [Fact] - public void StructuredParseSuccess() + public void ReserializeTestV1_0toV0_2() { var jsonFormatter = new JsonEventFormatter(); - var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json)); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv10)); + cloudEvent.SpecVersion = CloudEventsSpecVersion.V0_2; + 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.DataContentType, cloudEvent.DataContentType); + Assert.Equal(cloudEvent2.Data, cloudEvent.Data); + } + + [Fact] + public void StructuredParseSuccess02() + { + var jsonFormatter = new JsonEventFormatter(); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv02)); 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); var attr = cloudEvent.GetAttributes(); @@ -81,10 +128,28 @@ namespace CloudNative.CloudEvents.UnitTests } [Fact] - public void StructuredParseWithExtensionsSuccess() + public void StructuredParseSuccess10() { var jsonFormatter = new JsonEventFormatter(); - var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(json), new ComExampleExtension1Extension(), + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv10)); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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.DataContentType); + Assert.Equal("", cloudEvent.Data); + + var attr = cloudEvent.GetAttributes(); + Assert.Equal("value", (string)attr["comexampleextension1"]); + } + + [Fact] + public void StructuredParseWithExtensionsSuccess02() + { + var jsonFormatter = new JsonEventFormatter(); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv02), new ComExampleExtension1Extension(), new ComExampleExtension2Extension()); Assert.Equal(CloudEventsSpecVersion.V0_2, cloudEvent.SpecVersion); Assert.Equal("com.github.pull.create", cloudEvent.Type); @@ -92,11 +157,28 @@ namespace CloudNative.CloudEvents.UnitTests 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(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); Assert.Equal("value", cloudEvent.Extension().ComExampleExtension1); Assert.Equal(5, cloudEvent.Extension().ComExampleExtension2.OtherValue); } + + [Fact] + public void StructuredParseWithExtensionsSuccess10() + { + var jsonFormatter = new JsonEventFormatter(); + var cloudEvent = jsonFormatter.DecodeStructuredEvent(Encoding.UTF8.GetBytes(jsonv10), new ComExampleExtension1Extension()); + Assert.Equal(CloudEventsSpecVersion.V1_0, 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.DataContentType); + Assert.Equal("", cloudEvent.Data); + + Assert.Equal("value", cloudEvent.Extension().ComExampleExtension1); + } } } \ No newline at end of file diff --git a/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs b/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs index fb3dcc7..9e608ed 100644 --- a/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs +++ b/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs @@ -47,13 +47,12 @@ namespace CloudNative.CloudEvents.UnitTests { Id = "A234-1234-1234", Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), - ContentType = new ContentType(MediaTypeNames.Text.Xml), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; var attrs = cloudEvent.GetAttributes(); attrs["comexampleextension1"] = "value"; - attrs["comexampleextension2"] = new { othervalue = 5 }; var client = new MqttFactory().CreateMqttClient(); @@ -74,18 +73,17 @@ namespace CloudNative.CloudEvents.UnitTests await client.PublishAsync(new MqttCloudEventMessage(cloudEvent, new JsonEventFormatter()) { Topic = "abc" }); var receivedCloudEvent = await tcs.Task; - Assert.Equal(CloudEventsSpecVersion.V0_2, receivedCloudEvent.SpecVersion); + Assert.Equal(CloudEventsSpecVersion.Default, 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); Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), receivedCloudEvent.Time.Value.ToUniversalTime()); - Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.ContentType); + Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - Assert.Equal(5, (int)((dynamic)attr["comexampleextension2"]).othervalue);