-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend Templates testing framework to test through API #5677
Changes from 4 commits
5a4f2e8
1eec8a5
dc1ae71
26b23e7
2d4fde5
1a91b67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
Microsoft.TemplateEngine.Edge.Settings.ITemplateInfoHostJsonCache.HostData.get -> string? | ||
Microsoft.TemplateEngine.Edge.DefaultEnvironment.DefaultEnvironment(System.Collections.Generic.IReadOnlyDictionary<string!, string!>? additionalVirtualEnvironemnt) -> void | ||
Microsoft.TemplateEngine.Edge.Settings.ITemplateInfoHostJsonCache.HostData.get -> string? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,21 +10,23 @@ | |
using System.Threading.Tasks; | ||
using Microsoft.TemplateEngine.Abstractions; | ||
using Microsoft.TemplateEngine.Abstractions.Installer; | ||
using Microsoft.TemplateEngine.Abstractions.TemplateFiltering; | ||
using Microsoft.TemplateEngine.Abstractions.TemplatePackage; | ||
using Microsoft.TemplateEngine.Edge; | ||
using Microsoft.TemplateEngine.Edge.Settings; | ||
using Microsoft.TemplateEngine.Utils; | ||
using Microsoft.TemplateEngine.Edge.Template; | ||
using ITemplateCreationResult = Microsoft.TemplateEngine.Edge.Template.ITemplateCreationResult; | ||
using ITemplateMatchInfo = Microsoft.TemplateEngine.Abstractions.TemplateFiltering.ITemplateMatchInfo; | ||
using MatchInfo = Microsoft.TemplateEngine.Abstractions.TemplateFiltering.MatchInfo; | ||
using TemplateCreator = Microsoft.TemplateEngine.Edge.Template.TemplateCreator; | ||
using WellKnownSearchFilters = Microsoft.TemplateEngine.Utils.WellKnownSearchFilters; | ||
|
||
namespace Microsoft.TemplateEngine.IDE | ||
{ | ||
public class Bootstrapper : IDisposable | ||
{ | ||
private readonly ITemplateEngineHost _host; | ||
private readonly TemplateCreator _templateCreator; | ||
private readonly Edge.Settings.TemplatePackageManager _templatePackagesManager; | ||
private readonly TemplatePackageManager _templatePackagesManager; | ||
private readonly EngineEnvironmentSettings _engineEnvironmentSettings; | ||
|
||
/// <summary> | ||
|
@@ -35,19 +37,25 @@ public class Bootstrapper : IDisposable | |
/// <param name="loadDefaultComponents">if true, the default components (providers, installers, generator) will be loaded. Same as calling <see cref="LoadDefaultComponents()"/> after instance is created.</param> | ||
/// <param name="hostSettingsLocation">the file path to store host specific settings. Use null for default location. | ||
/// Note: this parameter changes only directory of host and host version specific settings. Global settings path remains unchanged.</param> | ||
public Bootstrapper(ITemplateEngineHost host, bool virtualizeConfiguration, bool loadDefaultComponents = true, string? hostSettingsLocation = null) | ||
/// <param name="additionalVirtualEnvironemnt">optional set of environment variables to be used.</param> | ||
JanKrivanek marked this conversation as resolved.
Show resolved
Hide resolved
JanKrivanek marked this conversation as resolved.
Show resolved
Hide resolved
JanKrivanek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public Bootstrapper( | ||
ITemplateEngineHost host, | ||
bool virtualizeConfiguration, | ||
bool loadDefaultComponents = true, | ||
string? hostSettingsLocation = null, | ||
IReadOnlyDictionary<string, string>? additionalVirtualEnvironemnt = null) | ||
{ | ||
_host = host ?? throw new ArgumentNullException(nameof(host)); | ||
IEnvironment environment = new DefaultEnvironment(additionalVirtualEnvironemnt); | ||
|
||
if (string.IsNullOrWhiteSpace(hostSettingsLocation)) | ||
{ | ||
_engineEnvironmentSettings = new EngineEnvironmentSettings(host, virtualizeSettings: virtualizeConfiguration); | ||
_engineEnvironmentSettings = new EngineEnvironmentSettings(host, virtualizeSettings: virtualizeConfiguration, environment: environment); | ||
} | ||
else | ||
{ | ||
string hostSettingsDir = Path.Combine(hostSettingsLocation, host.HostIdentifier); | ||
string hostVersionSettingsDir = Path.Combine(hostSettingsLocation, host.HostIdentifier, host.Version); | ||
IEnvironment environment = new DefaultEnvironment(); | ||
IPathInfo pathInfo = new DefaultPathInfo(environment, host, hostSettingsDir: hostSettingsDir, hostVersionSettingsDir: hostVersionSettingsDir); | ||
_engineEnvironmentSettings = new EngineEnvironmentSettings( | ||
host, | ||
|
@@ -57,7 +65,7 @@ public Bootstrapper(ITemplateEngineHost host, bool virtualizeConfiguration, bool | |
} | ||
|
||
_templateCreator = new TemplateCreator(_engineEnvironmentSettings); | ||
_templatePackagesManager = new Edge.Settings.TemplatePackageManager(_engineEnvironmentSettings); | ||
_templatePackagesManager = new TemplatePackageManager(_engineEnvironmentSettings); | ||
if (loadDefaultComponents) | ||
{ | ||
LoadDefaultComponents(); | ||
|
@@ -73,7 +81,7 @@ public void LoadDefaultComponents() | |
{ | ||
AddComponent(component.Type, component.Instance); | ||
} | ||
foreach ((Type Type, IIdentifiedComponent Instance) component in Edge.Components.AllComponents) | ||
foreach ((Type Type, IIdentifiedComponent Instance) component in Components.AllComponents) | ||
{ | ||
AddComponent(component.Type, component.Instance); | ||
} | ||
|
@@ -103,7 +111,7 @@ public Task<IReadOnlyList<ITemplateInfo>> GetTemplatesAsync(CancellationToken ca | |
/// <summary> | ||
/// Gets list of available templates, if <paramref name="filters"/> is provided returns only matching templates. | ||
/// </summary> | ||
/// <param name="filters">List of filters to apply. See <see cref="WellKnownSearchFilters"/> for predefined filters.</param> | ||
/// <param name="filters">List of filters to apply. See <see cref="Utils.WellKnownSearchFilters"/> for predefined filters.</param> | ||
/// <param name="exactMatchesOnly"> | ||
/// true: templates should match all filters; false: templates should match any filter. | ||
/// </param> | ||
|
@@ -158,6 +166,40 @@ public Task<ITemplateCreationResult> CreateAsync( | |
cancellationToken: cancellationToken); | ||
} | ||
|
||
/// <summary> | ||
/// Instantiates the template. | ||
/// </summary> | ||
/// <param name="info">The template to instantiate.</param> | ||
/// <param name="name">The name to use.</param> | ||
/// <param name="outputPath">The output directory for template instantiation.</param> | ||
/// <param name="inputParameters">The template parameters.</param> | ||
/// <param name="baselineName">The baseline configuration to use.</param> | ||
/// <param name="cancellationToken">A cancellation token to cancel the asynchronous operation.</param> | ||
/// <returns><see cref="ITemplateCreationResult"/> containing information on created template or error occurred.</returns> | ||
#pragma warning disable RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads | ||
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters | ||
public Task<ITemplateCreationResult> CreateAsync( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just a thought - should we make other one obsolete? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other |
||
ITemplateInfo info, | ||
string? name, | ||
string outputPath, | ||
InputDataSet? inputParameters, | ||
string? baselineName = null, | ||
CancellationToken cancellationToken = default) | ||
#pragma warning restore RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads | ||
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters | ||
{ | ||
return _templateCreator.InstantiateAsync( | ||
info, | ||
name, | ||
fallbackName: null, | ||
outputPath: outputPath, | ||
inputParameters: inputParameters, | ||
forceCreation: false, | ||
baselineName: baselineName, | ||
dryRun: false, | ||
cancellationToken: cancellationToken); | ||
} | ||
|
||
/// <summary> | ||
/// Dry runs the template with given parameters. | ||
/// </summary> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
| ||
Microsoft.TemplateEngine.IDE.Bootstrapper.Bootstrapper(Microsoft.TemplateEngine.Abstractions.ITemplateEngineHost! host, bool virtualizeConfiguration, bool loadDefaultComponents = true, string? hostSettingsLocation = null, System.Collections.Generic.IReadOnlyDictionary<string!, string!>? additionalVirtualEnvironemnt = null) -> void | ||
Microsoft.TemplateEngine.IDE.Bootstrapper.CreateAsync(Microsoft.TemplateEngine.Abstractions.ITemplateInfo! info, string? name, string! outputPath, Microsoft.TemplateEngine.Edge.Template.InputDataSet? inputParameters, string? baselineName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Microsoft.TemplateEngine.Edge.Template.ITemplateCreationResult!>! |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using Microsoft.TemplateEngine.Authoring.TemplateApiVerifier; | ||
using Microsoft.TemplateEngine.TestHelper; | ||
using Microsoft.TemplateEngine.Tests; | ||
using Xunit.Abstractions; | ||
|
@@ -17,6 +18,10 @@ public ExampleTemplateTest(ITestOutputHelper log) | |
_log = new XunitLoggerProvider(log).CreateLogger("TestRun"); | ||
} | ||
|
||
// Following 2 tests share identical snapshot folder - that's the reason for the additional | ||
// naming parameters (DoNotPrependCallerMethodNameToScenarioName, DoNotAppendTemplateArgsToScenarioName, ScenarioName) | ||
// The identity of snapshots ilustrates that execution through API and through full blown command leads to identical results | ||
|
||
[Fact] | ||
public async void VerificationEngineSampleDogfoodTest() | ||
{ | ||
|
@@ -33,10 +38,47 @@ public async void VerificationEngineSampleDogfoodTest() | |
SnapshotsDirectory = "Snapshots", | ||
OutputDirectory = workingDir, | ||
VerifyCommandOutput = true, | ||
DoNotPrependTemplateNameToScenarioName = true, | ||
DoNotPrependCallerMethodNameToScenarioName = true, | ||
DoNotAppendTemplateArgsToScenarioName = true, | ||
ScenarioName = "SampleDogfoodTest", | ||
// This is here just for testing and documentation purposes - showing functionality of differing snapshots for arch | ||
UniqueFor = UniqueForOption.Architecture, | ||
} | ||
.WithCustomScrubbers( | ||
ScrubbersDefinition.Empty | ||
.AddScrubber(sb => sb.Replace("B is enabled", "*******")) | ||
.AddScrubber((path, content) => | ||
{ | ||
if (path.Replace(Path.DirectorySeparatorChar, '/') == "std-streams/stdout.txt") | ||
{ | ||
content.Replace("SampleTestTemplate", "%TEMPLATE%"); | ||
} | ||
})); | ||
|
||
VerificationEngine engine = new VerificationEngine(_log); | ||
await engine.Execute(options); | ||
} | ||
|
||
[Fact] | ||
public async void VerificationEngineSampleDogfoodTest_ExecThroughApi() | ||
{ | ||
string workingDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName().Replace(".", string.Empty)); | ||
string templateShortName = "TestAssets.SampleTestTemplate"; | ||
|
||
//get the template location | ||
string templateLocation = Path.Combine(TestTemplatesLocation, "TestTemplate"); | ||
|
||
TemplateVerifierOptions options = new TemplateVerifierOptions(templateName: templateShortName) | ||
{ | ||
TemplatePath = templateLocation, | ||
SnapshotsDirectory = "Snapshots", | ||
OutputDirectory = workingDir, | ||
VerifyCommandOutput = true, | ||
DoNotPrependCallerMethodNameToScenarioName = true, | ||
ScenarioName = "SampleDogfoodTest", | ||
UniqueFor = UniqueForOption.Architecture, | ||
} | ||
.WithInstantiationThroughTemplateCreatorApi(new Dictionary<string, string?>() { { "paramB", "true" } }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @YuliiaKovalova this can be inspiration how the imported sample templates might be tested (only |
||
.WithCustomScrubbers( | ||
ScrubbersDefinition.Empty | ||
.AddScrubber(sb => sb.Replace("B is enabled", "*******")) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought - would it be better to do own implementation? Maybe something as
ExtendedEnvironment
?another thought: https://github.com/dotnet/sdk/blob/main/src/Cli/Microsoft.TemplateEngine.Cli/CliEnvironment.cs we can get rid of this custom implementation with this class now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were few options:
DefaultEnvironment
and extend.DefaultEnvironment
logic and add custom logicDefaultEnvironment
The last one felt as the one with least dept incured. Though I might miss some obvious reason why it might not be an optional choice - so I'm open to alternative thoughts :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference is the first one, just to intentionally keep it separate, so it is not misused, however I don't insist.