Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
liliankasem committed Nov 14, 2022
1 parent d3fdaad commit f074597
Show file tree
Hide file tree
Showing 19 changed files with 653 additions and 35 deletions.
27 changes: 27 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,24 @@ jobs:
inputs:
command: ci
workingDir: sample/CustomHandlerRetry
- task: PowerShell@2
# Temporary script to install required nuget packages for the dotnet isolated sample project
# that is being used for E2E tests. This script should be deleted and removed from the AzDO
# pipeline when these packages are published to nuget.
# Issue tracking removal of this task: https://github.com/Azure/azure-functions-host/issues/8910
displayName: 'Install MyGet nuget packages'
inputs:
targetType: 'inline'
script: |
dotnet add package Microsoft.Azure.WebJobs --version 3.0.36 --source https://www.myget.org/F/azure-appservice-staging/api/v3/index.json
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage --version 5.0.2-preview1-20221104.9 --source https://www.myget.org/F/azure-appservice/api/v3/index.json
- task: DotNetCoreCLI@2
displayName: 'Build dotnet isolated sample app'
inputs:
command: 'build'
projects: |
**\DotNetIsolated.csproj
- task: AzureKeyVault@1
inputs:
# Note: This is actually a Service Connection in DevOps, not an Azure subscription name
Expand Down Expand Up @@ -526,6 +544,15 @@ jobs:
arguments: '--filter "Group=SamplesEndToEndTests" --no-build'
projects: |
**\WebJobs.Script.Tests.Integration.csproj
- task: DotNetCoreCLI@2
displayName: "SDK-type binding end to end tests"
condition: succeededOrFailed()
inputs:
command: 'test'
testRunTitle: "SDK-type binding end to end tests"
arguments: '--filter "Group=SdkTypeBindingEndToEnd" --no-build'
projects: |
**\WebJobs.Script.Tests.Integration.csproj
- task: DotNetCoreCLI@2
displayName: "Drain mode end to end tests"
condition: succeededOrFailed()
Expand Down
77 changes: 77 additions & 0 deletions sample/DotNetIsolated/Blob/BlobInputBindingSamples.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
public class BlobInputBindingSamples
{
private readonly ILogger<BlobInputBindingSamples> _logger;

public BlobInputBindingSamples(ILogger<BlobInputBindingSamples> logger)
{
_logger = logger;
}

[Function(nameof(BlobInputClientFunction))]
public async Task<HttpResponseData> BlobInputClientFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
[BlobInput("test-input-sample/sample1.txt", Connection = "AzureWebJobsStorage")] BlobClient client)
{
var response = req.CreateResponse(HttpStatusCode.OK);
var downloadResult = await client.DownloadContentAsync();
await response.Body.WriteAsync(downloadResult.Value.Content);
return response;
}

[Function(nameof(BlobInputStreamFunction))]
public async Task<HttpResponseData> BlobInputStreamFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
[BlobInput("test-input-sample/sample1.txt", Connection = "AzureWebJobsStorage")] Stream stream)
{
var response = req.CreateResponse(HttpStatusCode.OK);
using var blobStreamReader = new StreamReader(stream);
await response.WriteStringAsync(blobStreamReader.ReadToEnd());
return response;
}

[Function(nameof(BlobInputByteArrayFunction))]
public async Task<HttpResponseData> BlobInputByteArrayFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
[BlobInput("test-input-sample/sample1.txt", Connection = "AzureWebJobsStorage")] Byte[] data)
{
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(Encoding.Default.GetString(data));
return response;
}

[Function(nameof(BlobInputStringFunction))]
public async Task<HttpResponseData> BlobInputStringFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
[BlobInput("test-input-sample/sample1.txt", Connection = "AzureWebJobsStorage")] string data)
{
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(data);
return response;
}

