Skip to content

Commit

Permalink
Bootstrap test resources when running tests (#23652)
Browse files Browse the repository at this point in the history
* Bootstrap test resources when running tests.

* PR FB

* PR FB

* Fix text

* PR FB

* Check for playback

* Check CI
  • Loading branch information
JoshLove-msft authored Sep 1, 2021
1 parent 8383d49 commit 5728315
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 15 deletions.
12 changes: 12 additions & 0 deletions eng/scripts/New-TestResources-Bootstrapper.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

param(
[string] $ServiceDirectory
)
$run = Read-Host "The resources needed to run the live tests could not be located.`nWould you like to run the resource creation script? [y/n]"
if ($run -eq 'y'){
& "$PSScriptRoot\..\common\TestResources\New-TestResources.ps1" $ServiceDirectory

Read-Host "Press enter to close this window and resume your test run."
}
115 changes: 100 additions & 15 deletions sdk/core/Azure.Core.TestFramework/src/TestEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
using System.Threading.Tasks;
using Azure.Identity;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using NUnit.Framework;

namespace Azure.Core.TestFramework
Expand All @@ -24,14 +27,22 @@ public abstract class TestEnvironment
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
public static string RepositoryRoot { get; }

private static readonly Dictionary<Type, Task> s_environmentStateCache = new Dictionary<Type, Task>();
private static readonly Dictionary<Type, Task> s_environmentStateCache = new();

private readonly string _prefix;

private TokenCredential _credential;
private TestRecording _recording;
private readonly string _serviceName;

private readonly Dictionary<string, string> _environmentFile = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private Dictionary<string, string> _environmentFile;
private readonly string _serviceSdkDirectory;

private static readonly HashSet<Type> s_bootstrappingAttemptedTypes = new();
private static readonly object s_syncLock = new();
private static readonly bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private Exception _bootstrappingException;
private readonly Type _type;

protected TestEnvironment()
{
Expand All @@ -42,28 +53,35 @@ protected TestEnvironment()

var testProject = GetSourcePath(GetType().Assembly);
var sdkDirectory = Path.GetFullPath(Path.Combine(RepositoryRoot, "sdk"));
var serviceName = Path.GetFullPath(testProject)
_serviceName = Path.GetFullPath(testProject)
.Substring(sdkDirectory.Length)
.Trim(Path.DirectorySeparatorChar)
.Split(Path.DirectorySeparatorChar).FirstOrDefault();

if (string.IsNullOrWhiteSpace(serviceName))
if (string.IsNullOrWhiteSpace(_serviceName))
{
throw new InvalidOperationException($"Unable to determine the service name from test project path {testProject}");
}

var serviceSdkDirectory = Path.Combine(sdkDirectory, serviceName);
_serviceSdkDirectory = Path.Combine(sdkDirectory, _serviceName);
if (!Directory.Exists(sdkDirectory))
{
throw new InvalidOperationException($"SDK directory {serviceSdkDirectory} not found");
throw new InvalidOperationException($"SDK directory {_serviceSdkDirectory} not found");
}

_prefix = serviceName.ToUpperInvariant() + "_";
_prefix = _serviceName.ToUpperInvariant() + "_";
_type = GetType();

ParseEnvironmentFile();
}

private void ParseEnvironmentFile()
{
_environmentFile = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var testEnvironmentFiles = new[]
{
Path.Combine(serviceSdkDirectory, "test-resources.bicep.env"),
Path.Combine(serviceSdkDirectory, "test-resources.json.env")
Path.Combine(_serviceSdkDirectory, "test-resources.bicep.env"),
Path.Combine(_serviceSdkDirectory, "test-resources.json.env")
};

foreach (var testEnvironmentFile in testEnvironmentFiles)
Expand Down Expand Up @@ -216,10 +234,10 @@ public async ValueTask WaitForEnvironmentAsync()
Task task;
lock (s_environmentStateCache)
{
if (!s_environmentStateCache.TryGetValue(GetType(), out task))
if (!s_environmentStateCache.TryGetValue(_type, out task))
{
task = WaitForEnvironmentInternalAsync();
s_environmentStateCache[GetType()] = task;
s_environmentStateCache[_type] = task;
}
}
await task;
Expand Down Expand Up @@ -304,6 +322,11 @@ protected string GetRecordedVariable(string name)
protected string GetRecordedVariable(string name, Action<RecordedVariableOptions> options)
{
var value = GetRecordedOptionalVariable(name, options);
if (value == null)
{
BootStrapTestResources();
value = GetRecordedOptionalVariable(name, options);
}
EnsureValue(name, value);
return value;
}
Expand Down Expand Up @@ -348,6 +371,11 @@ protected string GetOptionalVariable(string name)
protected string GetVariable(string name)
{
var value = GetOptionalVariable(name);
if (value == null)
{
BootStrapTestResources();
value = GetOptionalVariable(name);
}
EnsureValue(name, value);
return value;
}
Expand All @@ -356,10 +384,18 @@ private void EnsureValue(string name, string value)
{
if (value == null)
{
var prefixedName = _prefix + name;
throw new InvalidOperationException(
$"Unable to find environment variable {prefixedName} or {name} required by test." + Environment.NewLine +
"Make sure the test environment was initialized using eng/common/TestResources/New-TestResources.ps1 script.");
string prefixedName = _prefix + name;
string message = $"Unable to find environment variable {prefixedName} or {name} required by test." + Environment.NewLine +
"Make sure the test environment was initialized using the eng/common/TestResources/New-TestResources.ps1 script.";
if (_bootstrappingException != null)
{
message += Environment.NewLine + "Resource creation failed during the test run. Make sure PowerShell version 6 or higher is installed.";
throw new InvalidOperationException(
message,
_bootstrappingException);
}

throw new InvalidOperationException(message);
}
}

Expand Down Expand Up @@ -459,5 +495,54 @@ internal static bool GlobalDisableAutoRecording
return disableAutoRecording || GlobalIsRunningInCI;
}
}

private void BootStrapTestResources()
{
lock (s_syncLock)
{
try
{
if (!s_isWindows ||
s_bootstrappingAttemptedTypes.Contains(_type) ||
Mode == RecordedTestMode.Playback ||
GlobalIsRunningInCI)
{
return;
}

string path = Path.Combine(
RepositoryRoot,
"eng",
"scripts",
$"New-TestResources-Bootstrapper.ps1 {_serviceName}");

var processInfo = new ProcessStartInfo(
@"pwsh.exe",
path)
{
UseShellExecute = true
};
Process process = null;
try
{
process = Process.Start(processInfo);
}
catch (Exception ex)
{
_bootstrappingException = ex;
}

if (process != null)
{
process.WaitForExit();
ParseEnvironmentFile();
}
}
finally
{
s_bootstrappingAttemptedTypes.Add(_type);
}
}
}
}
}

0 comments on commit 5728315

Please sign in to comment.