Run app and verify response
This commit is contained in:
parent
ec34d7cbbb
commit
8fe927d40d
|
|
@ -1,12 +1,24 @@
|
||||||
using AspNetCoreSdkTests.Templates;
|
using AspNetCoreSdkTests.Templates;
|
||||||
using AspNetCoreSdkTests.Util;
|
using AspNetCoreSdkTests.Util;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace AspNetCoreSdkTests
|
namespace AspNetCoreSdkTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TemplateTests
|
public class TemplateTests
|
||||||
{
|
{
|
||||||
|
private static readonly TimeSpan _sleepBetweenHttpRequests = TimeSpan.FromMilliseconds(100);
|
||||||
|
|
||||||
|
private static readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler()
|
||||||
|
{
|
||||||
|
// Allow self-signed certs
|
||||||
|
ServerCertificateCustomValidationCallback = (m, c, ch, p) => true
|
||||||
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[TestCaseSource(typeof(TemplateData), nameof(TemplateData.Current))]
|
[TestCaseSource(typeof(TemplateData), nameof(TemplateData.Current))]
|
||||||
public void Restore(Template template, NuGetConfig nuGetConfig)
|
public void Restore(Template template, NuGetConfig nuGetConfig)
|
||||||
|
|
@ -34,5 +46,35 @@ namespace AspNetCoreSdkTests
|
||||||
CollectionAssert.AreEquivalent(template.ExpectedBinFilesAfterBuild, context.GetBinFiles());
|
CollectionAssert.AreEquivalent(template.ExpectedBinFilesAfterBuild, context.GetBinFiles());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCaseSource(typeof(TemplateData), nameof(TemplateData.CurrentWebApplications))]
|
||||||
|
public void Run(Template template, NuGetConfig nuGetConfig)
|
||||||
|
{
|
||||||
|
using (var context = new DotNetContext())
|
||||||
|
{
|
||||||
|
context.New(template);
|
||||||
|
context.Restore(nuGetConfig);
|
||||||
|
var (httpUrl, httpsUrl) = context.Run();
|
||||||
|
|
||||||
|
Assert.AreEqual(HttpStatusCode.OK, GetAsync(new Uri(new Uri(httpUrl), template.RelativeUrl)).StatusCode);
|
||||||
|
Assert.AreEqual(HttpStatusCode.OK, GetAsync(new Uri(new Uri(httpsUrl), template.RelativeUrl)).StatusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpResponseMessage GetAsync(Uri requestUri)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _httpClient.GetAsync(requestUri).Result;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Thread.Sleep(_sleepBetweenHttpRequests);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace AspNetCoreSdkTests.Templates
|
||||||
|
|
||||||
public override string OutputPath { get; } = Path.Combine("Debug", "netcoreapp2.1");
|
public override string OutputPath { get; } = Path.Combine("Debug", "netcoreapp2.1");
|
||||||
|
|
||||||
public override TemplateType Type => TemplateType.Application;
|
public override TemplateType Type => TemplateType.ConsoleApplication;
|
||||||
|
|
||||||
public override IEnumerable<string> ExpectedBinFilesAfterBuild => Enumerable.Concat(base.ExpectedBinFilesAfterBuild, new[]
|
public override IEnumerable<string> ExpectedBinFilesAfterBuild => Enumerable.Concat(base.ExpectedBinFilesAfterBuild, new[]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace AspNetCoreSdkTests.Templates
|
||||||
|
|
||||||
public override string OutputPath { get; } = Path.Combine("Debug", "netcoreapp2.1");
|
public override string OutputPath { get; } = Path.Combine("Debug", "netcoreapp2.1");
|
||||||
|
|
||||||
public override TemplateType Type => TemplateType.Application;
|
public override TemplateType Type => TemplateType.WebApplication;
|
||||||
|
|
||||||
public override IEnumerable<string> ExpectedObjFilesAfterBuild => Enumerable.Concat(base.ExpectedObjFilesAfterBuild, new[]
|
public override IEnumerable<string> ExpectedObjFilesAfterBuild => Enumerable.Concat(base.ExpectedObjFilesAfterBuild, new[]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace AspNetCoreSdkTests.Templates
|
||||||
{
|
{
|
||||||
public abstract string Name { get; }
|
public abstract string Name { get; }
|
||||||
public abstract TemplateType Type { get; }
|
public abstract TemplateType Type { get; }
|
||||||
|
public virtual string RelativeUrl => string.Empty;
|
||||||
|
|
||||||
public virtual IEnumerable<string> ExpectedObjFilesAfterRestore => new[]
|
public virtual IEnumerable<string> ExpectedObjFilesAfterRestore => new[]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,11 @@ namespace AspNetCoreSdkTests.Templates
|
||||||
d);
|
d);
|
||||||
|
|
||||||
public static IEnumerable<TestCaseData> Current => IgnoreRazorClassLibEmpty;
|
public static IEnumerable<TestCaseData> Current => IgnoreRazorClassLibEmpty;
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> CurrentWebApplications { get; } =
|
||||||
|
from d in Current
|
||||||
|
where ((Template)d.Arguments[0]).Type == TemplateType.WebApplication
|
||||||
|
select d;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
{
|
{
|
||||||
public enum TemplateType
|
public enum TemplateType
|
||||||
{
|
{
|
||||||
Application,
|
ClassLibrary,
|
||||||
ClassLibrary
|
ConsoleApplication,
|
||||||
|
WebApplication,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,7 @@
|
||||||
protected WebApiTemplate() { }
|
protected WebApiTemplate() { }
|
||||||
|
|
||||||
public override string Name => "webapi";
|
public override string Name => "webapi";
|
||||||
|
|
||||||
|
public override string RelativeUrl => "/api/values";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ namespace AspNetCoreSdkTests.Templates
|
||||||
|
|
||||||
public override string Name => "web";
|
public override string Name => "web";
|
||||||
|
|
||||||
|
public override TemplateType Type => TemplateType.WebApplication;
|
||||||
|
|
||||||
public override IEnumerable<string> ExpectedObjFilesAfterBuild => Enumerable.Concat(base.ExpectedObjFilesAfterBuild, new[]
|
public override IEnumerable<string> ExpectedObjFilesAfterBuild => Enumerable.Concat(base.ExpectedObjFilesAfterBuild, new[]
|
||||||
{
|
{
|
||||||
$"{Name}.RazorAssemblyInfo.cache",
|
$"{Name}.RazorAssemblyInfo.cache",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AspNetCoreSdkTests.Util
|
||||||
|
{
|
||||||
|
public class ConcurrentStringBuilder
|
||||||
|
{
|
||||||
|
private StringBuilder _stringBuilder = new StringBuilder();
|
||||||
|
private object _lock = new object();
|
||||||
|
|
||||||
|
public void AppendLine()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_stringBuilder.AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AppendLine(string data)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_stringBuilder.AppendLine(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _stringBuilder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,52 @@
|
||||||
using AspNetCoreSdkTests.Templates;
|
using AspNetCoreSdkTests.Templates;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace AspNetCoreSdkTests.Util
|
namespace AspNetCoreSdkTests.Util
|
||||||
{
|
{
|
||||||
public class DotNetContext : TempDir
|
public class DotNetContext : TempDir
|
||||||
{
|
{
|
||||||
|
private static readonly TimeSpan _sleepBetweenOutputContains = TimeSpan.FromMilliseconds(100);
|
||||||
|
|
||||||
|
private (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) _process;
|
||||||
|
|
||||||
public string New(Template template)
|
public string New(Template template)
|
||||||
{
|
{
|
||||||
return DotNet.New(template.Name, Path);
|
return DotNetUtil.New(template.Name, Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Restore(NuGetConfig config)
|
public string Restore(NuGetConfig config)
|
||||||
{
|
{
|
||||||
return DotNet.Restore(Path, config);
|
return DotNetUtil.Restore(Path, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Build()
|
public string Build()
|
||||||
{
|
{
|
||||||
return DotNet.Build(Path);
|
return DotNetUtil.Build(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (string httpUrl, string httpsUrl) Run()
|
||||||
|
{
|
||||||
|
_process = DotNetUtil.Run(Path);
|
||||||
|
|
||||||
|
// Extract URLs from output
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var output = _process.OutputBuilder.ToString();
|
||||||
|
if (output.Contains("Application started"))
|
||||||
|
{
|
||||||
|
var httpUrl = Regex.Match(output, @"Now listening on: (http:\S*)").Groups[1].Value;
|
||||||
|
var httpsUrl = Regex.Match(output, @"Now listening on: (https:\S*)").Groups[1].Value;
|
||||||
|
return (httpUrl, httpsUrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread.Sleep(_sleepBetweenOutputContains);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> GetObjFiles()
|
public IEnumerable<string> GetObjFiles()
|
||||||
|
|
@ -29,5 +58,17 @@ namespace AspNetCoreSdkTests.Util
|
||||||
{
|
{
|
||||||
return IOUtil.GetFiles(System.IO.Path.Combine(Path, "bin"));
|
return IOUtil.GetFiles(System.IO.Path.Combine(Path, "bin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
// Must stop process to release filehandles before calling base.Dispose() which deletes app dir
|
||||||
|
if (_process.Process != null)
|
||||||
|
{
|
||||||
|
DotNetUtil.StopProcess(_process.Process, _process.OutputBuilder, _process.ErrorBuilder, throwOnError: false);
|
||||||
|
_process.Process = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using System;
|
using Microsoft.Extensions.Internal;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace AspNetCoreSdkTests.Util
|
namespace AspNetCoreSdkTests.Util
|
||||||
{
|
{
|
||||||
internal static class DotNet
|
internal static class DotNetUtil
|
||||||
{
|
{
|
||||||
private static IEnumerable<KeyValuePair<string, string>> GetEnvironment(string workingDirectory)
|
private static IEnumerable<KeyValuePair<string, string>> GetEnvironment(string workingDirectory)
|
||||||
{
|
{
|
||||||
|
|
@ -32,6 +32,12 @@ namespace AspNetCoreSdkTests.Util
|
||||||
return RunDotNet("build --no-restore", workingDirectory, GetEnvironment(workingDirectory));
|
return RunDotNet("build --no-restore", workingDirectory, GetEnvironment(workingDirectory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) Run(string workingDirectory)
|
||||||
|
{
|
||||||
|
// Bind to dynamic port 0 to avoid port conflicts during parallel tests
|
||||||
|
return StartDotNet("run --no-restore --urls http://127.0.0.1:0;https://127.0.0.1:0", workingDirectory, GetEnvironment(workingDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
private static string RunDotNet(string arguments, string workingDirectory,
|
private static string RunDotNet(string arguments, string workingDirectory,
|
||||||
IEnumerable<KeyValuePair<string, string>> environment = null, bool throwOnError = true)
|
IEnumerable<KeyValuePair<string, string>> environment = null, bool throwOnError = true)
|
||||||
{
|
{
|
||||||
|
|
@ -39,13 +45,13 @@ namespace AspNetCoreSdkTests.Util
|
||||||
return WaitForExit(p.Process, p.OutputBuilder, p.ErrorBuilder, throwOnError: throwOnError);
|
return WaitForExit(p.Process, p.OutputBuilder, p.ErrorBuilder, throwOnError: throwOnError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (Process Process, StringBuilder OutputBuilder, StringBuilder ErrorBuilder) StartDotNet(
|
private static (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) StartDotNet(
|
||||||
string arguments, string workingDirectory, IEnumerable<KeyValuePair<string, string>> environment = null)
|
string arguments, string workingDirectory, IEnumerable<KeyValuePair<string, string>> environment = null)
|
||||||
{
|
{
|
||||||
return StartProcess("dotnet", arguments, workingDirectory, environment);
|
return StartProcess("dotnet", arguments, workingDirectory, environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (Process Process, StringBuilder OutputBuilder, StringBuilder ErrorBuilder) StartProcess(
|
private static (Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) StartProcess(
|
||||||
string filename, string arguments, string workingDirectory, IEnumerable<KeyValuePair<string, string>> environment = null)
|
string filename, string arguments, string workingDirectory, IEnumerable<KeyValuePair<string, string>> environment = null)
|
||||||
{
|
{
|
||||||
var process = new Process()
|
var process = new Process()
|
||||||
|
|
@ -70,13 +76,13 @@ namespace AspNetCoreSdkTests.Util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputBuilder = new StringBuilder();
|
var outputBuilder = new ConcurrentStringBuilder();
|
||||||
process.OutputDataReceived += (_, e) =>
|
process.OutputDataReceived += (_, e) =>
|
||||||
{
|
{
|
||||||
outputBuilder.AppendLine(e.Data);
|
outputBuilder.AppendLine(e.Data);
|
||||||
};
|
};
|
||||||
|
|
||||||
var errorBuilder = new StringBuilder();
|
var errorBuilder = new ConcurrentStringBuilder();
|
||||||
process.ErrorDataReceived += (_, e) =>
|
process.ErrorDataReceived += (_, e) =>
|
||||||
{
|
{
|
||||||
errorBuilder.AppendLine(e.Data);
|
errorBuilder.AppendLine(e.Data);
|
||||||
|
|
@ -89,7 +95,18 @@ namespace AspNetCoreSdkTests.Util
|
||||||
return (process, outputBuilder, errorBuilder);
|
return (process, outputBuilder, errorBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string WaitForExit(Process process, StringBuilder outputBuilder, StringBuilder errorBuilder,
|
public static string StopProcess(Process process, ConcurrentStringBuilder outputBuilder, ConcurrentStringBuilder errorBuilder,
|
||||||
|
bool throwOnError = true)
|
||||||
|
{
|
||||||
|
if (!process.HasExited)
|
||||||
|
{
|
||||||
|
process.KillTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WaitForExit(process, outputBuilder, errorBuilder, throwOnError: throwOnError);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string WaitForExit(Process process, ConcurrentStringBuilder outputBuilder, ConcurrentStringBuilder errorBuilder,
|
||||||
bool throwOnError = true)
|
bool throwOnError = true)
|
||||||
{
|
{
|
||||||
// Workaround issue where WaitForExit() blocks until child processes are killed, which is problematic
|
// Workaround issue where WaitForExit() blocks until child processes are killed, which is problematic
|
||||||
|
|
@ -100,7 +117,7 @@ namespace AspNetCoreSdkTests.Util
|
||||||
|
|
||||||
if (throwOnError && process.ExitCode != 0)
|
if (throwOnError && process.ExitCode != 0)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new ConcurrentStringBuilder();
|
||||||
|
|
||||||
sb.AppendLine($"Command {process.StartInfo.FileName} {process.StartInfo.Arguments} returned exit code {process.ExitCode}");
|
sb.AppendLine($"Command {process.StartInfo.FileName} {process.StartInfo.Arguments} returned exit code {process.ExitCode}");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
@ -111,7 +128,5 @@ namespace AspNetCoreSdkTests.Util
|
||||||
|
|
||||||
return outputBuilder.ToString();
|
return outputBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.Internal
|
||||||
|
{
|
||||||
|
internal static class ProcessExtensions
|
||||||
|
{
|
||||||
|
private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
|
public static void KillTree(this Process process)
|
||||||
|
{
|
||||||
|
process.KillTree(_defaultTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KillTree(this Process process, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
string stdout;
|
||||||
|
if (_isWindows)
|
||||||
|
{
|
||||||
|
RunProcessAndWaitForExit(
|
||||||
|
"taskkill",
|
||||||
|
$"/T /F /PID {process.Id}",
|
||||||
|
timeout,
|
||||||
|
out stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var children = new HashSet<int>();
|
||||||
|
GetAllChildIdsUnix(process.Id, children, timeout);
|
||||||
|
foreach (var childId in children)
|
||||||
|
{
|
||||||
|
KillProcessUnix(childId, timeout);
|
||||||
|
}
|
||||||
|
KillProcessUnix(process.Id, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
string stdout;
|
||||||
|
var exitCode = RunProcessAndWaitForExit(
|
||||||
|
"pgrep",
|
||||||
|
$"-P {parentId}",
|
||||||
|
timeout,
|
||||||
|
out stdout);
|
||||||
|
|
||||||
|
if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
|
||||||
|
{
|
||||||
|
using (var reader = new StringReader(stdout))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var text = reader.ReadLine();
|
||||||
|
if (text == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
if (int.TryParse(text, out id))
|
||||||
|
{
|
||||||
|
children.Add(id);
|
||||||
|
// Recursively get the children
|
||||||
|
GetAllChildIdsUnix(id, children, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void KillProcessUnix(int processId, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
string stdout;
|
||||||
|
RunProcessAndWaitForExit(
|
||||||
|
"kill",
|
||||||
|
$"-TERM {processId}",
|
||||||
|
timeout,
|
||||||
|
out stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
|
||||||
|
{
|
||||||
|
var startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = fileName,
|
||||||
|
Arguments = arguments,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
UseShellExecute = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var process = Process.Start(startInfo);
|
||||||
|
|
||||||
|
stdout = null;
|
||||||
|
if (process.WaitForExit((int)timeout.TotalMilliseconds))
|
||||||
|
{
|
||||||
|
stdout = process.StandardOutput.ReadToEnd();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
process.Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.ExitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ namespace AspNetCoreSdkTests.Util
|
||||||
Path = IOUtil.GetTempDir();
|
Path = IOUtil.GetTempDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
IOUtil.DeleteDir(Path);
|
IOUtil.DeleteDir(Path);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue