E2e test suite from Nodejs worker (#139)

* Add e2e test suite from java worker

* add to appveyor for CI

* remove Invoke-Test for e2e

* move test csproj

* fix path in module tests

* change to capital T

* uppercase another T

* delete extensions.csproj

* add silentlyContinue to Remove-Item

* props file is one directory up
This commit is contained in:
Tyler James Leonhardt 2019-02-01 18:15:39 -08:00 коммит произвёл GitHub
Родитель a998cbca9d
Коммит 9ebf44f942
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
48 изменённых файлов: 829 добавлений и 404 удалений

Просмотреть файл

@ -26,6 +26,7 @@ build_script:
test_script:
- pwsh: ./build.ps1 -NoBuild -Test
- pwsh: ./test/E2E/Start-E2ETest.ps1
on_finish:
- pwsh: dir *.PowerShellWorker.*.nupkg -Recurse | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }

Просмотреть файл

@ -9,7 +9,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Functions.P
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{12092936-4F2A-4B40-9AF2-56C840D44FEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Functions.PowerShellWorker.Test", "test\Microsoft.Azure.Functions.PowerShellWorker.Test.csproj", "{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test\Unit", "test\Unit", "{84b1665e-f5a8-4044-81da-611f1e40508f}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Functions.PowerShellWorker.Test", "test\Unit\Microsoft.Azure.Functions.PowerShellWorker.Test.csproj", "{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -51,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{939262BA-4823-405E-81CD-436C0B77D524} = {8C758288-3909-4CE1-972D-1BE966628D6C}
{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4} = {12092936-4F2A-4B40-9AF2-56C840D44FEA}
{84b1665e-f5a8-4044-81da-611f1e40508f} = {12092936-4F2A-4B40-9AF2-56C840D44FEA}
{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4} = {84b1665e-f5a8-4044-81da-611f1e40508f}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -87,9 +87,8 @@ if($Test.IsPresent) {
throw "Cannot find the 'Pester' module. Please specify '-Bootstrap' to install build dependencies."
}
dotnet test "$PSScriptRoot/test"
dotnet test "$PSScriptRoot/test/Unit"
if ($LASTEXITCODE -ne 0) { throw "xunit tests failed." }
Invoke-Tests -Path "$PSScriptRoot/test/Unit/Modules" -OutputFile UnitTestsResults.xml
Invoke-Tests -Path "$PSScriptRoot/test/E2E" -OutputFile E2ETestsResults.xml
}

Просмотреть файл

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Functions.PowerShellWorker.E2E", "Azure.Functions.PowerShellWorker.E2E\Azure.Functions.PowerShellWorker.E2E.csproj", "{E7229DBA-DCF2-44B9-ACB8-D6E8AE906AB3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E7229DBA-DCF2-44B9-ACB8-D6E8AE906AB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7229DBA-DCF2-44B9-ACB8-D6E8AE906AB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7229DBA-DCF2-44B9-ACB8-D6E8AE906AB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7229DBA-DCF2-44B9-ACB8-D6E8AE906AB3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {96355275-963C-4A13-92EB-5F7CB415269F}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.1.1" />
<PackageReference Include="Microsoft.Azure.EventHubs" Version="2.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="WindowsAzure.Storage" Version="9.3.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,47 @@
// 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 Azure.Functions.PowerShell.Tests.E2E
{
public static class Constants
{
public static string FunctionsHostUrl = "http://localhost:7071";
//Queue tests
public static class Queue {
public static string StorageConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
public static string OutputBindingName = "test-output-ps";
public static string InputBindingName = "test-input-ps";
}
// CosmosDB tests
public static class CosmosDB {
public static string CosmosDBConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsCosmosDBConnectionString");
public static string DbName = "ItemDb";
public static string InputCollectionName = "ItemCollectionIn";
public static string OutputCollectionName = "ItemCollectionOut";
public static string LeaseCollectionName = "leases";
}
// EventHubs
public static class EventHubs {
public static string EventHubsConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsEventHubSender");
public static class Json_Test {
public static string OutputName = "test-output-object-ps";
public static string InputName = "test-input-object-ps";
}
public static class String_Test {
public static string OutputName = "test-output-string-ps";
public static string InputName = "test-input-string-ps";
}
public static class Cardinality_One_Test {
public static string InputName = "test-input-one-ps";
public static string OutputName = "test-output-one-ps";
}
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
// 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 Xunit;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class CosmosDBEndToEndTests
{
[Fact]
public async Task CosmosDBTriggerAndOutput_Succeeds()
{
string expectedDocId = Guid.NewGuid().ToString();
try
{
//Setup
await CosmosDBHelpers.CreateDocumentCollections();
//Trigger
await CosmosDBHelpers.CreateDocument(expectedDocId);
//Read
var documentId = await CosmosDBHelpers.ReadDocument(expectedDocId);
Assert.Equal(expectedDocId, documentId);
}
finally
{
//Clean up
await CosmosDBHelpers.DeleteTestDocuments(expectedDocId);
}
}
}
}

Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class EventHubsEndToEndTests
{
[Fact]
public async Task EventHubTriggerAndOutputJSON_Succeeds()
{
string expectedEventId = Guid.NewGuid().ToString();
try
{
await SetupQueue(Constants.EventHubs.Json_Test.OutputName);
// Need to setup EventHubs: test-inputjson-powershell and test-outputjson-powershell
await EventHubsHelpers.SendJSONMessagesAsync(expectedEventId, Constants.EventHubs.Json_Test.InputName);
//Verify
var queueMessage = await StorageHelpers.ReadFromQueue(Constants.EventHubs.Json_Test.OutputName);
JObject json = JObject.Parse(queueMessage);
Assert.Contains(expectedEventId, json["value"].ToString());
}
finally
{
//Clear queue
await StorageHelpers.ClearQueue(Constants.EventHubs.Json_Test.OutputName);
}
}
[Fact]
public async Task EventHubTriggerAndOutputString_Succeeds()
{
string expectedEventId = Guid.NewGuid().ToString();
try
{
await SetupQueue(Constants.EventHubs.String_Test.OutputName);
// Need to setup EventHubs: test-input-one-ps
await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.EventHubs.String_Test.InputName);
//Verify
var queueMessage = await StorageHelpers.ReadFromQueue(Constants.EventHubs.String_Test.OutputName);
Assert.Contains(expectedEventId, queueMessage);
}
finally
{
//Clear queue
await StorageHelpers.ClearQueue(Constants.EventHubs.String_Test.OutputName);
}
}
[Fact]
public async Task EventHubTriggerCardinalityOne_Succeeds()
{
string expectedEventId = Guid.NewGuid().ToString();
try
{
await SetupQueue(Constants.EventHubs.Cardinality_One_Test.OutputName);
// Need to setup EventHubs: test-inputOne-powershell and test-outputone-powershell
await EventHubsHelpers.SendMessagesAsync(expectedEventId, Constants.EventHubs.Cardinality_One_Test.InputName);
//Verify
IEnumerable<string> queueMessages = await StorageHelpers.ReadMessagesFromQueue(Constants.EventHubs.Cardinality_One_Test.OutputName);
Assert.True(queueMessages.All(msg => msg.Contains(expectedEventId)));
}
finally
{
//Clear queue
await StorageHelpers.ClearQueue(Constants.EventHubs.Cardinality_One_Test.OutputName);
}
}
private static async Task SetupQueue(string queueName)
{
//Clear queue
await StorageHelpers.ClearQueue(queueName);
//Set up and trigger
await StorageHelpers.CreateQueue(queueName);
}
}
}

Просмотреть файл

@ -0,0 +1,129 @@
// 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 Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class TestDocument
{
public string id { get; set; }
public string name { get; set; }
}
public static class CosmosDBHelpers
{
private static DocumentClient _docDbClient;
private static Uri inputCollectionsUri = UriFactory.CreateDocumentCollectionUri(Constants.CosmosDB.DbName, Constants.CosmosDB.InputCollectionName);
private static Uri outputCollectionsUri = UriFactory.CreateDocumentCollectionUri(Constants.CosmosDB.DbName, Constants.CosmosDB.OutputCollectionName);
private static Uri leasesCollectionsUri = UriFactory.CreateDocumentCollectionUri(Constants.CosmosDB.DbName, Constants.CosmosDB.LeaseCollectionName);
static CosmosDBHelpers()
{
var builder = new System.Data.Common.DbConnectionStringBuilder();
builder.ConnectionString = Constants.CosmosDB.CosmosDBConnectionStringSetting;
var serviceUri = new Uri(builder["AccountEndpoint"].ToString());
_docDbClient = new DocumentClient(serviceUri, builder["AccountKey"].ToString());
}
// keep
public async static Task CreateDocument(string docId)
{
Document documentToTest = new Document()
{
Id = docId
};
Document insertedDoc = await _docDbClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(Constants.CosmosDB.DbName, Constants.CosmosDB.InputCollectionName), documentToTest);
}
public async static Task CreateDocument(TestDocument testDocument)
{
Document insertedDoc = await _docDbClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(Constants.CosmosDB.DbName, Constants.CosmosDB.InputCollectionName), testDocument);
}
// keep
public async static Task<string> ReadDocument(string docId)
{
var docUri = UriFactory.CreateDocumentUri(Constants.CosmosDB.DbName, Constants.CosmosDB.OutputCollectionName, docId);
Document retrievedDocument = null;
await Utilities.RetryAsync(async () =>
{
try
{
retrievedDocument = await _docDbClient.ReadDocumentAsync(docUri);
return true;
}
catch (DocumentClientException ex) when (ex.Error.Code == "NotFound")
{
return false;
}
}, 120000, 4000);
return retrievedDocument.Id;
}
// keep
public async static Task DeleteTestDocuments(string docId)
{
var inputDocUri = UriFactory.CreateDocumentUri(Constants.CosmosDB.DbName, Constants.CosmosDB.InputCollectionName, docId);
await DeleteDocument(inputDocUri);
var outputDocUri = UriFactory.CreateDocumentUri(Constants.CosmosDB.DbName, Constants.CosmosDB.OutputCollectionName, docId);
await DeleteDocument(outputDocUri);
}
private async static Task DeleteDocument(Uri docUri)
{
try
{
await _docDbClient.DeleteDocumentAsync(docUri);
}
catch (Exception)
{
//ignore
}
}
// keep
public async static Task CreateDocumentCollections()
{
Database db = await _docDbClient.CreateDatabaseIfNotExistsAsync(new Database { Id = Constants.CosmosDB.DbName });
Uri dbUri = UriFactory.CreateDatabaseUri(db.Id);
await CreateCollection(dbUri, Constants.CosmosDB.InputCollectionName);
await CreateCollection(dbUri, Constants.CosmosDB.OutputCollectionName);
await CreateCollection(dbUri, Constants.CosmosDB.LeaseCollectionName);
}
public async static Task DeleteDocumentCollections()
{
await DeleteCollection(inputCollectionsUri);
await DeleteCollection(outputCollectionsUri);
await DeleteCollection(leasesCollectionsUri);
}
private async static Task DeleteCollection(Uri collectionUri)
{
try
{
await _docDbClient.DeleteDocumentCollectionAsync(collectionUri);
}
catch (Exception)
{
//Ignore
}
}
private async static Task CreateCollection(Uri dbUri, string collectioName)
{
DocumentCollection collection = new DocumentCollection() { Id = collectioName };
await _docDbClient.CreateDocumentCollectionIfNotExistsAsync(dbUri, collection,
new RequestOptions()
{
OfferThroughput = 400
});
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// 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.EventHubs;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class EventHubsHelpers
{
public static async Task SendJSONMessagesAsync(string eventId, string eventHubName)
{
// write 3 events
List<EventData> events = new List<EventData>();
string[] ids = new string[3];
for (int i = 0; i < 3; i++)
{
ids[i] = eventId + $"TestEvent{i}";
JObject jo = new JObject
{
{ "value", ids[i] }
};
var evt = new EventData(Encoding.UTF8.GetBytes(jo.ToString(Formatting.None)));
evt.Properties.Add("TestIndex", i);
events.Add(evt);
}
EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(Constants.EventHubs.EventHubsConnectionStringSetting);
builder.EntityPath = eventHubName;
EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(builder.ToString());
await eventHubClient.SendAsync(events);
}
public static async Task SendMessagesAsync(string eventId, string evenHubName)
{
// write 3 events
List<EventData> events = new List<EventData>();
string[] ids = new string[3];
for (int i = 0; i < 3; i++)
{
ids[i] = eventId + $"TestEvent{i}";
var evt = new EventData(Encoding.UTF8.GetBytes(ids[i]));
evt.Properties.Add("TestIndex", i);
events.Add(evt);
}
EventHubsConnectionStringBuilder builder = new EventHubsConnectionStringBuilder(Constants.EventHubs.EventHubsConnectionStringSetting);
builder.EntityPath = evenHubName;
EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(builder.ToString());
await eventHubClient.SendAsync(events);
}
}
}

Просмотреть файл

@ -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 Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Azure.Functions.PowerShell.Tests.E2E
{
class StorageHelpers
{
public static CloudStorageAccount _storageAccount = CloudStorageAccount.Parse(Constants.Queue.StorageConnectionStringSetting);
public static CloudQueueClient _queueClient = _storageAccount.CreateCloudQueueClient();
public async static Task DeleteQueue(string queueName)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
await queue.DeleteAsync();
}
public async static Task ClearQueue(string queueName)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
if (await queue.ExistsAsync())
{
await queue.ClearAsync();
}
}
public async static Task CreateQueue(string queueName)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
await queue.CreateIfNotExistsAsync();
}
public async static Task<string> InsertIntoQueue(string queueName, string queueMessage)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
await queue.CreateIfNotExistsAsync();
CloudQueueMessage message = new CloudQueueMessage(queueMessage);
await queue.AddMessageAsync(message);
return message.Id;
}
public async static Task<string> ReadFromQueue(string queueName)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
CloudQueueMessage retrievedMessage = null;
await Utilities.RetryAsync(async () =>
{
retrievedMessage = await queue.GetMessageAsync();
return retrievedMessage != null;
});
await queue.DeleteMessageAsync(retrievedMessage);
return retrievedMessage.AsString;
}
public async static Task<IEnumerable<string>> ReadMessagesFromQueue(string queueName)
{
CloudQueue queue = _queueClient.GetQueueReference(queueName);
IEnumerable<CloudQueueMessage> retrievedMessages = null;
List<string> messages = new List<string>();
await Utilities.RetryAsync(async () =>
{
retrievedMessages = await queue.GetMessagesAsync(3);
return retrievedMessages != null;
});
foreach(CloudQueueMessage msg in retrievedMessages)
{
messages.Add(msg.AsString);
await queue.DeleteMessageAsync(msg);
}
return messages;
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System.Net;
using System.Threading.Tasks;
using Xunit;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class HttpEndToEndTests
{
[Theory]
[InlineData("HttpTrigger", "?name=Test", HttpStatusCode.OK, "Hello Test")]
[InlineData("HttpTrigger", "?name=John&lastName=Doe", HttpStatusCode.OK, "Hello John")]
[InlineData("HttpTriggerThrows", "", HttpStatusCode.InternalServerError, "")]
[InlineData("HttpTrigger", "", HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")]
public async Task HttpTriggerTests(string functionName, string queryString, HttpStatusCode expectedStatusCode, string expectedMessage)
{
// TODO: Verify exception on 500 after https://github.com/Azure/azure-functions-host/issues/3589
Assert.True(await Utilities.InvokeHttpTrigger(functionName, queryString, expectedStatusCode, expectedMessage));
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// 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 Xunit;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public class StorageEndToEndTests
{
[Fact]
public async Task QueueTriggerAndOutput_Succeeds()
{
string expectedQueueMessage = Guid.NewGuid().ToString();
//Clear queue
await StorageHelpers.ClearQueue(Constants.Queue.OutputBindingName);
await StorageHelpers.ClearQueue(Constants.Queue.InputBindingName);
//Set up and trigger
await StorageHelpers.CreateQueue(Constants.Queue.OutputBindingName);
await StorageHelpers.InsertIntoQueue(Constants.Queue.InputBindingName, expectedQueueMessage);
//Verify
var queueMessage = await StorageHelpers.ReadFromQueue(Constants.Queue.OutputBindingName);
Assert.Equal(expectedQueueMessage, queueMessage);
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// 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.Diagnostics;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
namespace Azure.Functions.PowerShell.Tests.E2E
{
public static class Utilities
{
public static async Task RetryAsync(Func<Task<bool>> condition, int timeout = 60 * 1000, int pollingInterval = 2 * 1000, bool throwWhenDebugging = false, Func<string> userMessageCallback = null)
{
DateTime start = DateTime.Now;
while (!await condition())
{
await Task.Delay(pollingInterval);
bool shouldThrow = !Debugger.IsAttached || (Debugger.IsAttached && throwWhenDebugging);
if (shouldThrow && (DateTime.Now - start).TotalMilliseconds > timeout)
{
string error = "Condition not reached within timeout.";
if (userMessageCallback != null)
{
error += " " + userMessageCallback();
}
throw new ApplicationException(error);
}
}
}
public static async Task<bool> InvokeHttpTrigger(string functionName, string queryString, HttpStatusCode expectedStatusCode, string expectedMessage, int expectedCode = 0)
{
string uri = $"api/{functionName}{queryString}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(Constants.FunctionsHostUrl);
var response = await httpClient.SendAsync(request);
if (expectedStatusCode != response.StatusCode && expectedCode != (int)response.StatusCode)
{
return false;
}
if (!string.IsNullOrEmpty(expectedMessage))
{
string actualMessage = await response.Content.ReadAsStringAsync();
return actualMessage.Contains(expectedMessage);
}
return true;
}
}
}

Просмотреть файл

@ -1,108 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
using namespace System.Net
Describe 'HttpTrigger Tests' {
BeforeAll {
$FUNCTIONS_BASE_URL = 'http://localhost:7071'
& "$PSScriptRoot/setupE2Etests.ps1"
{ Invoke-RestMethod $FUNCTIONS_BASE_URL } | Should -Not -Throw -Because 'The E2E tests require a Function App to be running on port 7071'
}
AfterAll {
Get-Job -Name FuncJob -ErrorAction SilentlyContinue | Stop-Job | Remove-Job
}
Context "Test basic HttpTrigger function - Ok" {
BeforeAll {
$testCases = @(
@{
FunctionName = 'TestBasicHttpTrigger'
ExpectedContent = 'Hello Atlas'
Parameter = 'Name'
},
@{
FunctionName = 'TestBasicHttpTriggerWithTriggerMetadata'
ExpectedContent = 'Hello Atlas'
Parameter = 'name'
},
@{
FunctionName = 'TestBasicHttpTriggerWithProfile'
ExpectedContent = 'PROFILE'
Parameter = 'Name'
},
@{
FunctionName = 'TestHttpTriggerWithEntryPoint'
ExpectedContent = 'Hello Atlas'
Parameter = 'name'
},
@{
FunctionName = 'TestHttpTriggerWithEntryPointAndTriggerMetadata'
ExpectedContent = 'Hello Atlas'
Parameter = 'Name'
},
@{
FunctionName = 'TestHttpTriggerWithEntryPointAndProfile'
ExpectedContent = 'PROFILE'
Parameter = 'name'
}
)
}
It "Http GET request - <FunctionName>" -TestCases $testCases {
param ($FunctionName, $ExpectedContent, $Parameter)
$res = Invoke-WebRequest "${FUNCTIONS_BASE_URL}/api/${FunctionName}?${Parameter}=Atlas"
$res.StatusCode | Should -Be ([HttpStatusCode]::Accepted)
$res.Content | Should -Be $ExpectedContent
}
It "Http POST request - <FunctionName>" -TestCases $testCases {
param ($FunctionName, $ExpectedContent, $Parameter)
$res = Invoke-WebRequest "${FUNCTIONS_BASE_URL}/api/${FunctionName}" -Body "{ `"$Parameter`" : `"Atlas`" }" -Method Post -ContentType "application/json"
$res.StatusCode | Should -Be ([HttpStatusCode]::Accepted)
$res.Content | Should -Be $ExpectedContent
}
}
It "Test basic HttpTrigger function - BadRequest - <FunctionName>" -TestCases @(
@{
FunctionName = 'TestBasicHttpTrigger'
InputNameData = $null
},
@{
FunctionName = 'TestBasicHttpTrigger'
},
@{
FunctionName = 'TestBasicHttpTriggerWithTriggerMetadata'
InputNameData = $null
},
@{
FunctionName = 'TestBasicHttpTriggerWithTriggerMetadata'
}
) {
param ($FunctionName, $InputNameData)
if (Test-Path 'variable:InputNameData') {
$url = "$FUNCTIONS_BASE_URL/api/$($FunctionName)?Name=$InputNameData"
} else {
$url = "$FUNCTIONS_BASE_URL/api/$($FunctionName)"
}
$res = { invoke-webrequest $url } |
Should -Throw -ExpectedMessage 'Response status code does not indicate success: 400 (Bad Request).' -PassThru
$res.Exception.Response.StatusCode | Should -Be ([HttpStatusCode]::BadRequest)
}
It "Test basic HttpTrigger function - InternalServerError" {
$res = { invoke-webrequest "$FUNCTIONS_BASE_URL/api/TestBadHttpTrigger" } |
Should -Throw -ExpectedMessage 'Response status code does not indicate success: 500 (Internal Server Error).' -PassThru
$res.Exception.Response.StatusCode | Should -Be ([HttpStatusCode]::InternalServerError)
}
}

Просмотреть файл

@ -1,6 +1,6 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
$arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()
@ -40,21 +40,48 @@ Copy-Item -Recurse -Force "$PSScriptRoot/../../src/bin/$configuration/netcoreapp
Write-Host "Staring Functions Host..."
$Env:AzureWebJobsScriptRoot = "$PSScriptRoot/TestFunctionApp"
$Env:FUNCTIONS_WORKER_RUNTIME = "powershell"
$Env:AZURE_FUNCTIONS_ENVIRONMENT = "development"
$Env:Path = "$Env:Path$([System.IO.Path]::PathSeparator)$FUNC_CLI_DIRECTORY"
$funcExePath = Join-Path $FUNC_CLI_DIRECTORY $FUNC_EXE_NAME
Start-Job -Name FuncJob -ArgumentList $funcExePath -ScriptBlock {
Push-Location $Env:AzureWebJobsScriptRoot
Write-Host "Installing extensions..."
Push-Location "$PSScriptRoot\TestFunctionApp"
if ($IsMacOS -or $IsLinux) {
chmod +x $args[0]
}
& $args[0] host start
if ($IsMacOS -or $IsLinux) {
chmod +x $funcExePath
}
Write-Host "Wait for Functions Host to start..."
Start-Sleep -s 10
& $funcExePath extensions install | ForEach-Object {
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
elseif ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
if ($LASTEXITCODE -ne 0) { throw "Installing extensions failed." }
Pop-Location
Write-Host "Starting functions host..."
$proc = start-process -NoNewWindow -PassThru -filepath $funcExePath -WorkingDirectory "$PSScriptRoot\TestFunctionApp" -ArgumentList "host start" -RedirectStandardOutput "output.txt"
Start-Sleep -s 30
Write-Host "Running E2E integration tests..." -ForegroundColor Green
Write-Host "-----------------------------------------------------------------------------`n" -ForegroundColor Green
dotnet test "$PSScriptRoot/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E.csproj"
if ($LASTEXITCODE -ne 0) { throw "xunit tests failed." }
Write-Host "-----------------------------------------------------------------------------" -ForegroundColor Green
Write-Host "Closing process..."
Stop-Process -Id $proc.Id -Erroraction Ignore
Write-Host "Host Logs:"
$host_logs = Get-Content -Path "output.txt" -Raw
Write-Host $host_logs
Remove-Item -Path "output.txt" -ErrorAction SilentlyContinue

Просмотреть файл

@ -0,0 +1,23 @@
{
"bindings": [
{
"type": "cosmosDBTrigger",
"name": "itemIn",
"direction": "in",
"leaseCollectionName": "leases",
"connectionStringSetting": "AzureWebJobsCosmosDBConnectionString",
"databaseName": "ItemDb",
"collectionName": "ItemCollectionIn",
"createLeaseCollectionIfNotExists": true
},
{
"type": "cosmosDB",
"name": "itemOut",
"direction": "out",
"leaseCollectionName": "leases",
"connectionStringSetting": "AzureWebJobsCosmosDBConnectionString",
"databaseName": "ItemDb",
"collectionName": "ItemCollectionOut"
}
]
}

Просмотреть файл

@ -0,0 +1,10 @@
param ($itemIn)
Write-Host "PowerShell Cosmos DB trigger function executed. Received document: $itemIn"
if ($itemIn -and $itemIn.Count -gt 0 ) {
$doc = $itemIn[0]
Write-Host "Document Id: $($doc.id)"
$doc.Description = "testdescription"
Push-OutputBinding -Name itemOut -Value $doc
}

Просмотреть файл

@ -0,0 +1,19 @@
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "test-input-object-ps",
"connection": "AzureWebJobsEventHubSender",
"cardinality": "many"
},
{
"type": "eventHub",
"name": "outEventHubMessage",
"eventHubName": "test-output-object-ps",
"connection": "AzureWebJobsEventHubSender",
"direction": "out"
}
]
}

Просмотреть файл

@ -0,0 +1,7 @@
param($eventHubMessages)
Write-Host "PowerShell eventhub trigger function called for object message array $eventHubMessages"
$eventHubMessages | ForEach-Object { "Processed message $_, value: $($_.value)" }
Push-OutputBinding -Name outEventHubMessage -Value $eventHubMessages[0]

Просмотреть файл

@ -0,0 +1,20 @@
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "test-input-string-ps",
"connection": "AzureWebJobsEventHubSender",
"cardinality": "many",
"dataType": "string"
},
{
"type": "eventHub",
"name": "outEventHubMessage",
"eventHubName": "test-output-string-ps",
"connection": "AzureWebJobsEventHubSender",
"direction": "out"
}
]
}

Просмотреть файл

@ -0,0 +1,7 @@
param($eventHubMessages)
Write-Host "PowerShell eventhub trigger function called for object message array $eventHubMessages"
$eventHubMessages | ForEach-Object { "Processed message $_, value: $($_.value)" }
Push-OutputBinding -Name outEventHubMessage -Value $eventHubMessages[0]

Просмотреть файл

@ -0,0 +1,19 @@
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "test-output-object-ps",
"connection": "AzureWebJobsEventHubSender",
"cardinality": "one"
},
{
"type": "queue",
"name": "outEventHubMessage",
"direction": "out",
"queueName": "test-output-object-ps",
"connection": "AzureWebJobsStorage"
}
]
}

Просмотреть файл

@ -0,0 +1,4 @@
param($eventHubMessages)
Write-Host "PowerShell EventHubVerifyStringObject function called for message $eventHubMessages"
Push-OutputBinding -Name outEventHubMessage -Value $eventHubMessages

Просмотреть файл

@ -0,0 +1,19 @@
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "test-output-string-ps",
"connection": "AzureWebJobsEventHubSender",
"cardinality": "one"
},
{
"type": "queue",
"name": "outEventHubMessage",
"direction": "out",
"queueName": "test-output-string-ps",
"connection": "AzureWebJobsStorage"
}
]
}

Просмотреть файл

@ -0,0 +1,4 @@
param($eventHubMessages)
Write-Host "PowerShell EventHubVerifyStringObject function called for message $eventHubMessages"
Push-OutputBinding -Name outEventHubMessage -Value $eventHubMessages

Просмотреть файл

@ -2,7 +2,7 @@
"disabled": false,
"bindings": [
{
"authLevel": "function",
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",

Просмотреть файл

@ -0,0 +1,23 @@
param($req)
# You can write to the Azure Functions log streams as you would in a normal PowerShell script.
Write-Verbose "PowerShell HTTP trigger function processed a request." -Verbose
# You can interact with query parameters, the body of the request, etc.
$name = $req.Query.Name
if (-not $name) { $name = $req.Body.Name }
if($name) {
$status = 200
$body = "Hello " + $name
}
else {
$status = 400
$body = "Please pass a name on the query string or in the request body."
}
# You associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})

Просмотреть файл

@ -2,7 +2,7 @@
"disabled": false,
"bindings": [
{
"authLevel": "function",
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",

Просмотреть файл

@ -0,0 +1,4 @@
param($req)
Write-Host "PowerShell HTTP trigger function processed a request."
throw "Test Exception"

Просмотреть файл

@ -1,3 +0,0 @@
function Get-ProfileString {
"PROFILE"
}

Просмотреть файл

@ -0,0 +1,18 @@
{
"bindings": [
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "test-input-ps",
"connection": "AzureWebJobsStorage"
},
{
"name": "outQueueItem",
"type": "queue",
"direction": "out",
"queueName": "test-output-ps",
"connection": "AzureWebJobsStorage"
}
]
}

Просмотреть файл

@ -0,0 +1,4 @@
param($myQueueItem)
Write-Host "PowerShell queue trigger function processed work item $myQueueItem"
Push-OutputBinding -Name outQueueItem -Value $myQueueItem

Просмотреть файл

@ -1,20 +0,0 @@
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}

Просмотреть файл

@ -1,9 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Input bindings are passed in via param block.
param($req)
throw 'Something happened.'

Просмотреть файл

@ -1,29 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Input bindings are passed in via param block.
param($req)
# You can write to the Azure Functions log streams as you would in a normal PowerShell script.
Write-Verbose "PowerShell HTTP trigger function processed a request." -Verbose
# You can interact with query parameters, the body of the request, etc.
$name = $req.Query.Name
if (-not $name) { $name = $req.Body.Name }
if($name) {
# Cast the value to HttpResponseContext explicitly.
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = 202
Body = "Hello " + $name
})
}
else {
# Convert value to HttpResponseContext implicitly for 'http' output.
Push-OutputBinding -Name res -Value @{
StatusCode = "400"
Body = "Please pass a name on the query string or in the request body."
}
}

