From 67b642a42d3c444a463823b09112076c594b0696 Mon Sep 17 00:00:00 2001 From: Lilian Kasem Date: Thu, 13 Jul 2023 12:27:09 -0700 Subject: [PATCH] Refactor EventGrid extension converter, tests, and samples (#1695, #1716, #1727, #1723) --- .../src/EventGridTriggerAttribute.cs | 2 +- .../EventGridBinaryDataConverter.cs | 70 +++--------- .../EventGridCloudEventConverter.cs | 25 ++--- .../TypeConverters/EventGridConverterBase.cs | 50 +++++++++ .../TypeConverters/EventGridEventConverter.cs | 25 ++--- .../src/TypeConverters/EventGridHelper.cs | 42 ------- .../EventGridStringArrayConverter.cs | 53 ++------- .../EventGrid/CloudEventSamples.cs | 48 ++++++++ .../EventGrid/EventGridEventSamples.cs | 48 ++++++++ .../EventGridTriggerBindingSamples.cs | 105 ------------------ .../functions.metadata | 72 ++++++++++++ .../EventGridBinaryDataConverterTests.cs | 65 +++++------ .../EventGridCloudEventConverterTests.cs | 68 +++++------- .../EventGrid/EventGridEventConverterTests.cs | 94 +++++++--------- .../EventGridStringArrayConverterTests.cs | 42 ++++--- .../EventGrid/EventGridTestHelper.cs | 54 +++++++++ 16 files changed, 446 insertions(+), 417 deletions(-) create mode 100644 extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridConverterBase.cs delete mode 100644 extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridHelper.cs create mode 100644 samples/WorkerBindingSamples/EventGrid/CloudEventSamples.cs create mode 100644 samples/WorkerBindingSamples/EventGrid/EventGridEventSamples.cs delete mode 100644 samples/WorkerBindingSamples/EventGrid/EventGridTriggerBindingSamples.cs create mode 100644 test/Worker.Extensions.Tests/EventGrid/EventGridTestHelper.cs diff --git a/extensions/Worker.Extensions.EventGrid/src/EventGridTriggerAttribute.cs b/extensions/Worker.Extensions.EventGrid/src/EventGridTriggerAttribute.cs index b0842fd0..6dd90d72 100644 --- a/extensions/Worker.Extensions.EventGrid/src/EventGridTriggerAttribute.cs +++ b/extensions/Worker.Extensions.EventGrid/src/EventGridTriggerAttribute.cs @@ -7,11 +7,11 @@ using Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters; namespace Microsoft.Azure.Functions.Worker { - [AllowConverterFallback(true)] [InputConverter(typeof(EventGridCloudEventConverter))] [InputConverter(typeof(EventGridEventConverter))] [InputConverter(typeof(EventGridBinaryDataConverter))] [InputConverter(typeof(EventGridStringArrayConverter))] + [ConverterFallbackBehavior(ConverterFallbackBehavior.Default)] public sealed class EventGridTriggerAttribute : TriggerBindingAttribute { private bool _isBatched = false; diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridBinaryDataConverter.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridBinaryDataConverter.cs index d55d9e28..e504bbae 100644 --- a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridBinaryDataConverter.cs +++ b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridBinaryDataConverter.cs @@ -3,76 +3,42 @@ using System; using System.Collections.Generic; -using System.Globalization; +using System.Linq; using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker.Converters; namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters { /// - /// Converter to bind to BinaryData or BinaryData[] parameter. + /// Converter to bind to or type parameters. /// - [SupportedConverterType(typeof(BinaryData))] - [SupportedConverterType(typeof(BinaryData[]))] - internal class EventGridBinaryDataConverter : IInputConverter + [SupportedTargetType(typeof(BinaryData))] + [SupportedTargetType(typeof(BinaryData[]))] + internal class EventGridBinaryDataConverter : EventGridConverterBase { - public ValueTask ConvertAsync(ConverterContext context) + protected override ConversionResult ConvertCore(Type targetType, string json) { - try + ConversionResult result = targetType switch { - if (context is null) - { - throw new ArgumentNullException(nameof(context)); - } + Type t when t == typeof(BinaryData) => ConversionResult.Success(BinaryData.FromString(json)), + Type t when t == typeof(BinaryData[]) => ConversionResult.Success(ConvertToBinaryDataArray(json)), + _ => ConversionResult.Failed(new InvalidOperationException($"'{targetType.Name}' is not supported by this converter.")) + }; - if (context.Source is not string contextSource) - { - return new(ConversionResult.Failed(new InvalidOperationException("Context source must be a non-null string. Current type of context source is " + context?.Source?.GetType()))); - } - - var targetType = context.TargetType; - - switch (targetType) - { - case Type t when t == typeof(BinaryData): - return new(ConversionResult.Success((BinaryData.FromString(contextSource)))); - case Type t when t == typeof(BinaryData[]): - return new(ConversionResult.Success(ConvertToBinaryDataArray(contextSource))); - } - } - catch (JsonException ex) - { - string msg = String.Format(CultureInfo.CurrentCulture, - @"Binding parameters to complex objects uses JSON serialization. - 1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or - 2. Change the event payload to be valid json."); - - return new(ConversionResult.Failed(new InvalidOperationException(msg, ex))); - } - catch (Exception ex) - { - return new(ConversionResult.Failed(ex)); - } - - return new(ConversionResult.Unhandled()); + return result; } - private BinaryData?[]? ConvertToBinaryDataArray(string contextSource) + private BinaryData[] ConvertToBinaryDataArray(string json) { - var jsonData = JsonSerializer.Deserialize(contextSource, typeof(List)) as List; - List binaryDataList = new List(); + var data = JsonSerializer.Deserialize>(json); + var result = data.Select(item => BinaryData.FromString(item.ToString())).ToArray(); - if (jsonData is not null) + if (result is null) { - foreach (var item in jsonData) - { - var binaryData = item == null? null: BinaryData.FromString(item.ToString()); - binaryDataList.Add(binaryData); - } + throw new Exception("Unable to convert to BinaryData[]."); } - return binaryDataList.ToArray(); + return result; } } } diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridCloudEventConverter.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridCloudEventConverter.cs index 67e4e3ea..6ce7155b 100644 --- a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridCloudEventConverter.cs +++ b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridCloudEventConverter.cs @@ -2,32 +2,29 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Threading.Tasks; +using System.Text.Json; using Azure.Messaging; using Microsoft.Azure.Functions.Worker.Converters; namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters { /// - /// Converter to bind to CloudEvent or CloudEvent[] parameter. + /// Converter to bind to or type parameters. /// - [SupportedConverterType(typeof(CloudEvent))] - [SupportedConverterType(typeof(CloudEvent[]))] - internal class EventGridCloudEventConverter: IInputConverter + [SupportedTargetType(typeof(CloudEvent))] + [SupportedTargetType(typeof(CloudEvent[]))] + internal class EventGridCloudEventConverter: EventGridConverterBase { - public ValueTask ConvertAsync(ConverterContext context) + protected override ConversionResult ConvertCore(Type targetType, string json) { - if (context is null) + var cloudEvent = JsonSerializer.Deserialize(json, targetType); + + if (cloudEvent is null) { - return new(ConversionResult.Failed(new ArgumentNullException(nameof(context)))); + return ConversionResult.Failed(new Exception("Unable to convert to CloudEvent.")); } - if (context.TargetType != typeof(CloudEvent) && context.TargetType != typeof(CloudEvent[])) - { - return new(ConversionResult.Unhandled()); - } - - return EventGridHelper.DeserializeToTargetType(context); + return ConversionResult.Success(cloudEvent); } } } diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridConverterBase.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridConverterBase.cs new file mode 100644 index 00000000..7d4eeb6f --- /dev/null +++ b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridConverterBase.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Azure.Functions.Worker.Converters; + +namespace Microsoft.Azure.Functions.Worker +{ + internal abstract class EventGridConverterBase : IInputConverter + { + public EventGridConverterBase() { } + + public ValueTask ConvertAsync(ConverterContext context) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + try + { + if (context.Source is not string json) + { + throw new InvalidOperationException("Context source must be a non-null string"); + } + + var result = ConvertCore(context.TargetType, json); + return new ValueTask(result); + } + catch (JsonException ex) + { + string msg = String.Format(CultureInfo.CurrentCulture, + @"Binding parameters to complex objects uses JSON serialization. + 1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or + 2. Change the queue payload to be valid json."); + + return new ValueTask(ConversionResult.Failed(new InvalidOperationException(msg, ex))); + } + catch (Exception ex) + { + return new ValueTask(ConversionResult.Failed(ex)); + } + } + + protected abstract ConversionResult ConvertCore(Type targetType, string json); + } +} diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridEventConverter.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridEventConverter.cs index 7397d227..9cf023f7 100644 --- a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridEventConverter.cs +++ b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridEventConverter.cs @@ -2,32 +2,29 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Threading.Tasks; +using System.Text.Json; using Azure.Messaging.EventGrid; using Microsoft.Azure.Functions.Worker.Converters; namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters { /// - /// Converter to bind to EventGridEvent or EventGridEvent[] parameter. + /// Converter to bind to or type parameters. /// - [SupportedConverterType(typeof(EventGridEvent))] - [SupportedConverterType(typeof(EventGridEvent[]))] - internal class EventGridEventConverter : IInputConverter + [SupportedTargetType(typeof(EventGridEvent))] + [SupportedTargetType(typeof(EventGridEvent[]))] + internal class EventGridEventConverter : EventGridConverterBase { - public ValueTask ConvertAsync(ConverterContext context) + protected override ConversionResult ConvertCore(Type targetType, string json) { - if (context is null) + var eventGridEvent = JsonSerializer.Deserialize(json, targetType); + + if (eventGridEvent is null) { - return new(ConversionResult.Failed(new ArgumentNullException(nameof(context)))); + return ConversionResult.Failed(new Exception("Unable to convert to EventGridEvent.")); } - if (context?.TargetType != typeof(EventGridEvent) && context?.TargetType != typeof(EventGridEvent[])) - { - return new(ConversionResult.Unhandled()); - } - - return EventGridHelper.DeserializeToTargetType(context); + return ConversionResult.Success(eventGridEvent); } } } diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridHelper.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridHelper.cs deleted file mode 100644 index 9347e21f..00000000 --- a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridHelper.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Globalization; -using System.Text.Json; -using System.Threading.Tasks; -using Microsoft.Azure.Functions.Worker.Converters; - -namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters -{ - internal static class EventGridHelper - { - internal static ValueTask DeserializeToTargetType(ConverterContext context) - { - try - { - if (context.Source is not string contextSource) - { - return new(ConversionResult.Failed(new InvalidOperationException("Context source must be a non-null string. Current type of context source is " + context?.Source?.GetType()))); - } - - var targetType = context.TargetType; - var item = JsonSerializer.Deserialize(contextSource, targetType); - return new(ConversionResult.Success(item)); - } - catch (JsonException ex) - { - string msg = String.Format(CultureInfo.CurrentCulture, - @"Binding parameters to complex objects uses JSON serialization. - 1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or - 2. Change the event payload to be valid json."); - - return new(ConversionResult.Failed(new InvalidOperationException(msg, ex))); - } - catch (Exception ex) - { - return new(ConversionResult.Failed(ex)); - } - } - } -} diff --git a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridStringArrayConverter.cs b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridStringArrayConverter.cs index e5bfe709..18b0688a 100644 --- a/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridStringArrayConverter.cs +++ b/extensions/Worker.Extensions.EventGrid/src/TypeConverters/EventGridStringArrayConverter.cs @@ -3,62 +3,29 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker.Converters; namespace Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters { /// - /// Converter to bind to string[] parameter. + /// Converter to bind to type parameters. /// - [SupportedConverterType(typeof(string[]))] - internal class EventGridStringArrayConverter : IInputConverter + [SupportedTargetType(typeof(string[]))] + internal class EventGridStringArrayConverter : EventGridConverterBase { - public ValueTask ConvertAsync(ConverterContext context) + protected override ConversionResult ConvertCore(Type targetType, string json) { - try + var jsonData = JsonSerializer.Deserialize>(json); + var result = jsonData.Select(d => d.ToString()).ToArray(); + + if (result is null) { - if (context is null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (context.TargetType != typeof(string[])) - { - return new(ConversionResult.Unhandled()); - } - - if (context.Source is not string contextSource) - { - return new(ConversionResult.Failed(new InvalidOperationException("Context source must be a non-null string. Current type of context source is " + context?.Source?.GetType()))); - } - - var jsonData = JsonSerializer.Deserialize(contextSource, typeof(List)) as List; - List stringList = new List(); - - if (jsonData is not null) - { - return new(ConversionResult.Success(jsonData.Select(d => d?.ToString()).ToArray())); - } - } - catch (JsonException ex) - { - string msg = String.Format(CultureInfo.CurrentCulture, - @"Binding parameters to complex objects uses JSON serialization. - 1. Bind the parameter type as 'string' instead to get the raw values and avoid JSON deserialization, or - 2. Change the event payload to be valid json."); - - return new(ConversionResult.Failed(new InvalidOperationException(msg, ex))); - } - catch (Exception ex) - { - return new(ConversionResult.Failed(ex)); + return ConversionResult.Failed(new Exception("Unable to convert to string[].")); } - return new(ConversionResult.Unhandled()); + return ConversionResult.Success(result); } } } diff --git a/samples/WorkerBindingSamples/EventGrid/CloudEventSamples.cs b/samples/WorkerBindingSamples/EventGrid/CloudEventSamples.cs new file mode 100644 index 00000000..1f3088bc --- /dev/null +++ b/samples/WorkerBindingSamples/EventGrid/CloudEventSamples.cs @@ -0,0 +1,48 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +// Default URL for triggering event grid function in the local environment. +// http://localhost:7071/runtime/webhooks/EventGrid?functionName={functionname} + +using Azure.Messaging; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace SampleApp +{ + /// + /// Samples demonstrating binding to the type. + /// + public class CloudEventSamples + { + private readonly ILogger _logger; + + public CloudEventSamples(ILogger logger) + { + _logger = logger; + } + + /// + /// This function demonstrates binding to a single . + /// + [Function(nameof(CloudEventFunction))] + public void CloudEventFunction([EventGridTrigger] CloudEvent cloudEvent) + { + _logger.LogInformation("Event type: {type}, Event subject: {subject}", cloudEvent.Type, cloudEvent.Subject); + } + + /// + /// This function demonstrates binding to an array of . + /// Note that when doing so, you must also set the property + /// to true. + /// + [Function(nameof(CloudEventBatchFunction))] + public void CloudEventBatchFunction([EventGridTrigger(IsBatched = true)] CloudEvent[] cloudEvents) + { + foreach (var cloudEvent in cloudEvents) + { + _logger.LogInformation("Event type: {type}, Event subject: {subject}", cloudEvent.Type, cloudEvent.Subject); + } + } + } +} diff --git a/samples/WorkerBindingSamples/EventGrid/EventGridEventSamples.cs b/samples/WorkerBindingSamples/EventGrid/EventGridEventSamples.cs new file mode 100644 index 00000000..024b60c3 --- /dev/null +++ b/samples/WorkerBindingSamples/EventGrid/EventGridEventSamples.cs @@ -0,0 +1,48 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +// Default URL for triggering event grid function in the local environment. +// http://localhost:7071/runtime/webhooks/EventGrid?functionName={functionname} + +using Azure.Messaging.EventGrid; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace SampleApp +{ + /// + /// Samples demonstrating binding to the type. + /// + public class EventGridEventSamples + { + private readonly ILogger _logger; + + public EventGridEventSamples(ILogger logger) + { + _logger = logger; + } + + /// + /// This function demonstrates binding to a single . + /// + [Function(nameof(EventGridEventFunction))] + public void EventGridEventFunction([EventGridTrigger] EventGridEvent eventGridEvent) + { + _logger.LogInformation("Event received: {event}", eventGridEvent.Data.ToString()); + } + + /// + /// This function demonstrates binding to an array of . + /// Note that when doing so, you must also set the property + /// to true. + /// + [Function(nameof(EventGridEventBatchFunction))] + public void EventGridEventBatchFunction([EventGridTrigger(IsBatched = true)] EventGridEvent[] eventGridEvents) + { + foreach (var eventGridEvent in eventGridEvents) + { + _logger.LogInformation("Event received: {event}", eventGridEvent.Data.ToString()); + } + } + } +} diff --git a/samples/WorkerBindingSamples/EventGrid/EventGridTriggerBindingSamples.cs b/samples/WorkerBindingSamples/EventGrid/EventGridTriggerBindingSamples.cs deleted file mode 100644 index 5ffd9123..00000000 --- a/samples/WorkerBindingSamples/EventGrid/EventGridTriggerBindingSamples.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Default URL for triggering event grid function in the local environment. -// http://localhost:7071/runtime/webhooks/EventGrid?functionName={functionname} -using System; -using Azure.Messaging; -using Azure.Messaging.EventGrid; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Logging; - -namespace WorkerBindingSamples.EventGrid -{ - public class EventGridTriggerBindingSamples - { - private readonly ILogger _logger; - - public EventGridTriggerBindingSamples(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - [Function("MyEventFunction")] - public void MyEventFunction([EventGridTrigger] MyEvent input) - { - _logger.LogInformation(input.Data?.ToString()); - } - - [Function("CloudEventFunction")] - public void CloudEventFunction([EventGridTrigger] CloudEvent input) - { - _logger.LogInformation("Event type: {type}, Event subject: {subject}", input.Type, input.Subject); - } - - [Function("MultipleCloudEventFunction")] - public void MultipleCloudEventFunction([EventGridTrigger(IsBatched = true)] CloudEvent[] input) - { - for (var i = 0; i < input.Length; i++) - { - var cloudEvent = input[i]; - _logger.LogInformation("Event type: {type}, Event subject: {subject}", cloudEvent.Type, cloudEvent.Subject); - } - } - - [Function("EventGridEvent")] - public void EventGridEvent([EventGridTrigger] EventGridEvent input) - { - _logger.LogInformation("Event received: {event}", input.Data.ToString()); - } - - [Function("EventGridEventArray")] - public void EventGridEventArray([EventGridTrigger(IsBatched = true)] EventGridEvent[] input) - { - for (var i = 0; i < input.Length; i++) - { - var eventGridEvent = input[i]; - _logger.LogInformation("Event received: {event}", eventGridEvent.Data.ToString()); - } - } - - [Function("BinaryDataEvent")] - public void BinaryDataEvent([EventGridTrigger] BinaryData input) - { - _logger.LogInformation("Event received: {event}", input.ToString()); - } - - [Function("BinaryDataArrayEvent")] - public void BinaryDataArrayEvent([EventGridTrigger(IsBatched = true)] BinaryData[] input) - { - for (var i = 0; i < input.Length; i++) - { - var binaryDataEvent = input[i]; - _logger.LogInformation("Event received: {event}", binaryDataEvent.ToString()); - } - } - - [Function("StringArrayEvent")] - public void StringArrayEvent([EventGridTrigger(IsBatched = true)] string[] input) - { - for (var i = 0; i < input.Length; i++) - { - var stringEventGrid = input[i]; - _logger.LogInformation("Event received: {event}", stringEventGrid); - } - } - - [Function("StringEvent")] - public void StringEvent([EventGridTrigger] string input) - { - _logger.LogInformation("Event received: {event}", input); - } - } - - public class MyEvent - { - public string? Id { get; set; } - - public string? Topic { get; set; } - - public string? Subject { get; set; } - - public string? EventType { get; set; } - - public DateTime EventTime { get; set; } - - public object? Data { get; set; } - } -} diff --git a/test/SdkE2ETests/Contents/WorkerBindingSamplesOutput/functions.metadata b/test/SdkE2ETests/Contents/WorkerBindingSamplesOutput/functions.metadata index 87adc894..abc769bc 100644 --- a/test/SdkE2ETests/Contents/WorkerBindingSamplesOutput/functions.metadata +++ b/test/SdkE2ETests/Contents/WorkerBindingSamplesOutput/functions.metadata @@ -314,5 +314,77 @@ } } ] + }, + { + "name": "CloudEventFunction", + "scriptFile": "WorkerBindingSamples.dll", + "entryPoint": "SampleApp.CloudEventSamples.CloudEventFunction", + "language": "dotnet-isolated", + "properties": { + "IsCodeless": false + }, + "bindings": [ + { + "name": "cloudEvent", + "direction": "In", + "type": "eventGridTrigger", + "cardinality": "One", + "properties": {} + } + ] + }, + { + "name": "CloudEventBatchFunction", + "scriptFile": "WorkerBindingSamples.dll", + "entryPoint": "SampleApp.CloudEventSamples.CloudEventBatchFunction", + "language": "dotnet-isolated", + "properties": { + "IsCodeless": false + }, + "bindings": [ + { + "name": "cloudEvents", + "direction": "In", + "type": "eventGridTrigger", + "cardinality": "Many", + "properties": {} + } + ] + }, + { + "name": "EventGridEventFunction", + "scriptFile": "WorkerBindingSamples.dll", + "entryPoint": "SampleApp.EventGridEventSamples.EventGridEventFunction", + "language": "dotnet-isolated", + "properties": { + "IsCodeless": false + }, + "bindings": [ + { + "name": "eventGridEvent", + "direction": "In", + "type": "eventGridTrigger", + "cardinality": "One", + "properties": {} + } + ] + }, + { + "name": "EventGridEventBatchFunction", + "scriptFile": "WorkerBindingSamples.dll", + "entryPoint": "SampleApp.EventGridEventSamples.EventGridEventBatchFunction", + "language": "dotnet-isolated", + "properties": { + "IsCodeless": false + }, + "bindings": [ + { + "name": "eventGridEvents", + "direction": "In", + "type": "eventGridTrigger", + "cardinality": "Many", + "properties": {} + } + ] } ] \ No newline at end of file diff --git a/test/Worker.Extensions.Tests/EventGrid/EventGridBinaryDataConverterTests.cs b/test/Worker.Extensions.Tests/EventGrid/EventGridBinaryDataConverterTests.cs index 30444150..0d7ad9f9 100644 --- a/test/Worker.Extensions.Tests/EventGrid/EventGridBinaryDataConverterTests.cs +++ b/test/Worker.Extensions.Tests/EventGrid/EventGridBinaryDataConverterTests.cs @@ -20,19 +20,41 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_SourceAsObject_ReturnsUnhandled() + public async Task ConvertAsync_Source_IsNotAString_ReturnsFailed() { var context = new TestConverterContext(typeof(BinaryData), new object()); var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Equal("Context source must be a non-null string", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_UnsupportedTargetType_ReturnsFailed() + { + var context = new TestConverterContext(typeof(string), ""); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); } [Fact] - public async Task ConvertAsync_Returns_Success() + public async Task ConvertAsync_InvalidJson_ThrowsJsonException_ReturnsFailed() { - var context = new TestConverterContext(typeof(BinaryData), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); + var context = new TestConverterContext(typeof(BinaryData[]), @"{""invalid"" :json""}"); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Contains("Binding parameters to complex objects uses JSON serialization", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_SingleBinaryData_ReturnsSuccess() + { + var context = new TestConverterContext(typeof(BinaryData), EventGridTestHelper.GetEventGridJsonData()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -41,28 +63,9 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_Returns_Unhandled_For_Unsupported_Type() + public async Task ConvertAsync_BinaryDataArray_ReturnsSuccess() { - var context = new TestConverterContext(typeof(string), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - [Fact] - public async Task ConvertAsync_SourceAsObject_BinaryDataCollectible_ReturnsUnhandled() - { - var context = new TestConverterContext(typeof(BinaryData[]), new object()); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_BinaryDataCollectible_Returns_Success() - { - var context = new TestConverterContext(typeof(BinaryData[]), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); + var context = new TestConverterContext(typeof(BinaryData[]), EventGridTestHelper.GetEventGridJsonDataArray()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -72,19 +75,9 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_BinaryDataCollectible_Returns_Unhandled_For_Unsupported_Type() + public async Task ConvertAsync_BinaryDataArray_SingleElement_ReturnsSuccess() { - var context = new TestConverterContext(typeof(string), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_SingleElement_Returns_Success() - { - var context = new TestConverterContext(typeof(BinaryData[]), "[{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}]"); + var context = new TestConverterContext(typeof(BinaryData[]), $"[{EventGridTestHelper.GetEventGridJsonData()}]"); var conversionResult = await _eventGridConverter.ConvertAsync(context); diff --git a/test/Worker.Extensions.Tests/EventGrid/EventGridCloudEventConverterTests.cs b/test/Worker.Extensions.Tests/EventGrid/EventGridCloudEventConverterTests.cs index d3e8cf3c..b0f944c7 100644 --- a/test/Worker.Extensions.Tests/EventGrid/EventGridCloudEventConverterTests.cs +++ b/test/Worker.Extensions.Tests/EventGrid/EventGridCloudEventConverterTests.cs @@ -1,10 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; using System.Threading.Tasks; using Azure.Messaging; -using Azure.Messaging.EventGrid; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Converters; using Microsoft.Azure.Functions.Worker.Extensions.EventGrid.TypeConverters; @@ -21,24 +19,45 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid public EventGridCloudEventConverterTests() { var host = new HostBuilder().ConfigureFunctionsWorkerDefaults((WorkerOptions options) => { }).Build(); - _eventGridConverter = new EventGridCloudEventConverter(); } [Fact] - public async Task ConvertAsync_SourceAsObject_ReturnsFailed() + public async Task ConvertAsync_Source_IsNotAString_ReturnsFailed() { var context = new TestConverterContext(typeof(CloudEvent), new object()); var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Equal("Context source must be a non-null string", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_UnsupportedTargetType_ReturnsFailed() + { + var context = new TestConverterContext(typeof(string), ""); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); } [Fact] - public async Task ConvertAsync_Returns_Success() + public async Task ConvertAsync_InvalidJson_ThrowsJsonException_ReturnsFailed() { - var context = new TestConverterContext(typeof(CloudEvent), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); + var context = new TestConverterContext(typeof(CloudEvent[]), @"{""invalid"" :json""}"); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Contains("Binding parameters to complex objects uses JSON serialization", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_SingleCloudEvent_ReturnsSuccess() + { + var context = new TestConverterContext(typeof(CloudEvent), EventGridTestHelper.GetEventGridJsonData()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -46,30 +65,11 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid Assert.True(conversionResult.Value is CloudEvent); } - [Fact] - public async Task ConvertAsync_Returns_Unhandled_For_Unsupported_Type() - { - var context = new TestConverterContext(typeof(string), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } [Fact] - public async Task ConvertAsync_SourceAsObject_CloudEventCollectible_ReturnsFailed() + public async Task ConvertAsync_CloudEventArray_ReturnsSuccess() { - var context = new TestConverterContext(typeof(CloudEvent[]), new object()); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_CloudEventCollectible_Returns_Success() - { - var context = new TestConverterContext(typeof(CloudEvent[]), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); + var context = new TestConverterContext(typeof(CloudEvent[]), EventGridTestHelper.GetEventGridJsonDataArray()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -79,19 +79,9 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_CloudEventCollectible_Returns_Unhandled_For_Unsupported_Type() + public async Task ConvertAsync_CloudEventArray_SingleElement_ReturnsSuccess() { - var context = new TestConverterContext(typeof(string), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_SingleElement_Returns_Success() - { - var context = new TestConverterContext(typeof(CloudEvent[]), "[{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}]"); + var context = new TestConverterContext(typeof(CloudEvent[]), $"[{EventGridTestHelper.GetEventGridJsonData()}]"); var conversionResult = await _eventGridConverter.ConvertAsync(context); diff --git a/test/Worker.Extensions.Tests/EventGrid/EventGridEventConverterTests.cs b/test/Worker.Extensions.Tests/EventGrid/EventGridEventConverterTests.cs index aa1e5d47..05405972 100644 --- a/test/Worker.Extensions.Tests/EventGrid/EventGridEventConverterTests.cs +++ b/test/Worker.Extensions.Tests/EventGrid/EventGridEventConverterTests.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; using System.Threading.Tasks; using Azure.Messaging.EventGrid; using Microsoft.Azure.Functions.Worker; @@ -25,19 +24,52 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_SourceAsObject_ReturnsUnhandled() + public async Task ConvertAsync_Source_IsNotAString_ReturnsUnhandled() { var context = new TestConverterContext(typeof(EventGridEvent), new object()); var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Equal("Context source must be a non-null string", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_UnsupportedTargetType_ReturnsFailed() + { + var context = new TestConverterContext(typeof(string), ""); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); } [Fact] - public async Task ConvertAsync_Returns_Success() + public async Task ConvertAsync_InvalidJson_ThrowsJsonException_ReturnsFailed() { - var context = new TestConverterContext(typeof(EventGridEvent), "{\"id\":\"'1\",\"topic\":\"hello\",\"subject\":\"yoursubject\",\"eventType\":\"yourEventType\",\"eventTime\":\"2018-01-23T17:02:19.6069787Z\",\"data\":\"test\",\"dataVersion\":\"test\"}"); + var context = new TestConverterContext(typeof(EventGridEvent), @"{""invalid"" :json""}"); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Contains("Binding parameters to complex objects uses JSON serialization", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_InvalidData_Throws_ReturnsFailed() + { + var context = new TestConverterContext(typeof(EventGridEvent), EventGridTestHelper.GetEventGridJsonData()); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Equal("Value cannot be null. (Parameter 'EventType')", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_SingleEventGridEvent_ReturnsSuccess() + { + var context = new TestConverterContext(typeof(EventGridEvent), EventGridTestHelper.GetEventGridEventJsonData()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -46,39 +78,9 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_Returns_Unhandled_For_Unsupported_Type() + public async Task ConvertAsync_EventGridArray_ReturnsSuccess() { - var context = new TestConverterContext(typeof(string), "{\"id\":\"'1\",\"topic\":\"hello\",\"subject\":\"yoursubject\",\"eventType\":\"yourEventType\",\"eventTime\":\"2018-01-23T17:02:19.6069787Z\",\"data\":\"test\",\"dataVersion\":\"test\"}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_Returns_Failed_Bad_Source() - { - var context = new TestConverterContext(typeof(EventGridEvent), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync__EventGridCollectible_SourceAsObject_ReturnsUnhandled() - { - var context = new TestConverterContext(typeof(EventGridEvent[]), new object()); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync__EventGridCollectible_Returns_Success() - { - var context = new TestConverterContext(typeof(EventGridEvent[]), "[{\"id\":\"'1\",\"topic\":\"hello\",\"subject\":\"yoursubject\",\"eventType\":\"yourEventType\",\"eventTime\":\"2018-01-23T17:02:19.6069787Z\",\"data\":\"test\",\"dataVersion\":\"test\"},{\"id\":\"'1\",\"topic\":\"hello\",\"subject\":\"yoursubject\",\"eventType\":\"yourEventType\",\"eventTime\":\"2018-01-23T17:02:19.6069787Z\",\"data\":\"lmao\",\"dataVersion\":\"test\"}]"); + var context = new TestConverterContext(typeof(EventGridEvent[]), EventGridTestHelper.GetEventGridEventJsonDataArray()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -86,25 +88,5 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid Assert.True(conversionResult.Value is EventGridEvent[]); Assert.Equal(2, ((EventGridEvent[])conversionResult.Value).Length); } - - [Fact] - public async Task ConvertAsync_EventGridCollectible_Returns_Unhandled_For_Unsupported_Type() - { - var context = new TestConverterContext(typeof(string), "{\"id\":\"'1\",\"topic\":\"hello\",\"subject\":\"yoursubject\",\"eventType\":\"yourEventType\",\"eventTime\":\"2018-01-23T17:02:19.6069787Z\",\"data\":\"test\",\"dataVersion\":\"test\"}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync__EventGridCollectible_Returns_Failed_Bad_Source() - { - var context = new TestConverterContext(typeof(EventGridEvent[]), "{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, conversionResult.Status); - } } } diff --git a/test/Worker.Extensions.Tests/EventGrid/EventGridStringArrayConverterTests.cs b/test/Worker.Extensions.Tests/EventGrid/EventGridStringArrayConverterTests.cs index 541d7647..491f5ee6 100644 --- a/test/Worker.Extensions.Tests/EventGrid/EventGridStringArrayConverterTests.cs +++ b/test/Worker.Extensions.Tests/EventGrid/EventGridStringArrayConverterTests.cs @@ -19,19 +19,41 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_SourceAsObject_ReturnsUnhandled() + public async Task ConvertAsync_Source_IsNotAString_ReturnsUnhandled() { var context = new TestConverterContext(typeof(string[]), new object()); var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Equal("Context source must be a non-null string", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_UnsupportedTargetType_ReturnsFailed() + { + var context = new TestConverterContext(typeof(byte[]), ""); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); } [Fact] - public async Task ConvertAsync_Returns_Success() + public async Task ConvertAsync_InvalidJson_ThrowsJsonException_ReturnsFailed() { - var context = new TestConverterContext(typeof(string[]), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); + var context = new TestConverterContext(typeof(string[]), @"{""invalid"" :json""}"); + + var conversionResult = await _eventGridConverter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, conversionResult.Status); + Assert.Contains("Binding parameters to complex objects uses JSON serialization", conversionResult.Error.Message); + } + + [Fact] + public async Task ConvertAsync_StringArray_ReturnsSuccess() + { + var context = new TestConverterContext(typeof(string[]), EventGridTestHelper.GetEventGridJsonDataArray()); var conversionResult = await _eventGridConverter.ConvertAsync(context); @@ -41,19 +63,9 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.EventGrid } [Fact] - public async Task ConvertAsync_Returns_Unhandled_For_Unsupported_Type() + public async Task ConvertAsync_StringArray_SingleElement_Returns_Success() { - var context = new TestConverterContext(typeof(string), "[{\"specversion\":\"1.0\",\"id\":\"b85d631a-101e-005a-02f2-cee7aa06f148\",\"type\":\"zohan.music.request\",\"source\":\"https://zohan.dev/music/\",\"subject\":\"zohan/music/requests/4322\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"Gerardo\",\"song\":\"Rico Suave\"}},{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"life is very lit\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"life is lit\"}}]"); - - var conversionResult = await _eventGridConverter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Unhandled, conversionResult.Status); - } - - [Fact] - public async Task ConvertAsync_SingleElement_Returns_Success() - { - var context = new TestConverterContext(typeof(string[]), "[{\"specversion\":\"1.0\",\"id\":\"2947780a-356b-c5a5-feb4-f5261fb2f155\",\"type\":\"test\",\"source\":\"moo\",\"subject\":\"lol test\",\"time\":\"2020-09-14T10:00:00Z\",\"data\":{\"artist\":\"wooo\",\"song\":\"some song\"}}]"); + var context = new TestConverterContext(typeof(string[]), $"[{EventGridTestHelper.GetEventGridJsonData()}]"); var conversionResult = await _eventGridConverter.ConvertAsync(context); diff --git a/test/Worker.Extensions.Tests/EventGrid/EventGridTestHelper.cs b/test/Worker.Extensions.Tests/EventGrid/EventGridTestHelper.cs new file mode 100644 index 00000000..9ab8fa60 --- /dev/null +++ b/test/Worker.Extensions.Tests/EventGrid/EventGridTestHelper.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using Google.Protobuf; +using Microsoft.Azure.Functions.Worker.Grpc.Messages; + +namespace Microsoft.Azure.Functions.Worker.Extensions.Tests +{ + internal static class EventGridTestHelper + { + public static string GetEventGridJsonData(string id = "2947780a-356b-c5a5-feb4-f5261fb2f155", string song = "Vampire") + { + return $@"{{ + ""specversion"" : ""1.0"", + ""id"" : ""{id}"", + ""type"" : ""UnitTestData"", + ""source"" : ""UnitTest"", + ""subject"" : ""Song"", + ""time"" : ""2020-09-14T10:00:00Z"", + ""data"" : {{ ""artist"":""Olivia Rodrigo"",""song"":""{song}"" }} + }}"; + } + + public static string GetEventGridJsonDataArray() + { + return $@"[ + {GetEventGridJsonData("2947780a-356b-c5a5-feb4-f5261fb2f155", "Driver's License")}, + {GetEventGridJsonData("b85d631a-101e-005a-02f2-cee7aa06f148", "Deja Vu")} + ]"; + } + + public static string GetEventGridEventJsonData(string id = "2947780a-356b-c5a5-feb4-f5261fb2f155", string song = "Vampire") + { + return $@"{{ + ""id"" : ""{id}"", + ""topic"" : ""UnitTestData"", + ""subject"" : ""Song"", + ""eventType"" : ""MyEvent"", + ""eventTime"" : ""2020-09-14T10:00:00Z"", + ""data"" : {{ ""artist"":""Olivia Rodrigo"",""song"":""{song}"" }}, + ""dataVersion"" : ""1.0"" + }}"; + } + + public static string GetEventGridEventJsonDataArray() + { + return $@"[ + {GetEventGridEventJsonData("2947780a-356b-c5a5-feb4-f5261fb2f155", "Driver's License")}, + {GetEventGridEventJsonData("b85d631a-101e-005a-02f2-cee7aa06f148", "Deja Vu")} + ]"; + } + } +} \ No newline at end of file