Simplify syntax

pull/360/head
NextTurn 2018-12-04 00:00:00 +08:00
parent 466b5264e1
commit 941e67d08c
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
16 changed files with 234 additions and 285 deletions

View File

@ -91,21 +91,19 @@ namespace winsw
try
{
using (var tr = new StreamReader(file, Encoding.UTF8))
using var tr = new StreamReader(file, Encoding.UTF8);
string? line;
while ((line = tr.ReadLine()) != null)
{
string? line;
while ((line = tr.ReadLine()) != null)
LogEvent("Handling copy: " + line);
string[] tokens = line.Split('>');
if (tokens.Length > 2)
{
LogEvent("Handling copy: " + line);
string[] tokens = line.Split('>');
if (tokens.Length > 2)
{
LogEvent("Too many delimiters in " + line);
continue;
}
CopyFile(tokens[0], tokens[1]);
LogEvent("Too many delimiters in " + line);
continue;
}
CopyFile(tokens[0], tokens[1]);
}
}
finally
@ -186,7 +184,7 @@ namespace winsw
}
}
protected override void OnStart(string[] _)
protected override void OnStart(string[] args)
{
_envs = _descriptor.EnvironmentVariables;
// TODO: Disabled according to security concerns in https://github.com/kohsuke/winsw/issues/54
@ -490,11 +488,11 @@ namespace winsw
bool isCLIMode = _args.Length > 0;
// If descriptor is not specified, initialize the new one (and load configs from there)
var d = descriptor ?? new ServiceDescriptor();
descriptor ??= new ServiceDescriptor();
// Configure the wrapper-internal logging.
// STDIN and STDOUT of the child process will be handled independently.
InitLoggers(d, isCLIMode);
InitLoggers(descriptor, isCLIMode);
if (isCLIMode) // CLI mode, in-service mode otherwise
{
@ -502,7 +500,7 @@ namespace winsw
// Get service info for the future use
Win32Services svc = new WmiRoot().GetCollection<Win32Services>();
Win32Service s = svc.Select(d.Id);
Win32Service s = svc.Select(descriptor.Id);
var args = new List<string>(Array.AsReadOnly(_args));
if (args[0] == "/redirect")
@ -530,14 +528,14 @@ namespace winsw
args[0] = args[0].ToLower();
if (args[0] == "install")
{
Log.Info("Installing the service with id '" + d.Id + "'");
Log.Info("Installing the service with id '" + descriptor.Id + "'");
// Check if the service exists
if (s != null)
{
Console.WriteLine("Service with id '" + d.Id + "' already exists");
Console.WriteLine("Service with id '" + descriptor.Id + "' already exists");
Console.WriteLine("To install the service, delete the existing one or change service Id in the configuration file");
throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
throw new Exception("Installation failure: Service with id '" + descriptor.Id + "' already exists");
}
string? username = null;
@ -561,11 +559,11 @@ namespace winsw
}
else
{
if (d.HasServiceAccount())
if (descriptor.HasServiceAccount())
{
username = d.ServiceAccountUser;
password = d.ServiceAccountPassword;
setallowlogonasaserviceright = d.AllowServiceAcountLogonRight;
username = descriptor.ServiceAccountUser;
password = descriptor.ServiceAccountPassword;
setallowlogonasaserviceright = descriptor.AllowServiceAcountLogonRight;
}
}
@ -575,16 +573,16 @@ namespace winsw
}
svc.Create(
d.Id,
d.Caption,
"\"" + d.ExecutablePath + "\"",
descriptor.Id,
descriptor.Caption,
"\"" + descriptor.ExecutablePath + "\"",
ServiceType.OwnProcess,
ErrorControl.UserNotified,
d.StartMode,
d.Interactive,
descriptor.StartMode,
descriptor.Interactive,
username,
password,
d.ServiceDependencies);
descriptor.ServiceDependencies);
// update the description
/* Somehow this doesn't work, even though it doesn't report an error
@ -594,29 +592,30 @@ namespace winsw
*/
// so using a classic method to set the description. Ugly.
Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services")
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
Registry.LocalMachine
.OpenSubKey("System")
.OpenSubKey("CurrentControlSet")
.OpenSubKey("Services")
.OpenSubKey(descriptor.Id, true)
.SetValue("Description", descriptor.Description);
var actions = d.FailureActions;
var isDelayedAutoStart = d.StartMode == StartMode.Automatic && d.DelayedAutoStart;
var actions = descriptor.FailureActions;
var isDelayedAutoStart = descriptor.StartMode == StartMode.Automatic && descriptor.DelayedAutoStart;
if (actions.Count > 0 || isDelayedAutoStart)
{
using (ServiceManager scm = new ServiceManager())
{
using (Service sc = scm.Open(d.Id))
{
// Delayed auto start
if (isDelayedAutoStart)
{
sc.SetDelayedAutoStart(true);
}
using ServiceManager scm = new ServiceManager();
using Service sc = scm.Open(descriptor.Id);
// Set the failure actions
if (actions.Count > 0)
{
sc.ChangeConfig(d.ResetFailureAfter, actions);
}
}
// Delayed auto start
if (isDelayedAutoStart)
{
sc.SetDelayedAutoStart(true);
}
// Set the failure actions
if (actions.Count > 0)
{
sc.ChangeConfig(descriptor.ResetFailureAfter, actions);
}
}
@ -625,10 +624,10 @@ namespace winsw
if (args[0] == "uninstall")
{
Log.Info("Uninstalling the service with id '" + d.Id + "'");
Log.Info("Uninstalling the service with id '" + descriptor.Id + "'");
if (s == null)
{
Log.Warn("The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
Log.Warn("The service with id '" + descriptor.Id + "' does not exist. Nothing to uninstall");
return; // there's no such service, so consider it already uninstalled
}
@ -636,7 +635,7 @@ namespace winsw
{
// We could fail the opeartion here, but it would be an incompatible change.
// So it is just a warning
Log.Warn("The service with id '" + d.Id + "' is running. It may be impossible to uninstall it");
Log.Warn("The service with id '" + descriptor.Id + "' is running. It may be impossible to uninstall it");
}
try
@ -647,7 +646,7 @@ namespace winsw
{
if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion)
{
Log.Error("Failed to uninstall the service with id '" + d.Id + "'"
Log.Error("Failed to uninstall the service with id '" + descriptor.Id + "'"
+ ". It has been marked for deletion.");
// TODO: change the default behavior to Error?
@ -655,7 +654,7 @@ namespace winsw
}
else
{
Log.Fatal("Failed to uninstall the service with id '" + d.Id + "'. WMI Error code is '" + e.ErrorCode + "'");
Log.Fatal("Failed to uninstall the service with id '" + descriptor.Id + "'. WMI Error code is '" + e.ErrorCode + "'");
}
throw e;
@ -666,7 +665,7 @@ namespace winsw
if (args[0] == "start")
{
Log.Info("Starting the service with id '" + d.Id + "'");
Log.Info("Starting the service with id '" + descriptor.Id + "'");
if (s == null)
ThrowNoSuchService();
@ -676,7 +675,7 @@ namespace winsw
if (args[0] == "stop")
{
Log.Info("Stopping the service with id '" + d.Id + "'");
Log.Info("Stopping the service with id '" + descriptor.Id + "'");
if (s == null)
ThrowNoSuchService();
@ -686,7 +685,7 @@ namespace winsw
if (args[0] == "restart")
{
Log.Info("Restarting the service with id '" + d.Id + "'");
Log.Info("Restarting the service with id '" + descriptor.Id + "'");
if (s == null)
ThrowNoSuchService();
@ -696,7 +695,7 @@ namespace winsw
while (s.Started)
{
Thread.Sleep(1000);
s = svc.Select(d.Id);
s = svc.Select(descriptor.Id);
}
s.StartService();
@ -705,12 +704,12 @@ namespace winsw
if (args[0] == "restart!")
{
Log.Info("Restarting the service with id '" + d.Id + "'");
Log.Info("Restarting the service with id '" + descriptor.Id + "'");
// run restart from another process group. see README.md for why this is useful.
STARTUPINFO si = default;
bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out _);
bool result = Kernel32.CreateProcess(null, descriptor.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out _);
if (!result)
{
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
@ -721,7 +720,7 @@ namespace winsw
if (args[0] == "status")
{
Log.Debug("User requested the status of the process with id '" + d.Id + "'");
Log.Debug("User requested the status of the process with id '" + descriptor.Id + "'");
if (s == null)
Console.WriteLine("NonExistent");
else if (s.Started)
@ -734,7 +733,7 @@ namespace winsw
if (args[0] == "test")
{
WrapperService wsvc = new WrapperService(d);
WrapperService wsvc = new WrapperService(descriptor);
wsvc.OnStart(args.ToArray());
Thread.Sleep(1000);
wsvc.OnStop();
@ -743,7 +742,7 @@ namespace winsw
if (args[0] == "testwait")
{
WrapperService wsvc = new WrapperService(d);
WrapperService wsvc = new WrapperService(descriptor);
wsvc.OnStart(args.ToArray());
Console.WriteLine("Press any key to stop the service...");
Console.Read();
@ -773,7 +772,7 @@ namespace winsw
Log.Info("Starting ServiceWrapper in the service mode");
}
Run(new WrapperService(d));
Run(new WrapperService(descriptor));
}
private static void InitLoggers(ServiceDescriptor d, bool enableCLILogging)
@ -839,10 +838,9 @@ namespace winsw
private static string ReadPassword()
{
StringBuilder buf = new StringBuilder();
ConsoleKeyInfo key;
while (true)
{
key = Console.ReadKey(true);
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
{
return buf.ToString();
@ -870,7 +868,7 @@ namespace winsw
printAvailableCommandsInfo();
Console.WriteLine();
Console.WriteLine("Extra options:");
Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file");
Console.WriteLine(" /redirect redirect the wrapper's STDOUT and STDERR to the specified file");
Console.WriteLine();
printVersion();
Console.WriteLine("More info: https://github.com/kohsuke/winsw");
@ -880,18 +878,19 @@ namespace winsw
// TODO: Rework to enum in winsw-2.0
private static void printAvailableCommandsInfo()
{
Console.WriteLine("Available commands:");
Console.WriteLine("- 'install' - install the service to Windows Service Controller");
Console.WriteLine("- 'uninstall' - uninstall the service");
Console.WriteLine("- 'start' - start the service (must be installed before)");
Console.WriteLine("- 'stop' - stop the service");
Console.WriteLine("- 'restart' - restart the service");
Console.WriteLine("- 'restart!' - self-restart (can be called from child processes)");
Console.WriteLine("- 'status' - check the current status of the service");
Console.WriteLine("- 'test' - check if the service can be started and then stopped");
Console.WriteLine("- 'testwait' - starts the service and waits until a key is pressed then stops the service");
Console.WriteLine("- 'version' - print the version info");
Console.WriteLine("- 'help' - print the help info (aliases: -h,--help,-?,/?)");
Console.WriteLine(
@"Available commands:
install install the service to Windows Service Controller
uninstall uninstall the service
start start the service (must be installed before)
stop stop the service
restart restart the service
restart! self-restart (can be called from child processes)
status check the current status of the service
test check if the service can be started and then stopped
testwait starts the service and waits until a key is pressed then stops the service
version print the version info
help print the help info (aliases: -h,--help,-?,/?)");
}
private static void printVersion()

View File

@ -439,9 +439,9 @@ namespace winsw
// Next day so check if file can be zipped
ZipFiles(baseDirectory, extension, baseFileName);
}
catch (Exception et)
catch (Exception ex)
{
EventLogger.LogEvent(string.Format("Failed to to trigger auto roll at time event due to: {0}", et.Message));
EventLogger.LogEvent($"Failed to to trigger auto roll at time event due to: {ex.Message}");
}
finally
{
@ -503,7 +503,7 @@ namespace winsw
}
catch (Exception e)
{
EventLogger.LogEvent(string.Format("Failed to roll size time log: {0}", e.Message));
EventLogger.LogEvent($"Failed to roll size time log: {e.Message}");
}
}
@ -635,12 +635,12 @@ namespace winsw
}
else
{
throw new IOException(string.Format("File {0} does not follow the pattern provided", f));
throw new IOException($"File {f} does not follow the pattern provided");
}
}
catch (Exception e)
{
throw new IOException(string.Format("Failed to process file {0} due to error {1}", f, e.Message), e);
throw new IOException($"Failed to process file {f} due to error {e.Message}", e);
}
}

View File

@ -245,7 +245,6 @@ namespace winsw.Native
// initialize an unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = default;
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (ushort)(privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (ushort)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);

View File

@ -64,35 +64,30 @@ namespace winsw
return PeriodicityType.ERRONEOUS;
}
private DateTime nextTriggeringTime(DateTime input, long increment)
private DateTime nextTriggeringTime(DateTime input, long increment) => periodicityType switch
{
DateTime output;
switch (periodicityType)
{
case PeriodicityType.TOP_OF_MILLISECOND:
output = new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second, input.Millisecond);
output = output.AddMilliseconds(increment);
return output;
case PeriodicityType.TOP_OF_SECOND:
output = new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second);
output = output.AddSeconds(increment);
return output;
case PeriodicityType.TOP_OF_MINUTE:
output = new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, 0);
output = output.AddMinutes(increment);
return output;
case PeriodicityType.TOP_OF_HOUR:
output = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
output = output.AddHours(increment);
return output;
case PeriodicityType.TOP_OF_DAY:
output = new DateTime(input.Year, input.Month, input.Day);
output = output.AddDays(increment);
return output;
default:
throw new Exception("invalid periodicity type: " + periodicityType);
}
}
PeriodicityType.TOP_OF_MILLISECOND =>
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second, input.Millisecond)
.AddMilliseconds(increment),
PeriodicityType.TOP_OF_SECOND =>
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second)
.AddSeconds(increment),
PeriodicityType.TOP_OF_MINUTE =>
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, 0)
.AddMinutes(increment),
PeriodicityType.TOP_OF_HOUR =>
new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0)
.AddHours(increment),
PeriodicityType.TOP_OF_DAY =>
new DateTime(input.Year, input.Month, input.Day)
.AddDays(increment),
_ => throw new Exception("invalid periodicity type: " + periodicityType),
};
public PeriodicityType periodicityType { get; set; }

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Xml;
using log4net;
using winsw.Extensions;

