Replace JSON test DSL with regular C# Xunit tests for consistency with other ASP.NET repos

This commit is contained in:
Steve Sanderson 2017-08-29 16:40:03 +01:00
parent 58211f89c7
commit 1f9dd4db5d
33 changed files with 473 additions and 1827 deletions

View File

@ -0,0 +1,20 @@
using Xunit;
namespace Templates.Test
{
public class EmptyWebTemplateTest : TemplateTestBase
{
[Theory]
[InlineData(null)]
[InlineData("net461")]
public void EmptyWebTemplate_Works(string targetFrameworkOverride)
{
RunDotNetNew("web", targetFrameworkOverride);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/");
}
}
}
}

View File

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using Xunit;
namespace Templates.Test.Helpers
{
public class AspNetProcess : IDisposable
{
private const string DefaultFramework = "netcoreapp2.0";
private const string ListeningMessagePrefix = "Now listening on: ";
private static int NextKestrelPort = 5000;
private readonly ProcessEx _process;
private readonly Uri _listeningUri;
private readonly HttpClient _httpClient;
public AspNetProcess(string workingDirectory, string projectName, string targetFrameworkOverride)
{
_httpClient = new HttpClient();
var buildProcess = ProcessEx.Run(workingDirectory, "dotnet", "build --no-restore -c Debug");
buildProcess.WaitForExit(assertSuccess: true);
var port = Interlocked.Increment(ref NextKestrelPort);
var envVars = new Dictionary<string, string>
{
{ "ASPNETCORE_URLS", "http://localhost:" + port }
};
var framework = string.IsNullOrEmpty(targetFrameworkOverride) ? DefaultFramework : targetFrameworkOverride;
if (framework.StartsWith("netcore"))
{
_process = ProcessEx.Run(workingDirectory, "dotnet", $"exec bin/Debug/{framework}/{projectName}.dll", envVars: envVars);
}
else
{
var exeFullPath = Path.Combine(workingDirectory, "bin", "Debug", framework, $"{projectName}.exe");
_process = ProcessEx.Run(workingDirectory, exeFullPath, envVars: envVars);
}
// Wait until the app is accepting HTTP requests
var listeningMessage = _process
.OutputLinesAsEnumerable
.Where(line => line != null)
.FirstOrDefault(line => line.StartsWith(ListeningMessagePrefix, StringComparison.Ordinal));
Assert.True(!string.IsNullOrEmpty(listeningMessage), $"ASP.NET process exited without listening for requests.\nOutput: { _process.Output }\nError: { _process.Error }");
// Verify we have a valid URL to make requests to
var listeningUrlString = listeningMessage.Substring(ListeningMessagePrefix.Length);
_listeningUri = new Uri(listeningUrlString, UriKind.Absolute);
}
internal void AssertOk(string requestUrl)
=> AssertStatusCode(requestUrl, HttpStatusCode.OK);
internal void AssertNotFound(string requestUrl)
=> AssertStatusCode(requestUrl, HttpStatusCode.NotFound);
internal void AssertStatusCode(string requestUrl, HttpStatusCode statusCode)
{
var request = new HttpRequestMessage(
HttpMethod.Get,
new Uri(_listeningUri, requestUrl));
var response = _httpClient.SendAsync(request).Result;
Assert.Equal(statusCode, response.StatusCode);
}
public void Dispose()
{
_httpClient.Dispose();
_process.Dispose();
}
}
}

107
test/Helpers/ProcessEx.cs Normal file
View File

@ -0,0 +1,107 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text;
using Xunit;
namespace Templates.Test.Helpers
{
internal class ProcessEx : IDisposable
{
private readonly Process _process;
private readonly StringBuilder _stderrCapture;
private readonly StringBuilder _stdoutCapture;
private BlockingCollection<string> _stdoutLines;
public static ProcessEx Run(string workingDirectory, string command, string args = null, IDictionary<string, string> envVars = null)
{
var startInfo = new ProcessStartInfo(command, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = workingDirectory
};
if (envVars != null)
{
foreach (var envVar in envVars)
{
startInfo.EnvironmentVariables.Add(envVar.Key, envVar.Value);
}
}
var proc = Process.Start(startInfo);
return new ProcessEx(proc);
}
public ProcessEx(Process proc)
{
_stdoutCapture = new StringBuilder();
_stderrCapture = new StringBuilder();
_stdoutLines = new BlockingCollection<string>();
_process = proc;
proc.EnableRaisingEvents = true;
proc.OutputDataReceived += OnOutputData;
proc.ErrorDataReceived += OnErrorData;
proc.Exited += OnProcessExited;
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
public string Error => _stderrCapture.ToString();
public string Output => _stdoutCapture.ToString();
public int ExitCode => _process.ExitCode;
private void OnErrorData(object sender, DataReceivedEventArgs e)
{
_stderrCapture.AppendLine(e.Data);
Console.Error.WriteLine(e.Data);
}
private void OnOutputData(object sender, DataReceivedEventArgs e)
{
_stdoutCapture.AppendLine(e.Data);
Console.WriteLine(e.Data);
if (_stdoutLines != null)
{
_stdoutLines.Add(e.Data);
}
}
private void OnProcessExited(object sender, EventArgs e)
{
_stdoutLines.CompleteAdding();
_stdoutLines = null;
}
public void WaitForExit(bool assertSuccess)
{
_process.WaitForExit();
if (assertSuccess && _process.ExitCode != 0)
{
throw new Exception($"Process exited with code {_process.ExitCode}\nStdErr: {Error}\nStdOut: {Output}");
}
}
public void Dispose()
{
if (_process != null && !_process.HasExited)
{
_process.Kill();
_process.WaitForExit();
}
}
public IEnumerable<string> OutputLinesAsEnumerable => _stdoutLines.GetConsumingEnumerable();
}
}

View File

@ -0,0 +1,124 @@
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using Templates.Test.Helpers;
using Xunit;
namespace Templates.Test
{
public class TemplateTestBase : IDisposable
{
protected string ProjectName { get; set; }
protected string TemplateOutputDir { get; private set; }
public TemplateTestBase()
{
ProjectName = Guid.NewGuid().ToString().Replace("-", "");
var assemblyPath = GetType().GetTypeInfo().Assembly.CodeBase;
var assemblyUri = new Uri(assemblyPath, UriKind.Absolute);
var basePath = Path.GetDirectoryName(assemblyUri.LocalPath);
TemplateOutputDir = Path.Combine(basePath, "TestTemplates", ProjectName);
Directory.CreateDirectory(TemplateOutputDir);
}
protected void InstallTemplatePackages()
{
throw new NotImplementedException();
}
protected void RunDotNetNew(string templateName, string targetFrameworkOverride, string auth = null, string language = null)
{
var args = $"new {templateName}";
if (!string.IsNullOrEmpty(targetFrameworkOverride))
{
args += $" --target-framework-override {targetFrameworkOverride}";
}
if (!string.IsNullOrEmpty(auth))
{
args += $" -au {auth}";
}
if (!string.IsNullOrEmpty(language))
{
args += $" -lang {language}";
}
ProcessEx.Run(TemplateOutputDir, "dotnet", args).WaitForExit(assertSuccess: true);
}
protected void AssertDirectoryExists(string path, bool shouldExist)
{
var fullPath = Path.Combine(TemplateOutputDir, path);
var doesExist = Directory.Exists(fullPath);
if (shouldExist)
{
Assert.True(doesExist, "Expected directory to exist, but it doesn't: " + path);
}
else
{
Assert.False(doesExist, "Expected directory not to exist, but it does: " + path);
}
}
protected void AssertFileExists(string path, bool shouldExist)
{
var fullPath = Path.Combine(TemplateOutputDir, path);
var doesExist = File.Exists(fullPath);
if (shouldExist)
{
Assert.True(doesExist, "Expected file to exist, but it doesn't: " + path);
}
else
{
Assert.False(doesExist, "Expected file not to exist, but it does: " + path);
}
}
protected string ReadFile(string path)
{
AssertFileExists(path, shouldExist: true);
return File.ReadAllText(Path.Combine(TemplateOutputDir, path));
}
protected AspNetProcess StartAspNetProcess(string targetFrameworkOverride)
{
return new AspNetProcess(TemplateOutputDir, ProjectName, targetFrameworkOverride);
}
public void Dispose()
{
DeleteOutputDirectory();
}
private void DeleteOutputDirectory()
{
var numAttempts = 5;
while (true)
{
try
{
Directory.Delete(TemplateOutputDir, true);
return;
}
catch (IOException)
{
numAttempts--;
if (numAttempts > 0)
{
Thread.Sleep(2000);
}
else
{
throw;
}
}
}
}
}
}

63
test/MvcTemplateTest.cs Normal file
View File

@ -0,0 +1,63 @@
using Xunit;
namespace Templates.Test
{
public class MvcTemplateTest : TemplateTestBase
{
[Theory]
[InlineData(/* netcoreapp */ null, /* C# */ null)]
[InlineData("net461", /* C# */ null)]
[InlineData(/* netcoreapp */ null, "F#")]
[InlineData("net461", "F#")]
public void MvcTemplate_NoAuth_Works(string targetFrameworkOverride, string languageOverride)
{
RunDotNetNew("mvc", targetFrameworkOverride, language: languageOverride);
AssertDirectoryExists("Areas", false);
AssertDirectoryExists("Extensions", false);
AssertFileExists("urlRewrite.config", false);
AssertFileExists("Controllers/AccountController.cs", false);
var projectExtension = languageOverride == "F#" ? "fsproj" : "csproj";
var projectFileContents = ReadFile($"{ProjectName}.{projectExtension}");
Assert.DoesNotContain(".db", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.DoesNotContain("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.DoesNotContain("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/");
aspNetProcess.AssertOk("/Home/About");
aspNetProcess.AssertOk("/Home/Contact");
}
}
[Theory]
[InlineData(null)]
[InlineData("net461")]
public void MvcTemplate_IndividualAuth_Works(string targetFrameworkOverride)
{
RunDotNetNew("mvc", targetFrameworkOverride, auth: "Individual");
AssertDirectoryExists("Extensions", true);
AssertFileExists("urlRewrite.config", false);
AssertFileExists("Controllers/AccountController.cs", true);
var projectFileContents = ReadFile($"{ProjectName}.csproj");
Assert.Contains(".db", projectFileContents);
Assert.Contains("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.Contains("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.Contains("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.Contains("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/");
aspNetProcess.AssertOk("/Home/About");
aspNetProcess.AssertOk("/Home/Contact");
}
}
}
}

View File

@ -0,0 +1,57 @@
using Xunit;
namespace Templates.Test
{
public class RazorPagesTemplateTest : TemplateTestBase
{
[Theory]
[InlineData(null)]
[InlineData("net461")]
public void RazorPagesTemplate_NoAuth_Works(string targetFrameworkOverride)
{
RunDotNetNew("razor", targetFrameworkOverride);
AssertDirectoryExists("Extensions", false);
AssertFileExists("Controllers/AccountController.cs", false);
var projectFileContents = ReadFile($"{ProjectName}.csproj");
Assert.DoesNotContain(".db", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.DoesNotContain("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.DoesNotContain("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.DoesNotContain("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/");
aspNetProcess.AssertOk("/About");
aspNetProcess.AssertOk("/Contact");
}
}
[Theory]
[InlineData(null)]
[InlineData("net461")]
public void RazorPagesTemplate_IndividualAuth_Works(string targetFrameworkOverride)
{
RunDotNetNew("razor", targetFrameworkOverride, auth: "Individual");
AssertDirectoryExists("Extensions", true);
AssertFileExists("Controllers/AccountController.cs", true);
var projectFileContents = ReadFile($"{ProjectName}.csproj");
Assert.Contains(".db", projectFileContents);
Assert.Contains("Microsoft.EntityFrameworkCore.Tools", projectFileContents);
Assert.Contains("Microsoft.VisualStudio.Web.CodeGeneration.Design", projectFileContents);
Assert.Contains("Microsoft.EntityFrameworkCore.Tools.DotNet", projectFileContents);
Assert.Contains("Microsoft.Extensions.SecretManager.Tools", projectFileContents);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/");
aspNetProcess.AssertOk("/About");
aspNetProcess.AssertOk("/Contact");
}
}
}
}

View File

@ -0,0 +1,21 @@
using Xunit;
namespace Templates.Test
{
public class WebApiTemplateTest : TemplateTestBase
{
[Theory]
[InlineData(null)]
[InlineData("net461")]
public void WebApiTemplate_Works(string targetFrameworkOverride)
{
RunDotNetNew("api", targetFrameworkOverride);
using (var aspNetProcess = StartAspNetProcess(targetFrameworkOverride))
{
aspNetProcess.AssertOk("/api/values");
aspNetProcess.AssertNotFound("/");
}
}
}
}

View File

@ -1,8 +0,0 @@
using Xunit;
namespace Templates.Test
{
public class WebTemplateTest
{
}
}

View File

@ -1,304 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
using ProjectTestRunner.Handlers;
using ProjectTestRunner.Helpers;
using Xunit;
using Xunit.Abstractions;
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace ProjectTestRunner
{
public class Battery
{
private static readonly IReadOnlyDictionary<string, IHandler> HandlerLookup = new Dictionary<string, IHandler>
{
{ ExecuteHandler.Handler, new ExecuteHandler() },
{ TaskKillHandler.Handler, new TaskKillHandler() },
{ HttpRequestHandler.Handler, new HttpRequestHandler() },
{ FindProcessHandler.Handler, new FindProcessHandler() },
{ FileInspectHandler.Handler, new FileInspectHandler() },
{ DirectoryInspectHandler.Handler, new DirectoryInspectHandler() },
};
private static readonly string Creator;
private static readonly string BasePath;
static Battery()
{
string assemblyPath = typeof(Battery).GetTypeInfo().Assembly.CodeBase;
Uri assemblyUri = new Uri(assemblyPath, UriKind.Absolute);
assemblyPath = assemblyUri.LocalPath;
BasePath = Path.GetDirectoryName(assemblyPath);
Creator = Environment.GetEnvironmentVariable("CREATION_TEST_RUNNER");
if (string.IsNullOrWhiteSpace(Creator))
{
Creator = "new";
}
Proc.Run("dotnet", $"--version").WaitForExit();
Proc.Run("dotnet", $"{Creator} --debug:reinit").WaitForExit();
Proc.Run("dotnet", $"{Creator}").WaitForExit();
string templateFeedDirectory = FindTemplateFeedDirectory(BasePath);
Proc.Run("dotnet", $"{Creator} -i \"{templateFeedDirectory}\"").WaitForExit();
}
public Battery(ITestOutputHelper outputHelper)
{
Console.SetOut(new OutputHelperHelper(outputHelper));
Console.SetError(new OutputHelperHelper(outputHelper));
}
[PrettyTheory, MemberData(nameof(Discover))]
public void Run(TemplateTestData testData)
{
bool success = true;
string[] allParts = new string[testData.Paths.Length + 2];
allParts[0] = BasePath;
allParts[1] = "TestCases";
for (int i = 0; i < testData.Paths.Length; ++i)
{
allParts[i + 2] = testData.Paths[i];
}
string contents = File.ReadAllText(Path.Combine(allParts));
contents = Environment.ExpandEnvironmentVariables(contents);
JObject json = JObject.Parse(contents);
if (json["skip"]?.Value<bool>() ?? false)
{
Console.WriteLine("Test Skipped");
return;
}
string targetPath = Path.Combine(GetTemplatePath(), "_" + Guid.NewGuid().ToString().Replace("-", ""));
try
{
string install = json["install"]?.ToString();
string command = testData.CreateCommand;
Console.WriteLine("Testing: " + testData.Name);
Dictionary<string, string> dict = new Dictionary<string, string>
{
{ "targetPath", targetPath},
{ "targetPathName", Path.GetFileName(targetPath)},
};
List<IHandlerResult> results = new List<IHandlerResult>();
IHandlerResult current;
string message;
if (!string.IsNullOrWhiteSpace(install))
{
Console.WriteLine($"Executing step {(results.Count + 1)} (install)...");
current = Install(Creator, install);
message = current.VerificationSuccess ? $"PASS ({current.Duration})" : $"FAIL ({current.Duration}): {current.FailureMessage}";
Console.WriteLine($" {message}");
Console.WriteLine(" ");
if (!current.VerificationSuccess)
{
success = false;
Assert.False(true, current.FailureMessage);
}
}
Console.WriteLine($"Executing step {(results.Count + 1)} (create)...");
current = Create(Creator, install, testData.CreateCommand, targetPath);
message = current.VerificationSuccess ? $"PASS ({current.Duration})" : $"FAIL ({current.Duration}): {current.FailureMessage}";
Console.WriteLine($" {message}");
Console.WriteLine(" ");
if (!current.VerificationSuccess)
{
success = false;
Assert.False(true, current.FailureMessage);
}
results.Add(current);
foreach (JObject entry in ((JArray)json["tasks"]).Children().OfType<JObject>())
{
string handlerKey = entry["handler"].ToString();
string variationKey = entry["variation"]?.ToString();
// running the right variation, or
if (string.Equals(testData.Variation, variationKey)
|| variationKey == null
|| (testData.Variation == null && variationKey.Equals(string.Empty)))
{
IHandler handler = HandlerLookup[handlerKey];
Console.WriteLine($"Executing step {(results.Count + 1)} ({handler.Summarize(dict, entry)})...");
current = handler.Execute(dict, results, entry);
message = current.VerificationSuccess ? $"PASS ({current.Duration})" : $"FAIL ({current.Duration}): {current.FailureMessage}";
Console.WriteLine($" {message}");
Console.WriteLine(" ");
results.Add(current);
}
}
foreach (IHandlerResult result in results)
{
success = !success ? success : result.VerificationSuccess;
Assert.False(!result.VerificationSuccess, result.FailureMessage);
}
}
finally
{
if (success)
{
for (int i = 0; i < 5; ++i)
{
try
{
DeleteDirectory(targetPath);
break;
}
catch
{
Thread.Sleep(500);
}
}
}
}
}
public static void DeleteDirectory(string directory)
{
string[] files = Directory.GetFiles(directory);
string[] dirs = Directory.GetDirectories(directory);
foreach (string file in files)
{
File.SetAttributes(file, FileAttributes.Normal);
File.Delete(file);
}
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
Directory.Delete(directory, true);
}
private IHandlerResult Install(string creator, string installPackage)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
Process install = Proc.Run("dotnet", $"{creator} -i \"{installPackage}\"");
install.WaitForExit();
if (install.ExitCode != 0)
{
return new GenericHandlerResult(watch.Elapsed, false, $"\"{installPackage}\" failed to install");
}
return new GenericHandlerResult(watch.Elapsed, true, null);
}
finally
{
watch.Stop();
}
}
private static string FindTemplateFeedDirectory(string batteryDirectory)
{
DirectoryInfo currentDirectory = new DirectoryInfo(batteryDirectory);
string templateFeed = Path.Combine(currentDirectory.FullName, "template_feed");
while (!Directory.Exists(templateFeed))
{
currentDirectory = currentDirectory.Parent;
templateFeed = Path.Combine(currentDirectory.FullName, "template_feed");
}
return templateFeed;
}
private static IHandlerResult Create(string creator, string installPackage, string command, string targetPath)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
Directory.CreateDirectory(targetPath);
Process create = Proc.Run("dotnet", $"{creator} {command} -o \"{targetPath}\"");
create.WaitForExit();
if (create.ExitCode != 0)
{
return new GenericHandlerResult(watch.Elapsed, false, $"\"{command}\" failed create");
}
Directory.SetCurrentDirectory(targetPath);
return new GenericHandlerResult(watch.Elapsed, true, null);
}
finally
{
watch.Stop();
}
}
private string GetTemplatePath()
{
return Path.Combine(BasePath, "TestTemplates");
}
public static IEnumerable<object[]> Discover()
{
string basePath = Path.Combine(BasePath, "TestCases");
foreach (string testCase in Directory.EnumerateFiles(basePath, "*.json", SearchOption.AllDirectories))
{
string contents = File.ReadAllText(Path.Combine(testCase));
contents = Environment.ExpandEnvironmentVariables(contents);
JObject json = JObject.Parse(contents);
string relPath = testCase.Substring(basePath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
var data = new TemplateTestData()
{
Paths = relPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar),
Name = json["name"].ToString(),
CreateCommand = json["create"].ToString(),
Variation = null
};
yield return new object[] { data };
if (json["variations"] != null)
{
foreach (JObject entry in ((JArray)json["variations"]).Children().OfType<JObject>())
{
var variation = new TemplateTestData()
{
Paths = relPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar),
Name = entry["name"]?.ToString() ?? data.Name,
Variation = entry["id"].ToString(),
CreateCommand = entry["create"]?.ToString() ?? data.CreateCommand
};
yield return new object[] { variation };
}
}
}
}
}
}

