diff --git a/.gitignore b/.gitignore
index 1a2e20de58..86bdc17724 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,13 @@
nugets
+deploy
build32
binaries
-obj
-bin
*.vshost.*
.nu
-_ReSharper.*
_UpgradeReport.*
-*.csproj.user
-*.resharper.user
-*.resharper
-*.suo
*.cache
*~
*.swp
-*.user
-TestResults
-TestResult.xml
results
CommonAssemblyInfo.cs
lib/sqlite/System.Data.SQLite.dll
@@ -35,3 +26,47 @@ _NCrunch_NServiceBus/*
logs
run-git.cmd
src/Chocolatey/Build/*
+
+# Created by https://www.gitignore.io
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Roslyn cache directories
+*.ide/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
diff --git a/installer/ServiceControl.aip b/installer/ServiceControl.aip
index d6a8bc28b6..b373c811df 100644
--- a/installer/ServiceControl.aip
+++ b/installer/ServiceControl.aip
@@ -19,10 +19,13 @@
+
+
+
@@ -52,147 +55,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -243,6 +118,9 @@
+
+
+
@@ -278,20 +156,22 @@
-
+
-
+
-
-
+
+
-
+
-
+
+
+
@@ -384,6 +264,12 @@
+
+
+
+
+
+
@@ -395,20 +281,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -420,6 +296,8 @@
+
+
@@ -443,14 +321,20 @@
+
+
+
+
-
+
+
-
+
+
@@ -466,13 +350,13 @@
-
+
-
+
-
+
@@ -485,6 +369,12 @@
+
+
+
+
+
+
diff --git a/src/Chocolatey/chocolateyInstall.ps1 b/src/Chocolatey/chocolateyInstall.ps1
index 4a1502f876..249b7acb57 100644
--- a/src/Chocolatey/chocolateyInstall.ps1
+++ b/src/Chocolatey/chocolateyInstall.ps1
@@ -10,7 +10,6 @@ else{
$url = "https://github.com/Particular/$packageName/releases/download/{{ReleaseName}}/Particular.$packageName-{{FileVersion}}.exe"
}
-
try {
$existngService = Get-Service -Name "Particular.Management" -ErrorAction SilentlyContinue
@@ -29,7 +28,7 @@ try {
}
Get-ChocolateyWebFile $packageName $file $url
- $msiArguments ="/quiet /L*V `"$logFile`""
+ $msiArguments ="/quiet PlatformInstaller=true /L*V `"$logFile`""
Write-Host "Starting installer with arguments: $msiArguments";
Start-ChocolateyProcessAsAdmin "$msiArguments" $file -validExitCodes 0
Write-ChocolateySuccess $packageName
diff --git a/src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSytemMessage_Tests.cs b/src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSystemMessage_Tests.cs
similarity index 97%
rename from src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSytemMessage_Tests.cs
rename to src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSystemMessage_Tests.cs
index 948e5781e3..6663f85199 100644
--- a/src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSytemMessage_Tests.cs
+++ b/src/ServiceControl.AcceptanceTests/Audit/Audit_Messages_Have_Proper_IsSystemMessage_Tests.cs
@@ -4,13 +4,11 @@
using Contexts;
using NServiceBus;
using NServiceBus.AcceptanceTesting;
- using NServiceBus.Features;
using NServiceBus.Transports;
using NUnit.Framework;
using ServiceControl.CompositeViews.Messages;
- using ServiceControl.MessageFailures.Api;
- class Audit_Messages_Have_Proper_IsSytemMessage_Tests: AcceptanceTest
+ class Audit_Messages_Have_Proper_IsSystemMessage_Tests: AcceptanceTest
{
[Test]
public void Should_set_the_IsSystemMessage_when_message_type_is_not_a_scheduled_task()
diff --git a/src/ServiceControl.AcceptanceTests/ExternalIntegrations/When_a_message_has_custom_checks.cs b/src/ServiceControl.AcceptanceTests/ExternalIntegrations/When_a_message_has_custom_checks.cs
new file mode 100644
index 0000000000..6c002f08a2
--- /dev/null
+++ b/src/ServiceControl.AcceptanceTests/ExternalIntegrations/When_a_message_has_custom_checks.cs
@@ -0,0 +1,150 @@
+namespace ServiceBus.Management.AcceptanceTests.ExternalIntegrations
+{
+ using System;
+ using Contexts;
+ using NServiceBus;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.Config;
+ using NServiceBus.Config.ConfigurationSource;
+ using NServiceBus.Features;
+ using NServiceBus.Unicast.Subscriptions;
+ using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions;
+ using NUnit.Framework;
+ using ServiceControl.Contracts;
+ using ServiceControl.Contracts.Operations;
+
+ [TestFixture]
+ public class When_a_message_has_custom_checks : AcceptanceTest
+ {
+ [Test]
+ public void Notification_should_be_published_on_the_bus()
+ {
+ var context = new MyContext();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given((bus, c) => Subscriptions.OnEndpointSubscribed(s =>
+ {
+ if (s.SubscriberReturnAddress.Queue.Contains("ExternalProcessor"))
+ {
+ c.ExternalProcessorSubscribed = true;
+ }
+ }, () => c.ExternalProcessorSubscribed = true))
+ .When(c => c.ExternalProcessorSubscribed, bus =>
+ {
+ bus.Publish(new ServiceControl.Contracts.CustomChecks.CustomCheckSucceeded
+ {
+ Category = "Testing",
+ CustomCheckId = "Success custom check",
+ OriginatingEndpoint = new EndpointDetails
+ {
+ Host = "MyHost",
+ HostId = Guid.Empty,
+ Name = "Testing"
+ },
+ SucceededAt = DateTime.Now,
+ });
+ bus.Publish(new ServiceControl.Contracts.CustomChecks.CustomCheckFailed
+ {
+ Category = "Testing",
+ CustomCheckId = "Fail custom check",
+ OriginatingEndpoint = new EndpointDetails
+ {
+ Host = "MyHost",
+ HostId = Guid.Empty,
+ Name = "Testing"
+ },
+ FailedAt = DateTime.Now,
+ FailureReason = "Because I can",
+ });
+ }).AppConfig(PathToAppConfig))
+ .WithEndpoint(b => b.Given((bus, c) =>
+ {
+ bus.Subscribe();
+ bus.Subscribe();
+ }))
+ .Done(c => c.CustomCheckFailedReceived && c.CustomCheckFailedReceived)
+ .Run();
+
+ Assert.IsTrue(context.CustomCheckFailedReceived);
+ Assert.IsTrue(context.CustomCheckSucceededReceived);
+ }
+
+ [Serializable]
+ public class Subscriptions
+ {
+ public static Action, Action> OnEndpointSubscribed = (actionToPerformIfMessageDrivenSubscriptions, actionToPerformIfMessageDrivenSubscriptionsNotRequired) =>
+ {
+ if (Feature.IsEnabled())
+ {
+ Configure.Instance.Builder.Build().ClientSubscribed +=
+ (sender, args) =>
+ {
+ actionToPerformIfMessageDrivenSubscriptions(args);
+ };
+
+ return;
+ }
+
+ actionToPerformIfMessageDrivenSubscriptionsNotRequired();
+ };
+ }
+
+ public class ExternalIntegrationsManagementEndpoint : EndpointConfigurationBuilder
+ {
+ public ExternalIntegrationsManagementEndpoint()
+ {
+ EndpointSetup();
+ }
+ }
+
+ public class ExternalProcessor : EndpointConfigurationBuilder
+ {
+ public ExternalProcessor()
+ {
+ EndpointSetup();
+ }
+
+ public class CustomCheckSucceededHandler : IHandleMessages
+ {
+ public MyContext Context { get; set; }
+
+ public void Handle(CustomCheckSucceeded message)
+ {
+ Context.CustomCheckSucceededReceived = true;
+ }
+ }
+
+ public class CustomCheckFailedHandler : IHandleMessages
+ {
+ public MyContext Context { get; set; }
+
+ public void Handle(CustomCheckFailed message)
+ {
+ Context.CustomCheckFailedReceived = true;
+ }
+ }
+
+ public class UnicastOverride : IProvideConfiguration
+ {
+ public UnicastBusConfig GetConfiguration()
+ {
+ var config = new UnicastBusConfig();
+ var serviceControlMapping = new MessageEndpointMapping
+ {
+ Messages = "ServiceControl.Contracts",
+ Endpoint = "Particular.ServiceControl"
+ };
+ config.MessageEndpointMappings.Add(serviceControlMapping);
+ return config;
+ }
+ }
+ }
+
+ public class MyContext : ScenarioContext
+ {
+ public bool CustomCheckSucceededReceived { get; set; }
+ public bool CustomCheckFailedReceived { get; set; }
+ public bool ExternalProcessorSubscribed { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ServiceControl.AcceptanceTests/ServiceControl.AcceptanceTests.csproj b/src/ServiceControl.AcceptanceTests/ServiceControl.AcceptanceTests.csproj
index 5c218c0aa3..60b7e852fe 100644
--- a/src/ServiceControl.AcceptanceTests/ServiceControl.AcceptanceTests.csproj
+++ b/src/ServiceControl.AcceptanceTests/ServiceControl.AcceptanceTests.csproj
@@ -114,7 +114,7 @@
False
- ..\packages\ServiceControl.Contracts.1.0.0\lib\net45\ServiceControl.Contracts.dll
+ ..\packages\ServiceControl.Contracts.1.1.0\lib\net45\ServiceControl.Contracts.dll
False
@@ -167,7 +167,7 @@
-
+
@@ -180,7 +180,8 @@
-
+
+
diff --git a/src/ServiceControl.AcceptanceTests/packages.config b/src/ServiceControl.AcceptanceTests/packages.config
index 20e9bb9490..f6614b1ca0 100644
--- a/src/ServiceControl.AcceptanceTests/packages.config
+++ b/src/ServiceControl.AcceptanceTests/packages.config
@@ -18,7 +18,7 @@
-
+
diff --git a/src/ServiceControl.Install.CustomActions/CustomAction.cs b/src/ServiceControl.Install.CustomActions/CustomAction.cs
index d555b4f252..b162b9f295 100644
--- a/src/ServiceControl.Install.CustomActions/CustomAction.cs
+++ b/src/ServiceControl.Install.CustomActions/CustomAction.cs
@@ -1,47 +1,115 @@
namespace ServiceControl.Install.CustomActions
{
using System;
+ using System.IO;
+ using System.Linq;
+ using System.Xml.Linq;
+ using System.Xml.XPath;
using Microsoft.Deployment.WindowsInstaller;
+ using Microsoft.Win32;
public class CustomActions
{
///
/// This custom action will test if a port number is in the range 0 to 49152. Sets VALID_PORT to TRUE/FALSE
///
- [CustomAction()]
+ [CustomAction]
public static ActionResult CheckValidPort(Session session)
+ {
+ if (!session.CustomActionData.ContainsKey("PORT"))
+ {
+ Log(session, "CheckValidPort custom action requires a port variable be passed to it in the from PORT=xxxx");
+ return ActionResult.Failure;
+ }
+ var port = session.CustomActionData["PORT"];
+ UInt16 portNumber;
+ if (UInt16.TryParse(port, out portNumber))
+ {
+ // Port number 49152 and above should not be used http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
+ if (portNumber < 49152)
+ {
+ session.Set("VALID_PORT", "TRUE");
+ return ActionResult.Success;
+ }
+ }
+ session.Set("VALID_PORT", "FALSE");
+ return ActionResult.Success;
+ }
+
+ [CustomAction]
+ public static ActionResult ReadForwardAuditMessagesFromConfig(Session session)
{
try
{
- Log(session, "Start custom action CheckValidPort");
- if (!session.CustomActionData.ContainsKey("PORT"))
+ if (session.CustomActionData.Keys.Count != 1)
{
- Log(session, "CheckValidPort custom action requires a port variable be passed to it in the from PORT=xxxx");
+ Log(session, "ReadForwardAuditMessagesFromConfig custom action requires a single property name to be passed in the CustomActionData. The result will passed to that property");
return ActionResult.Failure;
}
- var port = session.CustomActionData["PORT"];
- UInt16 portNumber;
- if (UInt16.TryParse(port, out portNumber))
+
+ var outputProperty = session.CustomActionData.Keys.First();
+
+ const string ServiceControlRegKey = @"SOFTWARE\ParticularSoftware\ServiceControl";
+ var targetPath = session.Get("APPDIR");
+ var configPath = Path.Combine(targetPath, @"ServiceControl.exe.config");
+ var entryValue = "null";
+
+ // Try to get value from existing config
+ if (File.Exists(configPath))
{
- // Port numbder 49152 and above should not be used http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
- if (portNumber < 49152)
+ var configDoc = XDocument.Load(configPath);
+ var entry = configDoc.XPathSelectElement(@"/configuration/appSettings/add[@key='ServiceControl/ForwardAuditMessages']");
+ entryValue = (entry != null) ? entry.Attribute("value").Value : "null";
+ }
+
+ // Fallback to getting value from registry.
+ if (!String.IsNullOrWhiteSpace(entryValue))
+ {
+ var key = Registry.LocalMachine.OpenSubKey(ServiceControlRegKey, RegistryKeyPermissionCheck.Default);
+ if (key != null)
{
- session.Set("VALID_PORT", "TRUE");
- return ActionResult.Success;
+ entryValue = (string) key.GetValue("ForwardAuditMessages", "null");
}
}
- session.Set("VALID_PORT", "FALSE");
+
+ entryValue = entryValue.ToLower();
+ switch (entryValue)
+ {
+ case "true" :
+ case "false" :
+ session.Set(outputProperty, entryValue);
+ break;
+ default:
+ session.Set(outputProperty,"null");
+ break;
+ }
return ActionResult.Success;
}
- finally
+ catch (Exception ex)
{
- Log(session, "End custom action CheckValidPort");
+ Log(session, "ReadForwardAuditMessagesFromConfig failed - {0}", ex);
+ return ActionResult.Failure;
}
}
- static void Log(Session session, string message)
+ [CustomAction]
+ public static ActionResult ValidateForwardAuditMessages(Session session)
+ {
+ var forwardAuditMessages = session.Get("FORWARDAUDITMESSAGES");
+ switch (forwardAuditMessages)
+ {
+ case "true":
+ case "false":
+ return ActionResult.Success;
+ }
+ Log(session, "A required settings has not been provided. ForwardAuditMessages must be explicitly set to true or false when installing via unattended mode. e.g. 'Particular.ServiceControl.exe /quiet ForwardAuditMessages=false'");
+ return ActionResult.Failure;
+
+ }
+
+ static void Log(Session session, string message, params object[] args)
{
- LogAction(session, message);
+ LogAction(session, string.Format(message, args));
}
public static Action LogAction = (s, m) => s.Log(m);
diff --git a/src/ServiceControl.IntegrationDemo/ServiceControl.IntegrationDemo.csproj b/src/ServiceControl.IntegrationDemo/ServiceControl.IntegrationDemo.csproj
index 34545b9be7..03ba1559e3 100644
--- a/src/ServiceControl.IntegrationDemo/ServiceControl.IntegrationDemo.csproj
+++ b/src/ServiceControl.IntegrationDemo/ServiceControl.IntegrationDemo.csproj
@@ -47,7 +47,7 @@
False
- ..\packages\ServiceControl.Contracts.1.0.0\lib\net45\ServiceControl.Contracts.dll
+ ..\packages\ServiceControl.Contracts.1.1.0\lib\net45\ServiceControl.Contracts.dll
diff --git a/src/ServiceControl.IntegrationDemo/packages.config b/src/ServiceControl.IntegrationDemo/packages.config
index 802e6629d0..4be01563f7 100644
--- a/src/ServiceControl.IntegrationDemo/packages.config
+++ b/src/ServiceControl.IntegrationDemo/packages.config
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/src/ServiceControl.UnitTests/AuditImport/AuditImportTests.cs b/src/ServiceControl.UnitTests/AuditImport/AuditImportTests.cs
new file mode 100644
index 0000000000..8741a5a204
--- /dev/null
+++ b/src/ServiceControl.UnitTests/AuditImport/AuditImportTests.cs
@@ -0,0 +1,26 @@
+namespace ServiceControl.UnitTests.AuditImport
+{
+ using System.Messaging;
+ using NServiceBus;
+ using NServiceBus.Transports.Msmq;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class AuditImportTests
+ {
+ [Test, Explicit]
+ public void SendAMessageWithInvalidHeadersToTheAuditQueue()
+ {
+ // Generate a bad msg to test MSMQ Audit Queue Importer
+ // This message should fail to parse to a transport message because of the bad header and so should end up in the Particular.ServiceControl.Errors queue
+ var q = new MessageQueue(MsmqUtilities.GetFullPath(Address.Parse("audit")), false, true, QueueAccessMode.Send);
+ using (var tx = new MessageQueueTransaction())
+ {
+ tx.Begin();
+ var message = new Message("Message with invalid headers"){Extension = new byte[]{1}};
+ q.Send(message, tx);
+ tx.Commit();
+ }
+ }
+ }
+}
diff --git a/src/ServiceControl.UnitTests/CompositeViews/FailedMessageTest.cs b/src/ServiceControl.UnitTests/CompositeViews/FailedMessageTest.cs
index e6b93a35da..f795a7e195 100644
--- a/src/ServiceControl.UnitTests/CompositeViews/FailedMessageTest.cs
+++ b/src/ServiceControl.UnitTests/CompositeViews/FailedMessageTest.cs
@@ -4,14 +4,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
- using Infrastructure.RavenDB;
using MessageFailures;
using NUnit.Framework;
using Raven.Client;
using ServiceControl.MessageFailures.Api;
[TestFixture]
- public class FailedMessagesTests : TestWithRavenDB
+ public class FailedMessagesTests
{
[Test]
public void Should_allow_errors_with_no_metadata()
diff --git a/src/ServiceControl.UnitTests/CompositeViews/MessagesViewTests.cs b/src/ServiceControl.UnitTests/CompositeViews/MessagesViewTests.cs
index 09aa78d95e..664f488bdb 100644
--- a/src/ServiceControl.UnitTests/CompositeViews/MessagesViewTests.cs
+++ b/src/ServiceControl.UnitTests/CompositeViews/MessagesViewTests.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Linq;
using Contracts.Operations;
- using Infrastructure.RavenDB;
using MessageAuditing;
using MessageFailures;
using NUnit.Framework;
@@ -13,7 +12,7 @@
using ServiceControl.CompositeViews.Messages;
[TestFixture]
- public class MessagesViewTests : TestWithRavenDB
+ public class MessagesViewTests
{
[Test]
public void Filter_out_system_messages()
@@ -82,7 +81,7 @@ public void Order_by_critical_time()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
using (var session = documentStore.OpenSession())
{
@@ -93,12 +92,12 @@ public void Order_by_critical_time()
.First();
Assert.AreEqual("1", firstByCriticalTime.Id);
- var firstByCriticalTimeDesc = session.Query()
+ var firstByCriticalTimeDescription = session.Query()
.OrderByDescending(x => x.CriticalTime)
.Where(x => x.CriticalTime != null)
.AsProjection()
.First();
- Assert.AreEqual("2", firstByCriticalTimeDesc.Id);
+ Assert.AreEqual("2", firstByCriticalTimeDescription.Id);
}
}
[Test]
@@ -125,7 +124,7 @@ public void Order_by_time_sent()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
using (var session = documentStore.OpenSession())
{
@@ -135,11 +134,11 @@ public void Order_by_time_sent()
.First();
Assert.AreEqual("3", firstByTimeSent.Id);
- var firstByTimeSentDesc = session.Query()
+ var firstByTimeSentDescription = session.Query()
.OrderByDescending(x => x.TimeSent)
.OfType()
.First();
- Assert.AreEqual("1", firstByTimeSentDesc.Id);
+ Assert.AreEqual("1", firstByTimeSentDescription.Id);
}
}
@@ -161,7 +160,7 @@ public void Correct_status_for_repeated_errors()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
using (var session = documentStore.OpenSession())
{
diff --git a/src/ServiceControl.UnitTests/Expiration/CustomExpirationBundleTests.cs b/src/ServiceControl.UnitTests/Expiration/CustomExpirationBundleTests.cs
index 0525e4717b..3b9d9f07b4 100644
--- a/src/ServiceControl.UnitTests/Expiration/CustomExpirationBundleTests.cs
+++ b/src/ServiceControl.UnitTests/Expiration/CustomExpirationBundleTests.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
- using Infrastructure.RavenDB;
using MessageAuditing;
using MessageFailures;
using NUnit.Framework;
@@ -13,7 +12,7 @@
using ServiceControl.Infrastructure.RavenDB.Expiration;
[TestFixture]
- public class CustomExpirationBundleTests : TestWithRavenDB
+ public class CustomExpirationBundleTests
{
[Test]
public void Processed_messages_are_being_expired()
@@ -38,7 +37,7 @@ public void Processed_messages_are_being_expired()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
Thread.Sleep(Settings.ExpirationProcessTimerInSeconds * 1000 * 2);
using (var session = documentStore.OpenSession())
@@ -85,7 +84,7 @@ public void Many_processed_messages_are_being_expired()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
Thread.Sleep(Settings.ExpirationProcessTimerInSeconds * 1000 * 10);
using (var session = documentStore.OpenSession())
{
@@ -125,7 +124,7 @@ public void Only_processed_messages_are_being_expired()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
Thread.Sleep(Settings.ExpirationProcessTimerInSeconds * 1000 * 2);
using (var session = documentStore.OpenSession())
@@ -155,7 +154,7 @@ public void Recent_processed_messages_are_not_being_expired()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
Thread.Sleep(Settings.ExpirationProcessTimerInSeconds * 1000 * 2);
using (var session = documentStore.OpenSession())
@@ -191,7 +190,7 @@ public void Errors_are_not_being_expired()
session.SaveChanges();
}
- WaitForIndexing(documentStore);
+ documentStore.WaitForIndexing();
Thread.Sleep(Settings.ExpirationProcessTimerInSeconds * 1000 * 2);
using (var session = documentStore.OpenSession())
diff --git a/src/ServiceControl.UnitTests/Expiration/PeriodicExecutorTests.cs b/src/ServiceControl.UnitTests/Expiration/PeriodicExecutorTests.cs
new file mode 100644
index 0000000000..bc52829596
--- /dev/null
+++ b/src/ServiceControl.UnitTests/Expiration/PeriodicExecutorTests.cs
@@ -0,0 +1,76 @@
+namespace ServiceControl.UnitTests.Expiration
+{
+ using System;
+ using System.Threading;
+ using NUnit.Framework;
+ using ServiceControl.Infrastructure.RavenDB.Expiration;
+
+ [TestFixture]
+ public class PeriodicExecutorTests
+ {
+ [Test]
+ public void If_execution_takes_longer_than_period_it_triggers_next_execution_immediately_after_previous()
+ {
+ var counter = 0;
+ var failure = false;
+ var lastEndTime = DateTime.MinValue;
+ var @event = new ManualResetEventSlim(false);
+ var delay = TimeSpan.Zero;
+ var executor = new PeriodicExecutor(() =>
+ {
+ delay = DateTime.Now - lastEndTime;
+ if (lastEndTime != DateTime.MinValue && delay > TimeSpan.FromMilliseconds(100))
+ {
+ @event.Set();
+ failure = true;
+ return;
+ }
+ counter++;
+ Thread.Sleep(2000);
+ lastEndTime = DateTime.Now;
+ if (counter == 2)
+ {
+ @event.Set();
+ }
+ }, TimeSpan.FromSeconds(1));
+ executor.Start(true);
+ @event.Wait();
+ executor.Stop(CancellationToken.None);
+ Assert.IsFalse(failure, string.Format("Time between finishing previous execution and starting this longer than {0} ms",delay));
+ }
+
+ [Test]
+ public void If_execution_throws_it_does_not_kill_the_executor()
+ {
+ var first = true;
+ var success = false;
+ var @event = new ManualResetEventSlim(false);
+ var executor = new PeriodicExecutor(() =>
+ {
+ if (first)
+ {
+ first = false;
+ throw new Exception();
+ }
+ success = true;
+ @event.Set();
+ }, TimeSpan.FromSeconds(1));
+ executor.Start(true);
+ @event.Wait();
+ executor.Stop(CancellationToken.None);
+ Assert.IsTrue(success);
+ }
+
+ [Test]
+ public void Can_shutdown_while_waiting()
+ {
+ var @event = new ManualResetEventSlim(false);
+ var executor = new PeriodicExecutor(@event.Set, TimeSpan.FromSeconds(10000));
+ executor.Start(false);
+ @event.Wait();
+ Thread.Sleep(1000);
+ executor.Stop(CancellationToken.None);
+ Assert.Pass();
+ }
+ }
+}
diff --git a/src/ServiceControl.UnitTests/Infrastructure/RavenDB/TestWithRavenDB.cs b/src/ServiceControl.UnitTests/Infrastructure/RavenDB/TestWithRavenDB.cs
deleted file mode 100644
index 4af228b1eb..0000000000
--- a/src/ServiceControl.UnitTests/Infrastructure/RavenDB/TestWithRavenDB.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-
-namespace ServiceControl.UnitTests.Infrastructure.RavenDB
-{
- using System.Diagnostics;
- using System.Threading;
- using NUnit.Framework;
- using Raven.Client;
- using Raven.Client.Embedded;
- using Raven.Database.Server;
- using Raven.Json.Linq;
-
- [TestFixture]
- public abstract class TestWithRavenDB
- {
- public static void WaitForIndexing(IDocumentStore store, string db = null, TimeSpan? timeout = null)
- {
- var databaseCommands = store.DatabaseCommands;
- if (db != null)
- databaseCommands = databaseCommands.ForDatabase(db);
- Assert.True(SpinWait.SpinUntil(() => databaseCommands.GetStatistics().StaleIndexes.Length == 0, timeout ?? TimeSpan.FromSeconds(10)));
- }
-
- public static void WaitForUserToContinueTheTest(EmbeddableDocumentStore documentStore, bool debug = true)
- {
- if (debug && Debugger.IsAttached == false)
- return;
-
- documentStore.SetStudioConfigToAllowSingleDb();
-
- documentStore.DatabaseCommands.Put("Pls Delete Me", null,
-
- RavenJObject.FromObject(new { StackTrace = new StackTrace(true) }),
- new RavenJObject());
-
- documentStore.Configuration.AnonymousUserAccessMode = AnonymousUserAccessMode.Admin;
- using (var server = new HttpServer(documentStore.Configuration, documentStore.DocumentDatabase))
- {
- server.StartListening();
- Process.Start(documentStore.Configuration.ServerUrl); // start the server
-
- do
- {
- Thread.Sleep(100);
- } while (documentStore.DatabaseCommands.Get("Pls Delete Me") != null && (debug == false || Debugger.IsAttached));
- }
- }
- }
-}
diff --git a/src/ServiceControl.UnitTests/RavenIndexAwaiter.cs b/src/ServiceControl.UnitTests/RavenIndexAwaiter.cs
new file mode 100644
index 0000000000..37daf1a96c
--- /dev/null
+++ b/src/ServiceControl.UnitTests/RavenIndexAwaiter.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Threading;
+using NUnit.Framework;
+using Raven.Client;
+
+public static class RavenIndexAwaiter
+{
+ public static void WaitForIndexing(this IDocumentStore store)
+ {
+ var databaseCommands = store.DatabaseCommands;
+ Assert.True(SpinWait.SpinUntil(() => databaseCommands.GetStatistics().StaleIndexes.Length == 0, TimeSpan.FromSeconds(10)));
+ }
+
+}
\ No newline at end of file
diff --git a/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj b/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj
index d7a7be25fb..eb7cb2246c 100644
--- a/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj
+++ b/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj
@@ -74,13 +74,14 @@
False
- ..\packages\ServiceControl.Contracts.1.0.0\lib\net45\ServiceControl.Contracts.dll
+ ..\packages\ServiceControl.Contracts.1.1.0\lib\net45\ServiceControl.Contracts.dll
+
False
..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll
@@ -89,14 +90,16 @@
+
+
-
+
diff --git a/src/ServiceControl.UnitTests/packages.config b/src/ServiceControl.UnitTests/packages.config
index 8c5257959e..ae64cdeafd 100644
--- a/src/ServiceControl.UnitTests/packages.config
+++ b/src/ServiceControl.UnitTests/packages.config
@@ -9,7 +9,7 @@
-
+
\ No newline at end of file
diff --git a/src/ServiceControl.sln.DotSettings b/src/ServiceControl.sln.DotSettings
index 411e1127cd..7244d3c82c 100644
--- a/src/ServiceControl.sln.DotSettings
+++ b/src/ServiceControl.sln.DotSettings
@@ -125,6 +125,16 @@
ERROR
ERROR
ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
+ ERROR
<?xml version="1.0" encoding="utf-16"?><Profile name="Format My Code Using "Particular" conventions"><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CssReformatCode>True</CssReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><CSShortenReferences>True</CSShortenReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CssAlphabetizeProperties>True</CssAlphabetizeProperties></Profile>
Default: Reformat Code
Format My Code Using "Particular" conventions
@@ -144,6 +154,167 @@
CHOP_ALWAYS
True
True
+ <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
+ <TypePattern DisplayName="COM interfaces or structs">
+ <TypePattern.Match>
+ <Or>
+ <And>
+ <Kind Is="Interface" />
+ <Or>
+ <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
+ <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
+ </Or>
+ </And>
+ <HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" />
+ </Or>
+ </TypePattern.Match>
+ </TypePattern>
+
+ <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
+ <TypePattern.Match>
+ <And>
+ <Kind Is="Class" />
+ <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="true" />
+ <HasAttribute Name="NUnit.Framework.TestCaseFixtureAttribute" Inherited="true" />
+ </And>
+ </TypePattern.Match>
+
+ <Entry DisplayName="Setup/Teardown Methods">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <Or>
+ <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="true" />
+ <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="true" />
+ <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="true" />
+ <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="true" />
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+
+ <Entry DisplayName="All other members" />
+
+ <Entry DisplayName="Test Methods" Priority="100">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" />
+ </And>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+ </TypePattern>
+
+ <TypePattern DisplayName="Default Pattern">
+ <Entry DisplayName="Public Delegates" Priority="100">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Delegate" />
+ </And>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="Public Enums" Priority="100">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Enum" />
+ </And>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="Static Fields and Constants">
+ <Entry.Match>
+ <Or>
+ <Kind Is="Constant" />
+ <And>
+ <Kind Is="Field" />
+ <Static />
+ </And>
+ </Or>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Kind>
+ <Kind.Order>
+ <DeclarationKind>Constant</DeclarationKind>
+ <DeclarationKind>Field</DeclarationKind>
+ </Kind.Order>
+ </Kind>
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="Fields">
+ <Entry.Match>
+ <And>
+ <Kind Is="Field" />
+ <Not>
+ <Static />
+ </Not>
+ </And>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Readonly />
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="Constructors">
+ <Entry.Match>
+ <Kind Is="Constructor" />
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <Static/>
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="Properties, Indexers">
+ <Entry.Match>
+ <Or>
+ <Kind Is="Property" />
+ <Kind Is="Indexer" />
+ </Or>
+ </Entry.Match>
+ </Entry>
+
+ <Entry DisplayName="Interface Implementations" Priority="100">
+ <Entry.Match>
+ <And>
+ <Kind Is="Member" />
+ <ImplementsInterface />
+ </And>
+ </Entry.Match>
+
+ <Entry.SortBy>
+ <ImplementsInterface Immediate="true" />
+ </Entry.SortBy>
+ </Entry>
+
+ <Entry DisplayName="All other members" />
+
+ <Entry DisplayName="Nested Types">
+ <Entry.Match>
+ <Kind Is="Type" />
+ </Entry.Match>
+ </Entry>
+ </TypePattern>
+</Patterns>
+
<?xml version="1.0" encoding="utf-8" ?>
<!--
@@ -408,7 +579,9 @@ II.2.12 <HandlesEvent />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ True
True
+ True
True
diff --git a/src/ServiceControl/Bootstrapper.cs b/src/ServiceControl/Bootstrapper.cs
index 5c4046d630..330f665dce 100644
--- a/src/ServiceControl/Bootstrapper.cs
+++ b/src/ServiceControl/Bootstrapper.cs
@@ -133,11 +133,12 @@ static void ConfigureLogging()
UseDefaultRowHighlightingRules = true,
};
- nlogConfig.LoggingRules.Add(new LoggingRule("Raven.*", LogLevel.Warn, fileTarget));
- nlogConfig.LoggingRules.Add(new LoggingRule("Raven.*", LogLevel.Warn, consoleTarget) { Final = true });
- nlogConfig.LoggingRules.Add(new LoggingRule("Particular.ServiceControl.Licensing.*", LogLevel.Info, fileTarget));
- nlogConfig.LoggingRules.Add(new LoggingRule("NServiceBus.Licensing.*", LogLevel.Error, fileTarget));
+ nlogConfig.LoggingRules.Add(new LoggingRule("Raven.*", LogLevel.Error, fileTarget));
+ nlogConfig.LoggingRules.Add(new LoggingRule("Raven.*", LogLevel.Error, consoleTarget) { Final = true });
+ nlogConfig.LoggingRules.Add(new LoggingRule("NServiceBus.RavenDB.Persistence.*", LogLevel.Error, fileTarget) { Final = true });
+ nlogConfig.LoggingRules.Add(new LoggingRule("NServiceBus.Licensing.*", LogLevel.Error, fileTarget) { Final = true });
nlogConfig.LoggingRules.Add(new LoggingRule("NServiceBus.Licensing.*", LogLevel.Error, consoleTarget) { Final = true });
+ nlogConfig.LoggingRules.Add(new LoggingRule("Particular.ServiceControl.Licensing.*", LogLevel.Info, fileTarget));
nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Warn, fileTarget));
nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget));
diff --git a/src/ServiceControl/ConfigTransportConfig.cs b/src/ServiceControl/ConfigTransportConfig.cs
index f73a11a9aa..d8b3c4c7de 100644
--- a/src/ServiceControl/ConfigTransportConfig.cs
+++ b/src/ServiceControl/ConfigTransportConfig.cs
@@ -2,6 +2,7 @@ namespace Particular.ServiceControl
{
using NServiceBus.Config;
using NServiceBus.Config.ConfigurationSource;
+ using ServiceBus.Management.Infrastructure.Settings;
class ConfigTransportConfig : IProvideConfiguration
{
@@ -9,7 +10,7 @@ public TransportConfig GetConfiguration()
{
return new TransportConfig
{
-
+ MaximumMessageThroughputPerSecond = Settings.MaximumMessageThroughputPerSecond,
MaximumConcurrencyLevel = 10,
MaxRetries = 3,
};
diff --git a/src/ServiceControl/ExternalIntegrations/CustomCheckFailedPublisher.cs b/src/ServiceControl/ExternalIntegrations/CustomCheckFailedPublisher.cs
new file mode 100644
index 0000000000..97991fdcde
--- /dev/null
+++ b/src/ServiceControl/ExternalIntegrations/CustomCheckFailedPublisher.cs
@@ -0,0 +1,51 @@
+namespace ServiceControl.ExternalIntegrations
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Raven.Client;
+ using CustomCheckFailed = ServiceControl.Contracts.CustomCheckFailed;
+
+
+ public class CustomCheckFailedPublisher : EventPublisher
+ {
+ protected override DispatchContext CreateDispatchRequest(Contracts.CustomChecks.CustomCheckFailed @event)
+ {
+ return new DispatchContext
+ {
+ EndpointHost = @event.OriginatingEndpoint.Host,
+ EndpointHostId = @event.OriginatingEndpoint.HostId,
+ EndpointName = @event.OriginatingEndpoint.Name,
+ FailedAt = @event.FailedAt,
+ Category = @event.Category,
+ FailureReason = @event.FailureReason,
+ CustomCheckId = @event.CustomCheckId,
+ };
+ }
+
+ protected override IEnumerable
False
- ..\packages\ServiceControl.Contracts.1.0.0\lib\net45\ServiceControl.Contracts.dll
+ ..\packages\ServiceControl.Contracts.1.1.0\lib\net45\ServiceControl.Contracts.dll
@@ -235,11 +250,13 @@
+
+
@@ -252,6 +269,7 @@
+
@@ -271,8 +289,12 @@
Component
+
+
+
+
@@ -441,11 +463,27 @@
- PreserveNewest
Designer
+
+
+ False
+ Microsoft .NET Framework 4.5 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
\ No newline at end of file
diff --git a/src/ServiceControl/packages.config b/src/ServiceControl/packages.config
index 11f9218c2d..ce6d4f2a21 100644
--- a/src/ServiceControl/packages.config
+++ b/src/ServiceControl/packages.config
@@ -31,7 +31,7 @@
-
+