Skip to content

Commit

Permalink
Implement initial support for SDK-type binding reference type (#1107, #…
Browse files Browse the repository at this point in the history
  • Loading branch information
liliankasem committed Jul 11, 2023
1 parent d54452e commit 05ee804
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 0 deletions.
7 changes: 7 additions & 0 deletions DotNetWorker.sln
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.Http.AspN
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.SignalRService.Tests", "test\Worker.Extensions.SignalRService.Tests\Worker.Extensions.SignalRService.Tests.csproj", "{286F9EE3-00AE-4EFA-BFD8-A2E58BC809D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkerExtensionTests", "test\WorkerExtensionTests\WorkerExtensionTests.csproj", "{17BDCE12-6964-4B87-B2AC-68CE270A3E9A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -320,6 +322,10 @@ Global
{286F9EE3-00AE-4EFA-BFD8-A2E58BC809D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{286F9EE3-00AE-4EFA-BFD8-A2E58BC809D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{286F9EE3-00AE-4EFA-BFD8-A2E58BC809D2}.Release|Any CPU.Build.0 = Release|Any CPU
{17BDCE12-6964-4B87-B2AC-68CE270A3E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17BDCE12-6964-4B87-B2AC-68CE270A3E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17BDCE12-6964-4B87-B2AC-68CE270A3E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17BDCE12-6964-4B87-B2AC-68CE270A3E9A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -376,6 +382,7 @@ Global
{B13C9E5F-0E4B-413E-90AE-20B84B100364} = {AA4D318D-101B-49E7-A4EC-B34165AEDB33}
{1F6B7CF6-0CC8-4C7F-825F-74B0BEC1CF0A} = {A7B4FF1E-3DF7-4F28-9333-D0961CDDF702}
{286F9EE3-00AE-4EFA-BFD8-A2E58BC809D2} = {FD7243E4-BF18-43F8-8744-BA1D17ACF378}
{17BDCE12-6964-4B87-B2AC-68CE270A3E9A} = {FD7243E4-BF18-43F8-8744-BA1D17ACF378}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {497D2ED4-A13E-4BCA-8D29-F30CA7D0EA4A}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;

namespace Microsoft.Azure.Functions.Worker.Extensions.Abstractions
{
/// <summary>
/// Specifies if a binding attribute supports deferred binding when generating function metadata.
/// This is to be used on input, output or trigger attributes that support deferred binding.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SupportsDeferredBindingAttribute : Attribute
{
}
}
16 changes: 16 additions & 0 deletions src/DotNetWorker.Core/CollectionModelBindingData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace Microsoft.Azure.Functions.Worker.Core
{
/// <summary>
/// A representation of Collection of Microsoft.Azure.WebJobs.ParameterBindingData
/// </summary>
public abstract class CollectionModelBindingData
{
/// <summary>
/// Gets the array of ModelBindingData
/// </summary>
public abstract ModelBindingData[] ModelBindingDataArray { get; }
}
}
33 changes: 33 additions & 0 deletions src/DotNetWorker.Core/ModelBindingData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;

namespace Microsoft.Azure.Functions.Worker.Core
{
/// <summary>
/// A representation of a Microsoft.Azure.WebJobs.ParameterBindingData
/// </summary>
public abstract class ModelBindingData
{
/// <summary>
/// Gets the version of the binding data content
/// </summary>
public abstract string Version { get; }

/// <summary>
/// Gets the extension source of the binding data i.e CosmosDB, AzureStorageBlobs
/// </summary>
public abstract string Source { get; }

/// <summary>
/// Gets the binding data content
/// </summary>
public abstract BinaryData Content { get; }

/// <summary>
/// Gets the content type of the binding data content i.e. "application/json"
/// </summary>
public abstract string ContentType { get; }
}
}
2 changes: 2 additions & 0 deletions src/DotNetWorker.Grpc/Features/GrpcFunctionBindingsFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public void SetOutputBinding(string name, object value)
TypedData.DataOneofCase.CollectionString => typedData.CollectionString.String,
TypedData.DataOneofCase.CollectionDouble => typedData.CollectionDouble.Double,
TypedData.DataOneofCase.CollectionSint64 => typedData.CollectionSint64.Sint64,
TypedData.DataOneofCase.ModelBindingData => new GrpcModelBindingData(typedData.ModelBindingData),
TypedData.DataOneofCase.CollectionModelBindingData => new GrpcCollectionModelBindingData(typedData.CollectionModelBindingData),
_ => throw new NotSupportedException($"{typedData.DataCase} is not supported."),
};
}
Expand Down
19 changes: 19 additions & 0 deletions src/DotNetWorker.Grpc/GrpcCollectionModelBindingData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.Linq;

namespace Microsoft.Azure.Functions.Worker.Grpc.Messages
{
internal partial class GrpcCollectionModelBindingData : Microsoft.Azure.Functions.Worker.Core.CollectionModelBindingData
{
public GrpcCollectionModelBindingData(CollectionModelBindingData modelBindingDataArray)
{
ModelBindingDataArray = modelBindingDataArray.ModelBindingData
.Select(p => new GrpcModelBindingData(p)).ToArray();
}

public override Core.ModelBindingData[] ModelBindingDataArray { get; }
}
}
26 changes: 26 additions & 0 deletions src/DotNetWorker.Grpc/GrpcModelBindingData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;

namespace Microsoft.Azure.Functions.Worker.Grpc.Messages
{
internal partial class GrpcModelBindingData : Microsoft.Azure.Functions.Worker.Core.ModelBindingData
{
private readonly ModelBindingData _modelBindingData;

public GrpcModelBindingData(ModelBindingData modelBindingData)
{
_modelBindingData = modelBindingData;
Content = BinaryData.FromBytes(_modelBindingData.Content.ToByteArray());
}

public override string Version => _modelBindingData.Version;

public override string Source => _modelBindingData.Source;

public override BinaryData Content { get; }

public override string ContentType => _modelBindingData.ContentType;
}
}
1 change: 1 addition & 0 deletions src/DotNetWorker.Grpc/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
[assembly: InternalsVisibleTo("Microsoft.Azure.Functions.Worker.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001005148be37ac1d9f58bd40a2e472c9d380d635b6048278f7d47480b08c928858f0f7fe17a6e4ce98da0e7a7f0b8c308aecd9e9b02d7e9680a5b5b75ac7773cec096fbbc64aebd429e77cb5f89a569a79b28e9c76426783f624b6b70327eb37341eb498a2c3918af97c4860db6cdca4732787150841e395a29cfacb959c1fd971c1")]
[assembly: InternalsVisibleTo("Microsoft.Azure.Functions.Worker, PublicKey=00240000048000009400000006020000002400005253413100040000010001005148be37ac1d9f58bd40a2e472c9d380d635b6048278f7d47480b08c928858f0f7fe17a6e4ce98da0e7a7f0b8c308aecd9e9b02d7e9680a5b5b75ac7773cec096fbbc64aebd429e77cb5f89a569a79b28e9c76426783f624b6b70327eb37341eb498a2c3918af97c4860db6cdca4732787150841e395a29cfacb959c1fd971c1")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Microsoft.Azure.Functions.WorkerExtension.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001005148be37ac1d9f58bd40a2e472c9d380d635b6048278f7d47480b08c928858f0f7fe17a6e4ce98da0e7a7f0b8c308aecd9e9b02d7e9680a5b5b75ac7773cec096fbbc64aebd429e77cb5f89a569a79b28e9c76426783f624b6b70327eb37341eb498a2c3918af97c4860db6cdca4732787150841e395a29cfacb959c1fd971c1")]
2 changes: 2 additions & 0 deletions src/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ pr:
include:
- src/
- test/DotNetWorkerTests
- test/WorkerExtensionTests
- test/E2ETests
- test/TestUtility
- sdk/
- samples/FunctionApp
- samples/WorkerBindingSamples
- tools/

jobs:
Expand Down
151 changes: 151 additions & 0 deletions test/DotNetWorkerTests/GrpcFunctionBindingsFeatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,156 @@ public GrpcFunctionBindingsFeatureTests()
.Setup(m => m.Create())
.Returns(new InvocationFeatures(Enumerable.Empty<IInvocationFeatureProvider>()));
}

[Fact]
public void BindFunctionTriggerAsync_Populates_ModelBindingData()
{
// Arrange
var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7";
var request = TestUtility.CreateInvocationRequest(invocationId);
request.TriggerMetadata.Add("myBlob", new TypedData() { ModelBindingData = new ModelBindingData() {
Version = "1.1.1",
Source = "blob",
Content = ByteString.CopyFromUtf8("stringText")} });

IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create();
var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token);

// Act
var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object);

// Assert
Assert.Single(functionBindingsFeature.TriggerMetadata);

functionBindingsFeature.TriggerMetadata.TryGetValue("myBlob", out object bindingData);
Assert.True(bindingData.GetType() == typeof(GrpcModelBindingData));
var grpcModelBindingData = (GrpcModelBindingData)bindingData;

Assert.True(grpcModelBindingData.Version == "1.1.1");
Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData));
}