Просмотреть файл

@ -1,12 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Input bindings are passed in via param block.
param($req)
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = 202
Body = (Get-ProfileString)
})

Просмотреть файл

@ -1,20 +0,0 @@
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}

Просмотреть файл

@ -1,29 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Input bindings are passed in via param block.
param($req, $TriggerMetadata)
# You can write to the Azure Functions log streams as you would in a normal PowerShell script.
Write-Verbose "PowerShell HTTP trigger function processed a request." -Verbose
# You can interact with query parameters, the body of the request, etc.
$name = $TriggerMetadata.req.Query.Name
if (-not $name) { $name = $TriggerMetadata.req.Body.Name }
if($name) {
# Cast the value to HttpResponseContext explicitly.
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = [System.Net.HttpStatusCode]::Accepted
Body = "Hello " + $name
})
}
else {
# Convert value to HttpResponseContext implicitly for 'http' output.
Push-OutputBinding -Name res -Value @{
StatusCode = 400
Body = "Please pass a name on the query string or in the request body."
}
}

Просмотреть файл

@ -1,22 +0,0 @@
{
"disabled": false,
"scriptFile": "module.psm1",
"entryPoint": "Run",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}

Просмотреть файл

@ -1,32 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
function Run
{
# Input bindings are passed in via param block.
param($req)
# You can write to the Azure Functions log streams as you would in a normal PowerShell script.
Write-Verbose "PowerShell HTTP trigger function processed a request." -Verbose
# You can interact with query parameters, the body of the request, etc.
$name = $req.Query.Name
if (-not $name) { $name = $req.Body.Name }
if($name) {
# Cast the value to HttpResponseContext explicitly.
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = 202
Body = "Hello " + $name
})
}
else {
# Convert value to HttpResponseContext implicitly for 'http' output.
Push-OutputBinding -Name res -Value @{
StatusCode = "400"
Body = "Please pass a name on the query string or in the request body."
}
}
}

