|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
using Microsoft.TemplateEngine.Abstractions;
using Microsoft.TemplateEngine.Cli.PostActionProcessors;
using Microsoft.TemplateEngine.Edge.Template;
using Microsoft.TemplateEngine.Mocks;
using Microsoft.TemplateEngine.TestHelper;
namespace Microsoft.TemplateEngine.Cli.UnitTests
{
public class PostActionDispatcherTests : IClassFixture<EnvironmentSettingsHelper>
{
private readonly EnvironmentSettingsHelper _environmentSettingsHelper;
public PostActionDispatcherTests(EnvironmentSettingsHelper environmentSettingsHelper)
{
_environmentSettingsHelper = environmentSettingsHelper;
}
[Fact]
public void CanProcessSuccessPostAction()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
var postAction = new MockPostAction(default, default, default, default, default!);
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Success, result);
Assert.Single(postActionProcessor.Calls);
Assert.Equal(engineEnvironmentSettings, postActionProcessor.Calls.Single().EngineEnvironmentSettings);
Assert.Equal(postAction, postActionProcessor.Calls.Single().PostAction);
Assert.Equal(creationEffects, postActionProcessor.Calls.Single().CreationEffects);
Assert.Equal(creationResult, postActionProcessor.Calls.Single().CreationResult);
Assert.Equal("TestPath", postActionProcessor.Calls.Single().OutputPath);
}
[Fact]
public void CanDryRunSuccessPostAction()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
var postAction = new MockPostAction(default, default, default, default, default!);
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
null,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: true, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Success, result);
Assert.Empty(postActionProcessor.Calls);
}
[Fact]
public void CanProcessFailedPostAction()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: false);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
var postAction = new MockPostAction(default, default, default, default, default!);
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Failure, result);
Assert.Equal(engineEnvironmentSettings, postActionProcessor.Calls.Single().EngineEnvironmentSettings);
Assert.Equal(postAction, postActionProcessor.Calls.Single().PostAction);
Assert.Equal(creationEffects, postActionProcessor.Calls.Single().CreationEffects);
Assert.Equal(creationResult, postActionProcessor.Calls.Single().CreationResult);
Assert.Equal("TestPath", postActionProcessor.Calls.Single().OutputPath);
}
[Fact]
public void CanDryRunFailedPostAction()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: false);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
var postAction = new MockPostAction(default, default, default, default, default!);
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: true, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Success, result);
Assert.Empty(postActionProcessor.Calls);
}
[Fact]
public void CanProcessUnknownPostAction()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: false);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = Guid.NewGuid(),
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Failure, result);
Assert.Empty(postActionProcessor.Calls);
}
[Fact]
public void CanProcessPostActionThrowingException()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ThrowExceptionPostAction());
var postAction = new MockPostAction(default, default, default, default, default!);
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Yes);
Assert.Equal(PostActionExecutionStatus.Failure, result);
}
[Fact]
public void CanContinueOnErrorWhenConfigured()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var trueProcessorGuid = Guid.NewGuid();
var falseProcessorGuid = Guid.NewGuid();
var trueProcessor = new CaptureMePostAction(expectedResult: true, guid: trueProcessorGuid);
var falseProcessor = new CaptureMePostAction(expectedResult: false, guid: falseProcessorGuid);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), trueProcessor);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), falseProcessor);
var postAction1 = new MockPostAction(default, default, default, default, default!)
{
ActionId = falseProcessorGuid,
ContinueOnError = true
};
var postAction2 = new MockPostAction(default, default, default, default, default!)
{
ActionId = trueProcessorGuid,
ContinueOnError = true
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction1, postAction2 });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Yes);
// in case continue on error is true, success status is returned on failure
Assert.Equal(PostActionExecutionStatus.Success, result);
//2 post actions were executed
Assert.Single(trueProcessor.Calls);
Assert.Single(falseProcessor.Calls);
Assert.Equal(postAction1, falseProcessor.Calls[0].PostAction);
Assert.Equal(postAction2, trueProcessor.Calls[0].PostAction);
}
[Fact]
public void CannotContinueOnErrorWhenNotConfigured()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var trueProcessorGuid = Guid.NewGuid();
var falseProcessorGuid = Guid.NewGuid();
var trueProcessor = new CaptureMePostAction(expectedResult: true, guid: trueProcessorGuid);
var falseProcessor = new CaptureMePostAction(expectedResult: false, guid: falseProcessorGuid);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), trueProcessor);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), falseProcessor);
var postAction1 = new MockPostAction(default, default, default, default, default!)
{
ActionId = falseProcessorGuid,
ContinueOnError = false
};
var postAction2 = new MockPostAction(default, default, default, default, default!)
{
ActionId = trueProcessorGuid,
ContinueOnError = false
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction1, postAction2 });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
"TestPath",
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Yes);
Assert.Equal(PostActionExecutionStatus.Failure, result);
//only first post action was executed
Assert.Empty(trueProcessor.Calls);
Assert.Single(falseProcessor.Calls);
Assert.Equal(postAction1, falseProcessor.Calls[0].PostAction);
}
[Fact]
public void CanProcessRunScriptPostAction_WhenRunScriptAllowed()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } }
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Yes);
//expect failure as post action fails
Assert.Equal(PostActionExecutionStatus.Failure, result);
}
[Fact]
public void CanProcessRunScriptPostAction_WhenRunScriptNotAllowed()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } }
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => string.Empty);
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.No);
Assert.Equal(PostActionExecutionStatus.Cancelled, result);
}
[Fact]
public void CanProcessRunScriptPostAction_WhenRunScriptPrompt_Yes()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } }
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => "Y"); // the user allows to run post action
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
//expect failure as post action fails
Assert.Equal(PostActionExecutionStatus.Failure, result);
}
[Fact]
public void CanProcessRunScriptPostAction_WhenRunScriptPrompt_No()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } }
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => "N"); // the user forbids to run post action
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Cancelled, result);
}
[Fact]
public void CanProcessRunScriptPostAction_DryRun()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } }
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => "N"); // the user forbids to run post action
//run script setting doesn't matter for dry run
var result = dispatcher.Process(templateCreationResult, isDryRun: true, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Success, result);
result = dispatcher.Process(templateCreationResult, isDryRun: true, AllowRunScripts.Yes);
Assert.Equal(PostActionExecutionStatus.Success, result);
result = dispatcher.Process(templateCreationResult, isDryRun: true, AllowRunScripts.No);
Assert.Equal(PostActionExecutionStatus.Success, result);
}
[Fact]
public void CanProcessRunScriptPostActionAndFailedPostAction_WhenRunScriptPrompt_No()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: false);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction1 = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } },
ContinueOnError = true
};
var postAction2 = new MockPostAction(default, default, default, default, default!)
{
ActionId = Guid.Empty, //CaptureMePostAction
ContinueOnError = true
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction1, postAction2 });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => "N"); // the user forbids to run post action
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Cancelled, result);
Assert.Single(postActionProcessor.Calls);
Assert.Equal(postAction2, postActionProcessor.Calls.Single().PostAction);
}
[Fact]
public void CanProcessRunScriptPostActionAndSuccessPostAction_WhenRunScriptPrompt_No()
{
var engineEnvironmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true);
var postActionProcessor = new CaptureMePostAction(expectedResult: true);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), postActionProcessor);
engineEnvironmentSettings.Components.AddComponent(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor());
var postAction1 = new MockPostAction(default, default, default, default, default!)
{
ActionId = ProcessStartPostActionProcessor.ActionProcessorId,
//the post action will fail, but that is OK for test purpose
Args = new Dictionary<string, string>()
{ { "executable", "do-not-exist" } },
ContinueOnError = true
};
var postAction2 = new MockPostAction(default, default, default, default, default!)
{
ActionId = Guid.Empty, //CaptureMePostAction
ContinueOnError = true
};
MockCreationResult creationResult = new(new List<IPostAction>() { postAction1, postAction2 });
MockCreationEffects creationEffects = new();
var templateCreationResult = new TemplateCreationResult(
CreationResultStatus.Success,
"TestTemplate",
null,
creationResult,
Path.GetTempPath(),
creationEffects);
PostActionDispatcher dispatcher = new(
engineEnvironmentSettings,
() => "N"); // the user forbids to run post action
var result = dispatcher.Process(templateCreationResult, isDryRun: false, AllowRunScripts.Prompt);
Assert.Equal(PostActionExecutionStatus.Cancelled, result);
Assert.NotEqual(PostActionExecutionStatus.Failure, result);
Assert.Single(postActionProcessor.Calls);
Assert.Equal(postAction2, postActionProcessor.Calls.Single().PostAction);
}
private class CaptureMePostAction : IPostActionProcessor
{
private readonly List<(
IEngineEnvironmentSettings EngineEnvironmentSettings,
IPostAction PostAction,
ICreationEffects CreationEffects,
ICreationResult CreationResult,
string OutputPath)> _receivedCalls = new();
private bool _expectedResult;
private string _testName;
private Guid _guid;
public CaptureMePostAction([CallerMemberName] string test = "", bool expectedResult = true, Guid guid = default)
{
_testName = test;
_expectedResult = expectedResult;
_guid = guid;
}
public Guid Id => _guid;
public IReadOnlyList<(
IEngineEnvironmentSettings EngineEnvironmentSettings,
IPostAction PostAction,
ICreationEffects CreationEffects,
ICreationResult CreationResult,
string OutputPath)> Calls => _receivedCalls;
public bool Process(
IEngineEnvironmentSettings environment,
IPostAction action,
ICreationEffects creationEffects,
ICreationResult templateCreationResult,
string outputBasePath)
{
_receivedCalls.Add((environment, action, creationEffects, templateCreationResult, outputBasePath));
return _expectedResult;
}
}
private class ThrowExceptionPostAction : IPostActionProcessor
{
public Guid Id => Guid.Empty;
public bool Process(
IEngineEnvironmentSettings environment,
IPostAction action,
ICreationEffects creationEffects,
ICreationResult templateCreationResult,
string outputBasePath)
{
throw new Exception("post action exception");
}
}
}
}
|