View File

@ -1,32 +0,0 @@
using System;
using System.Diagnostics;
namespace ProjectTestRunner.HandlerResults
{
internal class ExecuteHandlerResult : IHandlerResult
{
private readonly Process _process;
public ExecuteHandlerResult(TimeSpan duration, bool verificationSuccess, string failureMessage, Process process = null, string name = null)
{
Duration = duration;
_process = process;
Name = name;
VerificationSuccess = verificationSuccess;
FailureMessage = failureMessage;
}
public bool VerificationSuccess { get; }
public string FailureMessage { get; }
public string Name { get; }
public TimeSpan Duration { get; }
public void Kill()
{
_process?.Kill();
}
}
}

View File

@ -1,23 +0,0 @@
using System;
namespace ProjectTestRunner.HandlerResults
{
internal class GenericHandlerResult : IHandlerResult
{
public GenericHandlerResult(TimeSpan duration, bool verificationSuccess, string failureMessage, string name = null)
{
Duration = duration;
Name = name;
VerificationSuccess = verificationSuccess;
FailureMessage = failureMessage;
}
public string Name { get; }
public bool VerificationSuccess { get; }
public string FailureMessage { get; }
public TimeSpan Duration { get; }
}
}

View File

@ -1,15 +0,0 @@
using System;
namespace ProjectTestRunner.HandlerResults
{
public interface IHandlerResult
{
string Name { get; }
bool VerificationSuccess { get; }
string FailureMessage { get; }
TimeSpan Duration { get; }
}
}