Просмотреть файл

@ -1,22 +0,0 @@
{
"disabled": false,
"scriptFile": "module.psm1",
"entryPoint": "Run",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}

Просмотреть файл

@ -1,15 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
function Run
{
# Input bindings are passed in via param block.
param($req)
Push-OutputBinding -Name res -Value @{
StatusCode = 202
Body = (Get-ProfileString)
}
}

Просмотреть файл

@ -1,22 +0,0 @@
{
"disabled": false,
"scriptFile": "module.psm1",
"entryPoint": "Run",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}

Просмотреть файл

@ -1,32 +0,0 @@
#
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
function Run
{
# Input bindings are passed in via param block.
param($req, $TriggerMetadata)
# You can write to the Azure Functions log streams as you would in a normal PowerShell script.
Write-Verbose "PowerShell HTTP trigger function processed a request." -Verbose
# You can interact with query parameters, the body of the request, etc.
$name = $TriggerMetadata.req.Query.Name
if (-not $name) { $name = $TriggerMetadata.req.Body.Name }
if($name) {
# Cast the value to HttpResponseContext explicitly.
Push-OutputBinding -Name res -Value @{
StatusCode = [System.Net.HttpStatusCode]::Accepted
Body = "Hello " + $name
}
}
else {
# Convert value to HttpResponseContext implicitly for 'http' output.
Push-OutputBinding -Name res -Value ([HttpResponseContext]@{
StatusCode = 400
Body = "Please pass a name on the query string or in the request body."
})
}
}