[Function(nameof(BlobInputBookFunction))]
public async Task<HttpResponseData> BlobInputBookFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
[BlobInput("test-input-sample/book.json", Connection = "AzureWebJobsStorage")] Book data)
{
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(data.Name);
return response;
}
}
}
64 changes: 64 additions & 0 deletions sample/DotNetIsolated/Blob/BlobTriggerBindingSamples.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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.IO;
using System.Text;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
public static class BlobTriggerBindingSamples
{
[Function(nameof(BlobClientFunction))]
public static async Task BlobClientFunction(
[BlobTrigger("test-input-client/{name}", Connection = "AzureWebJobsStorage")] BlobClient client,
FunctionContext context)
{
var logger = context.GetLogger(nameof(BlobClientFunction));
var downloadResult = await client.DownloadContentAsync();
var content = downloadResult.Value.Content.ToString();
logger.LogInformation(content);
}

[Function(nameof(BlobStreamFunction))]
public static void BlobStreamFunction(
[BlobTrigger("test-input-stream/{name}", Connection = "AzureWebJobsStorage")] Stream stream,
FunctionContext context)
{
var logger = context.GetLogger(nameof(BlobStreamFunction));
using var blobStreamReader = new StreamReader(stream);
logger.LogInformation(blobStreamReader.ReadToEnd());
}

[Function(nameof(BlobByteArrayFunction))]
public static void BlobByteArrayFunction(
[BlobTrigger("test-input-byte/{name}", Connection = "AzureWebJobsStorage")] Byte[] data,
FunctionContext context)
{
var logger = context.GetLogger(nameof(BlobByteArrayFunction));
logger.LogInformation(Encoding.Default.GetString(data));
}

[Function(nameof(BlobStringFunction))]
public static void BlobStringFunction(
[BlobTrigger("test-input-string/{name}", Connection = "AzureWebJobsStorage")] string data,
FunctionContext context)
{
var logger = context.GetLogger(nameof(BlobStringFunction));
logger.LogInformation(data);
}

[Function(nameof(BlobBookFunction))]
public static void BlobBookFunction(
[BlobTrigger("test-input-book/{name}", Connection = "AzureWebJobsStorage")] Book data,
FunctionContext context)
{
var logger = context.GetLogger(nameof(BlobBookFunction));
logger.LogInformation($"{data.Id} - {data.Name}");
}
}
}
21 changes: 21 additions & 0 deletions sample/DotNetIsolated/Blob/ExpressionFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
public static class ExpressionFunction
{
[Function(nameof(ExpressionFunction))]
public static void Run(
[QueueTrigger("test-input-sample", Connection = "AzureWebJobsStorage")] Book book,
[BlobInput("test-input-sample/{id}.txt", Connection = "AzureWebJobsStorage")] string myBlob,
FunctionContext context)
{
var logger = context.GetLogger(nameof(ExpressionFunction));
logger.LogInformation(myBlob);
}
}
}
11 changes: 11 additions & 0 deletions sample/DotNetIsolated/Book.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace SampleApp
{
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
}
}
29 changes: 29 additions & 0 deletions sample/DotNetIsolated/DotNetIsolated.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>preview</LangVersion>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.11.0-preview2-20221104.9" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs" Version="5.0.2-preview1-20221104.9" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues" Version="5.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.8.0-preview3-20221104.9" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
19 changes: 19 additions & 0 deletions sample/DotNetIsolated/Program.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 Microsoft.Extensions.Hosting;