View File

@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
//
// directory: rel path to directory
// assertion: exists | does_not_exist
public class DirectoryInspectHandler : IHandler
{
public static string Handler => "directoryInspect";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string basePath = tokens["targetPath"];
string name = json["name"]?.ToString();
string directoryName = json["directory"].ToString();
string pathToDirectory = Path.Combine(basePath, directoryName);
string assertion = json["assertion"].ToString();
bool doesDirectoryExist = Directory.Exists(pathToDirectory);
if (string.Equals(assertion, "exists", StringComparison.OrdinalIgnoreCase))
{
if (!doesDirectoryExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected directory {directoryName} to exist, but it did not", name: name);
}
}
else if (string.Equals(assertion, "does_not_exist", StringComparison.OrdinalIgnoreCase))
{
if (doesDirectoryExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected directory {directoryName} to not exist, but it did", name: name);
}
}
return new GenericHandlerResult(watch.Elapsed, true, null);
}
catch (Exception ex)
{
return new GenericHandlerResult(watch.Elapsed, false, ex.Message);
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
string directoryName = json["directory"].ToString();
string assertion = json["assertion"].ToString().ToLowerInvariant().Replace("_", " ");
return $"Directory inspection - checking if directory \"{directoryName}\" {assertion}";
}
}
}

