diff --git a/test/E2ETests/E2EApps/E2EApp/Blob/BlobInputBindingFunctions.cs b/test/E2ETests/E2EApps/E2EApp/Blob/BlobInputBindingFunctions.cs new file mode 100644 index 000000000..4e6798c90 --- /dev/null +++ b/test/E2ETests/E2EApps/E2EApp/Blob/BlobInputBindingFunctions.cs @@ -0,0 +1,134 @@ +// 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.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Azure.Functions.Worker.E2EApp.Blob +{ + public class BlobInputBindingFunctions + { + private readonly ILogger _logger; + + public BlobInputBindingFunctions(ILogger logger) + { + _logger = logger; + } + + [Function(nameof(BlobInputClientTest))] + public async Task BlobInputClientTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] BlobClient client) + { + var downloadResult = await client.DownloadContentAsync(); + var response = req.CreateResponse(HttpStatusCode.OK); + await response.Body.WriteAsync(downloadResult.Value.Content); + return response; + } + + [Function(nameof(BlobInputContainerClientTest))] + public async Task BlobInputContainerClientTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] BlobContainerClient client) + { + var blobClient = client.GetBlobClient("testFile.txt"); + var downloadResult = await blobClient.DownloadContentAsync(); + var response = req.CreateResponse(HttpStatusCode.OK); + await response.Body.WriteAsync(downloadResult.Value.Content); + return response; + } + + [Function(nameof(BlobInputStreamTest))] + public async Task BlobInputStreamTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] Stream stream) + { + using var blobStreamReader = new StreamReader(stream); + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(blobStreamReader.ReadToEnd()); + return response; + } + + [Function(nameof(BlobInputByteTest))] + public async Task BlobInputByteTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] Byte[] data) + { + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(Encoding.Default.GetString(data)); + return response; + } + + [Function(nameof(BlobInputStringTest))] + public async Task BlobInputStringTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] string data) + { + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(data); + return response; + } + + [Function(nameof(BlobInputPocoTest))] + public async Task BlobInputPocoTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated/testFile.txt")] Book data) + { + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(data.Name); + return response; + } + + [Function(nameof(BlobInputCollectionTest))] + public async Task BlobInputCollectionTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated", IsBatched = true)] IEnumerable blobs) + { + List blobList = new(); + + foreach (BlobClient blob in blobs) + { + _logger.LogInformation("Blob name: {blobName}, Container name: {containerName}", blob.Name, blob.BlobContainerName); + blobList.Add(blob.Name); + } + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(blobList.ToString()); + return response; + } + + [Function(nameof(BlobInputStringArrayTest))] + public async Task BlobInputStringArrayTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated", IsBatched = true)] string[] blobContent) + { + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(blobContent.ToString()); + return response; + } + + [Function(nameof(BlobInputPocoArrayTest))] + public async Task BlobInputPocoArrayTest( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, + [BlobInput("test-input-dotnet-isolated", IsBatched = true)] Book[] books) + { + List bookNames = new(); + + foreach (var item in books) + { + bookNames.Add(item.Name); + } + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync(bookNames.ToString()); + return response; + } + } +} \ No newline at end of file diff --git a/test/E2ETests/E2EApps/E2EApp/Blob/BlobTestFunctions.cs b/test/E2ETests/E2EApps/E2EApp/Blob/BlobTestFunctions.cs deleted file mode 100644 index b375e044a..000000000 --- a/test/E2ETests/E2EApps/E2EApp/Blob/BlobTestFunctions.cs +++ /dev/null @@ -1,57 +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.Text.Json.Serialization; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Azure.Functions.Worker.E2EApp.Blob -{ - public class BlobTestFunctions - { - private readonly ILogger _logger; - - public BlobTestFunctions(ILogger logger) - { - _logger = logger; - } - - [Function(nameof(BlobTriggerToBlobTest))] - [BlobOutput("test-output-dotnet-isolated/{name}")] - public byte[] BlobTriggerToBlobTest( - [BlobTrigger("test-triggerinput-dotnet-isolated/{name}")] byte[] triggerBlob, string name, - [BlobInput("test-input-dotnet-isolated/{name}")] byte[] inputBlob, - FunctionContext context) - { - _logger.LogInformation("Trigger:\n Name: " + name + "\n Size: " + triggerBlob.Length + " Bytes"); - _logger.LogInformation("Input:\n Name: " + name + "\n Size: " + inputBlob.Length + " Bytes"); - return inputBlob; - } - - [Function(nameof(BlobTriggerPocoTest))] - [BlobOutput("test-outputpoco-dotnet-isolated/{name}")] - public TestBlobData BlobTriggerPocoTest( - [BlobTrigger("test-triggerinputpoco-dotnet-isolated/{name}")] TestBlobData triggerBlob, string name, - FunctionContext context) - { - _logger.LogInformation(".NET Blob trigger function processed a blob.\n Name: " + name + "\n Content: " + triggerBlob.BlobText); - return triggerBlob; - } - - [Function(nameof(BlobTriggerStringTest))] - [BlobOutput("test-outputstring-dotnet-isolated/{name}")] - public string BlobTriggerStringTest( - [BlobTrigger("test-triggerinputstring-dotnet-isolated/{name}")] string triggerBlobText, string name, - FunctionContext context) - { - _logger.LogInformation(".NET Blob trigger function processed a blob.\n Name: " + name + "\n Content: " + triggerBlobText); - return triggerBlobText; - } - - public class TestBlobData - { - [JsonPropertyName("text")] - public string BlobText { get; set; } - } - } -} diff --git a/test/E2ETests/E2EApps/E2EApp/Blob/BlobTriggerBindingFunctions.cs b/test/E2ETests/E2EApps/E2EApp/Blob/BlobTriggerBindingFunctions.cs new file mode 100644 index 000000000..ecce43f1a --- /dev/null +++ b/test/E2ETests/E2EApps/E2EApp/Blob/BlobTriggerBindingFunctions.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.IO; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Azure.Functions.Worker.E2EApp.Blob +{ + public class BlobTriggerBindingFunctions + { + private readonly ILogger _logger; + + public BlobTriggerBindingFunctions(ILogger logger) + { + _logger = logger; + } + + [Function(nameof(BlobTriggerToBlobTest))] + [BlobOutput("test-output-dotnet-isolated/{name}")] + public byte[] BlobTriggerToBlobTest( + [BlobTrigger("test-trigger-dotnet-isolated/{name}")] byte[] triggerBlob, string name, + [BlobInput("test-input-dotnet-isolated/{name}")] byte[] inputBlob, + FunctionContext context) + { + _logger.LogInformation("Trigger:\n Name: " + name + "\n Size: " + triggerBlob.Length + " Bytes"); + _logger.LogInformation("Input:\n Name: " + name + "\n Size: " + inputBlob.Length + " Bytes"); + return inputBlob; + } + + [Function(nameof(BlobTriggerPocoTest))] + [BlobOutput("test-output-poco-dotnet-isolated/{name}")] + public TestBlobData BlobTriggerPocoTest( + [BlobTrigger("test-trigger-poco-dotnet-isolated/{name}")] TestBlobData triggerBlob, string name, + FunctionContext context) + { + _logger.LogInformation(".NET Blob trigger function processed a blob.\n Name: " + name + "\n Content: " + triggerBlob.BlobText); + return triggerBlob; + } + + [Function(nameof(BlobTriggerStringTest))] + [BlobOutput("test-output-string-dotnet-isolated/{name}")] + public string BlobTriggerStringTest( + [BlobTrigger("test-trigger-string-dotnet-isolated/{name}")] string triggerBlobText, string name, + FunctionContext context) + { + _logger.LogInformation(".NET Blob trigger function processed a blob.\n Name: " + name + "\n Content: " + triggerBlobText); + return triggerBlobText; + } + + [Function(nameof(BlobTriggerStreamTest))] + public async Task BlobTriggerStreamTest( + [BlobTrigger("test-trigger-stream-dotnet-isolated/{name}")] Stream stream, string name, + FunctionContext context) + { + using var blobStreamReader = new StreamReader(stream); + string content = await blobStreamReader.ReadToEndAsync(); + _logger.LogInformation("StreamTriggerOutput: {c}", content); + } + + [Function(nameof(BlobTriggerBlobClientTest))] + public async Task BlobTriggerBlobClientTest( + [BlobTrigger("test-trigger-blobclient-dotnet-isolated/{name}")] BlobClient client, string name, + FunctionContext context) + { + var downloadResult = await client.DownloadContentAsync(); + string content = downloadResult.Value.Content.ToString(); + _logger.LogInformation("BlobClientTriggerOutput: {c}", content); + } + + [Function(nameof(BlobTriggerBlobContainerClientTest))] + public async Task BlobTriggerBlobContainerClientTest( + [BlobTrigger("test-trigger-containerclient-dotnet-isolated/{name}")] BlobContainerClient client, string name, + FunctionContext context) + { + var blobClient = client.GetBlobClient(name); + var downloadResult = await blobClient.DownloadContentAsync(); + string content = downloadResult.Value.Content.ToString(); + _logger.LogInformation("BlobContainerTriggerOutput: {c}", content); + } + + public class TestBlobData + { + [JsonPropertyName("text")] + public string BlobText { get; set; } + } + } +} diff --git a/test/E2ETests/E2EApps/E2EApp/Blob/Book.cs b/test/E2ETests/E2EApps/E2EApp/Blob/Book.cs new file mode 100644 index 000000000..2cea88356 --- /dev/null +++ b/test/E2ETests/E2EApps/E2EApp/Blob/Book.cs @@ -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 Microsoft.Azure.Functions.Worker.E2EApp.Blob +{ + public class Book + { + public string Id { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj b/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj index f6fd3de04..2c799e2ef 100644 --- a/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj +++ b/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj @@ -42,8 +42,8 @@ - - + + diff --git a/test/E2ETests/E2ETests/Constants.cs b/test/E2ETests/E2ETests/Constants.cs index 70256b28a..f9cd316f0 100644 --- a/test/E2ETests/E2ETests/Constants.cs +++ b/test/E2ETests/E2ETests/Constants.cs @@ -34,15 +34,19 @@ public static class Queue //Blob tests public static class Blob { - public const string TriggerInputBindingContainer = "test-triggerinput-dotnet-isolated"; + public const string TriggerInputBindingContainer = "test-trigger-dotnet-isolated"; public const string InputBindingContainer = "test-input-dotnet-isolated"; public const string OutputBindingContainer = "test-output-dotnet-isolated"; - - public const string TriggerPocoContainer = "test-triggerinputpoco-dotnet-isolated"; - public const string OutputPocoContainer = "test-outputpoco-dotnet-isolated"; - - public const string TriggerStringContainer = "test-triggerinputstring-dotnet-isolated"; - public const string OutputStringContainer = "test-outputstring-dotnet-isolated"; + public const string TriggerPocoContainer = "test-trigger-poco-dotnet-isolated"; + public const string OutputPocoContainer = "test-output-poco-dotnet-isolated"; + public const string TriggerStringContainer = "test-trigger-string-dotnet-isolated"; + public const string OutputStringContainer = "test-output-string-dotnet-isolated"; + public const string TriggerStreamContainer = "test-trigger-stream-dotnet-isolated"; + public const string OutputStreamContainer = "test-output-stream-dotnet-isolated"; + public const string TriggerBlobClientContainer = "test-trigger-blobclient-dotnet-isolated"; + public const string OutputBlobClientContainer = "test-output-blobclient-dotnet-isolated"; + public const string TriggerBlobContainerClientContainer = "test-trigger-containerclient-dotnet-isolated"; + public const string OutputBlobContainerClientContainer = "test-output-containerclient-dotnet-isolated"; } // CosmosDB tests diff --git a/test/E2ETests/E2ETests/CosmosDBEndToEndTests.cs b/test/E2ETests/E2ETests/Cosmos/CosmosDBEndToEndTests.cs similarity index 93% rename from test/E2ETests/E2ETests/CosmosDBEndToEndTests.cs rename to test/E2ETests/E2ETests/Cosmos/CosmosDBEndToEndTests.cs index e44d215eb..71fb75934 100644 --- a/test/E2ETests/E2ETests/CosmosDBEndToEndTests.cs +++ b/test/E2ETests/E2ETests/Cosmos/CosmosDBEndToEndTests.cs @@ -6,7 +6,7 @@ using Xunit; using Xunit.Abstractions; -namespace Microsoft.Azure.Functions.Tests.E2ETests +namespace Microsoft.Azure.Functions.Tests.E2ETests.Cosmos { [Collection(Constants.FunctionAppCollectionName)] public class CosmosDBEndToEndTests : IDisposable @@ -26,7 +26,7 @@ public async Task CosmosDBTriggerAndOutput_Succeeds() string expectedDocId = Guid.NewGuid().ToString(); try { - //Trigger + //Trigger await CosmosDBHelpers.CreateDocument(expectedDocId); //Read diff --git a/test/E2ETests/E2ETests/Helpers/StorageHelpers.cs b/test/E2ETests/E2ETests/Helpers/StorageHelpers.cs index 191717b48..f710ebcd7 100644 --- a/test/E2ETests/E2ETests/Helpers/StorageHelpers.cs +++ b/test/E2ETests/E2ETests/Helpers/StorageHelpers.cs @@ -108,6 +108,12 @@ public async static Task ClearBlobContainers() await ClearBlobContainer(Constants.Blob.OutputPocoContainer); await ClearBlobContainer(Constants.Blob.TriggerStringContainer); await ClearBlobContainer(Constants.Blob.OutputStringContainer); + await ClearBlobContainer(Constants.Blob.TriggerStreamContainer); + await ClearBlobContainer(Constants.Blob.OutputStreamContainer); + await ClearBlobContainer(Constants.Blob.TriggerBlobClientContainer); + await ClearBlobContainer(Constants.Blob.OutputBlobClientContainer); + await ClearBlobContainer(Constants.Blob.TriggerBlobContainerClientContainer); + await ClearBlobContainer(Constants.Blob.OutputBlobContainerClientContainer); } public static Task UploadFileToContainer(string containerName, string fileName) diff --git a/test/E2ETests/E2ETests/Storage/BlobEndToEndTests.cs b/test/E2ETests/E2ETests/Storage/BlobEndToEndTests.cs new file mode 100644 index 000000000..a3f41d63c --- /dev/null +++ b/test/E2ETests/E2ETests/Storage/BlobEndToEndTests.cs @@ -0,0 +1,292 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Azure.Functions.Tests.E2ETests.Storage +{ + [Collection(Constants.FunctionAppCollectionName)] + public class BlobEndToEndTests : IDisposable + { + private readonly IDisposable _disposeLog; + private FunctionAppFixture _fixture; + + public BlobEndToEndTests(FunctionAppFixture fixture, ITestOutputHelper testOutput) + { + _fixture = fixture; + _disposeLog = _fixture.TestLogs.UseTestLogger(testOutput); + } + + [Fact] + public async Task BlobTriggerToBlob_Succeeds() + { + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, fileName); + + //Trigger + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerInputBindingContainer, fileName); + + //Verify + string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputBindingContainer, fileName); + + Assert.Equal("Hello World", result); + } + + [Fact] + public async Task BlobTrigger_Poco_Succeeds() + { + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Trigger + var json = JsonSerializer.Serialize(new { text = "Hello World" }); + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerPocoContainer, fileName, json); + + //Verify + string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputPocoContainer, fileName); + + Assert.Equal(json, result); + } + + [Fact] + public async Task BlobTrigger_String_Succeeds() + { + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Trigger + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerStringContainer, fileName); + + //Verify + string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputStringContainer, fileName); + + Assert.Equal("Hello World", result); + } + + [Fact] + public async Task BlobTrigger_Stream_Succeeds() + { + string key = "StreamTriggerOutput: "; + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Trigger + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerStreamContainer, fileName); + + //Verify + IEnumerable logs = null; + await TestUtility.RetryAsync(() => + { + logs = _fixture.TestLogs.CoreToolsLogs.Where(p => p.Contains(key)); + return Task.FromResult(logs.Count() >= 1); + }); + + var lastLog = logs.Last(); + int subStringStart = lastLog.LastIndexOf(key) + key.Length; + var result = lastLog[subStringStart..]; + + Assert.Equal("Hello World", result); + } + + [Fact] + public async Task BlobTrigger_BlobClient_Succeeds() + { + string key = "BlobClientTriggerOutput: "; + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Trigger + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerBlobClientContainer, fileName); + + //Verify + IEnumerable logs = null; + await TestUtility.RetryAsync(() => + { + logs = _fixture.TestLogs.CoreToolsLogs.Where(p => p.Contains(key)); + return Task.FromResult(logs.Count() >= 1); + }); + + var lastLog = logs.Last(); + int subStringStart = lastLog.LastIndexOf(key) + key.Length; + var result = lastLog[subStringStart..]; + + Assert.Equal("Hello World", result); + } + + [Fact] + public async Task BlobTrigger_BlobContainerClient_Succeeds() + { + string key = "BlobContainerTriggerOutput: "; + string fileName = Guid.NewGuid().ToString(); + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Trigger + await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerBlobContainerClientContainer, fileName); + + //Verify + IEnumerable logs = null; + await TestUtility.RetryAsync(() => + { + logs = _fixture.TestLogs.CoreToolsLogs.Where(p => p.Contains(key)); + return Task.FromResult(logs.Count() >= 1); + }); + + var lastLog = logs.Last(); + int subStringStart = lastLog.LastIndexOf(key) + key.Length; + var result = lastLog[subStringStart..]; + + Assert.Equal("Hello World", result); + } + + [Theory] + [InlineData("BlobInputClientTest")] + [InlineData("BlobInputContainerClientTest")] + [InlineData("BlobInputStreamTest")] + [InlineData("BlobInputByteTest")] + [InlineData("BlobInputStringTest")] + public async Task BlobInput_SingleCardinality_Succeeds(string functionName) + { + string expectedMessage = "Hello World"; + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile", expectedMessage); + + //Trigger + HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger(functionName); + string actualMessage = await response.Content.ReadAsStringAsync(); + + //Verify + HttpStatusCode expectedStatusCode = HttpStatusCode.OK; + + Assert.Equal(expectedStatusCode, response.StatusCode); + Assert.Contains(expectedMessage, actualMessage); + } + + [Fact] + public async Task BlobInput_Poco_Succeeds() + { + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + var json = JsonSerializer.Serialize(new { id = "1", name = "To Kill a Mockingbird" }); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile", json); + + //Trigger + HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger("BlobInputPocoTest"); + string actualMessage = await response.Content.ReadAsStringAsync(); + + //Verify + string expectedMessage = "To Kill a Mockingbird"; + HttpStatusCode expectedStatusCode = HttpStatusCode.OK; + + Assert.Equal(expectedStatusCode, response.StatusCode); + Assert.Contains(expectedMessage, actualMessage); + } + + [Fact(Skip = "Collection support released in host version 4.16+")] + public async Task BlobInput_BlobClientCollection_Succeeds() + { + string expectedMessage = "testFile1, testFile2, testFile3"; + HttpStatusCode expectedStatusCode = HttpStatusCode.OK; + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile1"); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile2"); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile3"); + + //Trigger + HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger("BlobInputCollectionTest"); + string actualMessage = await response.Content.ReadAsStringAsync(); + + //Verify + Assert.Equal(expectedStatusCode, response.StatusCode); + Assert.Contains(expectedMessage, actualMessage); + } + + [Fact(Skip = "Collection support released in host version 4.16+")] + public async Task BlobInput_StringCollection_Succeeds() + { + string expectedMessage = "ABC, DEF, GHI"; + HttpStatusCode expectedStatusCode = HttpStatusCode.OK; + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile1", "ABC"); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile2", "DEF"); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "testFile3", "GHI"); + + //Trigger + HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger("BlobInputCollectionTest"); + string actualMessage = await response.Content.ReadAsStringAsync(); + + //Verify + Assert.Equal(expectedStatusCode, response.StatusCode); + Assert.Contains(expectedMessage, actualMessage); + } + + [Fact(Skip = "Collection support released in host version 4.16+")] + public async Task BlobInput_PocoCollection_Succeeds() + { + string book1 = $@"{{ ""id"": ""1"", ""name"": ""To Kill a Mockingbird""}}"; + string book2 = $@"{{ ""id"": ""2"", ""name"": ""Of Mice and Men""}}"; + string book3 = $@"{{ ""id"": ""3"", ""name"": ""The Wind in the Willows""}}"; + + string expectedMessage = "To Kill a Mockingbird, Of Mice and Men, The Wind in the Willows"; + HttpStatusCode expectedStatusCode = HttpStatusCode.OK; + + + //Cleanup + await StorageHelpers.ClearBlobContainers(); + + //Setup + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "book1", book1); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "book2", book2); + await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, "book3", book3); + + //Trigger + HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger("BlobInputPocoArrayTest"); + string actualMessage = await response.Content.ReadAsStringAsync(); + + //Verify + Assert.Equal(expectedStatusCode, response.StatusCode); + Assert.Contains(expectedMessage, actualMessage); + } + + public void Dispose() + { + _disposeLog?.Dispose(); + } + } +} diff --git a/test/E2ETests/E2ETests/StorageEndToEndTests.cs b/test/E2ETests/E2ETests/Storage/QueueEndToEndTests.cs similarity index 76% rename from test/E2ETests/E2ETests/StorageEndToEndTests.cs rename to test/E2ETests/E2ETests/Storage/QueueEndToEndTests.cs index 8271aad32..ed81d8cfa 100644 --- a/test/E2ETests/E2ETests/StorageEndToEndTests.cs +++ b/test/E2ETests/E2ETests/Storage/QueueEndToEndTests.cs @@ -9,14 +9,14 @@ using System.Threading.Tasks; using Xunit; -namespace Microsoft.Azure.Functions.Tests.E2ETests +namespace Microsoft.Azure.Functions.Tests.E2ETests.Storage { [Collection(Constants.FunctionAppCollectionName)] - public class StorageEndToEndTests + public class QueueEndToEndTests { private FunctionAppFixture _fixture; - public StorageEndToEndTests(FunctionAppFixture fixture) + public QueueEndToEndTests(FunctionAppFixture fixture) { _fixture = fixture; } @@ -29,7 +29,7 @@ public async Task QueueTriggerAndOutput_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.OutputBindingName); await StorageHelpers.ClearQueue(Constants.Queue.InputBindingName); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputBindingName); await StorageHelpers.InsertIntoQueue(Constants.Queue.InputBindingName, expectedQueueMessage); @@ -46,7 +46,7 @@ public async Task QueueTriggerAndArrayOutput_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.InputArrayBindingName); await StorageHelpers.ClearQueue(Constants.Queue.OutputArrayBindingName); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputArrayBindingName); await StorageHelpers.InsertIntoQueue(Constants.Queue.InputArrayBindingName, expectedQueueMessage); @@ -72,7 +72,7 @@ public async Task QueueTriggerAndListOutput_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.InputListBindingName); await StorageHelpers.ClearQueue(Constants.Queue.OutputListBindingName); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputListBindingName); await StorageHelpers.InsertIntoQueue(Constants.Queue.InputListBindingName, expectedQueueMessage); @@ -98,7 +98,7 @@ public async Task QueueTriggerAndBindingDataOutput_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.InputBindingDataName); await StorageHelpers.ClearQueue(Constants.Queue.OutputBindingDataName); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputBindingDataName); await StorageHelpers.InsertIntoQueue(Constants.Queue.InputBindingDataName, expectedQueueMessage); @@ -122,7 +122,7 @@ public async Task QueueTrigger_BindToTriggerMetadata_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.OutputBindingNameMetadata); await StorageHelpers.ClearQueue(Constants.Queue.InputBindingNameMetadata); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputBindingNameMetadata); string expectedQueueMessage = await StorageHelpers.InsertIntoQueue(Constants.Queue.InputBindingNameMetadata, inputQueueMessage); @@ -139,7 +139,7 @@ public async Task QueueTrigger_QueueOutput_Poco_Succeeds() await StorageHelpers.ClearQueue(Constants.Queue.OutputBindingNamePOCO); await StorageHelpers.ClearQueue(Constants.Queue.InputBindingNamePOCO); - //Set up and trigger + //Set up and trigger await StorageHelpers.CreateQueue(Constants.Queue.OutputBindingNamePOCO); string json = JsonSerializer.Serialize(new { id = expectedQueueMessage }); @@ -166,60 +166,5 @@ public async Task QueueOutput_PocoList_Succeeds() IEnumerable queueMessages = await StorageHelpers.ReadMessagesFromQueue(Constants.Queue.OutputBindingNamePOCO); Assert.True(queueMessages.All(msg => msg.Contains(expectedQueueMessage))); } - - [Fact] - public async Task BlobTriggerToBlob_Succeeds() - { - string fileName = Guid.NewGuid().ToString(); - - //cleanup - await StorageHelpers.ClearBlobContainers(); - - //Setup - await StorageHelpers.UploadFileToContainer(Constants.Blob.InputBindingContainer, fileName); - - //Trigger - await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerInputBindingContainer, fileName); - - //Verify - string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputBindingContainer, fileName); - - Assert.Equal("Hello World", result); - } - - [Fact] - public async Task BlobTriggerPoco_Succeeds() - { - string fileName = Guid.NewGuid().ToString(); - - //cleanup - await StorageHelpers.ClearBlobContainers(); - - //Trigger - var json = JsonSerializer.Serialize(new { text = "Hello World" }); - await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerPocoContainer, fileName, json); - - //Verify - string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputPocoContainer, fileName); - - Assert.Equal(json, result); - } - - [Fact] - public async Task BlobTriggerString_Succeeds() - { - string fileName = Guid.NewGuid().ToString(); - - //cleanup - await StorageHelpers.ClearBlobContainers(); - - //Trigger - await StorageHelpers.UploadFileToContainer(Constants.Blob.TriggerStringContainer, fileName); - - //Verify - string result = await StorageHelpers.DownloadFileFromContainer(Constants.Blob.OutputStringContainer, fileName); - - Assert.Equal("Hello World", result); - } } }