mirror of https://github.com/winsw/winsw
Increase code coverage
parent
70d83c045c
commit
94668c9f77
|
@ -1044,7 +1044,7 @@ namespace winsw
|
||||||
appenders.ToArray());
|
appenders.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe bool IsProcessElevated()
|
internal static unsafe bool IsProcessElevated()
|
||||||
{
|
{
|
||||||
IntPtr process = Kernel32.GetCurrentProcess();
|
IntPtr process = Kernel32.GetCurrentProcess();
|
||||||
if (!Advapi32.OpenProcessToken(process, TokenAccessLevels.Read, out IntPtr token))
|
if (!Advapi32.OpenProcessToken(process, TokenAccessLevels.Read, out IntPtr token))
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("winswTests")]
|
|
@ -12,7 +12,7 @@ namespace winswTests.Configuration
|
||||||
/// The test uses a relative path to example files, which is based on the current project structure.
|
/// The test uses a relative path to example files, which is based on the current project structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class ExamplesTest
|
public class ExamplesTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void AllOptionsConfigShouldDeclareDefaults()
|
public void AllOptionsConfigShouldDeclareDefaults()
|
||||||
|
@ -40,10 +40,21 @@ namespace winswTests.Configuration
|
||||||
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(desc);
|
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceDescriptor Load(string exampleName)
|
private static ServiceDescriptor Load(string exampleName)
|
||||||
{
|
{
|
||||||
var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
string path = Path.GetFullPath($@"{directory}\..\..\..\..\..\..\examples\sample-{exampleName}.xml");
|
while (true)
|
||||||
|
{
|
||||||
|
if (File.Exists(Path.Combine(directory, ".gitignore")))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
directory = Path.GetDirectoryName(directory);
|
||||||
|
Assert.That(directory, Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = Path.Combine(directory, $@"examples\sample-{exampleName}.xml");
|
||||||
Assert.That(path, Does.Exist);
|
Assert.That(path, Does.Exist);
|
||||||
|
|
||||||
XmlDocument dom = new XmlDocument();
|
XmlDocument dom = new XmlDocument();
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
|
||||||
#if VNEXT
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
#endif
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
using winswTests.Util;
|
using winswTests.Util;
|
||||||
|
@ -10,61 +6,11 @@ using winswTests.Util;
|
||||||
namespace winswTests
|
namespace winswTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class DownloadTest
|
public class DownloadConfigTests
|
||||||
{
|
{
|
||||||
private const string From = "https://www.nosuchhostexists.foo.myorg/foo.xml";
|
private const string From = "https://www.nosuchhostexists.foo.myorg/foo.xml";
|
||||||
private const string To = "%BASE%\\foo.xml";
|
private const string To = "%BASE%\\foo.xml";
|
||||||
|
|
||||||
[Test]
|
|
||||||
#if VNEXT
|
|
||||||
public async Task DownloadFileAsync()
|
|
||||||
#else
|
|
||||||
public void DownloadFile()
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
string from = Path.GetTempFileName();
|
|
||||||
string to = Path.GetTempFileName();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const string contents = "WinSW";
|
|
||||||
File.WriteAllText(from, contents);
|
|
||||||
#if VNEXT
|
|
||||||
await new Download(from, to).PerformAsync();
|
|
||||||
#else
|
|
||||||
new Download(from, to).Perform();
|
|
||||||
#endif
|
|
||||||
Assert.That(File.ReadAllText(to), Is.EqualTo(contents));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
File.Delete(from);
|
|
||||||
File.Delete(to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void DownloadFile_NonExistent()
|
|
||||||
{
|
|
||||||
string from = Path.GetTempPath() + Path.GetRandomFileName();
|
|
||||||
string to = Path.GetTempFileName();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Assert.That(
|
|
||||||
#if VNEXT
|
|
||||||
async () => await new Download(from, to).PerformAsync(),
|
|
||||||
#else
|
|
||||||
() => new Download(from, to).Perform(),
|
|
||||||
#endif
|
|
||||||
Throws.TypeOf<WebException>());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
File.Delete(to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Roundtrip_Defaults()
|
public void Roundtrip_Defaults()
|
||||||
{
|
{
|
|
@ -0,0 +1,231 @@
|
||||||
|
#if VNEXT
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using winsw;
|
||||||
|
using winswTests.Util;
|
||||||
|
|
||||||
|
namespace winswTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class DownloadTests
|
||||||
|
{
|
||||||
|
private readonly HttpListener globalListener = new HttpListener();
|
||||||
|
|
||||||
|
private readonly byte[] contents = { 0x57, 0x69, 0x6e, 0x53, 0x57 };
|
||||||
|
|
||||||
|
private string globalPrefix;
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0);
|
||||||
|
tcpListener.Start();
|
||||||
|
int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
|
||||||
|
string prefix = $"http://localhost:{port}/";
|
||||||
|
this.globalListener.Prefixes.Add(prefix);
|
||||||
|
this.globalPrefix = prefix;
|
||||||
|
{
|
||||||
|
tcpListener.Stop();
|
||||||
|
this.globalListener.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeTearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
this.globalListener.Stop();
|
||||||
|
this.globalListener.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TestClientServerAsync(Func<string, string, Task> client, Action<HttpListenerContext> server, AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous, [CallerMemberName] string path = null)
|
||||||
|
{
|
||||||
|
HttpListener listener = new HttpListener();
|
||||||
|
string prefix = $"{this.globalPrefix}{path}/";
|
||||||
|
listener.Prefixes.Add(prefix);
|
||||||
|
listener.AuthenticationSchemes = authenticationSchemes;
|
||||||
|
listener.Start();
|
||||||
|
|
||||||
|
Task serverTask = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
serverTask = ListenAsync();
|
||||||
|
|
||||||
|
string dest = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client(prefix, dest);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
listener.Stop();
|
||||||
|
listener.Close();
|
||||||
|
if (serverTask != null)
|
||||||
|
{
|
||||||
|
await serverTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task ListenAsync()
|
||||||
|
{
|
||||||
|
HttpListenerContext context = await listener.GetContextAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server(context);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
context.Response.Abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttpAsync()
|
||||||
|
{
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
await new Download(source, dest).PerformAsync();
|
||||||
|
Assert.That(File.ReadAllBytes(dest), Is.EqualTo(this.contents));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
context.Response.OutputStream.Write(this.contents, 0, this.contents.Length);
|
||||||
|
context.Response.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttp_NoAuthAsync()
|
||||||
|
{
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
await new Download(source, dest, false, Download.AuthType.none).PerformAsync();
|
||||||
|
Assert.That(File.ReadAllBytes(dest), Is.EqualTo(this.contents));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
if (((WebHeaderCollection)context.Request.Headers)[HttpRequestHeader.Authorization] != null)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
context.Response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.OutputStream.Write(this.contents, 0, this.contents.Length);
|
||||||
|
context.Response.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttp_BasicAuthAsync()
|
||||||
|
{
|
||||||
|
const string username = nameof(username);
|
||||||
|
const string password = nameof(password);
|
||||||
|
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
await new Download(source, dest, false, Download.AuthType.basic, username, password, true).PerformAsync();
|
||||||
|
Assert.That(File.ReadAllBytes(dest), Is.EqualTo(this.contents));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity;
|
||||||
|
if (identity.Name != username || identity.Password != password)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
context.Response.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.OutputStream.Write(this.contents, 0, this.contents.Length);
|
||||||
|
context.Response.Close();
|
||||||
|
},
|
||||||
|
AuthenticationSchemes.Basic);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttp_IfModifiedSince_ModifiedAsync()
|
||||||
|
{
|
||||||
|
DateTime lastModified = DateTime.Now.TrimToSeconds();
|
||||||
|
DateTime prevModified = lastModified.AddDays(-1);
|
||||||
|
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(dest, this.contents);
|
||||||
|
File.SetLastWriteTime(dest, prevModified);
|
||||||
|
await new Download(source, dest).PerformAsync();
|
||||||
|
Assert.That(File.GetLastWriteTime(dest), Is.EqualTo(lastModified));
|
||||||
|
Assert.That(File.ReadAllBytes(dest), Is.Not.EqualTo(this.contents));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
string ifModifiedSince = ((WebHeaderCollection)context.Request.Headers)[HttpRequestHeader.IfModifiedSince];
|
||||||
|
if (ifModifiedSince != null && DateTime.Parse(ifModifiedSince) >= lastModified)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.NotModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.Headers[HttpResponseHeader.LastModified] = lastModified.ToUniversalTime().ToString("r");
|
||||||
|
context.Response.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttp_IfModifiedSince_NotModifiedAsync()
|
||||||
|
{
|
||||||
|
DateTime lastModified = DateTime.Now.TrimToSeconds();
|
||||||
|
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(dest, this.contents);
|
||||||
|
File.SetLastWriteTime(dest, lastModified);
|
||||||
|
await new Download(source, dest).PerformAsync();
|
||||||
|
Assert.That(File.GetLastWriteTime(dest), Is.EqualTo(lastModified));
|
||||||
|
Assert.That(File.ReadAllBytes(dest), Is.EqualTo(this.contents));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
string ifModifiedSince = ((WebHeaderCollection)context.Request.Headers)[HttpRequestHeader.IfModifiedSince];
|
||||||
|
if (ifModifiedSince != null && DateTime.Parse(ifModifiedSince) >= lastModified)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.NotModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.Headers[HttpResponseHeader.LastModified] = lastModified.ToUniversalTime().ToString("r");
|
||||||
|
context.Response.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestHttp_NotFound_ThrowsAsync()
|
||||||
|
{
|
||||||
|
await this.TestClientServerAsync(
|
||||||
|
async (source, dest) =>
|
||||||
|
{
|
||||||
|
WebException exception = await AsyncAssert.ThrowsAsync<WebException>(
|
||||||
|
async () => await new Download(source, dest).PerformAsync());
|
||||||
|
|
||||||
|
Assert.That(exception.Status, Is.EqualTo(WebExceptionStatus.ProtocolError));
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
context.Response.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Principal;
|
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
|
@ -8,8 +7,31 @@ using winswTests.Util;
|
||||||
namespace winswTests
|
namespace winswTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class MainTest
|
public class MainTest
|
||||||
{
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestInstall()
|
||||||
|
{
|
||||||
|
TestHelper.RequireProcessElevated();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = CLITestHelper.CLITest(new[] { "install" });
|
||||||
|
|
||||||
|
using ServiceController controller = new ServiceController(CLITestHelper.Id);
|
||||||
|
Assert.That(controller.DisplayName, Is.EqualTo(CLITestHelper.Name));
|
||||||
|
Assert.That(controller.CanStop, Is.False);
|
||||||
|
Assert.That(controller.CanShutdown, Is.False);
|
||||||
|
Assert.That(controller.CanPauseAndContinue, Is.False);
|
||||||
|
Assert.That(controller.Status, Is.EqualTo(ServiceControllerStatus.Stopped));
|
||||||
|
Assert.That(controller.ServiceType, Is.EqualTo(ServiceType.Win32OwnProcess));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_ = CLITestHelper.CLITest(new[] { "uninstall" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void PrintVersion()
|
public void PrintVersion()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#if VNEXT
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Constraints;
|
||||||
|
|
||||||
|
namespace winswTests.Util
|
||||||
|
{
|
||||||
|
internal static class AsyncAssert
|
||||||
|
{
|
||||||
|
internal static async Task<TActual> ThrowsAsync<TActual>(AsyncTestDelegate code)
|
||||||
|
where TActual : Exception
|
||||||
|
{
|
||||||
|
Exception caught = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await code();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
caught = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(caught, new ExceptionTypeConstraint(typeof(TActual)));
|
||||||
|
return (TActual)caught;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,12 @@
|
||||||
|
#if VNEXT
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace winswTests.Util
|
||||||
|
{
|
||||||
|
internal static class DateTimeExtensions
|
||||||
|
{
|
||||||
|
internal static DateTime TrimToSeconds(this DateTime dateTime) =>
|
||||||
|
dateTime.AddTicks(-(dateTime.Ticks % TimeSpan.TicksPerSecond));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,16 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using winsw;
|
||||||
|
|
||||||
|
namespace winswTests.Util
|
||||||
|
{
|
||||||
|
internal static class TestHelper
|
||||||
|
{
|
||||||
|
internal static void RequireProcessElevated()
|
||||||
|
{
|
||||||
|
if (!WrapperService.IsProcessElevated())
|
||||||
|
{
|
||||||
|
Assert.Ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue