adding support for running integration tests using packaged build.

pull/6/head
kay.one 11 years ago
parent dc1895ee48
commit eab6c3a4b5

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@ -17,8 +18,7 @@ namespace NzbDrone.App.Test
[TestFixture] [TestFixture]
public class ContainerFixture : TestBase public class ContainerFixture : TestBase
{ {
StartupArguments args = new StartupArguments("first", "second");
string[] args = new[]{"first","second"};
[Test] [Test]
public void should_be_able_to_resolve_indexers() public void should_be_able_to_resolve_indexers()

@ -26,12 +26,19 @@ namespace NzbDrone.Common.Test
Path.IsPathRooted(Subject.AppDataFolder).Should().BeTrue("Path is not rooted"); Path.IsPathRooted(Subject.AppDataFolder).Should().BeTrue("Path is not rooted");
} }
[Test] [Test]
public void IsProduction_should_return_false_when_run_within_nunit() public void IsProduction_should_return_false_when_run_within_nunit()
{ {
RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName); RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName);
} }
[Test]
public void should_use_path_from_arg_if_provided()
{
var args = new StartupArguments("-data=\"c:\\users\\test\\\"");
Mocker.SetConstant<IStartupArguments>(args);
Subject.AppDataFolder.Should().Be("c:\\users\\test\\");
}
} }
} }

@ -26,5 +26,17 @@ namespace NzbDrone.Common.Test.EnvironmentTests
args.Flags.Contains("t").Should().BeTrue(); args.Flags.Contains("t").Should().BeTrue();
} }
[TestCase("/key=value")]
[TestCase("/KEY=value")]
[TestCase(" /key=\"value\"")]
public void should_parse_args_with_alues(string arg)
{
var args = new StartupArguments(new[] { arg });
args.Args.Should().HaveCount(1);
args.Args["key"].Should().Be("value");
}
} }
} }

@ -1,6 +1,7 @@
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging;
using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Lifecycle;
using NzbDrone.Host; using NzbDrone.Host;
@ -14,7 +15,7 @@ namespace NzbDrone.Common.Test
[SetUp] [SetUp]
public void setup() public void setup()
{ {
Mocker.SetConstant(MainAppContainerBuilder.BuildContainer(new string[0])); Mocker.SetConstant(MainAppContainerBuilder.BuildContainer(new StartupArguments()));
} }
[Test] [Test]

@ -21,7 +21,7 @@ namespace NzbDrone.Common.EnvironmentInfo
private readonly Environment.SpecialFolder DATA_SPECIAL_FOLDER = Environment.SpecialFolder.CommonApplicationData; private readonly Environment.SpecialFolder DATA_SPECIAL_FOLDER = Environment.SpecialFolder.CommonApplicationData;
public AppFolderInfo(IDiskProvider diskProvider) public AppFolderInfo(IDiskProvider diskProvider, IStartupArguments startupArguments)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
@ -32,7 +32,17 @@ namespace NzbDrone.Common.EnvironmentInfo
_logger = LogManager.GetCurrentClassLogger(); _logger = LogManager.GetCurrentClassLogger();
AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.Create), "NzbDrone"); if (startupArguments.Args.ContainsKey(StartupArguments.APPDATA))
{
AppDataFolder = startupArguments.Args[StartupArguments.APPDATA];
}
else
{
AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "NzbDrone");
}
_diskProvider.EnsureFolder(AppDataFolder);
StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName; StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
TempFolder = Path.GetTempPath(); TempFolder = Path.GetTempPath();

@ -1,26 +1,49 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
namespace NzbDrone.Common.EnvironmentInfo namespace NzbDrone.Common.EnvironmentInfo
{ {
public class StartupArguments public interface IStartupArguments
{ {
HashSet<string> Flags { get; }
Dictionary<string, string> Args { get; }
}
public const string NO_BROWSER = "no-browser"; public class StartupArguments : IStartupArguments
{
public const string APPDATA = "data";
public const string NO_BROWSER = "nobrowser";
public const string INSTALL_SERVICE = "i"; public const string INSTALL_SERVICE = "i";
public const string UNINSTALL_SERVICE = "u"; public const string UNINSTALL_SERVICE = "u";
public const string HELP = "?"; public const string HELP = "?";
public StartupArguments(string[] args) public StartupArguments(params string[] args)
{ {
Flags = new HashSet<string>(); Flags = new HashSet<string>();
Args = new Dictionary<string, string>();
foreach (var s in args) foreach (var s in args)
{ {
var flag = s.Trim(' ', '/', '-').ToLower(); var flag = s.Trim(' ', '/', '-').ToLower();
Flags.Add(flag);
var argParts = flag.Split('=');
if (argParts.Length == 2)
{
Args.Add(argParts[0].Trim(), argParts[1].Trim(' ', '"'));
}
else
{
Flags.Add(flag);
}
} }
Instance = this;
} }
public HashSet<string> Flags { get; private set; } public HashSet<string> Flags { get; private set; }
public Dictionary<string, string> Args { get; private set; }
public static IStartupArguments Instance { get; private set; }
} }
} }