View File

@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
using ProjectTestRunner.Helpers;
namespace ProjectTestRunner.Handlers
{
public class ExecuteHandler : IHandler
{
public static string Handler => "execute";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string args = json["args"]?.ToString() ?? string.Empty;
foreach (KeyValuePair<string, string> entry in tokens)
{
args = args.Replace($"%{entry.Key}%", entry.Value);
}
string command = json["command"].ToString();
foreach (KeyValuePair<string, string> entry in tokens)
{
command = command.Replace($"%{entry.Key}%", entry.Value);
}
ProcessEx p = Proc.Run(command, args);
string name = json["name"]?.ToString();
if (json["noExit"]?.Value<bool>() ?? false)
{
if (p.WaitForExit(json["exitTimeout"]?.Value<int>() ?? 1000))
{
return new ExecuteHandlerResult(watch.Elapsed, false, "Process exited unexpectedly", name: name);
}
return new ExecuteHandlerResult(watch.Elapsed, true, null, p, name);
}
else
{
p.WaitForExit();
int expectedExitCode = json["exitCode"]?.Value<int>() ?? 0;
bool success = expectedExitCode == p.ExitCode;
if (!success)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Process exited with code {p.ExitCode} instead of {expectedExitCode}", name: name);
}
JArray expectations = json["expectations"]?.Value<JArray>();
if(expectations != null)
{
foreach(JObject expectation in expectations.Children().OfType<JObject>())
{
string assertion = expectation["assertion"]?.Value<string>()?.ToUpperInvariant();
string s;
StringComparison c;
switch (assertion)
{
case "OUTPUT_CONTAINS":
s = expectation["text"]?.Value<string>();
if(!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if(p.Output.IndexOf(s, c) < 0)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected output to contain \"{s}\" ({c}), but it did not", name: name);
}
break;
case "OUTPUT_DOES_NOT_CONTAIN":
s = expectation["text"]?.Value<string>();
if (!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if (p.Output.IndexOf(s, c) > -1)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected output to NOT contain \"{s}\" ({c}), but it did", name: name);
}
break;
default:
return new ExecuteHandlerResult(watch.Elapsed, false, $"Unkown assertion: {assertion}", name: name);
}
}
}
return new ExecuteHandlerResult(watch.Elapsed, true, null, name: name);
}
}
finally
{
watch.Stop();
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
string args = json["args"]?.ToString() ?? string.Empty;
foreach (KeyValuePair<string, string> entry in tokens)
{
args = args.Replace($"%{entry.Key}%", entry.Value);
}
string command = json["command"].ToString();
foreach (KeyValuePair<string, string> entry in tokens)
{
command = command.Replace($"%{entry.Key}%", entry.Value);
}
return $"Execute {command} {args}";
}
}
}

View File

@ -1,155 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
// file: rel path to file
// Note: For filenames that get modified by the template creation name, use the literal "%targetPathName%".
// It gets replaced with the creation name.
// Example: "filename": "%targetPathName%.csproj"
// expectations:
// assertion: exists | does_not_exist | contains | does_not_contain
// text: text to check for when using (file_contains | file_does_not_contain)
// comparison: a StringComparison enum value
// Example:
// {
// "handler": "fileInspect",
// "file": "filename"
// "expectations": [
// {
// "assertion": "exists"
// },
// {
// "assertion": "contains",
// "text": "netcoreapp1.0",
// "comparison": "Ordinal",
// },
// {
// "assertion": "does_not_contain",
// "text": "TargetFrameworkOverride",
// }
public class FileInspectHandler : IHandler
{
public static string Handler => "fileInspect";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string basePath = tokens["targetPath"];
string outputName = tokens["targetPathName"];
string name = json["name"]?.ToString();
string filename = json["file"].ToString();
foreach (KeyValuePair<string, string> entry in tokens)
{
filename = filename.Replace($"%{entry.Key}%", entry.Value);
}
string pathToFile = Path.Combine(basePath, filename);
bool doesFileExist = File.Exists(pathToFile);
string fileContent = null;
JArray expectations = json["expectations"]?.Value<JArray>();
if (expectations != null)
{
foreach (JObject expectation in expectations.Children().OfType<JObject>())
{
string assertion = expectation["assertion"]?.Value<string>()?.ToUpperInvariant();
string text;
StringComparison comparison;
switch (assertion)
{
case "EXISTS":
if (!doesFileExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to exist, but it did not", name: name);
}
break;
case "DOES_NOT_EXIST":
if (doesFileExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to not exist, but it did", name: name);
}
break;
case "CONTAINS":
text = expectation["text"]?.Value<string>();
if (!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out comparison))
{
comparison = StringComparison.OrdinalIgnoreCase;
}
if (!doesFileExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to contain \"{text}\" ({comparison}), but file did not exist", name: name);
}
if (fileContent == null)
{
fileContent = File.ReadAllText(pathToFile);
}
if (fileContent.IndexOf(text, comparison) < 0)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to contain \"{text}\" ({comparison}), but it did not", name: name);
}
break;
case "DOES_NOT_CONTAIN":
text = expectation["text"].Value<string>();
if (!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out comparison))
{
comparison = StringComparison.OrdinalIgnoreCase;
}
if (!doesFileExist)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to not contain \"{text}\" ({comparison}), but file did not exist", name: name);
}
if (fileContent == null)
{
fileContent = File.ReadAllText(pathToFile);
}
if (fileContent.IndexOf(text, comparison) >= 0)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected file \"{filename}\" to not contain \"{text}\" ({comparison}), but it did", name: name);
}
break;
}
}
}
return new GenericHandlerResult(watch.Elapsed, true, null);
}
catch (Exception ex)
{
return new GenericHandlerResult(watch.Elapsed, false, ex.Message);
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
string filename = json["file"].ToString();
return $"File Inspection - inspecting file = \"{filename}\"";
}
}
}

View File

@ -1,70 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
public class FindProcessHandler : IHandler
{
public static string Handler => "find";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string[] args = json["args"].Values<string>().ToArray();
for (int i = 0; i < args.Length; ++i)
{
if (tokens.TryGetValue(args[i].Trim('%'), out string val))
{
args[i] = val;
}
}
string name = json["name"].ToString();
Process p = Process.GetProcesses().FirstOrDefault(x =>
{
ProcessStartInfo info = null;
try
{
info = x.StartInfo;
}
catch
{
return false;
}
return args.All(y => info.Arguments.Contains(y));
});
return new ExecuteHandlerResult(watch.Elapsed, p != null, p != null ? null : "Unable to find process", p, name);
}
finally
{
watch.Stop();
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
string[] args = json["args"].Values<string>().ToArray();
for (int i = 0; i < args.Length; ++i)
{
if (tokens.TryGetValue(args[i].Trim('%'), out string val))
{
args[i] = val;
}
}
return $"Find process with args [{string.Join(", ", args)}]";
}
}
}

View File

@ -1,185 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
public class HttpRequestHandler : IHandler
{
public static string Handler => "httpRequest";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string name = json["name"]?.ToString();
string url = json["url"].ToString();
int status = json["statusCode"].Value<int>();
string verb = json["verb"].ToString();
string body = json["body"]?.ToString();
string requestMediaType = json["requestMediaType"]?.ToString();
string requestEncoding = json["requestEncoding"]?.ToString();
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(verb), url);
if (body != null)
{
if (!string.IsNullOrEmpty(requestEncoding))
{
if (!string.IsNullOrEmpty(requestMediaType))
{
message.Content = new StringContent(body, Encoding.GetEncoding(requestEncoding), requestMediaType);
}
else
{
message.Content = new StringContent(body, Encoding.GetEncoding(requestEncoding));
}
}
else
{
message.Content = new StringContent(body);
}
}
try
{
HttpResponseMessage response = client.SendAsync(message).Result;
bool success = status == (int)response.StatusCode;
string responseText = response.Content.ReadAsStringAsync().Result;
JArray expectations = json["expectations"]?.Value<JArray>();
if(expectations != null)
{
foreach(JObject expectation in expectations.Children().OfType<JObject>())
{
string assertion = expectation["assertion"]?.Value<string>()?.ToUpperInvariant();
string s, key;
StringComparison c;
IEnumerable<string> values;
switch (assertion)
{
case "RESPONSE_CONTAINS":
s = expectation["text"]?.Value<string>();
if(!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if(responseText.IndexOf(s, c) < 0)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected output to contain \"{s}\" ({c}), but it did not", name: name);
}
break;
case "RESPONSE_DOES_NOT_CONTAIN":
s = expectation["text"]?.Value<string>();
if(!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if(responseText.IndexOf(s, c) > -1)
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected output to NOT contain \"{s}\" ({c}), but it did", name: name);
}
break;
case "RESPONSE_HEADER_CONTAINS":
key = expectation["key"]?.Value<string>();
s = expectation["text"]?.Value<string>();
if(!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if(!response.Headers.TryGetValues(key, out values))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to be present, but it was not", name: name);
}
if(!values.Any(x => x.IndexOf(s, c) > -1))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to have a value \"{s}\", but it did not", name: name);
}
break;
case "HAS_HEADER":
key = expectation["key"]?.Value<string>();
if(!response.Headers.TryGetValues(key, out values))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to be present, but it was not", name: name);
}
break;
case "RESPONSE_HEADER_DOES_NOT_CONTAIN":
key = expectation["key"]?.Value<string>();
s = expectation["text"]?.Value<string>();
if(!Enum.TryParse(expectation["comparison"]?.Value<string>() ?? "OrdinalIgnoreCase", out c))
{
c = StringComparison.OrdinalIgnoreCase;
}
if(!response.Headers.TryGetValues(key, out values))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to be present, but it was not", name: name);
}
if(values.Any(x => x.IndexOf(s, c) > -1))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to NOT have a value \"{s}\", but it did", name: name);
}
break;
case "DOES_NOT_HAVE_HEADER":
key = expectation["key"]?.Value<string>();
if(response.Headers.TryGetValues(key, out values))
{
return new ExecuteHandlerResult(watch.Elapsed, false, $"Expected a response header called \"{key}\" to NOT be present, but it was", name: name);
}
break;
}
}
}
return new GenericHandlerResult(watch.Elapsed, success, success ? null : $"Expected {status} but got {response.StatusCode}");
}
catch (Exception ex)
{
return new GenericHandlerResult(watch.Elapsed, false, ex.Message);
}
}
finally
{
watch.Stop();
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
string url = json["url"].ToString();
int status = json["statusCode"].Value<int>();
string verb = json["verb"].ToString();
string body = json["body"]?.ToString();
string requestMediaType = json["requestMediaType"]?.ToString();
string requestEncoding = json["requestEncoding"]?.ToString();
return $"Web Request - {verb} {url} (Body? {body != null}, Encoding? {requestEncoding}, MediaType? {requestMediaType}) -> Expect {status}";
}
}
}