[Fact]
public void BindFunctionInputAsync_Populates_ModelBindingData()
{
// Arrange
var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7";
var request = TestUtility.CreateInvocationRequest(invocationId);
request.InputData.Insert(0, new ParameterBinding()
{
Name = "myBlob",
Data = new TypedData()
{
ModelBindingData = new ModelBindingData()
{
Version = "1.1.1",
Source = "blob",
Content = ByteString.CopyFromUtf8("stringText")
}
}
});

IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create();
var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token);

// Act
var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object);

// Assert
Assert.Single(functionBindingsFeature.InputData);

functionBindingsFeature.InputData.TryGetValue("myBlob", out object bindingData);
Assert.True(bindingData.GetType() == typeof(GrpcModelBindingData));
var grpcModelBindingData = (GrpcModelBindingData)bindingData;

Assert.True(grpcModelBindingData.Version == "1.1.1");
Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData));
}

[Fact]
public void BindFunctionTriggerAsync_Populates_CollectionModelBindingData()
{
// Arrange
var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7";
var request = TestUtility.CreateInvocationRequest(invocationId);

var modelBindingData = new ModelBindingData()
{
Version = "1.1.1",
Source = "blob",
Content = ByteString.CopyFromUtf8("stringText")
};

var collectionModelBindingData = new CollectionModelBindingData();
collectionModelBindingData.ModelBindingData.Add(modelBindingData);

request.TriggerMetadata.Add("myBlob", new TypedData()
{
CollectionModelBindingData = collectionModelBindingData
});

IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create();
var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token);