View File

@ -1,5 +1,4 @@
using System;
using System.Xml;
using System.Xml;
using winsw.Util;
namespace winsw.Plugins.SharedDirectoryMapper

View File

@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.Diagnostics;
namespace winsw.Plugins.SharedDirectoryMapper
{

View File

@ -144,10 +144,7 @@ namespace winswTests
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"digest\"/>")
.ToServiceDescriptor(true);
ExceptionHelper.assertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), () =>
{
var d = GetSingleEntry(sd);
});
ExceptionHelper.AssertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), () => _ = GetSingleEntry(sd));
}
private Download GetSingleEntry(ServiceDescriptor sd)
@ -163,10 +160,7 @@ namespace winswTests
.WithDownload(download)
.ToServiceDescriptor(true);
ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), () =>
{
var d = GetSingleEntry(sd);
});
ExceptionHelper.AssertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), () => _ = GetSingleEntry(sd));
}
}
}

View File

@ -16,27 +16,27 @@ namespace winswTests.Extensions
{
ServiceDescriptor _testServiceDescriptor;
string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
readonly string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
[SetUp]
public void SetUp()
{
string seedXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ "<service> "
+ " <id>SERVICE_NAME</id> "
+ " <name>Jenkins Slave</name> "
+ " <description>This service runs a slave for Jenkins continuous integration system.</description> "
+ " <executable>C:\\Program Files\\Java\\jre7\\bin\\java.exe</executable> "
+ " <arguments>-Xrs -jar \\\"%BASE%\\slave.jar\\\" -jnlpUrl ...</arguments> "
+ " <logmode>rotate</logmode> "
+ " <extensions> "
+ " <extension enabled=\"true\" className=\"" + testExtension + "\" id=\"killRunawayProcess\"> "
+ " <pidfile>foo/bar/pid.txt</pidfile>"
+ " <stopTimeout>5000</stopTimeout> "
+ " <stopParentFirst>true</stopParentFirst>"
+ " </extension> "
+ " </extensions> "
+ "</service>";
string seedXml =
$@"<service>
<id>SERVICE_NAME</id>
<name>Jenkins Slave</name>
<description>This service runs a slave for Jenkins continuous integration system.</description>
<executable>C:\Program Files\Java\jre7\bin\java.exe</executable>
<arguments>-Xrs -jar \""%BASE%\slave.jar\"" -jnlpUrl ...</arguments>
<logmode>rotate</logmode>
<extensions>
<extension enabled=""true"" className=""{testExtension}"" id=""killRunawayProcess"">
<pidfile>foo/bar/pid.txt</pidfile>
<stopTimeout>5000</stopTimeout>
<stopParentFirst>true</stopParentFirst>
</extension>
</extensions>
</service>";
_testServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
}

View File

@ -10,34 +10,34 @@ namespace winswTests.Extensions
{
ServiceDescriptor _testServiceDescriptor;
string testExtension = GetExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
readonly string testExtension = GetExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
[SetUp]
public void SetUp()
{
string seedXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ "<service> "
+ " <id>SERVICE_NAME</id> "
+ " <name>Jenkins Slave</name> "
+ " <description>This service runs a slave for Jenkins continuous integration system.</description> "
+ " <executable>C:\\Program Files\\Java\\jre7\\bin\\java.exe</executable> "
+ " <arguments>-Xrs -jar \\\"%BASE%\\slave.jar\\\" -jnlpUrl ...</arguments> "
+ " <logmode>rotate</logmode> "
+ " <extensions> "
+ " <extension enabled=\"true\" className=\"" + testExtension + "\" id=\"mapNetworDirs\"> "
+ " <mapping> "
+ " <map enabled=\"false\" label=\"N:\" uncpath=\"\\\\UNC\"/> "
+ " <map enabled=\"false\" label=\"M:\" uncpath=\"\\\\UNC2\"/> "
+ " </mapping> "
+ " </extension> "
+ " <extension enabled=\"true\" className=\"" + testExtension + "\" id=\"mapNetworDirs2\"> "
+ " <mapping> "
+ " <map enabled=\"false\" label=\"X:\" uncpath=\"\\\\UNC\"/> "
+ " <map enabled=\"false\" label=\"Y:\" uncpath=\"\\\\UNC2\"/> "
+ " </mapping> "
+ " </extension> "
+ " </extensions> "
+ "</service>";
string seedXml =
$@"<service>
<id>SERVICE_NAME</id>
<name>Jenkins Slave</name>
<description>This service runs a slave for Jenkins continuous integration system.</description>
<executable>C:\Program Files\Java\jre7\bin\java.exe</executable>
<arguments>-Xrs -jar \""%BASE%\slave.jar\"" -jnlpUrl ...</arguments>
<logmode>rotate</logmode>
<extensions>
<extension enabled=""true"" className=""{testExtension}"" id=""mapNetworDirs"">
<mapping>
<map enabled=""false"" label=""N:"" uncpath=""\\UNC""/>
<map enabled=""false"" label=""M:"" uncpath=""\\UNC2""/>
</mapping>
</extension>
<extension enabled=""true"" className=""{testExtension}"" id=""mapNetworDirs2"">
<mapping>
<map enabled=""false"" label=""X:"" uncpath=""\\UNC""/>
<map enabled=""false"" label=""Y:"" uncpath=""\\UNC2""/>
</mapping>
</extension>
</extensions>
</service>";
_testServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
}

View File

@ -21,24 +21,23 @@ namespace winswTests
[SetUp]
public void SetUp()
{
const string seedXml = "<service>"
+ "<id>service.exe</id>"
+ "<name>Service</name>"
+ "<description>The service.</description>"
+ "<executable>node.exe</executable>"
+ "<arguments>My Arguments</arguments>"
+ "<logmode>rotate</logmode>"
+ "<serviceaccount>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<allowservicelogon>" + AllowServiceAccountLogonRight + "</allowservicelogon>"
+ "</serviceaccount>"
+ "<workingdirectory>"
+ ExpectedWorkingDirectory
+ "</workingdirectory>"
+ @"<logpath>C:\logs</logpath>"
+ "</service>";
string seedXml =
$@"<service>
<id>service.exe</id>
<name>Service</name>
<description>The service.</description>
<executable>node.exe</executable>
<arguments>My Arguments</arguments>
<logmode>rotate</logmode>
<serviceaccount>
<domain>{Domain}</domain>
<user>{Username}</user>
<password>{Password}</password>
<allowservicelogon>{AllowServiceAccountLogonRight}</allowservicelogon>
</serviceaccount>
<workingdirectory>{ExpectedWorkingDirectory}</workingdirectory>
<logpath>C:\logs</logpath>
</service>";
_extendedServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
}
@ -51,54 +50,52 @@ namespace winswTests
[Test]
public void IncorrectStartMode()
{
const string SeedXml = "<service>"
+ "<id>service.exe</id>"
+ "<name>Service</name>"
+ "<description>The service.</description>"
+ "<executable>node.exe</executable>"
+ "<arguments>My Arguments</arguments>"
+ "<startmode>rotate</startmode>"
+ "<logmode>rotate</logmode>"
+ "<serviceaccount>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<allowservicelogon>" + AllowServiceAccountLogonRight + "</allowservicelogon>"
+ "</serviceaccount>"
+ "<workingdirectory>"
+ ExpectedWorkingDirectory
+ "</workingdirectory>"
+ @"<logpath>C:\logs</logpath>"
+ "</service>";
string seedXml =
$@"<service>
<id>service.exe</id>
<name>Service</name>
<description>The service.</description>
<executable>node.exe</executable>
<arguments>My Arguments</arguments>
<startmode>rotate</startmode>
<logmode>rotate</logmode>
<serviceaccount>
<domain>{Domain}</domain>
<user>{Username}</user>
<password>{Password}</password>
<allowservicelogon>{AllowServiceAccountLogonRight}</allowservicelogon>
</serviceaccount>
<workingdirectory>{ExpectedWorkingDirectory}</workingdirectory>
<logpath>C:\logs</logpath>
</service>";
_extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
Assert.Throws(typeof(ArgumentException), () => _ = _extendedServiceDescriptor.StartMode);
_extendedServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
Assert.Throws<ArgumentException>(() => _ = _extendedServiceDescriptor.StartMode);
}
[Test]
public void ChangedStartMode()
{
const string SeedXml = "<service>"
+ "<id>service.exe</id>"
+ "<name>Service</name>"
+ "<description>The service.</description>"
+ "<executable>node.exe</executable>"
+ "<arguments>My Arguments</arguments>"
+ "<startmode>manual</startmode>"
+ "<logmode>rotate</logmode>"
+ "<serviceaccount>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<allowservicelogon>" + AllowServiceAccountLogonRight + "</allowservicelogon>"
+ "</serviceaccount>"
+ "<workingdirectory>"
+ ExpectedWorkingDirectory
+ "</workingdirectory>"
+ @"<logpath>C:\logs</logpath>"
+ "</service>";
string seedXml =
$@"<service>
<id>service.exe</id>
<name>Service</name>
<description>The service.</description>
<executable>node.exe</executable>
<arguments>My Arguments</arguments>
<startmode>manual</startmode>
<logmode>rotate</logmode>
<serviceaccount>
<domain>{Domain}</domain>
<user>{Username}</user>
<password>{Password}</password>
<allowservicelogon>{AllowServiceAccountLogonRight}</allowservicelogon>
</serviceaccount>
<workingdirectory>{ExpectedWorkingDirectory}</workingdirectory>
<logpath>C:\logs</logpath>
</service>";
_extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
_extendedServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
}

View File

@ -9,18 +9,17 @@ namespace winswTests.Util
/// </summary>
public static class CLITestHelper
{
private const string SeedXml = "<service>"
+ "<id>service.exe</id>"
+ "<name>Service</name>"
+ "<description>The service.</description>"
+ "<executable>node.exe</executable>"
+ "<arguments>My Arguments</arguments>"
+ "<logmode>rotate</logmode>"
+ "<workingdirectory>"
+ @"C:\winsw\workdir"
+ "</workingdirectory>"
+ @"<logpath>C:\winsw\logs</logpath>"
+ "</service>";
private const string SeedXml =
@"<service>
<id>service.exe</id>
<name>Service</name>
<description>The service.</description>
<executable>node.exe</executable>
<arguments>My Arguments</arguments>
<logmode>rotate</logmode>
<workingdirectory>C:\winsw\workdir</workingdirectory>
<logpath>C:\winsw\logs</logpath>
</service>";
private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
@ -33,15 +32,13 @@ namespace winswTests.Util
/// <exception cref="Exception">Command failure</exception>
public static string CLITest(string[] args, ServiceDescriptor descriptor = null)
{
using (StringWriter sw = new StringWriter())
{
TextWriter tmp = Console.Out;
Console.SetOut(sw);
WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor);
Console.SetOut(tmp);
Console.Write(sw.ToString());
return sw.ToString();
}
using StringWriter sw = new StringWriter();
TextWriter tmp = Console.Out;
Console.SetOut(sw);
WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor);
Console.SetOut(tmp);
Console.Write(sw.ToString());
return sw.ToString();
}
/// <summary>

View File

@ -20,7 +20,7 @@ namespace winswTests.Util
public string XMLComment { get; set; }
public List<string> ExtensionXmls { get; private set; }
private List<string> configEntries;
private readonly List<string> configEntries;
// TODO: Switch to the initializer?
private ConfigXmlBuilder()

View File

@ -5,28 +5,10 @@ namespace winswTests.Util
{
class ExceptionHelper
{
public static void assertFails(string expectedMessagePart, Type expectedExceptionType, ExceptionHelperExecutionBody body)
public static void AssertFails(string expectedMessagePart, Type expectedExceptionType, TestDelegate body)
{
try
{
body();
}
catch (Exception ex)
{
Console.Out.WriteLine("Caught exception: " + ex);
Assert.That(ex, Is.InstanceOf(expectedExceptionType ?? typeof(Exception)), "Wrong exception type");
if (expectedMessagePart != null)
{
Assert.That(ex.Message, Does.Contain(expectedMessagePart), "Wrong error message");
}
// Else the exception is fine
return;
}
Assert.Fail("Expected exception " + expectedExceptionType + " to be thrown by the operation");
Exception exception = Assert.Throws(expectedExceptionType ?? typeof(Exception), body);
StringAssert.Contains(expectedMessagePart, exception.Message);
}
}
public delegate void ExceptionHelperExecutionBody();
}

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using NUnit.Framework;
using winsw.Util;
@ -38,12 +38,11 @@ namespace winswTests.Util
var envVars = FilesystemTestHelper.parseSetOutput(envFile);
string[] keys = new string[envVars.Count];
envVars.Keys.CopyTo(keys, 0);
String availableVars = "[" + string.Join(",", keys) + "]";
string availableVars = "[" + string.Join(",", keys) + "]";
Assert.That(envVars.ContainsKey("TEST_KEY"), "No TEST_KEY in the injected vars: " + availableVars);
// And just ensure that the parsing logic is case-sensitive
Assert.That(!envVars.ContainsKey("test_key"), "Test error: the environment parsing logic is case-insensitive");
}
[Test]
@ -51,8 +50,8 @@ namespace winswTests.Util
{
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
string scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
var lotsOfStdOut = string.Join(string.Empty, _Range(1, 1000));
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut));
var lotsOfStdOut = string.Join(string.Empty, Enumerable.Range(1, 1000));
File.WriteAllText(scriptFile, $"echo \"{lotsOfStdOut}\"");
Process proc = new Process();
var ps = proc.StartInfo;
@ -65,16 +64,5 @@ namespace winswTests.Util
Assert.Fail("Process " + proc + " didn't exit after 5 seconds");
}
}
private string[] _Range(int start, int limit)
{
var range = new List<string>();
for (var i = start; i < limit; i++)
{
range.Add(i.ToString());
}
return range.ToArray();
}
}
}

View File

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Version><!-- Populated by AppVeyor --></Version>
<RootNamespace>winswTests</RootNamespace>
</PropertyGroup>