View File

@ -1,15 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
public interface IHandler
{
string HandlerName { get; }
IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json);
string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json);
}
}

View File

@ -1,41 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json.Linq;
using ProjectTestRunner.HandlerResults;
namespace ProjectTestRunner.Handlers
{
public class TaskKillHandler : IHandler
{
public static string Handler => "taskkill";
public string HandlerName => Handler;
public IHandlerResult Execute(IReadOnlyDictionary<string, string> tokens, IReadOnlyList<IHandlerResult> results, JObject json)
{
Stopwatch watch = Stopwatch.StartNew();
try
{
string targetName = json["name"].ToString();
IHandlerResult result = results.FirstOrDefault(x => x.Name == targetName);
if (result is ExecuteHandlerResult xr)
{
xr.Kill();
}
return new GenericHandlerResult(watch.Elapsed, true, null);
}
finally
{
watch.Stop();
}
}
public string Summarize(IReadOnlyDictionary<string, string> tokens, JObject json)
{
return "Kill process in named step " + json["name"].ToString();
}
}
}

View File

@ -1,32 +0,0 @@
using System.IO;
using System.Text;
using Xunit.Abstractions;
namespace ProjectTestRunner.Helpers
{
internal class OutputHelperHelper : TextWriter
{
private ITestOutputHelper _outputHelper;
public OutputHelperHelper(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}
public override Encoding Encoding => Encoding.UTF8;
public override void Write(char value)
{
}
public override void WriteLine(string format, params object[] arg)
{
_outputHelper.WriteLine(format, arg);
}
public override void WriteLine(string message)
{
_outputHelper.WriteLine(message ?? "");
}
}
}

View File

