mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
More nzbdrone.exe refactoring.
This commit is contained in:
parent
69ba365cd3
commit
8bf4f81a04
39
NzbDrone.App.Test/ApplicationTest.cs
Normal file
39
NzbDrone.App.Test/ApplicationTest.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AutoMoq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Providers;
|
||||
|
||||
namespace NzbDrone.App.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class MonitoringProviderTest
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Ensure_priority_doesnt_fail_on_invalid_iis_proccess_id()
|
||||
{
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var processMock = mocker.GetMock<ProcessProvider>();
|
||||
processMock.Setup(c => c.GetCurrentProcess())
|
||||
.Returns(Builder<ProcessInfo>.CreateNew().With(c => c.Priority == ProcessPriorityClass.Normal).Build());
|
||||
|
||||
processMock.Setup(c => c.GetProcessById(It.IsAny<int>())).Returns((ProcessInfo)null);
|
||||
|
||||
var subject = mocker.Resolve<MonitoringProvider>();
|
||||
|
||||
|
||||
//Act
|
||||
subject.EnsurePriority(null, null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
166
NzbDrone.App.Test/AutoMoq/AutoMoqer.cs
Normal file
166
NzbDrone.App.Test/AutoMoq/AutoMoqer.cs
Normal file
@ -0,0 +1,166 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AutoMoq.Unity;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Moq;
|
||||
using Moq.Language.Flow;
|
||||
|
||||
[assembly: InternalsVisibleTo("AutoMoq.Tests")]
|
||||
|
||||
namespace AutoMoq
|
||||
{
|
||||
public class AutoMoqer
|
||||
{
|
||||
internal readonly MockBehavior DefaultBehavior = MockBehavior.Default;
|
||||
internal Type ResolveType;
|
||||
private IUnityContainer container;
|
||||
private IDictionary<Type, object> registeredMocks;
|
||||
|
||||
public AutoMoqer()
|
||||
{
|
||||
SetupAutoMoqer(new UnityContainer());
|
||||
}
|
||||
|
||||
public AutoMoqer(MockBehavior defaultBehavior)
|
||||
{
|
||||
DefaultBehavior = defaultBehavior;
|
||||
SetupAutoMoqer(new UnityContainer());
|
||||
|
||||
}
|
||||
|
||||
internal AutoMoqer(IUnityContainer container)
|
||||
{
|
||||
SetupAutoMoqer(container);
|
||||
}
|
||||
|
||||
public virtual T Resolve<T>()
|
||||
{
|
||||
ResolveType = typeof(T);
|
||||
var result = container.Resolve<T>();
|
||||
SetConstant(result);
|
||||
ResolveType = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual Mock<T> GetMock<T>() where T : class
|
||||
{
|
||||
return GetMock<T>(DefaultBehavior);
|
||||
}
|
||||
|
||||
public virtual Mock<T> GetMock<T>(MockBehavior behavior) where T : class
|
||||
{
|
||||
ResolveType = null;
|
||||
var type = GetTheMockType<T>();
|
||||
if (GetMockHasNotBeenCalledForThisType(type))
|
||||
{
|
||||
CreateANewMockAndRegisterIt<T>(type, behavior);
|
||||
}
|
||||
|
||||
var mock = TheRegisteredMockForThisType<T>(type);
|
||||
|
||||
if (behavior != MockBehavior.Default && mock.Behavior == MockBehavior.Default)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to change be behaviour of a an existing mock.");
|
||||
}
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
internal virtual void SetMock(Type type, Mock mock)
|
||||
{
|
||||
if (registeredMocks.ContainsKey(type) == false)
|
||||
registeredMocks.Add(type, mock);
|
||||
}
|
||||
|
||||
public virtual void SetConstant<T>(T instance)
|
||||
{
|
||||
container.RegisterInstance(instance);
|
||||
SetMock(instance.GetType(), null);
|
||||
}
|
||||
|
||||
public ISetup<T> Setup<T>(Expression<Action<T>> expression) where T : class
|
||||
{
|
||||
return GetMock<T>().Setup(expression);
|
||||
}
|
||||
|
||||
public ISetup<T, TResult> Setup<T, TResult>(Expression<Func<T, TResult>> expression) where T : class
|
||||
{
|
||||
return GetMock<T>().Setup(expression);
|
||||
}
|
||||
|
||||
public void Verify<T>(Expression<Action<T>> expression) where T : class
|
||||
{
|
||||
GetMock<T>().Verify(expression);
|
||||
}
|
||||
|
||||
public void Verify<T>(Expression<Action<T>> expression, string failMessage) where T : class
|
||||
{
|
||||
GetMock<T>().Verify(expression, failMessage);
|
||||
}
|
||||
|
||||
public void Verify<T>(Expression<Action<T>> expression, Times times) where T : class
|
||||
{
|
||||
GetMock<T>().Verify(expression, times);
|
||||
}
|
||||
|
||||
public void Verify<T>(Expression<Action<T>> expression, Times times, string failMessage) where T : class
|
||||
{
|
||||
GetMock<T>().Verify(expression, times, failMessage);
|
||||
}
|
||||
|
||||
public void VerifyAllMocks()
|
||||
{
|
||||
foreach (var registeredMock in registeredMocks)
|
||||
{
|
||||
var mock = registeredMock.Value as Mock;
|
||||
if (mock != null)
|
||||
mock.VerifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private void SetupAutoMoqer(IUnityContainer container)
|
||||
{
|
||||
this.container = container;
|
||||
container.RegisterInstance(this);
|
||||
|
||||
registeredMocks = new Dictionary<Type, object>();
|
||||
AddTheAutoMockingContainerExtensionToTheContainer(container);
|
||||
}
|
||||
|
||||
private static void AddTheAutoMockingContainerExtensionToTheContainer(IUnityContainer container)
|
||||
{
|
||||
container.AddNewExtension<AutoMockingContainerExtension>();
|
||||
return;
|
||||
}
|
||||
|
||||
private Mock<T> TheRegisteredMockForThisType<T>(Type type) where T : class
|
||||
{
|
||||
return (Mock<T>)registeredMocks.Where(x => x.Key == type).First().Value;
|
||||
}
|
||||
|
||||
private void CreateANewMockAndRegisterIt<T>(Type type, MockBehavior behavior) where T : class
|
||||
{
|
||||
var mock = new Mock<T>(behavior);
|
||||
container.RegisterInstance(mock.Object);
|
||||
SetMock(type, mock);
|
||||
}
|
||||
|
||||
private bool GetMockHasNotBeenCalledForThisType(Type type)
|
||||
{
|
||||
return registeredMocks.ContainsKey(type) == false;
|
||||
}
|
||||
|
||||
private static Type GetTheMockType<T>() where T : class
|
||||
{
|
||||
return typeof(T);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
187
NzbDrone.App.Test/AutoMoq/AutoMoqerTest.cs
Normal file
187
NzbDrone.App.Test/AutoMoq/AutoMoqerTest.cs
Normal file
@ -0,0 +1,187 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
using System;
|
||||
using AutoMoq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test
|
||||
{
|
||||
[TestFixture]
|
||||
// ReSharper disable InconsistentNaming
|
||||
public class AutoMoqerTest
|
||||
{
|
||||
[Test]
|
||||
public void GetMock_on_interface_returns_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
//Act
|
||||
var mock = mocker.GetMock<IDependency>();
|
||||
|
||||
//Assert
|
||||
Assert.IsNotNull(mock);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetMock_on_concrete_returns_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
//Act
|
||||
var mock = mocker.GetMock<ConcreteClass>();
|
||||
|
||||
//Assert
|
||||
Assert.IsNotNull(mock);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Resolve_doesnt_return_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<ConcreteClass>().Do();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual("hello", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Resolve_with_dependency_doesnt_return_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<VirtualDependency>().VirtualMethod();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual("hello", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Resolve_with_mocked_dependency_uses_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
mocker.GetMock<VirtualDependency>()
|
||||
.Setup(m => m.VirtualMethod())
|
||||
.Returns("mocked");
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<ClassWithVirtualDependencies>().CallVirtualChild();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual("mocked", result);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Resolve_with_unbound_concerete_dependency_uses_mock()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<ClassWithVirtualDependencies>().CallVirtualChild();
|
||||
|
||||
var mockedResult = new Mock<VirtualDependency>().Object.VirtualMethod();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(mockedResult, result);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Resolve_with_constant_concerete_dependency_uses_constant()
|
||||
{
|
||||
//Arrange
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var constant = new VirtualDependency { PropValue = Guid.NewGuid().ToString() };
|
||||
|
||||
mocker.SetConstant(constant);
|
||||
|
||||
//Act
|
||||
var result = mocker.Resolve<ClassWithVirtualDependencies>().GetVirtualProperty();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(constant.PropValue, result);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConcreteClass
|
||||
{
|
||||
public string Do()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
public class Dependency : IDependency
|
||||
{
|
||||
}
|
||||
|
||||
public interface IDependency
|
||||
{
|
||||
}
|
||||
|
||||
public class ClassWithDependencies
|
||||
{
|
||||
public ClassWithDependencies(IDependency dependency)
|
||||
{
|
||||
Dependency = dependency;
|
||||
}
|
||||
|
||||
public IDependency Dependency { get; set; }
|
||||
}
|
||||
|
||||
public class ClassWithVirtualDependencies
|
||||
{
|
||||
private readonly VirtualDependency _virtualDependency;
|
||||
|
||||
public ClassWithVirtualDependencies(IDependency dependency, VirtualDependency virtualDependency)
|
||||
{
|
||||
_virtualDependency = virtualDependency;
|
||||
Dependency = dependency;
|
||||
}
|
||||
|
||||
public IDependency Dependency { get; set; }
|
||||
|
||||
public string CallVirtualChild()
|
||||
{
|
||||
return _virtualDependency.VirtualMethod();
|
||||
}
|
||||
|
||||
public string GetVirtualProperty()
|
||||
{
|
||||
return _virtualDependency.PropValue;
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualDependency
|
||||
{
|
||||
private readonly IDependency _dependency;
|
||||
|
||||
public VirtualDependency()
|
||||
{
|
||||
}
|
||||
|
||||
public VirtualDependency(IDependency dependency)
|
||||
{
|
||||
_dependency = dependency;
|
||||
}
|
||||
|
||||
public string PropValue { get; set; }
|
||||
|
||||
public virtual string VirtualMethod()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
}
|
22
NzbDrone.App.Test/AutoMoq/License.txt
Normal file
22
NzbDrone.App.Test/AutoMoq/License.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 2010 Darren Cauthon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,84 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Practices.ObjectBuilder2;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Moq;
|
||||
|
||||
namespace AutoMoq.Unity
|
||||
{
|
||||
internal class AutoMockingBuilderStrategy : BuilderStrategy
|
||||
{
|
||||
private readonly IUnityContainer _container;
|
||||
private readonly MockRepository _mockFactory;
|
||||
private readonly IEnumerable<Type> _registeredTypes;
|
||||
|
||||
public AutoMockingBuilderStrategy(IEnumerable<Type> registeredTypes, IUnityContainer container)
|
||||
{
|
||||
var autoMoqer = container.Resolve<AutoMoqer>();
|
||||
_mockFactory = new MockRepository(autoMoqer.DefaultBehavior);
|
||||
_registeredTypes = registeredTypes;
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public override void PreBuildUp(IBuilderContext context)
|
||||
{
|
||||
var autoMoqer = _container.Resolve<AutoMoqer>();
|
||||
|
||||
var type = GetTheTypeFromTheBuilderContext(context);
|
||||
if (AMockObjectShouldBeCreatedForThisType(type))
|
||||
{
|
||||
var mock = CreateAMockObject(type);
|
||||
context.Existing = mock.Object;
|
||||
autoMoqer.SetMock(type, mock);
|
||||
}
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private bool AMockObjectShouldBeCreatedForThisType(Type type)
|
||||
{
|
||||
var mocker = _container.Resolve<AutoMoqer>();
|
||||
return TypeIsNotRegistered(type) && (mocker.ResolveType == null || mocker.ResolveType != type);
|
||||
//return TypeIsNotRegistered(type) && type.IsInterface;
|
||||
}
|
||||
|
||||
private static Type GetTheTypeFromTheBuilderContext(IBuilderContext context)
|
||||
{
|
||||
return (context.OriginalBuildKey).Type;
|
||||
}
|
||||
|
||||
private bool TypeIsNotRegistered(Type type)
|
||||
{
|
||||
return _registeredTypes.Any(x => x.Equals(type)) == false;
|
||||
}
|
||||
|
||||
private Mock CreateAMockObject(Type type)
|
||||
{
|
||||
var createMethod = GenerateAnInterfaceMockCreationMethod(type);
|
||||
|
||||
return InvokeTheMockCreationMethod(createMethod);
|
||||
}
|
||||
|
||||
private Mock InvokeTheMockCreationMethod(MethodInfo createMethod)
|
||||
{
|
||||
return (Mock)createMethod.Invoke(_mockFactory, new object[] { new List<object>().ToArray() });
|
||||
}
|
||||
|
||||
private MethodInfo GenerateAnInterfaceMockCreationMethod(Type type)
|
||||
{
|
||||
var createMethodWithNoParameters = _mockFactory.GetType().GetMethod("Create", EmptyArgumentList());
|
||||
|
||||
return createMethodWithNoParameters.MakeGenericMethod(new[] { type });
|
||||
}
|
||||
|
||||
private static Type[] EmptyArgumentList()
|
||||
{
|
||||
return new[] { typeof(object[]) };
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Microsoft.Practices.Unity.ObjectBuilder;
|
||||
|
||||
namespace AutoMoq.Unity
|
||||
{
|
||||
internal class AutoMockingContainerExtension : UnityContainerExtension
|
||||
{
|
||||
private readonly IList<Type> registeredTypes = new List<Type>();
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
SetEventsOnContainerToTrackAllRegisteredTypes();
|
||||
SetBuildingStrategyForBuildingUnregisteredTypes();
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private void SetEventsOnContainerToTrackAllRegisteredTypes()
|
||||
{
|
||||
Context.Registering += ((sender, e) => RegisterType(e.TypeFrom));
|
||||
Context.RegisteringInstance += ((sender, e) => RegisterType(e.RegisteredType));
|
||||
}
|
||||
|
||||
private void RegisterType(Type typeToRegister)
|
||||
{
|
||||
registeredTypes.Add(typeToRegister);
|
||||
}
|
||||
|
||||
private void SetBuildingStrategyForBuildingUnregisteredTypes()
|
||||
{
|
||||
var strategy = new AutoMockingBuilderStrategy(registeredTypes, Container);
|
||||
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
38
NzbDrone.App.Test/IISProviderTest.cs
Normal file
38
NzbDrone.App.Test/IISProviderTest.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AutoMoq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Providers;
|
||||
|
||||
namespace NzbDrone.App.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class IISProviderTest
|
||||
{
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void start_should_set_IISProccessId_property()
|
||||
{
|
||||
var mocker = new AutoMoqer();
|
||||
|
||||
var configMock = mocker.GetMock<ConfigProvider>();
|
||||
configMock.SetupGet(c => c.IISExePath).Returns("NzbDrone.Test.Dummy.exe");
|
||||
|
||||
mocker.Resolve<ProcessProvider>();
|
||||
|
||||
var iisProvider = mocker.Resolve<IISProvider>();
|
||||
|
||||
iisProvider.StartServer();
|
||||
|
||||
iisProvider.IISProcessId.Should().NotBe(0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -31,9 +31,21 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FizzWare.NBuilder">
|
||||
<HintPath>..\packages\NBuilder.3.0.1\lib\FizzWare.NBuilder.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FluentAssertions">
|
||||
<HintPath>..\packages\FluentAssertions.1.5.0.0\Lib\.NetFramework 4.0\FluentAssertions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.ServiceLocation">
|
||||
<HintPath>..\packages\CommonServiceLocator.1.0\lib\NET35\Microsoft.Practices.ServiceLocation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.Unity">
|
||||
<HintPath>..\packages\Unity.2.1.505.0\lib\NET35\Microsoft.Practices.Unity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.Unity.Configuration">
|
||||
<HintPath>..\packages\Unity.2.1.505.0\lib\NET35\Microsoft.Practices.Unity.Configuration.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq">
|
||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
@ -56,6 +68,13 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutoMoq\AutoMoqer.cs" />
|
||||
<Compile Include="AutoMoq\AutoMoqerTest.cs" />
|
||||
<Compile Include="AutoMoq\Unity\AutoMockingBuilderStrategy.cs" />
|
||||
<Compile Include="AutoMoq\Unity\AutoMockingContainerExtension.cs" />
|
||||
<Compile Include="ApplicationTest.cs" />
|
||||
<Compile Include="IISProviderTest.cs" />
|
||||
<Compile Include="ProcessProviderTests.cs" />
|
||||
<Compile Include="EnviromentControllerTest.cs" />
|
||||
<Compile Include="ServiceControllerTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@ -64,11 +83,18 @@
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NzbDrone.Test.Dummy\NzbDrone.Test.Dummy.csproj">
|
||||
<Project>{FAFB5948-A222-4CF6-AD14-026BE7564802}</Project>
|
||||
<Name>NzbDrone.Test.Dummy</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone\NzbDrone.csproj">
|
||||
<Project>{D12F7F2F-8A3C-415F-88FA-6DD061A84869}</Project>
|
||||
<Name>NzbDrone</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="AutoMoq\License.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
53
NzbDrone.App.Test/ProcessProviderTests.cs
Normal file
53
NzbDrone.App.Test/ProcessProviderTests.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Providers;
|
||||
|
||||
namespace NzbDrone.App.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class ProcessProviderTests
|
||||
{
|
||||
ProcessProvider _processProvider;
|
||||
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_processProvider = new ProcessProvider();
|
||||
}
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(123332324)]
|
||||
public void Kill_should_not_fail_on_invalid_process_is(int processId)
|
||||
{
|
||||
_processProvider.Kill(processId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetById_should_return_null_if_process_doesnt_exist()
|
||||
{
|
||||
_processProvider.GetProcessById(1234567).Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Should_be_able_to_kill_procces()
|
||||
{
|
||||
var dummyProcess = StartDummyProcess();
|
||||
_processProvider.Kill(dummyProcess.Id);
|
||||
dummyProcess.HasExited.Should().BeTrue();
|
||||
}
|
||||
|
||||
|
||||
public Process StartDummyProcess()
|
||||
{
|
||||
return Process.Start("NzbDrone.Test.Dummy.exe");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonServiceLocator" version="1.0" />
|
||||
<package id="FluentAssertions" version="1.5.0.0" />
|
||||
<package id="Moq" version="4.0.10827" />
|
||||
<package id="NBuilder" version="3.0.1" />
|
||||
<package id="NUnit" version="2.5.10.11092" />
|
||||
<package id="Unity" version="2.1.505.0" />
|
||||
</packages>
|
57
NzbDrone.Test.Dummy/NzbDrone.Test.Dummy.csproj
Normal file
57
NzbDrone.Test.Dummy/NzbDrone.Test.Dummy.csproj
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{FAFB5948-A222-4CF6-AD14-026BE7564802}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NzbDrone.Test.Dummy</RootNamespace>
|
||||
<AssemblyName>NzbDrone.Test.Dummy</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
17
NzbDrone.Test.Dummy/Program.cs
Normal file
17
NzbDrone.Test.Dummy/Program.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Test.Dummy
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Dummy process. ID:{0} Path:{1}", Process.GetCurrentProcess().Id, Process.GetCurrentProcess().MainModule.FileName);
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
}
|
36
NzbDrone.Test.Dummy/Properties/AssemblyInfo.cs
Normal file
36
NzbDrone.Test.Dummy/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("NzbDrone.Test.Dummy")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("NzbDrone.Test.Dummy")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("7b773a86-574d-48c3-9e89-6f2e0dff714b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
15
NzbDrone.sln
15
NzbDrone.sln
@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{57A04B72
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.App.Test", "NzbDrone.App.Test\NzbDrone.App.Test.csproj", "{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Test.Dummy", "NzbDrone.Test.Dummy\NzbDrone.Test.Dummy.csproj", "{FAFB5948-A222-4CF6-AD14-026BE7564802}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -91,6 +93,18 @@ Global
|
||||
{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x64.ActiveCfg = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.Build.0 = Debug|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x64.ActiveCfg = Release|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.ActiveCfg = Release|x86
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -98,6 +112,7 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{193ADD3B-792B-4173-8E4C-5A3F8F0237F0} = {57A04B72-8088-4F75-A582-1158CF8291F7}
|
||||
{C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5} = {57A04B72-8088-4F75-A582-1158CF8291F7}
|
||||
{FAFB5948-A222-4CF6-AD14-026BE7564802} = {57A04B72-8088-4F75-A582-1158CF8291F7}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35
|
||||
|
@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using NLog;
|
||||
using NzbDrone.Providers;
|
||||
|
||||
namespace NzbDrone
|
||||
{
|
||||
internal class Application
|
||||
public class Application
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetLogger("Application");
|
||||
|
||||
@ -36,22 +34,14 @@ public Application(ConfigProvider configProvider, WebClient webClient, IISProvid
|
||||
Logger.Info("Starting NZBDrone. Start-up Path:'{0}'", _configProvider.ApplicationRoot);
|
||||
Thread.CurrentThread.Name = "Host";
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += ((s, e) => AppDomainException(e));
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += ProgramExited;
|
||||
AppDomain.CurrentDomain.DomainUnload += ProgramExited;
|
||||
}
|
||||
|
||||
internal void Start()
|
||||
public void Start()
|
||||
{
|
||||
_iisProvider.StopServer();
|
||||
_iisProvider.StartServer();
|
||||
|
||||
_debuggerProvider.Attach();
|
||||
|
||||
var prioCheckTimer = new System.Timers.Timer(5000);
|
||||
prioCheckTimer.Elapsed += EnsurePriority;
|
||||
prioCheckTimer.Enabled = true;
|
||||
_debuggerProvider.Attach();
|
||||
|
||||
if (_enviromentProvider.IsUserInteractive && _configProvider.LaunchBrowser)
|
||||
{
|
||||
@ -79,51 +69,10 @@ internal void Start()
|
||||
}
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void AppDomainException(object excepion)
|
||||
{
|
||||
Console.WriteLine("EPIC FAIL: {0}", excepion);
|
||||
Logger.Fatal("EPIC FAIL: {0}", excepion);
|
||||
|
||||
#if RELEASE
|
||||
new Client
|
||||
{
|
||||
ApiKey = "43BBF60A-EB2A-4C1C-B09E-422ADF637265",
|
||||
ApplicationName = "NZBDrone",
|
||||
CurrentException = excepion as Exception
|
||||
}.Submit();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
internal void EnsurePriority(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
var currentProcessId = _processProvider.GetCurrentProcessId();
|
||||
if (_processProvider.GetProcessPriority(currentProcessId) != ProcessPriorityClass.Normal)
|
||||
{
|
||||
_processProvider.SetPriority(_processProvider.GetCurrentProcessId(), ProcessPriorityClass.Normal);
|
||||
}
|
||||
|
||||
var iisProcessPriority = _processProvider.GetProcessPriority(_iisProvider.IISProcessId);
|
||||
if (iisProcessPriority != ProcessPriorityClass.Normal && iisProcessPriority != ProcessPriorityClass.AboveNormal)
|
||||
{
|
||||
_processProvider.SetPriority(_iisProvider.IISProcessId, ProcessPriorityClass.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProgramExited(object sender, EventArgs e)
|
||||
{
|
||||
_iisProvider.StopServer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Application.cs" />
|
||||
<Compile Include="ProcessInfo.cs" />
|
||||
<Compile Include="Providers\ConsoleProvider.cs" />
|
||||
<Compile Include="Providers\DebuggerProvider.cs" />
|
||||
<Compile Include="Providers\EnviromentProvider.cs" />
|
||||
@ -97,6 +98,7 @@
|
||||
<Compile Include="Providers\IISProvider.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Providers\MonitoringProvider.cs" />
|
||||
<Compile Include="Providers\ProcessProvider.cs" />
|
||||
<Compile Include="Providers\ServiceProvider.cs" />
|
||||
<Compile Include="Providers\WebClientProvider.cs" />
|
||||
|
@ -10,17 +10,12 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using EnvDTE;
|
||||
using EnvDTE80;
|
||||
using NLog;
|
||||
using Thread = System.Threading.Thread;
|
||||
|
||||
namespace NzbDrone
|
||||
{
|
||||
public class ProcessAttacher
|
||||
{
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetLogger("Application");
|
||||
|
||||
|
||||
public static void Attach()
|
||||
{
|
||||
DTE2 dte2;
|
||||
|
18
NzbDrone/ProcessInfo.cs
Normal file
18
NzbDrone/ProcessInfo.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone
|
||||
{
|
||||
public class ProcessInfo
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public ProcessPriorityClass Priority { get; set; }
|
||||
public string StartPath { get; set; }
|
||||
|
||||
public bool HasExited { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using NLog;
|
||||
using Ninject;
|
||||
using NzbDrone.Providers;
|
||||
|
||||
namespace NzbDrone
|
||||
{
|
||||
internal static class Program
|
||||
public static class Program
|
||||
{
|
||||
public static readonly StandardKernel Kernel = new StandardKernel();
|
||||
|
||||
@ -14,8 +15,20 @@ private static void Main()
|
||||
{
|
||||
try
|
||||
{
|
||||
Kernel.Bind<ConfigProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<ConsoleProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<DebuggerProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<EnviromentProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<IISProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<MonitoringProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<ProcessProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<ServiceProvider>().ToSelf().InSingletonScope();
|
||||
Kernel.Bind<WebClientProvider>().ToSelf().InSingletonScope();
|
||||
|
||||
Console.WriteLine("Starting Console.");
|
||||
Kernel.Get<MonitoringProvider>().Start();
|
||||
Kernel.Get<Application>().Start();
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -36,4 +36,4 @@
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyVersion("0.5.0.*")]
|
||||
[assembly: AssemblyVersion("0.5.0.*")]
|
||||
|
@ -3,15 +3,17 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
internal class ConfigProvider
|
||||
public class ConfigProvider
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetLogger("ConfigProvider");
|
||||
|
||||
internal virtual string ApplicationRoot
|
||||
public virtual string ApplicationRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -27,38 +29,74 @@ internal virtual string ApplicationRoot
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual int Port
|
||||
public virtual int Port
|
||||
{
|
||||
get { return GetValueInt("Port"); }
|
||||
}
|
||||
|
||||
internal virtual bool LaunchBrowser
|
||||
public virtual bool LaunchBrowser
|
||||
{
|
||||
get { return GetValueBoolean("LaunchBrowser"); }
|
||||
}
|
||||
|
||||
internal virtual string AppDataDirectory
|
||||
public virtual string AppDataDirectory
|
||||
{
|
||||
get { return Path.Combine(ApplicationRoot, "NzbDrone.Web", "App_Data"); }
|
||||
}
|
||||
|
||||
internal virtual string ConfigFile
|
||||
public virtual string ConfigFile
|
||||
{
|
||||
get { return Path.Combine(AppDataDirectory, "Config.xml"); }
|
||||
}
|
||||
|
||||
internal virtual string IISFolder
|
||||
public virtual string IISFolder
|
||||
{
|
||||
get { return Path.Combine(ApplicationRoot, @"IISExpress\"); }
|
||||
}
|
||||
|
||||
internal virtual void ConfigureNlog()
|
||||
public virtual string IISExePath
|
||||
{
|
||||
get { return IISFolder + @"iisexpress.exe"; }
|
||||
}
|
||||
|
||||
public virtual string IISConfigPath
|
||||
{
|
||||
get { return Path.Combine(IISFolder, "AppServer", "applicationhost.config"); }
|
||||
}
|
||||
|
||||
public virtual void ConfigureNlog()
|
||||
{
|
||||
LogManager.Configuration = new XmlLoggingConfiguration(
|
||||
Path.Combine(ApplicationRoot, "NzbDrone.Web\\log.config"), false);
|
||||
}
|
||||
|
||||
internal virtual void CreateDefaultConfigFile()
|
||||
public virtual void UpdateIISConfig(string configPath)
|
||||
{
|
||||
Logger.Info(@"Server configuration file: {0}", configPath);
|
||||
Logger.Info(@"Configuring server to: [http://localhost:{0}]", Port);
|
||||
|
||||
var configXml = XDocument.Load(configPath);
|
||||
|
||||
var bindings =
|
||||
configXml.XPathSelectElement("configuration/system.applicationHost/sites").Elements("site").Where(
|
||||
d => d.Attribute("name").Value.ToLowerInvariant() == "nzbdrone").First().Element("bindings");
|
||||
bindings.Descendants().Remove();
|
||||
bindings.Add(
|
||||
new XElement("binding",
|
||||
new XAttribute("protocol", "http"),
|
||||
new XAttribute("bindingInformation", String.Format("*:{0}:localhost", Port))
|
||||
));
|
||||
|
||||
bindings.Add(
|
||||
new XElement("binding",
|
||||
new XAttribute("protocol", "http"),
|
||||
new XAttribute("bindingInformation", String.Format("*:{0}:", Port))
|
||||
));
|
||||
|
||||
configXml.Save(configPath);
|
||||
}
|
||||
|
||||
public virtual void CreateDefaultConfigFile()
|
||||
{
|
||||
//Create the config file here
|
||||
Directory.CreateDirectory(AppDataDirectory);
|
||||
@ -69,7 +107,7 @@ internal virtual void CreateDefaultConfigFile()
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void WriteDefaultConfig()
|
||||
public virtual void WriteDefaultConfig()
|
||||
{
|
||||
var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
|
@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
internal class DebuggerProvider
|
||||
public class DebuggerProvider
|
||||
{
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetLogger("DebuggerProvider");
|
||||
|
||||
|
||||
internal virtual void Attach()
|
||||
public virtual void Attach()
|
||||
{
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached)
|
||||
|
@ -1,104 +1,79 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Timers;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using NLog;
|
||||
using Ninject;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
internal class IISProvider
|
||||
public class IISProvider
|
||||
{
|
||||
private readonly ConfigProvider _configProvider;
|
||||
private readonly ProcessProvider _processProvider;
|
||||
private static readonly Logger IISLogger = LogManager.GetLogger("IISExpress");
|
||||
private static readonly Logger Logger = LogManager.GetLogger("IISProvider");
|
||||
|
||||
private readonly string IISExe;
|
||||
private readonly string IISConfigPath;
|
||||
|
||||
private static Timer _pingTimer;
|
||||
private static int _pingFailCounter;
|
||||
|
||||
private static Process _iisProcess;
|
||||
|
||||
|
||||
public IISProvider(ConfigProvider configProvider)
|
||||
[Inject]
|
||||
public IISProvider(ConfigProvider configProvider, ProcessProvider processProvider)
|
||||
{
|
||||
_configProvider = configProvider;
|
||||
IISExe = Path.Combine(_configProvider.IISFolder, @"iisexpress.exe");
|
||||
IISConfigPath = Path.Combine(_configProvider.IISFolder, "AppServer", "applicationhost.config");
|
||||
_processProvider = processProvider;
|
||||
|
||||
}
|
||||
|
||||
internal string AppUrl
|
||||
public IISProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string AppUrl
|
||||
{
|
||||
get { return string.Format("http://localhost:{0}/", _configProvider.Port); }
|
||||
}
|
||||
|
||||
internal int IISProcessId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_iisProcess == null)
|
||||
{
|
||||
throw new InvalidOperationException("IIS Process isn't running yet.");
|
||||
}
|
||||
public int IISProcessId { get; private set; }
|
||||
|
||||
return _iisProcess.Id;
|
||||
}
|
||||
}
|
||||
public bool ServerStarted { get; private set; }
|
||||
|
||||
internal Process StartServer()
|
||||
public void StartServer()
|
||||
{
|
||||
Logger.Info("Preparing IISExpress Server...");
|
||||
_iisProcess = new Process();
|
||||
|
||||
_iisProcess.StartInfo.FileName = IISExe;
|
||||
_iisProcess.StartInfo.Arguments = String.Format("/config:\"{0}\" /trace:i", IISConfigPath);//"/config:"""" /trace:i";
|
||||
_iisProcess.StartInfo.WorkingDirectory = _configProvider.ApplicationRoot;
|
||||
var startInfo = new ProcessStartInfo();
|
||||
|
||||
_iisProcess.StartInfo.UseShellExecute = false;
|
||||
_iisProcess.StartInfo.RedirectStandardOutput = true;
|
||||
_iisProcess.StartInfo.RedirectStandardError = true;
|
||||
_iisProcess.StartInfo.CreateNoWindow = true;
|
||||
startInfo.FileName = _configProvider.IISExePath;
|
||||
startInfo.Arguments = String.Format("/config:\"{0}\" /trace:i", _configProvider.IISConfigPath);
|
||||
startInfo.WorkingDirectory = _configProvider.ApplicationRoot;
|
||||
|
||||
|
||||
_iisProcess.OutputDataReceived += (OnOutputDataReceived);
|
||||
_iisProcess.ErrorDataReceived += (OnErrorDataReceived);
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.RedirectStandardError = true;
|
||||
startInfo.CreateNoWindow = true;
|
||||
|
||||
//Set Variables for the config file.
|
||||
_iisProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PATH", _configProvider.ApplicationRoot);
|
||||
_iisProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PID", Process.GetCurrentProcess().Id.ToString());
|
||||
startInfo.EnvironmentVariables.Add("NZBDRONE_PATH", _configProvider.ApplicationRoot);
|
||||
startInfo.EnvironmentVariables.Add("NZBDRONE_PID", Process.GetCurrentProcess().Id.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
UpdateIISConfig();
|
||||
_configProvider.UpdateIISConfig(_configProvider.IISConfigPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("An error has occurred while trying to update the config file.", e);
|
||||
}
|
||||
|
||||
var iisProcess = _processProvider.Start(startInfo);
|
||||
IISProcessId = iisProcess.Id;
|
||||
|
||||
Logger.Info("Starting process. [{0}]", _iisProcess.StartInfo.FileName);
|
||||
iisProcess.OutputDataReceived += (OnOutputDataReceived);
|
||||
iisProcess.ErrorDataReceived += (OnErrorDataReceived);
|
||||
|
||||
iisProcess.BeginErrorReadLine();
|
||||
iisProcess.BeginOutputReadLine();
|
||||
|
||||
|
||||
_iisProcess.Start();
|
||||
_iisProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
|
||||
|
||||
_iisProcess.BeginErrorReadLine();
|
||||
_iisProcess.BeginOutputReadLine();
|
||||
|
||||
//Start Ping
|
||||
_pingTimer = new Timer(300000) { AutoReset = true };
|
||||
_pingTimer.Elapsed += (PingServer);
|
||||
_pingTimer.Start();
|
||||
|
||||
return _iisProcess;
|
||||
ServerStarted = true;
|
||||
}
|
||||
|
||||
private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
@ -109,19 +84,18 @@ private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
IISLogger.Error(e.Data);
|
||||
}
|
||||
|
||||
internal void StopServer()
|
||||
public void StopServer()
|
||||
{
|
||||
KillProcess(_iisProcess);
|
||||
_processProvider.Kill(IISProcessId);
|
||||
|
||||
Logger.Info("Finding orphaned IIS Processes.");
|
||||
foreach (var process in Process.GetProcessesByName("IISExpress"))
|
||||
foreach (var process in _processProvider.GetProcessByName("IISExpress"))
|
||||
{
|
||||
string processPath = process.MainModule.FileName;
|
||||
Logger.Info("[{0}]IIS Process found. Path:{1}", process.Id, processPath);
|
||||
if (NormalizePath(processPath) == NormalizePath(IISExe))
|
||||
Logger.Info("[{0}]IIS Process found. Path:{1}", process.Id, process.StartPath);
|
||||
if (NormalizePath(process.StartPath) == NormalizePath(_configProvider.IISExePath))
|
||||
{
|
||||
Logger.Info("[{0}]Process is considered orphaned.", process.Id);
|
||||
KillProcess(process);
|
||||
_processProvider.Kill(process.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -130,41 +104,14 @@ internal void StopServer()
|
||||
}
|
||||
}
|
||||
|
||||
private void RestartServer()
|
||||
public void RestartServer()
|
||||
{
|
||||
_pingTimer.Stop();
|
||||
ServerStarted = false;
|
||||
Logger.Warn("Attempting to restart server.");
|
||||
StopServer();
|
||||
StartServer();
|
||||
}
|
||||
|
||||
private void PingServer(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = new WebClient().DownloadString(AppUrl + "/health");
|
||||
|
||||
if (!response.Contains("OK"))
|
||||
{
|
||||
throw new ServerException("Health services responded with an invalid response.");
|
||||
}
|
||||
if (_pingFailCounter > 0)
|
||||
{
|
||||
Logger.Info("Application pool has been successfully recovered.");
|
||||
}
|
||||
_pingFailCounter = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_pingFailCounter++;
|
||||
Logger.ErrorException("Application pool is not responding. Count " + _pingFailCounter, ex);
|
||||
if (_pingFailCounter > 2)
|
||||
{
|
||||
RestartServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOutputDataReceived(object s, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e == null || String.IsNullOrWhiteSpace(e.Data) || e.Data.StartsWith("Request started:") ||
|
||||
@ -180,47 +127,7 @@ private void OnOutputDataReceived(object s, DataReceivedEventArgs e)
|
||||
IISLogger.Trace(e.Data);
|
||||
}
|
||||
|
||||
private void UpdateIISConfig()
|
||||
{
|
||||
string configPath = Path.Combine(_configProvider.IISFolder, @"AppServer\applicationhost.config");
|
||||
|
||||
Logger.Info(@"Server configuration file: {0}", configPath);
|
||||
Logger.Info(@"Configuring server to: [http://localhost:{0}]", _configProvider.Port);
|
||||
|
||||
var configXml = XDocument.Load(configPath);
|
||||
|
||||
var bindings =
|
||||
configXml.XPathSelectElement("configuration/system.applicationHost/sites").Elements("site").Where(
|
||||
d => d.Attribute("name").Value.ToLowerInvariant() == "nzbdrone").First().Element("bindings");
|
||||
bindings.Descendants().Remove();
|
||||
bindings.Add(
|
||||
new XElement("binding",
|
||||
new XAttribute("protocol", "http"),
|
||||
new XAttribute("bindingInformation", String.Format("*:{0}:localhost", _configProvider.Port))
|
||||
));
|
||||
|
||||
bindings.Add(
|
||||
new XElement("binding",
|
||||
new XAttribute("protocol", "http"),
|
||||
new XAttribute("bindingInformation", String.Format("*:{0}:", _configProvider.Port))
|
||||
));
|
||||
|
||||
configXml.Save(configPath);
|
||||
}
|
||||
|
||||
private void KillProcess(Process process)
|
||||
{
|
||||
if (process != null && !process.HasExited)
|
||||
{
|
||||
Logger.Info("[{0}]Killing process", process.Id);
|
||||
process.Kill();
|
||||
Logger.Info("[{0}]Waiting for exit", process.Id);
|
||||
process.WaitForExit();
|
||||
Logger.Info("[{0}]Process terminated successfully", process.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public string NormalizePath(string path)
|
||||
private string NormalizePath(string path)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(path))
|
||||
throw new ArgumentException("Path can not be null or empty");
|
||||
|
115
NzbDrone/Providers/MonitoringProvider.cs
Normal file
115
NzbDrone/Providers/MonitoringProvider.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Timers;
|
||||
using NLog;
|
||||
using Ninject;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
public class MonitoringProvider
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetLogger("MonitoringProvider");
|
||||
|
||||
private readonly IISProvider _iisProvider;
|
||||
private readonly ProcessProvider _processProvider;
|
||||
|
||||
private int _pingFailCounter;
|
||||
private Timer _pingTimer;
|
||||
|
||||
[Inject]
|
||||
public MonitoringProvider(ProcessProvider processProvider, IISProvider iisProvider)
|
||||
{
|
||||
_processProvider = processProvider;
|
||||
_iisProvider = iisProvider;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += ((s, e) => AppDomainException(e));
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += ProgramExited;
|
||||
AppDomain.CurrentDomain.DomainUnload += ProgramExited;
|
||||
|
||||
var prioCheckTimer = new Timer(5000);
|
||||
prioCheckTimer.Elapsed += EnsurePriority;
|
||||
prioCheckTimer.Enabled = true;
|
||||
|
||||
_pingTimer = new Timer(60000) { AutoReset = true };
|
||||
_pingTimer.Elapsed += (PingServer);
|
||||
_pingTimer.Start();
|
||||
}
|
||||
|
||||
public MonitoringProvider()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public virtual void EnsurePriority(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
var currentProcess = _processProvider.GetCurrentProcess();
|
||||
if (currentProcess.Priority != ProcessPriorityClass.Normal)
|
||||
{
|
||||
_processProvider.SetPriority(currentProcess.Id, ProcessPriorityClass.Normal);
|
||||
}
|
||||
|
||||
var iisProcess = _processProvider.GetProcessById(_iisProvider.IISProcessId);
|
||||
if (iisProcess != null && iisProcess.Priority != ProcessPriorityClass.Normal &&
|
||||
iisProcess.Priority != ProcessPriorityClass.AboveNormal)
|
||||
{
|
||||
_processProvider.SetPriority(iisProcess.Id, ProcessPriorityClass.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void PingServer(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (!_iisProvider.ServerStarted) return;
|
||||
|
||||
try
|
||||
{
|
||||
string response = new WebClient().DownloadString(_iisProvider.AppUrl + "/health");
|
||||
|
||||
if (!response.Contains("OK"))
|
||||
{
|
||||
throw new ServerException("Health services responded with an invalid response.");
|
||||
}
|
||||
if (_pingFailCounter > 0)
|
||||
{
|
||||
Logger.Info("Application pool has been successfully recovered.");
|
||||
}
|
||||
_pingFailCounter = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_pingFailCounter++;
|
||||
Logger.ErrorException("Application pool is not responding. Count " + _pingFailCounter, ex);
|
||||
if (_pingFailCounter > 2)
|
||||
{
|
||||
_iisProvider.RestartServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProgramExited(object sender, EventArgs e)
|
||||
{
|
||||
_iisProvider.StopServer();
|
||||
}
|
||||
|
||||
|
||||
private static void AppDomainException(object excepion)
|
||||
{
|
||||
Console.WriteLine("EPIC FAIL: {0}", excepion);
|
||||
Logger.Fatal("EPIC FAIL: {0}", excepion);
|
||||
|
||||
#if RELEASE
|
||||
new Client
|
||||
{
|
||||
ApiKey = "43BBF60A-EB2A-4C1C-B09E-422ADF637265",
|
||||
ApplicationName = "NZBDrone",
|
||||
CurrentException = excepion as Exception
|
||||
}.Submit();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
@ -12,31 +10,77 @@ public class ProcessProvider
|
||||
private static readonly Logger Logger = LogManager.GetLogger("ProcessProvider");
|
||||
|
||||
|
||||
public virtual ProcessInfo GetCurrentProcess()
|
||||
{
|
||||
return ConvertToProcessInfo(Process.GetCurrentProcess());
|
||||
}
|
||||
|
||||
public virtual ProcessInfo GetProcessById(int id)
|
||||
{
|
||||
return ConvertToProcessInfo(Process.GetProcesses().Where(p => p.Id == id).FirstOrDefault());
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ProcessInfo> GetProcessByName(string name)
|
||||
{
|
||||
return Process.GetProcessesByName(name).Select(ConvertToProcessInfo);
|
||||
}
|
||||
|
||||
public virtual void Start(string path)
|
||||
{
|
||||
Process.Start(path);
|
||||
}
|
||||
|
||||
public virtual Process Start(ProcessStartInfo startInfo)
|
||||
{
|
||||
Logger.Info("Starting process. [{0}]", startInfo.FileName);
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = startInfo
|
||||
};
|
||||
process.Start();
|
||||
return process;
|
||||
}
|
||||
|
||||
public virtual void Kill(int processId)
|
||||
{
|
||||
if (processId == 0) return;
|
||||
if (!Process.GetProcesses().Any(p => p.Id == processId)) return;
|
||||
|
||||
var process = Process.GetProcessById(processId);
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
Logger.Info("[{0}]Killing process", process.Id);
|
||||
process.Kill();
|
||||
Logger.Info("[{0}]Waiting for exit", process.Id);
|
||||
process.WaitForExit();
|
||||
Logger.Info("[{0}]Process terminated successfully", process.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetPriority(int processId, ProcessPriorityClass priority)
|
||||
{
|
||||
var process = Process.GetProcessById(processId);
|
||||
|
||||
Logger.Info("Updating [{0}] process priority from {1} to {2}",
|
||||
process.ProcessName,
|
||||
process.PriorityClass,
|
||||
priority);
|
||||
process.ProcessName,
|
||||
process.PriorityClass,
|
||||
priority);
|
||||
|
||||
process.PriorityClass = priority;
|
||||
}
|
||||
|
||||
public virtual ProcessPriorityClass GetProcessPriority(int processId)
|
||||
private static ProcessInfo ConvertToProcessInfo(Process process)
|
||||
{
|
||||
return Process.GetProcessById(processId).PriorityClass;
|
||||
}
|
||||
if (process == null) return null;
|
||||
|
||||
public virtual int GetCurrentProcessId()
|
||||
{
|
||||
return Process.GetCurrentProcess().Id;
|
||||
}
|
||||
|
||||
public virtual Process Start(string path)
|
||||
{
|
||||
return Process.Start(path);
|
||||
return new ProcessInfo
|
||||
{
|
||||
Id = process.Id,
|
||||
Priority = process.PriorityClass,
|
||||
StartPath = process.MainModule.FileName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace NzbDrone.Providers
|
||||
{
|
||||
internal class WebClientProvider
|
||||
public class WebClientProvider
|
||||
{
|
||||
|
||||
public virtual string DownloadString(string url)
|
||||
|
BIN
packages/NBuilder.3.0.1/NBuilder.3.0.1.nupkg
vendored
Normal file
BIN
packages/NBuilder.3.0.1/NBuilder.3.0.1.nupkg
vendored
Normal file
Binary file not shown.
BIN
packages/NBuilder.3.0.1/lib/FizzWare.NBuilder.dll
vendored
Normal file
BIN
packages/NBuilder.3.0.1/lib/FizzWare.NBuilder.dll
vendored
Normal file
Binary file not shown.
BIN
packages/NBuilder.3.0.1/lib/Silverlight 3.0/FizzWare.NBuilder-Silverlight.dll
vendored
Normal file
BIN
packages/NBuilder.3.0.1/lib/Silverlight 3.0/FizzWare.NBuilder-Silverlight.dll
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user