diff --git a/extensions/Worker.Extensions.Kafka/release_notes.md b/extensions/Worker.Extensions.Kafka/release_notes.md index e73c591ab..7a6d56c7a 100644 --- a/extensions/Worker.Extensions.Kafka/release_notes.md +++ b/extensions/Worker.Extensions.Kafka/release_notes.md @@ -4,6 +4,6 @@ - My change description (#PR/#issue) --> -### Microsoft.Azure.Functions.Worker.Extensions.Kafka +### Microsoft.Azure.Functions.Worker.Extensions.Kafka 3.10.1 -- +- Add `DefaultValue` attribute to Kafka Trigger's `IsBatched` prop to signal default cardinality value to source generators (#2139) diff --git a/extensions/Worker.Extensions.Kafka/src/KafkaTriggerAttribute.cs b/extensions/Worker.Extensions.Kafka/src/KafkaTriggerAttribute.cs index 6708f7593..bc79ca515 100644 --- a/extensions/Worker.Extensions.Kafka/src/KafkaTriggerAttribute.cs +++ b/extensions/Worker.Extensions.Kafka/src/KafkaTriggerAttribute.cs @@ -130,6 +130,7 @@ public KafkaTriggerAttribute(string brokerList, string topic) /// /// Gets or sets the configuration to enable batch processing of events. Default value is "false". /// + [DefaultValue(false)] public bool IsBatched { get => _isBatched; diff --git a/extensions/Worker.Extensions.Kafka/src/Worker.Extensions.Kafka.csproj b/extensions/Worker.Extensions.Kafka/src/Worker.Extensions.Kafka.csproj index bbf3f596c..d72dba8fe 100644 --- a/extensions/Worker.Extensions.Kafka/src/Worker.Extensions.Kafka.csproj +++ b/extensions/Worker.Extensions.Kafka/src/Worker.Extensions.Kafka.csproj @@ -5,7 +5,7 @@ Kafka extensions for .NET isolated functions - 3.10.0 + 3.10.1 false diff --git a/test/Sdk.Generator.Tests/FunctionMetadataProviderGeneratorTests/KafkaTests.cs b/test/Sdk.Generator.Tests/FunctionMetadataProviderGeneratorTests/KafkaTests.cs new file mode 100644 index 000000000..e8a35e556 --- /dev/null +++ b/test/Sdk.Generator.Tests/FunctionMetadataProviderGeneratorTests/KafkaTests.cs @@ -0,0 +1,149 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.Azure.Functions.Worker.Sdk.Generators; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace Microsoft.Azure.Functions.SdkGeneratorTests +{ + public partial class FunctionMetadataProviderGeneratorTests + { + public class KafkaTests + { + private readonly Assembly[] _referencedExtensionAssemblies; + + public KafkaTests() + { + // load all extensions used in tests (match extensions tested on E2E app? Or include ALL extensions?) + var abstractionsExtension = Assembly.LoadFrom("Microsoft.Azure.Functions.Worker.Extensions.Abstractions.dll"); + var hostingExtension = Assembly.LoadFrom("Microsoft.Extensions.Hosting.dll"); + var diExtension = Assembly.LoadFrom("Microsoft.Extensions.DependencyInjection.dll"); + var hostingAbExtension = Assembly.LoadFrom("Microsoft.Extensions.Hosting.Abstractions.dll"); + var diAbExtension = Assembly.LoadFrom("Microsoft.Extensions.DependencyInjection.Abstractions.dll"); + var kafkaExtension = Assembly.LoadFrom("Microsoft.Azure.Functions.Worker.Extensions.Kafka.dll"); + + _referencedExtensionAssemblies = new[] + { + abstractionsExtension, + hostingExtension, + hostingAbExtension, + diExtension, + diAbExtension, + kafkaExtension + }; + } + + [Theory] + [InlineData(LanguageVersion.CSharp7_3)] + [InlineData(LanguageVersion.CSharp8)] + [InlineData(LanguageVersion.CSharp9)] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + [InlineData(LanguageVersion.Latest)] + public async Task GenerateSimpleKafkaTriggerTest(LanguageVersion languageVersion) + { + string inputCode = """ + using System; + using Microsoft.Azure.Functions.Worker; + + namespace FunctionApp + { + public static class KafkaFunction + { + [Function(nameof(KafkaFunction))] + [FixedDelayRetry(5, "00:00:10")] + [KafkaOutput("LocalBroker", "stringTopicTenPartitions")] + public static string Run([KafkaTrigger("LocalBroker", "stringTopicTenPartitions", + ConsumerGroup = "$Default", AuthenticationMode = BrokerAuthenticationMode.Plain)] string input, + FunctionContext context) + { + throw new NotImplementedException(); + } + } + } + """; + + string expectedGeneratedFileName = $"GeneratedFunctionMetadataProvider.g.cs"; + string expectedOutput = """ + // + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Text.Json; + using System.Threading.Tasks; + using Microsoft.Azure.Functions.Worker; + using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Hosting; + + namespace TestProject + { + /// + /// Custom implementation that returns function metadata definitions for the current worker."/> + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class GeneratedFunctionMetadataProvider : IFunctionMetadataProvider + { + /// + public Task> GetFunctionMetadataAsync(string directory) + { + var metadataList = new List(); + var Function0RawBindings = new List(); + Function0RawBindings.Add(@"{""name"":""$return"",""type"":""kafka"",""direction"":""Out"",""brokerList"":""LocalBroker"",""topic"":""stringTopicTenPartitions""}"); + Function0RawBindings.Add(@"{""name"":""input"",""type"":""kafkaTrigger"",""direction"":""In"",""brokerList"":""LocalBroker"",""topic"":""stringTopicTenPartitions"",""consumerGroup"":""$Default"",""authenticationMode"":""Plain"",""cardinality"":""One"",""dataType"":""String""}"); + + var Function0 = new DefaultFunctionMetadata + { + Language = "dotnet-isolated", + Name = "KafkaFunction", + EntryPoint = "FunctionApp.KafkaFunction.Run", + RawBindings = Function0RawBindings, + Retry = new DefaultRetryOptions + { + MaxRetryCount = 5, + DelayInterval = TimeSpan.Parse("00:00:10") + }, + ScriptFile = "TestProject.dll" + }; + metadataList.Add(Function0); + + return Task.FromResult(metadataList.ToImmutableArray()); + } + } + + /// + /// Extension methods to enable registration of the custom implementation generated for the current worker. + /// + public static class WorkerHostBuilderFunctionMetadataProviderExtension + { + /// + /// Adds the GeneratedFunctionMetadataProvider to the service collection. + /// During initialization, the worker will return generated function metadata instead of relying on the Azure Functions host for function indexing. + /// + public static IHostBuilder ConfigureGeneratedFunctionMetadataProvider(this IHostBuilder builder) + { + builder.ConfigureServices(s => + { + s.AddSingleton(); + }); + return builder; + } + } + } + """; + + await TestHelpers.RunTestAsync( + _referencedExtensionAssemblies, + inputCode, + expectedGeneratedFileName, + expectedOutput, + languageVersion: languageVersion); + } + } + } +} diff --git a/test/Sdk.Generator.Tests/Sdk.Generator.Tests.csproj b/test/Sdk.Generator.Tests/Sdk.Generator.Tests.csproj index 8feb33d9a..340bba70c 100644 --- a/test/Sdk.Generator.Tests/Sdk.Generator.Tests.csproj +++ b/test/Sdk.Generator.Tests/Sdk.Generator.Tests.csproj @@ -46,7 +46,8 @@ + - + \ No newline at end of file