Просмотреть файл

@ -1,8 +1,8 @@
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "powershell",
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
},
"ConnectionStrings": {}
"AzureWebJobsEventHubSender":"",
"AzureWebJobsCosmosDBConnectionString":"",
"FUNCTIONS_WORKER_RUNTIME": "powershell"
}
}

Просмотреть файл

@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\PowerShellWorker.Common.props" />
<Import Project="..\..\PowerShellWorker.Common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
@ -15,21 +15,21 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Microsoft.Azure.Functions.PowerShellWorker.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Azure.Functions.PowerShellWorker.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="Unit\PowerShell\TestScripts\**\*">
<Content Include="PowerShell\TestScripts\**\*">
<Link>TestScripts\PowerShell\%(RecursiveDir)\%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Unit\Function\TestScripts\**\*">
<Content Include="Function\TestScripts\**\*">
<Link>TestScripts\Function\%(RecursiveDir)\%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Unit\xunit.runner.json">
<Content Include="xunit.runner.json">
<Link>xunit.runner.json</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>

Просмотреть файл

@ -7,7 +7,7 @@ Describe 'Azure Functions PowerShell Langauge Worker Helper Module Tests' {
BeforeAll {
# Move the .psd1 and .psm1 files to the publish folder so that the dlls can be found
$binFolder = Resolve-Path -Path "$PSScriptRoot/../../bin"
$binFolder = Resolve-Path -Path "$PSScriptRoot/../bin"
$workerDll = Get-ChildItem -Path $binFolder -Filter "Microsoft.Azure.Functions.PowerShellWorker.dll" -Recurse | Select-Object -First 1
$moduleFolder = Join-Path -Path $workerDll.Directory.FullName -ChildPath "Modules\Microsoft.Azure.Functions.PowerShellWorker"