diff --git a/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs b/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs index 6728ff9..338d1bb 100644 --- a/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs +++ b/src/CloudNative.CloudEvents.Amqp/AmqpClientExtensions.cs @@ -73,13 +73,14 @@ namespace CloudNative.CloudEvents.Amqp : CloudEventsSpecVersion.Default)) : CloudEventsSpecVersion.Default; - var cloudEvent = new CloudEvent(specVersion , extensions); + var cloudEvent = new CloudEvent(specVersion, extensions); var attributes = cloudEvent.GetAttributes(); foreach (var prop in message.ApplicationProperties.Map) { - if (prop.Key is string && - ((string)prop.Key).StartsWith(AmqpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase)) + if (prop.Key is string key && + key.StartsWith(AmqpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase)) { + string attrName = key.Substring(AmqpHeaderPrefix.Length).ToLowerInvariant(); if (cloudEvent.SpecVersion != CloudEventsSpecVersion.V1_0 && prop.Value is Map) { IDictionary exp = new ExpandoObject(); @@ -88,13 +89,22 @@ namespace CloudNative.CloudEvents.Amqp exp[props.Key.ToString()] = props.Value; } - attributes[((string)prop.Key).Substring(AmqpHeaderPrefix.Length).ToLowerInvariant()] = - exp; + attributes[attrName] = exp; + } + else if (prop.Value is DateTime dt) + { + if (dt.Kind != DateTimeKind.Utc) + { + // This should only happen for MinValue and MaxValue... + // just respecify as UTC. (We could add validation that it really + // *is* MinValue or MaxValue if we wanted to.) + dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); + } + attributes[attrName] = (DateTimeOffset) dt; } else { - attributes[((string)prop.Key).Substring(AmqpHeaderPrefix.Length).ToLowerInvariant()] = - prop.Value; + attributes[attrName] = prop.Value; } } } diff --git a/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs b/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs index 4aa5080..c2794ef 100644 --- a/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs +++ b/src/CloudNative.CloudEvents.Amqp/AmqpCloudEventMessage.cs @@ -59,13 +59,20 @@ namespace CloudNative.CloudEvents.Amqp if (!attribute.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion)) && !attribute.Key.Equals(CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion))) { + string key = "cloudEvents:" + attribute.Key; if (attribute.Value is Uri) { - this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value.ToString()); + this.ApplicationProperties.Map.Add(key, attribute.Value.ToString()); } - else if (attribute.Value is DateTime || attribute.Value is DateTime || attribute.Value is string) + else if (attribute.Value is DateTimeOffset dto) { - this.ApplicationProperties.Map.Add("cloudEvents:" + attribute.Key, attribute.Value); + // AMQPNetLite doesn't support DateTimeOffset values, so convert to UTC. + // That means we can't roundtrip events with non-UTC timestamps, but that's not awful. + this.ApplicationProperties.Map.Add(key, dto.UtcDateTime); + } + else if (attribute.Value is string) + { + this.ApplicationProperties.Map.Add(key, attribute.Value); } else { diff --git a/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs b/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs index f4c759c..fd18236 100644 --- a/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs +++ b/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs @@ -89,14 +89,14 @@ namespace CloudNative.CloudEvents { continue; } - if (keyValuePair.Key == CloudEventAttributes.SourceAttributeName() || - keyValuePair.Key == CloudEventAttributes.DataSchemaAttributeName()) + if (keyValuePair.Key == CloudEventAttributes.SourceAttributeName(specVersion) || + keyValuePair.Key == CloudEventAttributes.DataSchemaAttributeName(specVersion)) { attributes[keyValuePair.Key] = new Uri((string)keyValuePair.Value); } - else if (keyValuePair.Key == CloudEventAttributes.TimeAttributeName()) + else if (keyValuePair.Key == CloudEventAttributes.TimeAttributeName(specVersion)) { - attributes[keyValuePair.Key] = DateTime.Parse((string)keyValuePair.Value); + attributes[keyValuePair.Key] = Timestamps.Parse((string)keyValuePair.Value); } else { @@ -121,24 +121,24 @@ namespace CloudNative.CloudEvents continue; } - if (keyValuePair.Value is ContentType && !string.IsNullOrEmpty(((ContentType)keyValuePair.Value).MediaType)) + if (keyValuePair.Value is ContentType valueContentType && !string.IsNullOrEmpty(valueContentType.MediaType)) { - recordAttributes[keyValuePair.Key] = ((ContentType)keyValuePair.Value).ToString(); + recordAttributes[keyValuePair.Key] = valueContentType.ToString(); } - else if (keyValuePair.Value is Uri) + else if (keyValuePair.Value is Uri uri) { - recordAttributes[keyValuePair.Key] = ((Uri)keyValuePair.Value).ToString(); + recordAttributes[keyValuePair.Key] = uri .ToString(); } - else if (keyValuePair.Value is DateTime) + else if (keyValuePair.Value is DateTimeOffset timestamp) { - recordAttributes[keyValuePair.Key] = ((DateTime)keyValuePair.Value).ToString("o"); + recordAttributes[keyValuePair.Key] = Timestamps.Format(timestamp); } else if (cloudEvent.SpecVersion == CloudEventsSpecVersion.V1_0 && keyValuePair.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion))) { - if (keyValuePair.Value is Stream) + if (keyValuePair.Value is Stream stream) { - using (var sr = new BinaryReader((Stream)keyValuePair.Value)) + using (var sr = new BinaryReader(stream)) { record.Add("data", sr.ReadBytes((int)sr.BaseStream.Length)); } diff --git a/src/CloudNative.CloudEvents/CloudEvent.cs b/src/CloudNative.CloudEvents/CloudEvent.cs index eb25eed..bd149f1 100644 --- a/src/CloudNative.CloudEvents/CloudEvent.cs +++ b/src/CloudNative.CloudEvents/CloudEvent.cs @@ -26,7 +26,7 @@ namespace CloudNative.CloudEvents /// 'id' of the CloudEvent /// 'time' of the CloudEvent /// Extensions to be added to this CloudEvents - public CloudEvent(string type, Uri source, string id = null, DateTime? time = null, + public CloudEvent(string type, Uri source, string id = null, DateTimeOffset? time = null, params ICloudEventExtension[] extensions) : this(CloudEventsSpecVersion.Default, type, source, id, time, extensions) { } @@ -40,13 +40,13 @@ namespace CloudNative.CloudEvents /// 'id' of the CloudEvent /// 'time' of the CloudEvent /// Extensions to be added to this CloudEvents - public CloudEvent(CloudEventsSpecVersion specVersion, string type, Uri source, string id = null, DateTime? time = null, + public CloudEvent(CloudEventsSpecVersion specVersion, string type, Uri source, string id = null, DateTimeOffset? time = null, params ICloudEventExtension[] extensions) : this(specVersion, extensions) { Type = type; Source = source; Id = id ?? Guid.NewGuid().ToString(); - Time = time ?? DateTime.UtcNow; + Time = time ?? DateTimeOffset.UtcNow; } /// @@ -59,7 +59,7 @@ namespace CloudNative.CloudEvents /// 'id' of the CloudEvent /// 'time' of the CloudEvent /// Extensions to be added to this CloudEvents - public CloudEvent(CloudEventsSpecVersion specVersion, string type, Uri source, string subject, string id = null, DateTime? time = null, + public CloudEvent(CloudEventsSpecVersion specVersion, string type, Uri source, string subject, string id = null, DateTimeOffset? time = null, params ICloudEventExtension[] extensions) : this(specVersion, type, source, id, time, extensions) { Subject = subject; @@ -179,9 +179,9 @@ namespace CloudNative.CloudEvents /// CloudEvents 'time' attribute. Timestamp of when the event happened. /// /// - public DateTime? Time + public DateTimeOffset? Time { - get => (DateTime?)attributes[CloudEventAttributes.TimeAttributeName(attributes.SpecVersion)]; + get => (DateTimeOffset?)attributes[CloudEventAttributes.TimeAttributeName(attributes.SpecVersion)]; set => attributes[CloudEventAttributes.TimeAttributeName(attributes.SpecVersion)] = value; } diff --git a/src/CloudNative.CloudEvents/CloudEventAttributes.cs b/src/CloudNative.CloudEvents/CloudEventAttributes.cs index 4e0159f..57266a3 100644 --- a/src/CloudNative.CloudEvents/CloudEventAttributes.cs +++ b/src/CloudNative.CloudEvents/CloudEventAttributes.cs @@ -7,8 +7,6 @@ namespace CloudNative.CloudEvents using System; using System.Collections; using System.Collections.Generic; - using System.Collections.Specialized; - using System.Globalization; using System.Net.Mime; /// @@ -319,17 +317,16 @@ namespace CloudNative.CloudEvents } else if (key.Equals(TimeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { - if (value is DateTime) + if (value is DateTimeOffset) { return true; } if (value is string) { - if (DateTime.TryParse((string)value, CultureInfo.InvariantCulture, - DateTimeStyles.AssumeUniversal, out var dateTimeVal)) + if (Timestamps.TryParse((string)value, out var result)) { - value = dateTimeVal; + value = result; return true; } } diff --git a/src/CloudNative.CloudEvents/CloudEventContent.cs b/src/CloudNative.CloudEvents/CloudEventContent.cs index d54e4a6..c9bd257 100644 --- a/src/CloudNative.CloudEvents/CloudEventContent.cs +++ b/src/CloudNative.CloudEvents/CloudEventContent.cs @@ -12,7 +12,6 @@ namespace CloudNative.CloudEvents using System.Net.Mime; using System.Text; using System.Threading.Tasks; - using System.Xml; /// /// This class is for use with `HttpClient` and constructs content and headers for @@ -108,7 +107,7 @@ namespace CloudNative.CloudEvents { string text => WebUtility.UrlEncode(text), ContentType contentType => contentType.ToString(), - DateTime dt => XmlConvert.ToString(dt, XmlDateTimeSerializationMode.Utc), + DateTimeOffset dto => Timestamps.Format(dto), Uri uri => uri.ToString(), int integer => integer.ToString(), _ => WebUtility.UrlEncode(Encoding.UTF8.GetString( diff --git a/src/CloudNative.CloudEvents/HttpClientExtension.cs b/src/CloudNative.CloudEvents/HttpClientExtension.cs index 4d8753d..d1ef34d 100644 --- a/src/CloudNative.CloudEvents/HttpClientExtension.cs +++ b/src/CloudNative.CloudEvents/HttpClientExtension.cs @@ -494,7 +494,7 @@ namespace CloudNative.CloudEvents switch (attributeValue) { case string text: return text; - case DateTime dateTime: return dateTime.ToString("u"); + case DateTimeOffset dateTimeOffset: return Timestamps.Format(dateTimeOffset); case Uri uri: return uri.ToString(); case int integer: return integer.ToString(CultureInfo.InvariantCulture); default: diff --git a/src/CloudNative.CloudEvents/JsonEventFormatter.cs b/src/CloudNative.CloudEvents/JsonEventFormatter.cs index 4ddf378..174bf66 100644 --- a/src/CloudNative.CloudEvents/JsonEventFormatter.cs +++ b/src/CloudNative.CloudEvents/JsonEventFormatter.cs @@ -19,7 +19,6 @@ namespace CloudNative.CloudEvents /// public class JsonEventFormatter : ICloudEventFormatter { - public const string MediaTypeSuffix = "+json"; public CloudEvent DecodeStructuredEvent(Stream data, params ICloudEventExtension[] extensions) @@ -29,14 +28,20 @@ namespace CloudNative.CloudEvents public async Task DecodeStructuredEventAsync(Stream data, IEnumerable extensions) { - var jsonReader = new JsonTextReader(new StreamReader(data, Encoding.UTF8, true, 8192, true)); + var jsonReader = new JsonTextReader(new StreamReader(data, Encoding.UTF8, true, 8192, true)) + { + DateParseHandling = DateParseHandling.DateTimeOffset + }; var jObject = await JObject.LoadAsync(jsonReader); return DecodeJObject(jObject, extensions); } public CloudEvent DecodeStructuredEvent(Stream data, IEnumerable extensions = null) { - var jsonReader = new JsonTextReader(new StreamReader(data, Encoding.UTF8, true, 8192, true)); + var jsonReader = new JsonTextReader(new StreamReader(data, Encoding.UTF8, true, 8192, true)) + { + DateParseHandling = DateParseHandling.DateTimeOffset + }; var jObject = JObject.Load(jsonReader); return DecodeJObject(jObject, extensions); } @@ -46,12 +51,8 @@ namespace CloudNative.CloudEvents return DecodeStructuredEvent(data, (IEnumerable)extensions); } - public CloudEvent DecodeStructuredEvent(byte[] data, IEnumerable extensions = null) - { - var jsonText = Encoding.UTF8.GetString(data); - var jObject = JObject.Parse(jsonText); - return DecodeJObject(jObject, extensions); - } + public CloudEvent DecodeStructuredEvent(byte[] data, IEnumerable extensions = null) => + DecodeStructuredEvent(new MemoryStream(data), extensions); public CloudEvent DecodeJObject(JObject jObject, IEnumerable extensions = null) { @@ -101,7 +102,8 @@ namespace CloudNative.CloudEvents attributes[keyValuePair.Key] = keyValuePair.Value.ToObject(); break; case JTokenType.Date: - attributes[keyValuePair.Key] = keyValuePair.Value.ToObject(); + // TODO: Check this is appropriate. (Should we use Timestamps instead?) + attributes[keyValuePair.Key] = keyValuePair.Value.ToObject(); break; case JTokenType.Uri: attributes[keyValuePair.Key] = keyValuePair.Value.ToObject(); @@ -137,24 +139,24 @@ namespace CloudNative.CloudEvents continue; } - if (keyValuePair.Value is ContentType && !string.IsNullOrEmpty(((ContentType)keyValuePair.Value).MediaType)) + if (keyValuePair.Value is ContentType contentTypeValue && !string.IsNullOrEmpty(contentTypeValue.MediaType)) { - jObject[keyValuePair.Key] = JToken.FromObject(((ContentType)keyValuePair.Value).ToString()); + jObject[keyValuePair.Key] = JToken.FromObject(contentTypeValue.ToString()); } else if (cloudEvent.SpecVersion == CloudEventsSpecVersion.V1_0 && keyValuePair.Key.Equals(CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion))) { - if (keyValuePair.Value is Stream) + if (keyValuePair.Value is Stream stream) { - using (var sr = new BinaryReader((Stream)keyValuePair.Value)) + using (var sr = new BinaryReader(stream)) { jObject["data_base64"] = Convert.ToBase64String(sr.ReadBytes((int)sr.BaseStream.Length)); } } - else if (keyValuePair.Value is IEnumerable) + else if (keyValuePair.Value is IEnumerable bytes) { - jObject["data_base64"] = - Convert.ToBase64String(((IEnumerable)keyValuePair.Value).ToArray()); + // TODO: Avoid creating a copy if it's already a byte array. + jObject["data_base64"] = Convert.ToBase64String(bytes.ToArray()); } else { @@ -180,7 +182,7 @@ namespace CloudNative.CloudEvents if (name.Equals(CloudEventAttributes.TimeAttributeName(specVersion))) { - return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), typeof(DateTime)); + return Timestamps.Parse(Encoding.UTF8.GetString(data)); } if (name.Equals(CloudEventAttributes.SourceAttributeName(specVersion)) || @@ -200,6 +202,7 @@ namespace CloudNative.CloudEvents { foreach (var extension in extensions) { + // TODO: Use appropriate parsing, e.g. for timestamps Type type = extension.GetAttributeType(name); if (type != null) { @@ -231,11 +234,17 @@ namespace CloudNative.CloudEvents Type type = extension.GetAttributeType(name); if (type != null) { + // TODO: Use appropriate formatting, e.g. for timestamps return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Convert.ChangeType(value, type))); } } } + if (value is DateTimeOffset dto) + { + return Encoding.UTF8.GetBytes(Timestamps.Format(dto)); + } + return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)); } } diff --git a/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs b/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs index 3902595..b62bfcc 100644 --- a/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/AmqpTest.cs @@ -9,6 +9,7 @@ namespace CloudNative.CloudEvents.UnitTests using CloudNative.CloudEvents.Amqp; using global::Amqp; using Xunit; + using static TestHelpers; public class AmqpTest { @@ -26,7 +27,7 @@ namespace CloudNative.CloudEvents.UnitTests subject: "123") { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero), DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -47,8 +48,7 @@ namespace CloudNative.CloudEvents.UnitTests Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull"), receivedCloudEvent.Source); Assert.Equal("123", receivedCloudEvent.Subject); Assert.Equal("A234-1234-1234", receivedCloudEvent.Id); - Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), - receivedCloudEvent.Time.Value.ToUniversalTime()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); @@ -68,7 +68,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero), DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -88,14 +88,34 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); 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("value", (string)attr["comexampleextension1"]); + } + + [Fact] + public void AmqpNormalizesTimestampsToUtc() + { + var cloudEvent = new CloudEvent("com.github.pull.create", + new Uri("https://github.com/cloudevents/spec/pull/123")) + { + Id = "A234-1234-1234", + // 2018-04-05T18:31:00+01:00 => 2018-04-05T17:31:00Z + Time = new DateTimeOffset(2018, 4, 5, 18, 31, 0, TimeSpan.FromHours(1)), + DataContentType = new ContentType(MediaTypeNames.Text.Xml), + Data = "" + }; + + var message = new AmqpCloudEventMessage(cloudEvent, ContentMode.Binary, new JsonEventFormatter()); + var encodedAmqpMessage = message.Encode(); + + var message1 = Message.Decode(encodedAmqpMessage); + var receivedCloudEvent = message1.ToCloudEvent(); + + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); } } } \ No newline at end of file diff --git a/test/CloudNative.CloudEvents.UnitTests/AvroTest.cs b/test/CloudNative.CloudEvents.UnitTests/AvroTest.cs index 0324a69..6b1aa58 100644 --- a/test/CloudNative.CloudEvents.UnitTests/AvroTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/AvroTest.cs @@ -8,6 +8,7 @@ namespace CloudNative.CloudEvents.UnitTests using System.Net.Mime; using System.Text; using Xunit; + using static TestHelpers; public class AvroTest { @@ -36,7 +37,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(cloudEvent2.Time.Value, cloudEvent.Time.Value); Assert.Equal(cloudEvent2.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -55,8 +56,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -78,8 +78,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); diff --git a/test/CloudNative.CloudEvents.UnitTests/CloudEventContentTest.cs b/test/CloudNative.CloudEvents.UnitTests/CloudEventContentTest.cs index aaeddc4..00e3e14 100644 --- a/test/CloudNative.CloudEvents.UnitTests/CloudEventContentTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/CloudEventContentTest.cs @@ -39,6 +39,6 @@ namespace CloudNative.CloudEvents.UnitTests static CloudEvent CreateEmptyCloudEvent() => new CloudEvent(CloudEventsSpecVersion.V1_0, "type", - new Uri("https://source"), "subject", "id", DateTime.UtcNow); + new Uri("https://source"), "subject", "id", DateTimeOffset.UtcNow); } } diff --git a/test/CloudNative.CloudEvents.UnitTests/CloudEventTest.cs b/test/CloudNative.CloudEvents.UnitTests/CloudEventTest.cs index 9335a98..46c52be 100644 --- a/test/CloudNative.CloudEvents.UnitTests/CloudEventTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/CloudEventTest.cs @@ -14,7 +14,7 @@ namespace CloudNative.CloudEvents.UnitTests public void SetAttributePropertiesToNull() { var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0, "type", - new Uri("https://source"), "subject", "id", DateTime.UtcNow) + new Uri("https://source"), "subject", "id", DateTimeOffset.UtcNow) { Data = "some data", DataContentType = new ContentType("text/plain"), diff --git a/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs b/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs index f1c6688..93831f4 100644 --- a/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/ConstructorTest.cs @@ -7,9 +7,12 @@ namespace CloudNative.CloudEvents.UnitTests using System; using System.Net.Mime; using Xunit; + using static TestHelpers; public class ConstructorTest { + private static readonly DateTimeOffset sampleTimestamp = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero); + [Fact] public void CreateBaseEvent1() { @@ -17,7 +20,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -30,8 +33,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -47,7 +49,7 @@ namespace CloudNative.CloudEvents.UnitTests "com.github.pull.create", new Uri("https://github.com/cloudevents/spec/pull/123"), "A234-1234-1234", - new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc)) + sampleTimestamp) { DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" @@ -61,8 +63,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -79,7 +80,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -92,8 +93,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -109,7 +109,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -124,8 +124,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -142,7 +141,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -156,8 +155,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -172,7 +170,7 @@ namespace CloudNative.CloudEvents.UnitTests "com.github.pull.create", new Uri("https://github.com/cloudevents/spec/pull/123"), "A234-1234-1234", - new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + sampleTimestamp, new ComExampleExtension1Extension() { ComExampleExtension1 = "value" @@ -186,8 +184,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); diff --git a/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs b/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs index d81da4c..19aa48b 100644 --- a/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/ExtensionsTest.cs @@ -9,6 +9,7 @@ namespace CloudNative.CloudEvents.UnitTests using System.Text; using CloudNative.CloudEvents.Extensions; using Xunit; + using static TestHelpers; public class ExtensionsTest { @@ -72,9 +73,8 @@ namespace CloudNative.CloudEvents.UnitTests 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()); - + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); + Assert.Equal("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", cloudEvent.Extension().TraceParent); Assert.Equal("rojo=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01,congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4=", cloudEvent.Extension().TraceState); } @@ -91,8 +91,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", cloudEvent.Extension().TraceParent); Assert.Equal("rojo=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01,congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4=", cloudEvent.Extension().TraceState); @@ -107,8 +106,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal("Integer", cloudEvent.Extension().SequenceType); Assert.Equal("25", cloudEvent.Extension().Sequence); @@ -126,8 +124,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal("Integer", cloudEvent.Extension().SequenceType); Assert.Equal("25", cloudEvent.Extension().Sequence); @@ -142,8 +139,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(25, cloudEvent.Extension().Sequence); } @@ -160,8 +156,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(25, cloudEvent.Extension().Sequence); } @@ -175,8 +170,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(1, cloudEvent.Extension().SampledRate.Value); } @@ -193,8 +187,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(1, cloudEvent.Extension().SampledRate.Value); } diff --git a/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs b/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs index 26e2844..208083a 100644 --- a/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/HttpTest.cs @@ -13,9 +13,12 @@ namespace CloudNative.CloudEvents.UnitTests using System.Net.Mime; using System.Threading.Tasks; using Xunit; + using static TestHelpers; public class HttpTest : IDisposable { + private static readonly DateTimeOffset sampleTimestamp = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero); + const string listenerAddress = "http://localhost:52671/"; const string testContextHeader = "testcontext"; @@ -94,7 +97,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -134,8 +137,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); using (var sr = new StreamReader((Stream)receivedCloudEvent.Data)) { @@ -154,7 +156,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -179,8 +181,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); // The non-ASCII attribute value should have been URL-encoded using UTF-8 for the header. @@ -231,7 +232,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -267,8 +268,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); @@ -284,7 +284,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -321,8 +321,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); @@ -359,7 +358,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -384,8 +383,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); using (var sr = new StreamReader((Stream) receivedCloudEvent.Data)) { @@ -427,7 +425,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = sampleTimestamp, DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -455,8 +453,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(sampleTimestamp, cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); diff --git a/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs b/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs index 1a6b4f4..8131c41 100644 --- a/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/JsonTest.cs @@ -8,6 +8,7 @@ namespace CloudNative.CloudEvents.UnitTests using System.Net.Mime; using System.Text; using Xunit; + using static TestHelpers; public class JsonTest { @@ -50,7 +51,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(cloudEvent2.Time, cloudEvent.Time); Assert.Equal(cloudEvent2.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -67,7 +68,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(cloudEvent2.Time, cloudEvent.Time); Assert.Equal(cloudEvent2.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -85,7 +86,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(cloudEvent2.Time, cloudEvent.Time); Assert.Equal(cloudEvent2.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -103,7 +104,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual(cloudEvent2.Time, cloudEvent.Time); Assert.Equal(cloudEvent2.DataContentType, cloudEvent.DataContentType); Assert.Equal(cloudEvent2.Data, cloudEvent.Data); } @@ -117,8 +118,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -136,8 +136,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -155,8 +154,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); @@ -173,8 +171,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", cloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), cloudEvent.DataContentType); Assert.Equal("", cloudEvent.Data); diff --git a/test/CloudNative.CloudEvents.UnitTests/KafkaTest.cs b/test/CloudNative.CloudEvents.UnitTests/KafkaTest.cs index 2fc354e..ffb0209 100644 --- a/test/CloudNative.CloudEvents.UnitTests/KafkaTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/KafkaTest.cs @@ -15,6 +15,7 @@ namespace CloudNative.CloudEvents.UnitTests using System.Collections.Generic; using System.Text; using CloudNative.CloudEvents.Extensions; + using static TestHelpers; public class KafkaTest { @@ -33,7 +34,7 @@ namespace CloudNative.CloudEvents.UnitTests subject: "123") { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero), DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -58,8 +59,7 @@ namespace CloudNative.CloudEvents.UnitTests Assert.Equal(new Uri("https://github.com/cloudevents/spec/pull"), receivedCloudEvent.Source); Assert.Equal("123", receivedCloudEvent.Subject); Assert.Equal("A234-1234-1234", receivedCloudEvent.Id); - Assert.Equal(DateTime.Parse("2018-04-05T17:31:00Z").ToUniversalTime(), - receivedCloudEvent.Time.Value.ToUniversalTime()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); @@ -80,7 +80,7 @@ namespace CloudNative.CloudEvents.UnitTests extensions: new PartitioningExtension()) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero), DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = Encoding.UTF8.GetBytes("") }; @@ -95,7 +95,11 @@ namespace CloudNative.CloudEvents.UnitTests // using serialization to create fully independent copy thus simulating message transport // real transport will work in a similar way var serialized = JsonConvert.SerializeObject(message, new HeaderConverter()); - var messageCopy = JsonConvert.DeserializeObject>(serialized, new HeadersConverter(), new HeaderConverter()); + var settings = new JsonSerializerSettings + { + Converters = { new HeadersConverter(), new HeaderConverter() } + }; + var messageCopy = JsonConvert.DeserializeObject>(serialized, settings); Assert.True(messageCopy.IsCloudEvent()); var receivedCloudEvent = messageCopy.ToCloudEvent(jsonEventFormatter, new PartitioningExtension()); @@ -104,8 +108,7 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal(Encoding.UTF8.GetBytes(""), receivedCloudEvent.Data); Assert.Equal("hello much wow", receivedCloudEvent.Extension().PartitioningKeyValue); diff --git a/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs b/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs index 9e608ed..7a06149 100644 --- a/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs +++ b/test/CloudNative.CloudEvents.UnitTests/MqttTests.cs @@ -17,6 +17,7 @@ namespace CloudNative.CloudEvents.UnitTests using MQTTnet; using MQTTnet.Client; using MQTTnet.Server; + using static TestHelpers; public class MqttTest : IDisposable { @@ -46,7 +47,7 @@ namespace CloudNative.CloudEvents.UnitTests new Uri("https://github.com/cloudevents/spec/pull/123")) { Id = "A234-1234-1234", - Time = new DateTime(2018, 4, 5, 17, 31, 0, DateTimeKind.Utc), + Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero), DataContentType = new ContentType(MediaTypeNames.Text.Xml), Data = "" }; @@ -77,19 +78,12 @@ namespace CloudNative.CloudEvents.UnitTests 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()); + AssertTimestampsEqual("2018-04-05T17:31:00Z", receivedCloudEvent.Time.Value); Assert.Equal(new ContentType(MediaTypeNames.Text.Xml), receivedCloudEvent.DataContentType); Assert.Equal("", receivedCloudEvent.Data); var attr = receivedCloudEvent.GetAttributes(); Assert.Equal("value", (string)attr["comexampleextension1"]); - - - - - } - } } \ No newline at end of file