// Act
var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object);

// Assert
Assert.Single(functionBindingsFeature.TriggerMetadata);

functionBindingsFeature.TriggerMetadata.TryGetValue("myBlob", out object bindingData);
Assert.True(bindingData.GetType() == typeof(GrpcCollectionModelBindingData));
var grpcCollectionModelBindingData = (GrpcCollectionModelBindingData)bindingData;

Assert.True(grpcCollectionModelBindingData.ModelBindingDataArray.Count() == 1);
var grpcModelBindingData = grpcCollectionModelBindingData.ModelBindingDataArray[0];
Assert.True(grpcModelBindingData.Version == "1.1.1");
Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData));
}

[Fact]
public void BindFunctionInputAsync_Populates_CollectionModelBindingData()
{
// Arrange
var invocationId = "5fb3a9b4-0b38-450a-9d46-35946e7edea7";
var request = TestUtility.CreateInvocationRequest(invocationId);

var modelBindingData = new ModelBindingData()
{
Version = "1.1.1",
Source = "blob",
Content = ByteString.CopyFromUtf8("stringText")
};

var collectionModelBindingData = new CollectionModelBindingData();
collectionModelBindingData.ModelBindingData.Add(modelBindingData);

request.InputData.Insert(0, new ParameterBinding()
{
Name = "myBlob",
Data = new TypedData()
{
CollectionModelBindingData = collectionModelBindingData
}
});

IInvocationFeatures invocationFeatures = _mockInvocationFeaturesFactory.Object.Create();
var context = _mockApplication.Object.CreateContext(invocationFeatures, new CancellationTokenSource().Token);

// Act
var functionBindingsFeature = new GrpcFunctionBindingsFeature(context, request, _mockOutputBindingsInfoProvider.Object);

// Assert
Assert.Single(functionBindingsFeature.InputData);

functionBindingsFeature.InputData.TryGetValue("myBlob", out object bindingData);
Assert.True(bindingData.GetType() == typeof(GrpcCollectionModelBindingData));
var grpcCollectionModelBindingData = (GrpcCollectionModelBindingData)bindingData;

Assert.True(grpcCollectionModelBindingData.ModelBindingDataArray.Count() == 1);
var grpcModelBindingData = grpcCollectionModelBindingData.ModelBindingDataArray[0];
Assert.True(grpcModelBindingData.Version == "1.1.1");
Assert.True(grpcModelBindingData.Content.GetType() == typeof(BinaryData));
}
}
}
3 changes: 3 additions & 0 deletions test/DotNetWorkerTests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System.Runtime.CompilerServices;
using Xunit;

[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: InternalsVisibleTo("Microsoft.Azure.Functions.WorkerExtension.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001005148be37ac1d9f58bd40a2e472c9d380d635b6048278f7d47480b08c928858f0f7fe17a6e4ce98da0e7a7f0b8c308aecd9e9b02d7e9680a5b5b75ac7773cec096fbbc64aebd429e77cb5f89a569a79b28e9c76426783f624b6b70327eb37341eb498a2c3918af97c4860db6cdca4732787150841e395a29cfacb959c1fd971c1")]

29 changes: 29 additions & 0 deletions test/WorkerExtensionTests/WorkerExtensionTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
<AssemblyName>Microsoft.Azure.Functions.WorkerExtension.Tests</AssemblyName>
<RootNamespace>Microsoft.Azure.Functions.WorkerExtension.Tests</RootNamespace>
<SignAssembly>true</SignAssembly>
<LangVersion>preview</LangVersion>
<AssemblyOriginatorKeyFile>..\..\key.snk</AssemblyOriginatorKeyFile>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\extensions\Worker.Extensions.Storage\src\Worker.Extensions.Storage.csproj" />
<ProjectReference Include="..\DotNetWorkerTests\DotNetWorkerTests.csproj" />
</ItemGroup>

</Project>

0 comments on commit 05ee804

Please sign in to comment.