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

View File

@ -439,9 +439,9 @@ namespace winsw
// Next day so check if file can be zipped // Next day so check if file can be zipped
ZipFiles(baseDirectory, extension, baseFileName); 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 finally
{ {
@ -503,7 +503,7 @@ namespace winsw
} }
catch (Exception e) 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 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) 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 // initialize an unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1]; LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = default;
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName); userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (ushort)(privilegeName.Length * UnicodeEncoding.CharSize); userRights[0].Length = (ushort)(privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (ushort)((privilegeName.Length + 1) * UnicodeEncoding.CharSize); userRights[0].MaximumLength = (ushort)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,28 +5,10 @@ namespace winswTests.Util
{ {
class ExceptionHelper class ExceptionHelper
{ {
public static void assertFails(string expectedMessagePart, Type expectedExceptionType, ExceptionHelperExecutionBody body) public static void AssertFails(string expectedMessagePart, Type expectedExceptionType, TestDelegate body)
{ {
try Exception exception = Assert.Throws(expectedExceptionType ?? typeof(Exception), body);
{ StringAssert.Contains(expectedMessagePart, exception.Message);
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");
} }
} }
public delegate void ExceptionHelperExecutionBody();
} }

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using winsw.Util; using winsw.Util;
@ -38,12 +38,11 @@ namespace winswTests.Util
var envVars = FilesystemTestHelper.parseSetOutput(envFile); var envVars = FilesystemTestHelper.parseSetOutput(envFile);
string[] keys = new string[envVars.Count]; string[] keys = new string[envVars.Count];
envVars.Keys.CopyTo(keys, 0); 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); Assert.That(envVars.ContainsKey("TEST_KEY"), "No TEST_KEY in the injected vars: " + availableVars);
// And just ensure that the parsing logic is case-sensitive // 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"); Assert.That(!envVars.ContainsKey("test_key"), "Test error: the environment parsing logic is case-insensitive");
} }
[Test] [Test]
@ -51,8 +50,8 @@ namespace winswTests.Util
{ {
var tmpDir = FilesystemTestHelper.CreateTmpDirectory(); var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
string scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat"); string scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
var lotsOfStdOut = string.Join(string.Empty, _Range(1, 1000)); var lotsOfStdOut = string.Join(string.Empty, Enumerable.Range(1, 1000));
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut)); File.WriteAllText(scriptFile, $"echo \"{lotsOfStdOut}\"");
Process proc = new Process(); Process proc = new Process();
var ps = proc.StartInfo; var ps = proc.StartInfo;
@ -65,16 +64,5 @@ namespace winswTests.Util
Assert.Fail("Process " + proc + " didn't exit after 5 seconds"); 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> <PropertyGroup>
<TargetFrameworks>net40;net461;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Version><!-- Populated by AppVeyor --></Version> <Version><!-- Populated by AppVeyor --></Version>
<RootNamespace>winswTests</RootNamespace> <RootNamespace>winswTests</RootNamespace>
</PropertyGroup> </PropertyGroup>