Skip to content

Commit 53b0896

Browse files
authored
emulated tests support (#790)
* test: emulated based tests * test: add storage emulated tests * fix: poolname * fix: run emulated containers on linux * fix name * switch win docker to run linux container * install docker * restart docker * npm install * add utility * fix * azurite * finish
1 parent 8934e63 commit 53b0896

25 files changed

+5289
-1
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.27703.2042
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Functions.Java.Tests.E2E", "Azure.Functions.Java.Tests.E2E\Azure.Functions.Java.Tests.E2E.csproj", "{830D2261-3E35-46A6-8B52-08233D852ED0}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{830D2261-3E35-46A6-8B52-08233D852ED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{830D2261-3E35-46A6-8B52-08233D852ED0}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{830D2261-3E35-46A6-8B52-08233D852ED0}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{830D2261-3E35-46A6-8B52-08233D852ED0}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {45378AFC-889B-4751-A494-44B73F8EA77E}
24+
EndGlobalSection
25+
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
12+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
13+
<PackageReference Include="WindowsAzure.Storage" Version="9.3.2" />
14+
<PackageReference Include="xunit" Version="2.3.1" />
15+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<None Update="confluent_cloud_cacert.pem">
20+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
21+
</None>
22+
<None Update="testBlobTrigger.txt">
23+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
24+
</None>
25+
</ItemGroup>
26+
27+
</Project>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Azure.Functions.Java.Tests.E2E
7+
{
8+
public static class Constants
9+
{
10+
public static string FunctionsHostUrl = Environment.GetEnvironmentVariable("FunctionAppUrl") ?? "http://localhost:7071";
11+
public static string StorageConnectionStringSetting = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
12+
13+
14+
//Queue tests
15+
public static string OutputBindingQueueName = "test-output-java";
16+
public static string InputBindingQueueName = "test-input-java";
17+
public static string OutputBindingQueueNamePOJO = "test-output-java-pojo";
18+
public static string InputBindingQueueNamePOJO = "test-input-java-pojo";
19+
public static string InputBindingQueueNameMetadata = "test-input-java-metadata";
20+
public static string OutputBindingQueueNameMetadata = "test-output-java-metadata";
21+
public static string TestQueueMessage = "Hello, World";
22+
23+
//Blob tests
24+
public static string TriggerInputBindingBlobContainer = "test-triggerinput-java-new";
25+
public static string InputBindingBlobContainer = "test-input-java-new";
26+
public static string OutputBindingBlobContainer = "test-output-java-new";
27+
28+
// Xunit Fixtures and Collections
29+
public const string FunctionAppCollectionName = "FunctionAppCollection";
30+
}
31+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
9+
namespace Azure.Functions.Java.Tests.E2E
10+
{
11+
public static class FixtureHelpers
12+
{
13+
public static Process GetFuncHostProcess(bool enableAuth = false)
14+
{
15+
var funcHostProcess = new Process();
16+
var rootDir = Path.GetFullPath(@"../../../../../..");
17+
18+
funcHostProcess.StartInfo.UseShellExecute = false;
19+
funcHostProcess.StartInfo.RedirectStandardError = true;
20+
funcHostProcess.StartInfo.RedirectStandardOutput = true;
21+
funcHostProcess.StartInfo.CreateNoWindow = true;
22+
funcHostProcess.StartInfo.WorkingDirectory = Path.Combine(rootDir, @"emulatedtests/target/azure-functions/azure-functions-java-emulatedtests");
23+
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
24+
{
25+
funcHostProcess.StartInfo.FileName = Path.Combine(rootDir, @"Azure.Functions.Cli/func.exe");
26+
}
27+
else
28+
{
29+
funcHostProcess.StartInfo.FileName = Path.Combine(rootDir, @"Azure.Functions.Cli/func");
30+
}
31+
funcHostProcess.StartInfo.ArgumentList.Add("start");
32+
if (enableAuth)
33+
{
34+
funcHostProcess.StartInfo.ArgumentList.Add("--enableAuth");
35+
}
36+
37+
return funcHostProcess;
38+
}
39+
40+
public static void StartProcessWithLogging(Process funcProcess)
41+
{
42+
funcProcess.ErrorDataReceived += (sender, e) => Console.WriteLine(e?.Data);
43+
funcProcess.OutputDataReceived += (sender, e) => Console.WriteLine(e?.Data);
44+
45+
funcProcess.Start();
46+
47+
funcProcess.BeginErrorReadLine();
48+
funcProcess.BeginOutputReadLine();
49+
}
50+
51+
public static void KillExistingFuncHosts()
52+
{
53+
foreach (var func in Process.GetProcessesByName("func"))
54+
{
55+
func.Kill();
56+
}
57+
}
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Threading;
7+
using Microsoft.Extensions.Logging;
8+
using Xunit;
9+
10+
namespace Azure.Functions.Java.Tests.E2E
11+
{
12+
public class FunctionAppFixture : IDisposable
13+
{
14+
private readonly ILogger _logger;
15+
private bool _disposed;
16+
private Process _funcProcess;
17+
18+
public FunctionAppFixture()
19+
{
20+
// initialize logging
21+
#pragma warning disable CS0618 // Type or member is obsolete
22+
ILoggerFactory loggerFactory = new LoggerFactory().AddConsole();
23+
#pragma warning restore CS0618 // Type or member is obsolete
24+
_logger = loggerFactory.CreateLogger<FunctionAppFixture>();
25+
26+
// start host via CLI if testing locally
27+
if (Constants.FunctionsHostUrl.Contains("localhost"))
28+
{
29+
// kill existing func processes
30+
_logger.LogInformation("Shutting down any running functions hosts..");
31+
FixtureHelpers.KillExistingFuncHosts();
32+
33+
// start functions process
34+
_logger.LogInformation($"Starting functions host for {Constants.FunctionAppCollectionName}..");
35+
_funcProcess = FixtureHelpers.GetFuncHostProcess();
36+
37+
FixtureHelpers.StartProcessWithLogging(_funcProcess);
38+
39+
_logger.LogInformation($"Waiting for functions host to be ready...");
40+
Thread.Sleep(TimeSpan.FromSeconds(30));
41+
}
42+
}
43+
44+
protected virtual void Dispose(bool disposing)
45+
{
46+
if (!_disposed)
47+
{
48+
if (disposing)
49+
{
50+
_logger.LogInformation("FunctionAppFixture disposing.");
51+
52+
if (_funcProcess != null)
53+
{
54+
_logger.LogInformation($"Shutting down functions host for {Constants.FunctionAppCollectionName}");
55+
_funcProcess.Kill();
56+
_funcProcess.Dispose();
57+
}
58+
}
59+
60+
_disposed = true;
61+
}
62+
}
63+
64+
public void Dispose()
65+
{
66+
Dispose(true);
67+
}
68+
}
69+
70+
[CollectionDefinition(Constants.FunctionAppCollectionName)]
71+
public class FunctionAppCollection : ICollectionFixture<FunctionAppFixture>
72+
{
73+
// This class has no code, and is never created. Its purpose is simply
74+
// to be the place to apply [CollectionDefinition] and all the
75+
// ICollectionFixture<> interfaces.
76+
}
77+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using Microsoft.WindowsAzure.Storage;
5+
using Microsoft.WindowsAzure.Storage.Blob;
6+
using Microsoft.WindowsAzure.Storage.Queue;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.IO;
10+
using System.Threading.Tasks;
11+
12+
namespace Azure.Functions.Java.Tests.E2E
13+
{
14+
class StorageHelpers
15+
{
16+
public static CloudStorageAccount _storageAccount = CloudStorageAccount.Parse(Constants.StorageConnectionStringSetting);
17+
public static CloudQueueClient _queueClient = _storageAccount.CreateCloudQueueClient();
18+
public static CloudBlobClient _cloudBlobClient = _storageAccount.CreateCloudBlobClient();
19+
20+
public async static Task DeleteQueue(string queueName)
21+
{
22+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
23+
await queue.DeleteAsync();
24+
}
25+
26+
public async static Task ClearQueue(string queueName)
27+
{
28+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
29+
if (await queue.ExistsAsync())
30+
{
31+
await queue.ClearAsync();
32+
}
33+
}
34+
35+
public async static Task CreateQueue(string queueName)
36+
{
37+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
38+
await queue.CreateIfNotExistsAsync();
39+
}
40+
41+
public async static Task<string> InsertIntoQueue(string queueName, string queueMessage)
42+
{
43+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
44+
await queue.CreateIfNotExistsAsync();
45+
CloudQueueMessage message = new CloudQueueMessage(queueMessage);
46+
await queue.AddMessageAsync(message);
47+
return message.Id;
48+
}
49+
50+
public async static Task<string> ReadFromQueue(string queueName)
51+
{
52+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
53+
CloudQueueMessage retrievedMessage = null;
54+
await Utilities.RetryAsync(async () =>
55+
{
56+
retrievedMessage = await queue.GetMessageAsync();
57+
return retrievedMessage != null;
58+
}, pollingInterval: 4000);
59+
await queue.DeleteMessageAsync(retrievedMessage);
60+
return retrievedMessage.AsString;
61+
}
62+
63+
public async static Task<IEnumerable<string>> ReadMessagesFromQueue(string queueName)
64+
{
65+
CloudQueue queue = _queueClient.GetQueueReference(queueName);
66+
IEnumerable<CloudQueueMessage> retrievedMessages = null;
67+
List<string> messages = new List<string>();
68+
await Utilities.RetryAsync(async () =>
69+
{
70+
retrievedMessages = await queue.GetMessagesAsync(3);
71+
return retrievedMessages != null;
72+
});
73+
foreach(CloudQueueMessage msg in retrievedMessages)
74+
{
75+
messages.Add(msg.AsString);
76+
await queue.DeleteMessageAsync(msg);
77+
}
78+
return messages;
79+
}
80+
81+
82+
public async static Task ClearBlobContainers()
83+
{
84+
await ClearBlobContainer(Constants.TriggerInputBindingBlobContainer);
85+
await ClearBlobContainer(Constants.InputBindingBlobContainer);
86+
await ClearBlobContainer(Constants.OutputBindingBlobContainer);
87+
}
88+
89+
public async static Task CreateBlobContainers()
90+
{
91+
await CreateBlobContainer(Constants.TriggerInputBindingBlobContainer);
92+
await CreateBlobContainer(Constants.InputBindingBlobContainer);
93+
await CreateBlobContainer(Constants.OutputBindingBlobContainer);
94+
}
95+
96+
public async static Task UpdloadFileToContainer(string containerName, string expectedFileName)
97+
{
98+
string sourceFile = $"{expectedFileName}.txt";
99+
File.WriteAllText(sourceFile, "Hello World");
100+
CloudBlobContainer cloudBlobContainer = _cloudBlobClient.GetContainerReference(containerName);
101+
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(sourceFile);
102+
await cloudBlockBlob.UploadFromFileAsync(sourceFile);
103+
}
104+
105+
public async static Task<string> DownloadFileFromContainer(string containerName, string expectedFileName)
106+
{
107+
string destinationFile = $"{expectedFileName}_DOWNLOADED.txt";
108+
string sourceFile = $"{expectedFileName}.txt";
109+
CloudBlobContainer cloudBlobContainer = _cloudBlobClient.GetContainerReference(containerName);
110+
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(sourceFile);
111+
await Utilities.RetryAsync(async () =>
112+
{
113+
return await cloudBlockBlob.ExistsAsync();
114+
}, pollingInterval: 4000, timeout: 120 * 1000);
115+
await cloudBlockBlob.DownloadToFileAsync(destinationFile, FileMode.Create);
116+
return File.ReadAllText(destinationFile);
117+
}
118+
119+
120+
private static async Task<CloudBlobContainer> CreateBlobContainer(string containerName)
121+
{
122+
BlobContainerPermissions permissions = new BlobContainerPermissions
123+
{
124+
PublicAccess = BlobContainerPublicAccessType.Blob
125+
};
126+
CloudBlobContainer cloudBlobContainer = _cloudBlobClient.GetContainerReference(containerName);
127+
await cloudBlobContainer.CreateIfNotExistsAsync();
128+
await cloudBlobContainer.SetPermissionsAsync(permissions);
129+
return cloudBlobContainer;
130+
}
131+
132+
private static async Task ClearBlobContainer(string containerName)
133+
{
134+
CloudBlobContainer cloudBlobContainer = _cloudBlobClient.GetContainerReference(containerName);
135+
BlobContinuationToken blobContinuationToken = null;
136+
do
137+
{
138+
if (!await cloudBlobContainer.ExistsAsync()) { continue; }
139+
var results = await cloudBlobContainer.ListBlobsSegmentedAsync(null, blobContinuationToken);
140+
// Get the value of the continuation token returned by the listing call.
141+
blobContinuationToken = results.ContinuationToken;
142+
foreach (IListBlobItem item in results.Results)
143+
{
144+
Console.WriteLine(item.Uri);
145+
String blobName = System.IO.Path.GetFileName(item.Uri.AbsolutePath);
146+
CloudBlob cloudBlob = cloudBlobContainer.GetBlobReference(blobName);
147+
await cloudBlob.DeleteIfExistsAsync();
148+
}
149+
} while (blobContinuationToken != null); // Loop while the continuation token is not null.
150+
}
151+
}
152+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"profiles": {
3+
"Azure.Functions.Java.Tests.E2E": {
4+
"commandName": "Project"
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)