@ -15,8 +15,7 @@ namespace NzbDrone.Common.Instrumentation
public ApplicationLogLayoutRenderer() public ApplicationLogLayoutRenderer()
{ {
_appData = Path.Combine(new AppFolderInfo(new DiskProvider()).GetLogFolder(), "nzbdrone.txt"); _appData = Path.Combine(new AppFolderInfo(new DiskProvider(), StartupArguments.Instance ).GetLogFolder(), "nzbdrone.txt");
} }
protected override void Append(StringBuilder builder, LogEventInfo logEvent) protected override void Append(StringBuilder builder, LogEventInfo logEvent)

@ -16,7 +16,7 @@ namespace NzbDrone.Common.Instrumentation
public UpdateLogLayoutRenderer() public UpdateLogLayoutRenderer()
{ {
_appData = Path.Combine(new AppFolderInfo(new DiskProvider()).GetUpdateLogFolder(), DateTime.Now.ToString("yy.MM.d-HH.mm") + ".txt"); _appData = Path.Combine(new AppFolderInfo(new DiskProvider(), StartupArguments.Instance).GetUpdateLogFolder(), DateTime.Now.ToString("yy.MM.d-HH.mm") + ".txt");
} }

@ -96,7 +96,10 @@ namespace NzbDrone.Common
logger.Info("Starting {0} {1}", path, args); logger.Info("Starting {0} {1}", path, args);
var process = Process.Start(startInfo); var process = new Process
{
StartInfo = startInfo
};
process.OutputDataReceived += (sender, eventArgs) => process.OutputDataReceived += (sender, eventArgs) =>
{ {

@ -1,4 +1,5 @@
using System; using System;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Console namespace NzbDrone.Console
{ {
@ -8,7 +9,7 @@ namespace NzbDrone.Console
{ {
try try
{ {
Host.Bootstrap.Start(args); Host.Bootstrap.Start(new StartupArguments(args));
} }
catch (Exception e) catch (Exception e)
{ {

@ -65,8 +65,6 @@ namespace NzbDrone.Core.Test.Framework
public abstract class DbTest : CoreTest public abstract class DbTest : CoreTest
{ {
private ITestDatabase _db; private ITestDatabase _db;
private IDatabase _database;
protected virtual MigrationType MigrationType protected virtual MigrationType MigrationType
{ {

@ -17,7 +17,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.SetConstant<IAppFolderInfo>(new AppFolderInfo(new DiskProvider())); Mocker.SetConstant<IAppFolderInfo>(new AppFolderInfo(new DiskProvider(), Mocker.Resolve<IStartupArguments>()));
} }
[Test] [Test]

@ -22,13 +22,13 @@ namespace NzbDrone.Host
private readonly IHostController _hostController; private readonly IHostController _hostController;
private readonly IProcessProvider _processProvider; private readonly IProcessProvider _processProvider;
private readonly PriorityMonitor _priorityMonitor; private readonly PriorityMonitor _priorityMonitor;
private readonly StartupArguments _startupArguments; private readonly IStartupArguments _startupArguments;
private readonly IFirewallAdapter _firewallAdapter; private readonly IFirewallAdapter _firewallAdapter;
private readonly IUrlAclAdapter _urlAclAdapter; private readonly IUrlAclAdapter _urlAclAdapter;
private readonly Logger _logger; private readonly Logger _logger;
public NzbDroneServiceFactory(IConfigFileProvider configFileProvider, IHostController hostController, IRuntimeInfo runtimeInfo, public NzbDroneServiceFactory(IConfigFileProvider configFileProvider, IHostController hostController, IRuntimeInfo runtimeInfo,
IProcessProvider processProvider, PriorityMonitor priorityMonitor, StartupArguments startupArguments, IProcessProvider processProvider, PriorityMonitor priorityMonitor, IStartupArguments startupArguments,
IFirewallAdapter firewallAdapter, IUrlAclAdapter urlAclAdapter, Logger logger) IFirewallAdapter firewallAdapter, IUrlAclAdapter urlAclAdapter, Logger logger)
{ {
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;

@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Reflection; using System.Reflection;
using NLog; using NLog;
using NzbDrone.Common.Composition; using NzbDrone.Common.Composition;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Security; using NzbDrone.Common.Security;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
@ -11,17 +12,16 @@ namespace NzbDrone.Host
{ {
public static class Bootstrap public static class Bootstrap
{ {
private static readonly Logger Logger = LogManager.GetLogger("AppMain"); public static IContainer Start(StartupArguments args)
public static IContainer Start(string[] args)
{ {
var logger = LogManager.GetLogger("AppMain");
try try
{ {
GlobalExceptionHandlers.Register(); GlobalExceptionHandlers.Register();
IgnoreCertErrorPolicy.Register(); IgnoreCertErrorPolicy.Register();
Logger.Info("Starting NzbDrone Console. Version {0}", Assembly.GetExecutingAssembly().GetName().Version); logger.Info("Starting NzbDrone Console. Version {0}", Assembly.GetExecutingAssembly().GetName().Version);
//Check if full version .NET is installed. //Check if full version .NET is installed.
try try
@ -30,7 +30,7 @@ namespace NzbDrone.Host
} }
catch (Exception) catch (Exception)
{ {
Logger.Error("It looks like you don't have full version of .NET Framework installed. Press any key and you will be directed to the download page."); logger.Error("It looks like you don't have full version of .NET Framework installed. Press any key and you will be directed to the download page.");
Console.Read(); Console.Read();
try try
@ -39,7 +39,7 @@ namespace NzbDrone.Host
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Warn("Oops. can't start default browser. Please visit http://www.microsoft.com/download/en/details.aspx?id=17851 to download .NET Framework 4."); logger.Warn("Oops. can't start default browser. Please visit http://www.microsoft.com/download/en/details.aspx?id=17851 to download .NET Framework 4.");
Console.ReadLine(); Console.ReadLine();
} }
@ -48,14 +48,19 @@ namespace NzbDrone.Host
var container = MainAppContainerBuilder.BuildContainer(args); var container = MainAppContainerBuilder.BuildContainer(args);
throw new IndexOutOfRangeException();
DbFactory.RegisterDatabase(container); DbFactory.RegisterDatabase(container);
container.Resolve<Router>().Route(); container.Resolve<Router>().Route();
return container; return container;
} }
catch (Exception e) catch (Exception e)
{ {
Logger.FatalException("Epic Fail " + e.Message, e); logger.FatalException("Epic Fail " + e.Message, e);
throw; throw;
} }
} }

@ -11,22 +11,22 @@ namespace NzbDrone.Host
{ {
public class MainAppContainerBuilder : ContainerBuilderBase public class MainAppContainerBuilder : ContainerBuilderBase
{ {
public static IContainer BuildContainer(string[] args) public static IContainer BuildContainer(StartupArguments args)
{ {
return new MainAppContainerBuilder(args).Container; return new MainAppContainerBuilder(args).Container;
} }
private MainAppContainerBuilder(string[] args) private MainAppContainerBuilder(StartupArguments args)
: base("NzbDrone.Host", "NzbDrone.Common", "NzbDrone.Core", "NzbDrone.Api") : base("NzbDrone.Host", "NzbDrone.Common", "NzbDrone.Core", "NzbDrone.Api")
{ {
Container.Register<IStartupArguments>(args);
AutoRegisterImplementations<NzbDronePersistentConnection>(); AutoRegisterImplementations<NzbDronePersistentConnection>();
Container.Register(typeof(IBasicRepository<RootFolder>), typeof(BasicRepository<RootFolder>)); Container.Register(typeof(IBasicRepository<RootFolder>), typeof(BasicRepository<RootFolder>));
Container.Register(typeof(IBasicRepository<NamingConfig>), typeof(BasicRepository<NamingConfig>)); Container.Register(typeof(IBasicRepository<NamingConfig>), typeof(BasicRepository<NamingConfig>));
Container.Register<INancyBootstrapper, NancyBootstrapper>(); Container.Register<INancyBootstrapper, NancyBootstrapper>();
Container.Register(new StartupArguments(args));
} }
} }
} }

@ -8,12 +8,12 @@ namespace NzbDrone.Host
{ {
private readonly INzbDroneServiceFactory _nzbDroneServiceFactory; private readonly INzbDroneServiceFactory _nzbDroneServiceFactory;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly StartupArguments _startupArguments; private readonly IStartupArguments _startupArguments;
private readonly IConsoleService _consoleService; private readonly IConsoleService _consoleService;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly Logger _logger; private readonly Logger _logger;
public Router(INzbDroneServiceFactory nzbDroneServiceFactory, IServiceProvider serviceProvider, StartupArguments startupArguments, public Router(INzbDroneServiceFactory nzbDroneServiceFactory, IServiceProvider serviceProvider, IStartupArguments startupArguments,
IConsoleService consoleService, IRuntimeInfo runtimeInfo, Logger logger) IConsoleService consoleService, IRuntimeInfo runtimeInfo, Logger logger)
{ {
_nzbDroneServiceFactory = nzbDroneServiceFactory; _nzbDroneServiceFactory = nzbDroneServiceFactory;

@ -19,7 +19,6 @@ namespace NzbDrone.Integration.Test.Client
return Get<List<SeriesResource>>(request); return Get<List<SeriesResource>>(request);
} }
public SeriesResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK) public SeriesResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK)
{ {
var request = BuildRequest(slug); var request = BuildRequest(slug);
@ -27,4 +26,15 @@ namespace NzbDrone.Integration.Test.Client
} }
} }
public class SystemInfoClient : ClientBase<SeriesResource>
{
public SystemInfoClient(IRestClient restClient)
: base(restClient)
{
}
}
} }

@ -1,20 +1,12 @@
using System.Collections.Generic; using System;
using Moq; using System.ComponentModel;
using NLog; using System.Diagnostics;
using NLog.Config; using System.IO;
using NLog.Targets; using System.Threading;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Api;
using NzbDrone.Api.Commands; using NzbDrone.Api.Commands;
using NzbDrone.Api.RootFolders; using NzbDrone.Api.RootFolders;
using NzbDrone.Common.Composition;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Jobs;
using NzbDrone.Host;
using NzbDrone.Host.Owin;
using NzbDrone.Host.Owin.MiddleWare;
using NzbDrone.Integration.Test.Client; using NzbDrone.Integration.Test.Client;
using NzbDrone.Test.Common.Categories; using NzbDrone.Test.Common.Categories;
using RestSharp; using RestSharp;
@ -25,64 +17,110 @@ namespace NzbDrone.Integration.Test
[IntegrationTest] [IntegrationTest]
public abstract class IntegrationTest public abstract class IntegrationTest
{ {
private NancyBootstrapper _bootstrapper;
private IHostController _hostController;
protected RestClient RestClient { get; private set; } protected RestClient RestClient { get; private set; }
private static readonly Logger Logger = LogManager.GetLogger("TEST");
protected IContainer Container { get; private set; }
protected SeriesClient Series; protected SeriesClient Series;
protected ClientBase<RootFolderResource> RootFolders; protected ClientBase<RootFolderResource> RootFolders;
protected ClientBase<CommandResource> Commands; protected ClientBase<CommandResource> Commands;
protected ReleaseClient Releases; protected ReleaseClient Releases;
protected IndexerClient Indexers; protected IndexerClient Indexers;
private static void ResetLogger() [SetUp]
public void SmokeTestSetup()
{ {
LogManager.Configuration = new LoggingConfiguration(); new StartupArguments();
var consoleTarget = new ConsoleTarget { Layout = "${time} - ${logger} - ${message} ${exception}" };
LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget); KillNzbDrone();
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
LogManager.ReconfigExistingLoggers(); InitRestClients();
PackageStart();
} }
private static void KillNzbDrone()
{
foreach (var p in Process.GetProcessesByName("NzbDrone.Console"))
{
try
{
p.Kill();
}
catch (Win32Exception)
{
}
}
}
[SetUp] private string AppDate;
public void SmokeTestSetup()
private void PackageStart()
{ {
ResetLogger(); AppDate = Path.Combine(Directory.GetCurrentDirectory(), "_intg_" + DateTime.Now.Ticks);
Start("..\\..\\..\\..\\_output\\NzbDrone.Console.exe");
Container = MainAppContainerBuilder.BuildContainer(new string[0]); while (RestClient.Get(new RestRequest("system/status")).ResponseStatus != ResponseStatus.Completed)
Container.Register(typeof(IAppFolderInfo), new IntegrationTestFolderInfo()); {
Thread.Sleep(1000);
}
}
DbFactory.RegisterDatabase(Container); private Process Start(string path)
{
var taskManagerMock = new Mock<ITaskManager>(); var args = "-nobrowser -data=\"" + AppDate + "\"";
taskManagerMock.Setup(c => c.GetPending()).Returns(new List<ScheduledTask>());
Container.TinyContainer.Register(taskManagerMock.Object); var startInfo = new ProcessStartInfo(path, args)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
_bootstrapper = new NancyBootstrapper(Container.TinyContainer); Console.WriteLine("Starting {0} {1}", path, args);
var process = new Process
{
StartInfo = startInfo
};
var hostConfig = new Mock<IConfigFileProvider>(); process.OutputDataReceived += (sender, eventArgs) =>
hostConfig.SetupGet(c => c.Port).Returns(1313); {
if (string.IsNullOrWhiteSpace(eventArgs.Data)) return;
_hostController = new OwinHostController(hostConfig.Object, new[] { new NancyMiddleWare(_bootstrapper) }, Logger); if (eventArgs.Data.Contains("Press enter to exit"))
{
Assert.Fail("Process waiting for input");
}
Console.WriteLine(eventArgs.Data);
};
InitRestClients(); process.ErrorDataReceived += (sender, eventArgs) =>
{
if (string.IsNullOrWhiteSpace(eventArgs.Data)) return;
if (eventArgs.Data.Contains("Press enter to exit"))
{
Assert.Fail("Process waiting for input");
}
Console.WriteLine(eventArgs.Data);
};
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
_hostController.StartServer(); return process;
} }
private void InitRestClients() private void InitRestClients()
{ {
RestClient = new RestClient(_hostController.AppUrl + "/api/"); RestClient = new RestClient("http://localhost:8989/api");
Series = new SeriesClient(RestClient); Series = new SeriesClient(RestClient);
Releases = new ReleaseClient(RestClient); Releases = new ReleaseClient(RestClient);
RootFolders = new ClientBase<RootFolderResource>(RestClient); RootFolders = new ClientBase<RootFolderResource>(RestClient);
@ -93,8 +131,7 @@ namespace NzbDrone.Integration.Test
[TearDown] [TearDown]
public void SmokeTestTearDown() public void SmokeTestTearDown()
{ {
_hostController.StopServer(); KillNzbDrone();
_bootstrapper.Shutdown();
} }
} }

@ -2,15 +2,20 @@ using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets; using NLog.Targets;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Test.Common namespace NzbDrone.Test.Common
{ {
public abstract class LoggingTest public abstract class LoggingTest
{ {
protected Logger TestLogger = LogManager.GetLogger("TestLogger"); protected static Logger TestLogger;
protected static void InitLogging() protected static void InitLogging()
{ {
new StartupArguments();
TestLogger = LogManager.GetLogger("TestLogger");
if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration) if (LogManager.Configuration == null || LogManager.Configuration is XmlLoggingConfiguration)
{ {
LogManager.Configuration = new LoggingConfiguration(); LogManager.Configuration = new LoggingConfiguration();

@ -81,7 +81,7 @@ namespace NzbDrone.Test.Common
Mocker.SetConstant(LogManager.GetLogger("TestLogger")); Mocker.SetConstant(LogManager.GetLogger("TestLogger"));
Mocker.SetConstant(new StartupArguments(new string[0])); Mocker.SetConstant<IStartupArguments>(new StartupArguments(new string[0]));
LogManager.ReconfigExistingLoggers(); LogManager.ReconfigExistingLoggers();

@ -1,5 +1,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.SysTray; using NzbDrone.SysTray;
namespace NzbDrone namespace NzbDrone
@ -10,7 +11,7 @@ namespace NzbDrone
{ {
try try
{ {
var container = Host.Bootstrap.Start(args); var container = Host.Bootstrap.Start(new StartupArguments(args));
container.Register<ISystemTrayApp, SystemTrayApp>(); container.Register<ISystemTrayApp, SystemTrayApp>();
container.Resolve<ISystemTrayApp>().Start(); container.Resolve<ISystemTrayApp>().Start();
} }

Loading…
Cancel
Save