namespace SampleApp
{
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();

host.Run();
}
}
}
11 changes: 11 additions & 0 deletions sample/DotNetIsolated/host.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.33" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.35" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.11" />
<PackageReference Include="Microsoft.Azure.WebJobs.Host.Storage" Version="4.0.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit" Version="1.0.1-beta1.21177.1" />
Expand Down
6 changes: 4 additions & 2 deletions test/WebJobs.Script.Tests.Integration/TestFunctionHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.EnvironmentVariables;
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -76,7 +77,8 @@ public TestFunctionHost(string scriptPath, string logPath,
Action<ILoggingBuilder> configureScriptHostLogging = null,
Action<IServiceCollection> configureScriptHostServices = null,
Action<IConfigurationBuilder> configureWebHostAppConfiguration = null,
bool addTestSettings = true)
bool addTestSettings = true,
bool setStorageEnvironmentVariable = false)
{
_appRoot = scriptPath;

Expand Down Expand Up @@ -134,7 +136,7 @@ public TestFunctionHost(string scriptPath, string logPath,
{
if (addTestSettings)
{
scriptHostConfigurationBuilder.AddTestSettings();
scriptHostConfigurationBuilder.AddTestSettings(setStorageEnvironmentVariable);
}
configureScriptHostAppConfiguration?.Invoke(scriptHostConfigurationBuilder);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ public abstract class EndToEndTestFixture : IAsyncLifetime
private int _workerProcessCount;
private string _functionsWorkerRuntimeVersion;
private bool _addTestSettings;
private bool _setStorageEnvironmentVariable;

protected EndToEndTestFixture(string rootPath, string testId,
string functionsWorkerRuntime,
int workerProcessesCount = 1,
protected EndToEndTestFixture(string rootPath, string testId,
string functionsWorkerRuntime,
int workerProcessesCount = 1,
string functionsWorkerRuntimeVersion = null,
bool addTestSettings = true)
bool addTestSettings = true,
bool setStorageEnvironmentVariable = false)
{
FixtureId = testId;

Expand All @@ -51,6 +53,7 @@ protected EndToEndTestFixture(string rootPath, string testId,
_workerProcessCount = workerProcessesCount;
_functionsWorkerRuntimeVersion = functionsWorkerRuntimeVersion;
_addTestSettings = addTestSettings;
_setStorageEnvironmentVariable = setStorageEnvironmentVariable;
}

public CloudBlobContainer TestInputContainer { get; private set; }
Expand Down Expand Up @@ -133,7 +136,7 @@ string GetDestPath(int counter)
FunctionsSyncManagerMock = new Mock<IFunctionsSyncManager>(MockBehavior.Strict);
FunctionsSyncManagerMock.Setup(p => p.TrySyncTriggersAsync(It.IsAny<bool>())).ReturnsAsync(new SyncTriggersResult { Success = true });

Host = new TestFunctionHost(_copiedRootPath, logPath, addTestSettings: _addTestSettings,
Host = new TestFunctionHost(_copiedRootPath, logPath, addTestSettings: _addTestSettings, setStorageEnvironmentVariable: _setStorageEnvironmentVariable,
configureScriptHostWebJobsBuilder: webJobsBuilder =>
{
ConfigureScriptHost(webJobsBuilder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,22 +405,35 @@ protected async Task<JObject> GetFunctionTestResult(string functionName)
string logEntry = null;

await TestHelpers.Await(() =>
{
// search the logs for token "TestResult:" and parse the following JSON
var logs = Fixture.Host.GetScriptHostLogMessages(LogCategories.CreateFunctionUserCategory(functionName));
if (logs != null)
{
logEntry = logs.Select(p => p.FormattedMessage).SingleOrDefault(p => p != null && p.Contains("TestResult:"));
}
return logEntry != null;
});
{
// search the logs for token "TestResult:" and parse the following JSON
var logs = Fixture.Host.GetScriptHostLogMessages(LogCategories.CreateFunctionUserCategory(functionName));
if (logs != null)
{
logEntry = logs.Select(p => p.FormattedMessage).SingleOrDefault(p => p != null && p.Contains("TestResult:"));
}
return logEntry != null;
});

int idx = logEntry.IndexOf("{");
logEntry = logEntry.Substring(idx);

return JObject.Parse(logEntry);
}

protected async Task<IEnumerable<LogMessage>> GetFunctionLogs(string functionName)
{
IEnumerable<LogMessage> logs = null;

await TestHelpers.Await(() =>
{
logs = Fixture.Host.GetScriptHostLogMessages(LogCategories.CreateFunctionUserCategory(functionName));
return logs != null;
}, timeout: 30000, pollingInterval: 500);

return logs;
}

public class ScenarioInput
{
[JsonProperty("scenario")]
Expand Down
Loading

0 comments on commit f074597

Please sign in to comment.