@ -1,13 +0,0 @@
using System.Runtime.CompilerServices;
using Xunit;
namespace ProjectTestRunner.Helpers
{
public class PrettyTheoryAttribute : TheoryAttribute
{
public PrettyTheoryAttribute([CallerMemberName] string memberName = null)
{
DisplayName = memberName;
}
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Diagnostics;
namespace ProjectTestRunner.Helpers
{
public class Proc
{
public static ProcessEx Run(string command, string args)
{
ProcessStartInfo psi = new ProcessStartInfo(command, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
Process p = Process.Start(psi);
ProcessEx wrapper = new ProcessEx(p);
return wrapper;
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.Diagnostics;
using System.Text;
namespace ProjectTestRunner.Helpers
{
public class ProcessEx
{
private readonly Process _process;
private readonly StringBuilder _stderr;
private readonly StringBuilder _stdout;
public ProcessEx(Process p)
{
_stdout = new StringBuilder();
_stderr = new StringBuilder();
_process = p;
p.OutputDataReceived += OnOutputData;
p.ErrorDataReceived += OnErrorData;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
}
public string Error => _stderr.ToString();
public string Output => _stdout.ToString();
public int ExitCode => _process.ExitCode;
public static implicit operator Process(ProcessEx self)
{
return self._process;
}
private void OnErrorData(object sender, DataReceivedEventArgs e)
{
_stderr.AppendLine(e.Data);
try
{
Console.Error.WriteLine(e.Data);
}
catch
{
}
}
private void OnOutputData(object sender, DataReceivedEventArgs e)
{
_stdout.AppendLine(e.Data);
try
{
Console.WriteLine(e.Data);
}
catch
{
}
}
public bool WaitForExit(int milliseconds)
{
return _process.WaitForExit(milliseconds);
}
public void WaitForExit()
{
_process.WaitForExit();
}
}
}

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
</packageSources>
</configuration>

View File

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\Templates.Settings.Targets" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<OutputPath>$(TestFolder)</OutputPath>
<IntermediatePath>$(IntermediateFolder)\Test</IntermediatePath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170517-02" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<None Update="TestCases\**\*.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit.Abstractions;
namespace ProjectTestRunner
{
public class TemplateTestData : IXunitSerializable
{
public TemplateTestData()
{
}
public string Name { get; set; }
public string Variation { get; set; }
public string CreateCommand { get; set; }
public string[] Paths { get; set; }
public void Deserialize(IXunitSerializationInfo info)
{
Name = info.GetValue<string>(nameof(Name));
Variation = info.GetValue<string>(nameof(Variation));
CreateCommand = info.GetValue<string>(nameof(CreateCommand));
Paths = info.GetValue<string[]>(nameof(Paths));
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue(nameof(Name), Name, typeof(string));
info.AddValue(nameof(Variation), Variation, typeof(string));
info.AddValue(nameof(CreateCommand), CreateCommand, typeof(string));
info.AddValue(nameof(Paths), Paths, typeof(string[]));
}
public override string ToString()
{
return Name;
}
}
}

View File

@ -1,123 +0,0 @@
{
"create": "mvc --no-restore",
"name": "MVC (C#, default framework, default auth)",
"variations": [
{
"id": "fullFramework",
"name": "MVC (C#, net461 framework, default auth)",
"create": "mvc --target-framework-override net461 --no-restore "
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"handler": "directoryInspect",
"directory": "Areas",
"assertion": "does_not_exist"
},
{
"handler": "directoryInspect",
"directory": "Extensions",
"assertion": "does_not_exist"
},
{
"handler": "fileInspect",
"file": "urlRewrite.config",
"expectations": [
{
"assertion": "does_not_exist"
}
],
},
{
"handler": "fileInspect",
"file": "Controllers/AccountController.cs",
"expectations": [
{
"assertion": "does_not_exist"
}
]
},
{
"handler": "fileInspect",
"file": "%targetPathName%.csproj",
"expectations": [
{
"assertion": "exists"
},
{
"assertion": "does_not_contain",
"text": ".db"
},
{
"assertion": "does_not_contain",
"text": "Microsoft.EntityFrameworkCore.Tools"
},
{
"assertion": "does_not_contain",
"text": "Microsoft.VisualStudio.Web.CodeGeneration.Design"
},
{
"assertion": "does_not_contain",
"text": "Microsoft.EntityFrameworkCore.Tools.DotNet"
},
{
"assertion": "does_not_contain",
"text": "Microsoft.Extensions.SecretManager.Tools"
},
]
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/About",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/Contact",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,109 +0,0 @@
{
"create": "mvc -au Individual --KestrelPort 5000 --no-restore",
"name": "MVC (C#, default framework, local individual auth)",
"variations": [
{
"id": "fullFramework",
"name": "MVC (C#, net461 framework, local individual auth)",
"create": "mvc -au Individual --KestrelPort 5000 --target-framework-override net461 --no-restore"
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"handler": "directoryInspect",
"directory": "Extensions",
"assertion": "exists"
},
{
"handler": "fileInspect",
"file": "Controllers/AccountController.cs",
"expectations": [
{
"assertion": "exists"
}
]
},
{
"handler": "fileInspect",
"file": "%targetPathName%.csproj",
"expectations": [
{
"assertion": "exists"
},
{
"assertion": "contains",
"text": ".db"
},
{
"assertion": "contains",
"text": "Microsoft.EntityFrameworkCore.Tools"
},
{
"assertion": "contains",
"text": "Microsoft.VisualStudio.Web.CodeGeneration.Design"
},
{
"assertion": "contains",
"text": "Microsoft.EntityFrameworkCore.Tools.DotNet"
},
{
"assertion": "contains",
"text": "Microsoft.Extensions.SecretManager.Tools"
},
]
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/About",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/Contact",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,66 +0,0 @@
{
"create": "razor --no-restore",
"name": "Razor Pages (C#, default framework, default auth)",
"variations": [
{
"id": "fullFramework",
"name": "Razor Pages (C#, net461 framework, default auth)",
"create": "razor --target-framework-override net461 --no-restore "
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/About",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Contact",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,109 +0,0 @@
{
"create": "razor -au Individual --KestrelPort 5000 --no-restore",
"name": "Razor Pages (C#, default framework, local individual auth)",
"variations": [
{
"id": "fullFramework",
"name": "Razor Pages (C#, net461 framework, local individual auth)",
"create": "razor -au Individual --KestrelPort 5000 --target-framework-override net461 --no-restore"
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"handler": "directoryInspect",
"directory": "Extensions",
"assertion": "exists"
},
{
"handler": "fileInspect",
"file": "Controllers/AccountController.cs",
"expectations": [
{
"assertion": "exists"
}
]
},
{
"handler": "fileInspect",
"file": "%targetPathName%.csproj",
"expectations": [
{
"assertion": "exists"
},
{
"assertion": "contains",
"text": ".db"
},
{
"assertion": "contains",
"text": "Microsoft.EntityFrameworkCore.Tools"
},
{
"assertion": "contains",
"text": "Microsoft.VisualStudio.Web.CodeGeneration.Design"
},
{
"assertion": "contains",
"text": "Microsoft.EntityFrameworkCore.Tools.DotNet"
},
{
"assertion": "contains",
"text": "Microsoft.Extensions.SecretManager.Tools"
},
]
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/About",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Contact",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,54 +0,0 @@
{
"create": "web --no-restore",
"name": "Empty Web (C#, default framework, default auth)",
"variations": [
{
"id": "fullFramework",
"name": "Empty Web (C#, net461 framework, default auth)",
"create": "web --target-framework-override net461 --no-restore "
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,60 +0,0 @@
{
"create": "api --no-restore",
"name": "WebAPI (C#, default framework, default auth)",
"variations": [
{
"id": "fullFramework",
"name": "WebAPI (C#, net461 framework, default auth)",
"create": "api --target-framework-override net461 --no-restore"
}
],
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"name": "RunApp",
"variation": "",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"name": "RunApp",
"variation": "fullFramework",
"handler": "execute",
"command": "bin/Debug/net461/%targetPathName%.exe",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/api/values",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 404,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}

View File

@ -1,50 +0,0 @@
{
"create": "mvc --language F# --no-restore",
"name": "MVC (F#, default framework, default auth)",
"tasks": [
{
"handler": "execute",
"command": "dotnet",
"args": "restore -s https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json -s https://dotnet.myget.org/F/msbuild/api/v3/index.json -s https://api.nuget.org/v3/index.json",
"noExit": false,
"exitCode": 0
},
{
"handler": "execute",
"command": "dotnet",
"args": "build -c Debug",
"noExit": false,
"exitCode": 0
},
{
"name": "RunApp",
"handler": "execute",
"command": "dotnet",
"args": "exec bin/Debug/netcoreapp2.0/%targetPathName%.dll",
"noExit": true,
"exitTimeout": 5000
},
{
"handler": "httpRequest",
"url": "http://localhost:5000",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/About",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "httpRequest",
"url": "http://localhost:5000/Home/Contact",
"statusCode": 200,
"verb": "GET"
},
{
"handler": "taskkill",
"name": "RunApp"
}
]
}