mirror of https://github.com/winsw/winsw
Yaml support for extensions
parent
348d524c79
commit
8c4241369c
|
@ -280,6 +280,7 @@ namespace WinSW
|
|||
Log.Info("Starting " + this.descriptor.Executable + ' ' + startArguments);
|
||||
|
||||
// Load and start extensions
|
||||
Console.WriteLine("Loading extensinos");
|
||||
this.ExtensionManager.LoadExtensions();
|
||||
this.ExtensionManager.FireOnWrapperStarted();
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using WMI;
|
||||
|
||||
namespace WinSW.Configuration
|
||||
|
@ -133,7 +132,7 @@ namespace WinSW.Configuration
|
|||
public bool BeepOnShutdown => false;
|
||||
|
||||
// Extensions
|
||||
public XmlNode? ExtensionsConfiguration => null;
|
||||
public object? ExtensionsConfiguration => null;
|
||||
|
||||
public string BaseName
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace WinSW.Configuration
|
|||
bool BeepOnShutdown { get; }
|
||||
|
||||
// Extensions
|
||||
XmlNode? ExtensionsConfiguration { get; }
|
||||
object? ExtensionsConfiguration { get; }
|
||||
|
||||
List<string> ExtensionIds { get; }
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using WinSW.Native;
|
||||
using WinSW.Util;
|
||||
using WMI;
|
||||
|
@ -100,7 +99,7 @@ namespace WinSW.Configuration
|
|||
public string? SecurityDescriptorYaml { get; set; }
|
||||
|
||||
[YamlMember(Alias = "extensions")]
|
||||
public List<string>? YamlExtensionIds { get; set; }
|
||||
public object? YamlExtensions { get; set; }
|
||||
|
||||
public class YamlEnv
|
||||
{
|
||||
|
@ -641,10 +640,26 @@ namespace WinSW.Configuration
|
|||
|
||||
public string LogMode => this.Log.Mode is null ? this.Defaults.LogMode : this.Log.Mode;
|
||||
|
||||
// TODO - Extensions
|
||||
XmlNode? IWinSWConfiguration.ExtensionsConfiguration => throw new NotImplementedException();
|
||||
public object? ExtensionsConfiguration => this.YamlExtensions;
|
||||
|
||||
public List<string> ExtensionIds => this.YamlExtensionIds ?? this.Defaults.ExtensionIds;
|
||||
public List<string> ExtensionIds
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = new List<string>(0);
|
||||
var extensions = this.ExtensionsConfiguration;
|
||||
var extensionConfigListObject = new ObjectQuery(extensions).ToList<object>();
|
||||
|
||||
foreach (var item in extensionConfigListObject)
|
||||
{
|
||||
var configObject = new ObjectQuery(item);
|
||||
var id = configObject.On("id").ToString();
|
||||
result.Add(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public string BaseName => this.Defaults.BaseName;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Xml;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Configuration;
|
||||
|
||||
namespace WinSW.Extensions
|
||||
{
|
||||
|
@ -11,7 +10,7 @@ namespace WinSW.Extensions
|
|||
public WinSWExtensionDescriptor Descriptor { get; set; }
|
||||
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
|
||||
|
||||
public virtual void Configure(IWinSWConfiguration descriptor, XmlNode node)
|
||||
public virtual void Configure(IWinSWConfiguration descriptor, object settings)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using System.Collections.Generic;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Util;
|
||||
|
||||
namespace WinSW.Extensions
|
||||
{
|
||||
public class ExtensionConfigurationProvider
|
||||
{
|
||||
private readonly IWinSWConfiguration serviceDescriptor;
|
||||
|
||||
private readonly List<WinSWExtensionConfiguration> extensionConfigList;
|
||||
|
||||
public ExtensionConfigurationProvider(IWinSWConfiguration serviceConfigs)
|
||||
{
|
||||
this.serviceDescriptor = serviceConfigs;
|
||||
this.extensionConfigList = this.CreateExtensionConfigList();
|
||||
}
|
||||
|
||||
public WinSWExtensionConfiguration? GetExtenstionConfiguration(string id)
|
||||
{
|
||||
foreach (var item in this.extensionConfigList)
|
||||
{
|
||||
if (item.Id.Equals(id))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<WinSWExtensionConfiguration> CreateExtensionConfigList()
|
||||
{
|
||||
var result = new List<WinSWExtensionConfiguration>(0);
|
||||
|
||||
var extensions = this.serviceDescriptor.ExtensionsConfiguration;
|
||||
var extensionNodes = new ObjectQuery(extensions).ToList<object>();
|
||||
|
||||
foreach (var extension in extensionNodes)
|
||||
{
|
||||
var query = new ObjectQuery(extension);
|
||||
|
||||
var id = query.On("id").ToString();
|
||||
var enabled = query.On("enabled").ToBoolean();
|
||||
var className = query.On("classname").ToString();
|
||||
var settings = query.On("settings");
|
||||
|
||||
var extensionConfig = new WinSWExtensionConfiguration(id, enabled, className, settings);
|
||||
result.Add(extensionConfig);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Xml;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Configuration;
|
||||
|
||||
namespace WinSW.Extensions
|
||||
{
|
||||
|
@ -27,8 +26,7 @@ namespace WinSW.Extensions
|
|||
/// Init handler. Extension should load it's config during that step
|
||||
/// </summary>
|
||||
/// <param name="descriptor">Service descriptor</param>
|
||||
/// <param name="node">Configuration node</param>
|
||||
void Configure(IWinSWConfiguration descriptor, XmlNode node);
|
||||
void Configure(IWinSWConfiguration descriptor, object settings);
|
||||
|
||||
/// <summary>
|
||||
/// Start handler. Called during startup of the service before the child process.
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
namespace WinSW.Extensions
|
||||
{
|
||||
public class WinSWExtensionConfiguration
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public string ClassName { get; set; }
|
||||
|
||||
public object Settings { get; set; }
|
||||
|
||||
public WinSWExtensionConfiguration(string id, bool enabled, string className, object settings)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Enabled = enabled;
|
||||
this.ClassName = className;
|
||||
this.Settings = settings;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ namespace WinSW.Extensions
|
|||
/// </summary>
|
||||
public string ClassName { get; private set; }
|
||||
|
||||
private WinSWExtensionDescriptor(string id, string className, bool enabled)
|
||||
public WinSWExtensionDescriptor(string id, string className, bool enabled)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Enabled = enabled;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using WinSW.Configuration;
|
||||
|
||||
|
@ -12,12 +11,15 @@ namespace WinSW.Extensions
|
|||
|
||||
public IWinSWConfiguration ServiceDescriptor { get; private set; }
|
||||
|
||||
public ExtensionConfigurationProvider ConfigProvider { get; private set; }
|
||||
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager));
|
||||
|
||||
public WinSWExtensionManager(IWinSWConfiguration serviceDescriptor)
|
||||
{
|
||||
this.ServiceDescriptor = serviceDescriptor;
|
||||
this.Extensions = new Dictionary<string, IWinSWExtension>();
|
||||
this.ConfigProvider = new ExtensionConfigurationProvider(this.ServiceDescriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -127,21 +129,25 @@ namespace WinSW.Extensions
|
|||
throw new ExtensionException(id, "Extension has been already loaded");
|
||||
}
|
||||
|
||||
XmlNode? extensionsConfig = this.ServiceDescriptor.ExtensionsConfiguration;
|
||||
XmlElement? configNode = extensionsConfig is null ? null : extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement;
|
||||
var configNode = this.ConfigProvider.GetExtenstionConfiguration(id);
|
||||
|
||||
if (configNode is null)
|
||||
{
|
||||
throw new ExtensionException(id, "Cannot get the configuration entry");
|
||||
}
|
||||
|
||||
var descriptor = WinSWExtensionDescriptor.FromXml(configNode);
|
||||
Console.WriteLine(configNode.Id);
|
||||
Console.WriteLine(configNode.ClassName);
|
||||
Console.WriteLine(configNode.Enabled);
|
||||
|
||||
var descriptor = new WinSWExtensionDescriptor(configNode.Id, configNode.ClassName, configNode.Enabled);
|
||||
if (descriptor.Enabled)
|
||||
{
|
||||
IWinSWExtension extension = this.CreateExtensionInstance(descriptor.Id, descriptor.ClassName);
|
||||
extension.Descriptor = descriptor;
|
||||
try
|
||||
{
|
||||
extension.Configure(this.ServiceDescriptor, configNode);
|
||||
extension.Configure(this.ServiceDescriptor, configNode.Settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ // Consider any unexpected exception as fatal
|
||||
|
|
|
@ -208,7 +208,7 @@ namespace WinSW
|
|||
}
|
||||
}
|
||||
|
||||
public List<string> ExtensionIds
|
||||
/*public List<string> ExtensionIds
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -227,9 +227,18 @@ namespace WinSW
|
|||
|
||||
return result;
|
||||
}
|
||||
}*/
|
||||
|
||||
public List<string> ExtensionIds
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<string>(0);
|
||||
}
|
||||
}
|
||||
|
||||
public XmlNode? ExtensionsConfiguration => this.dom.SelectSingleNode("//extensions");
|
||||
// public XmlNode? ExtensionsConfiguration => this.dom.SelectSingleNode("//extensions");
|
||||
public object? ExtensionsConfiguration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Combines the contents of all the elements of the given name,
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace WinSW
|
|||
using (var reader = new StreamReader(basepath + ".yml"))
|
||||
{
|
||||
var file = reader.ReadToEnd();
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var deserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().Build();
|
||||
|
||||
this.Configurations = deserializer.Deserialize<YamlConfiguration>(file);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace WinSW
|
|||
|
||||
public static ServiceDescriptorYaml FromYaml(string yaml)
|
||||
{
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var deserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().Build();
|
||||
var configs = deserializer.Deserialize<YamlConfiguration>(yaml);
|
||||
return new ServiceDescriptorYaml(configs);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace WinSW.Util
|
||||
{
|
||||
public class ObjectQuery
|
||||
{
|
||||
private readonly object configObject;
|
||||
private object? current;
|
||||
private string? key;
|
||||
|
||||
public ObjectQuery(object? config)
|
||||
{
|
||||
if (config is null)
|
||||
{
|
||||
throw new InvalidDataException("Query object is null");
|
||||
}
|
||||
|
||||
this.configObject = config;
|
||||
this.current = this.configObject;
|
||||
}
|
||||
|
||||
public ObjectQuery On(string key)
|
||||
{
|
||||
this.key = key;
|
||||
this.current = this.Query(this.configObject, key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObjectQuery Get(string key)
|
||||
{
|
||||
if (this.current == null)
|
||||
{
|
||||
throw new InvalidDataException("The key <" + key + "> is not exist");
|
||||
}
|
||||
|
||||
this.key = key;
|
||||
this.current = this.Query(this.current, key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new string ToString()
|
||||
{
|
||||
if (this.current == null)
|
||||
{
|
||||
throw new InvalidDataException("The key <" + this.key + "> is not exist");
|
||||
}
|
||||
|
||||
var result = this.current as string;
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new InvalidDataException(this.key + " can't converto to a string");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<T> ToList<T>()
|
||||
{
|
||||
if (this.current == null)
|
||||
{
|
||||
throw new InvalidDataException("The key <" + this.key + "> is not exist");
|
||||
}
|
||||
|
||||
var list = this.current as List<object>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
throw new InvalidDataException(this.key + " can't converto to List<" + typeof(T) + ">");
|
||||
}
|
||||
|
||||
var result = new List<T>(0);
|
||||
foreach (var item in list)
|
||||
{
|
||||
result.Add((T)item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool ToBoolean()
|
||||
{
|
||||
if (this.current == null)
|
||||
{
|
||||
throw new InvalidDataException("The key <" + this.key + "> is not exist");
|
||||
}
|
||||
|
||||
var value = this.current as string;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new InvalidDataException(this.key + " can't convert into bool");
|
||||
}
|
||||
|
||||
if (value == "true" || value == "yes" || value == "on")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (value == "false" || value == "no" || value == "off")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException(value + " cannot convert into bool");
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectQuery At(int index)
|
||||
{
|
||||
if (this.current == null)
|
||||
{
|
||||
throw new InvalidDataException("The key <" + this.key + "> is not exist");
|
||||
}
|
||||
|
||||
var list = this.current as List<object>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
throw new InvalidDataException("Can't execute At(index) on " + this.key);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = list[index];
|
||||
this.current = result;
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw new InvalidDataException("Index " + index + " not in range");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private object? Query(object dic, string key)
|
||||
{
|
||||
if (dic == null)
|
||||
{
|
||||
throw new InvalidDataException(key + " is not found");
|
||||
}
|
||||
|
||||
var dict = dic as IDictionary<object, object>;
|
||||
if (dict != null)
|
||||
{
|
||||
foreach (KeyValuePair<object, object> kvp in dict)
|
||||
{
|
||||
if (kvp.Key as string == key)
|
||||
{
|
||||
return kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using System.Collections.Specialized;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Extensions;
|
||||
|
@ -180,17 +179,15 @@ namespace WinSW.Plugins.RunawayProcessKiller
|
|||
return parameters.Environment;
|
||||
}
|
||||
|
||||
public override void Configure(IWinSWConfiguration descriptor, XmlNode node)
|
||||
public override void Configure(IWinSWConfiguration descriptor, object settings)
|
||||
{
|
||||
// We expect the upper logic to process any errors
|
||||
// TODO: a better parser API for types would be useful
|
||||
this.Pidfile = XmlHelper.SingleElement(node, "pidfile", false)!;
|
||||
this.StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)!));
|
||||
this.StopParentProcessFirst = bool.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false)!);
|
||||
var configQuery = new ObjectQuery(settings);
|
||||
|
||||
this.Pidfile = configQuery.On("pidfile").ToString();
|
||||
this.StopTimeout = TimeSpan.FromMilliseconds(int.Parse(configQuery.On("stopTimeOut").ToString()));
|
||||
this.StopParentProcessFirst = configQuery.On("StopParentFirst").ToBoolean();
|
||||
this.CheckWinSWEnvironmentVariable = configQuery.On("checkWinSWEnvironmentVariable").ToBoolean();
|
||||
this.ServiceId = descriptor.Id;
|
||||
// TODO: Consider making it documented
|
||||
var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true);
|
||||
this.CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable is null ? true : bool.Parse(checkWinSWEnvironmentVariable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Extensions;
|
||||
|
@ -27,19 +26,21 @@ namespace WinSW.Plugins.SharedDirectoryMapper
|
|||
this._entries.Add(config);
|
||||
}
|
||||
|
||||
public override void Configure(IWinSWConfiguration descriptor, XmlNode node)
|
||||
public override void Configure(IWinSWConfiguration descriptor, object settings)
|
||||
{
|
||||
XmlNodeList? mapNodes = XmlHelper.SingleNode(node, "mapping", false)!.SelectNodes("map");
|
||||
if (mapNodes != null)
|
||||
var configObject = new ObjectQuery(settings);
|
||||
|
||||
var maps = configObject.On("mapping").ToList<object>();
|
||||
|
||||
foreach (var map in maps)
|
||||
{
|
||||
for (int i = 0; i < mapNodes.Count; i++)
|
||||
{
|
||||
if (mapNodes[i] is XmlElement mapElement)
|
||||
{
|
||||
var config = SharedDirectoryMapperConfig.FromXml(mapElement);
|
||||
this._entries.Add(config);
|
||||
}
|
||||
}
|
||||
var mapObject = new ObjectQuery(map);
|
||||
var enable = mapObject.On("enabled").ToBoolean();
|
||||
var label = mapObject.On("label").ToString();
|
||||
var uncpath = mapObject.On("uncpath").ToString();
|
||||
|
||||
var config = new SharedDirectoryMapperConfig(enable, label, uncpath);
|
||||
this._entries.Add(config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,61 +63,5 @@ $@"<service>
|
|||
manager.FireOnWrapperStarted();
|
||||
manager.FireBeforeWrapperStopped();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldKillTheSpawnedProcess()
|
||||
{
|
||||
Assert.Ignore();
|
||||
|
||||
var winswId = "myAppWithRunaway";
|
||||
var extensionId = "runawayProcessKiller";
|
||||
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
|
||||
|
||||
// Spawn the test process
|
||||
Process proc = new Process();
|
||||
var ps = proc.StartInfo;
|
||||
ps.FileName = "cmd.exe";
|
||||
ps.Arguments = "/c pause";
|
||||
ps.UseShellExecute = false;
|
||||
ps.RedirectStandardOutput = true;
|
||||
ps.EnvironmentVariables[WinSWSystem.EnvVarNameServiceId] = winswId;
|
||||
proc.Start();
|
||||
|
||||
try
|
||||
{
|
||||
// Generate extension and ensure that the roundtrip is correct
|
||||
var pidfile = Path.Combine(tmpDir, "process.pid");
|
||||
var sd = ConfigXmlBuilder.create(id: winswId)
|
||||
.WithRunawayProcessKiller(new RunawayProcessKillerExtension(pidfile), extensionId)
|
||||
.ToServiceDescriptor();
|
||||
WinSWExtensionManager manager = new WinSWExtensionManager(sd);
|
||||
manager.LoadExtensions();
|
||||
var extension = manager.Extensions[extensionId] as RunawayProcessKillerExtension;
|
||||
Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded");
|
||||
Assert.AreEqual(pidfile, extension.Pidfile, "PidFile should have been retained during the config roundtrip");
|
||||
|
||||
// Inject PID
|
||||
File.WriteAllText(pidfile, proc.Id.ToString());
|
||||
|
||||
// Try to terminate
|
||||
Assert.That(!proc.HasExited, "Process " + proc + " has exited before the RunawayProcessKiller extension invocation");
|
||||
_ = proc.StandardOutput.Read();
|
||||
extension.OnWrapperStarted();
|
||||
Assert.That(proc.HasExited, "Process " + proc + " should have been terminated by RunawayProcessKiller");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!proc.HasExited)
|
||||
{
|
||||
Console.Error.WriteLine("Test: Killing runaway process with ID=" + proc.Id);
|
||||
ProcessHelper.StopProcessAndChildren(proc.Id, TimeSpan.FromMilliseconds(100), false);
|
||||
if (!proc.HasExited)
|
||||
{
|
||||
// The test is failed here anyway, but we add additional diagnostics info
|
||||
Console.Error.WriteLine("Test: ProcessHelper failed to properly terminate process with ID=" + proc.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
using NUnit.Framework;
|
||||
using WinSW;
|
||||
using WinSW.Configuration;
|
||||
using WinSW.Extensions;
|
||||
using WinSW.Plugins.RunawayProcessKiller;
|
||||
using winswTests.Extensions;
|
||||
|
||||
namespace winswTests
|
||||
{
|
||||
public class YamlExtensionTest : ExtensionTestBase
|
||||
{
|
||||
private IWinSWConfiguration _testServiceDescriptor { get; set; }
|
||||
|
||||
readonly string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
|
||||
string yamlDoc = $@"id: SERVICE_NAME
|
||||
name: Jenkins Slave
|
||||
description: This service runs Jenkins automation server.
|
||||
executable: java
|
||||
arguments: -Xrs -jar \""%BASE%\slave.jar\"" -jnlpUrl ...
|
||||
extensions:
|
||||
- id: killOnStartup
|
||||
enabled: yes
|
||||
classname: ""{this.testExtension}""
|
||||
settings:
|
||||
pidfile: foo/bar/pid.txt
|
||||
stopTimeOut: 5000
|
||||
StopParentFirst: true";
|
||||
|
||||
this._testServiceDescriptor = ServiceDescriptorYaml.FromYaml(yamlDoc).Configurations;
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void LoadExtensions()
|
||||
{
|
||||
|
||||
WinSWExtensionManager manager = new WinSWExtensionManager(this._testServiceDescriptor);
|
||||
manager.LoadExtensions();
|
||||
Assert.AreEqual(1, manager.Extensions.Count, "One extension should be loaded");
|
||||
|
||||
// Check the file is correct
|
||||
var extension = manager.Extensions["killRunawayProcess"] as RunawayProcessKillerExtension;
|
||||
Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded");
|
||||
Assert.AreEqual("foo/bar/pid.txt", extension.Pidfile, "Loaded PID file path is not equal to the expected one");
|
||||
Assert.AreEqual(5000, extension.StopTimeout.TotalMilliseconds, "Loaded Stop Timeout is not equal to the expected one");
|
||||
Assert.AreEqual(true, extension.StopParentProcessFirst, "Loaded StopParentFirst is not equal to the expected one");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue