diff --git a/Foundatio.sln b/Foundatio.sln index c7662f36e..cca87af11 100644 --- a/Foundatio.sln +++ b/Foundatio.sln @@ -54,7 +54,7 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Foundatio.RabbitMQPublishCo EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Foundatio.RabbitMQSubscribeConsole", "samples\Foundatio.RabbitMQSubscribeConsole\Foundatio.RabbitMQSubscribeConsole.xproj", "{5250856E-2587-4ED3-AA1A-DD673EC46EF0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Foundatio.WindowsServerServiceBus", "src\Foundatio.WindowsServerServiceBus\Foundatio.WindowsServerServiceBus.csproj", "{5CACEF55-E509-4043-B9C8-19C28D9154E3}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Foundatio.WindowsServerServiceBus", "src\Foundatio.WindowsServerServiceBus\Foundatio.WindowsServerServiceBus.xproj", "{2AE275A8-1541-4D97-B26D-5BEFB07B5DE7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -142,10 +142,10 @@ Global {5250856E-2587-4ED3-AA1A-DD673EC46EF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {5250856E-2587-4ED3-AA1A-DD673EC46EF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {5250856E-2587-4ED3-AA1A-DD673EC46EF0}.Release|Any CPU.Build.0 = Release|Any CPU - {5CACEF55-E509-4043-B9C8-19C28D9154E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5CACEF55-E509-4043-B9C8-19C28D9154E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5CACEF55-E509-4043-B9C8-19C28D9154E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5CACEF55-E509-4043-B9C8-19C28D9154E3}.Release|Any CPU.Build.0 = Release|Any CPU + {2AE275A8-1541-4D97-B26D-5BEFB07B5DE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AE275A8-1541-4D97-B26D-5BEFB07B5DE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AE275A8-1541-4D97-B26D-5BEFB07B5DE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AE275A8-1541-4D97-B26D-5BEFB07B5DE7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Foundatio.WindowsServerServiceBus/Extensions/TaskExtensions.cs b/src/Foundatio.WindowsServerServiceBus/Extensions/TaskExtensions.cs new file mode 100644 index 000000000..892c04e0e --- /dev/null +++ b/src/Foundatio.WindowsServerServiceBus/Extensions/TaskExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Foundatio.Extensions { + internal static class TaskExtensions { + [DebuggerStepThrough] + public static ConfiguredTaskAwaitable AnyContext(this Task task) { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + + [DebuggerStepThrough] + public static ConfiguredTaskAwaitable AnyContext(this Task task) { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + } +} diff --git a/src/Foundatio.WindowsServerServiceBus/Foundatio.WindowsServerServiceBus.xproj b/src/Foundatio.WindowsServerServiceBus/Foundatio.WindowsServerServiceBus.xproj new file mode 100644 index 000000000..224731e36 --- /dev/null +++ b/src/Foundatio.WindowsServerServiceBus/Foundatio.WindowsServerServiceBus.xproj @@ -0,0 +1,18 @@ + + + + 14.0.25123 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 2ae275a8-1541-4d97-b26d-5befb07b5de7 + Foundatio.WindowsServerServiceBus + .\obj + .\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/Queue/WindowsServerServiceBusQueue.cs b/src/Foundatio.WindowsServerServiceBus/Queue/WindowsServerServiceBusQueue.cs index 2e4008413..0f861dac2 100644 --- a/src/Foundatio.WindowsServerServiceBus/Queue/WindowsServerServiceBusQueue.cs +++ b/src/Foundatio.WindowsServerServiceBus/Queue/WindowsServerServiceBusQueue.cs @@ -7,14 +7,15 @@ using Foundatio.Serializer; using Microsoft.ServiceBus; using Microsoft.ServiceBus.Messaging; +using Nito.AsyncEx; namespace Foundatio.Queues { public class WindowsServerServiceBusQueue : QueueBase where T : class { - private readonly string _queueName; + private readonly string _connectionString; private readonly NamespaceManager _namespaceManager; - private readonly QueueClient _queueClient; + private QueueClient _queueClient; private QueueDescription _queueDescription; private long _enqueuedCount; private long _dequeuedCount; @@ -22,55 +23,34 @@ public class WindowsServerServiceBusQueue : QueueBase where T : class private long _abandonedCount; private long _workerErrorCount; private readonly int _retries; + private readonly RetryPolicy _retryPolicy; private readonly TimeSpan _workItemTimeout = TimeSpan.FromMinutes(5); - - public WindowsServerServiceBusQueue(string connectionString, string queueName = null, int retries = 2, TimeSpan? workItemTimeout = null, bool shouldRecreate = false, RetryPolicy retryPolicy = null, ISerializer serializer = null, IEnumerable> behaviors = null, ILoggerFactory loggerFactory = null) : base(serializer, behaviors, loggerFactory) - { - _queueName = queueName ?? typeof(T).Name; + private readonly TimeSpan _autoDeleteOnIdle = TimeSpan.MaxValue; + private readonly TimeSpan _defaultMessageTimeToLive = TimeSpan.MaxValue; + private readonly AsyncLock _lock = new AsyncLock(); + + public WindowsServerServiceBusQueue(string connectionString, string queueName = null, int retries = 2, TimeSpan? workItemTimeout = null, RetryPolicy retryPolicy = null, ISerializer serializer = null, IEnumerable> behaviors = null, ILoggerFactory loggerFactory = null, TimeSpan? autoDeleteOnIdle = null, TimeSpan? defaultMessageTimeToLive = null) : base(serializer, behaviors, loggerFactory) { + _connectionString = connectionString; + if (!String.IsNullOrEmpty(queueName)) + _queueName = queueName; _namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString); _retries = retries; + _retryPolicy = retryPolicy; + if (workItemTimeout.HasValue && workItemTimeout.Value < TimeSpan.FromMinutes(5)) + { _workItemTimeout = workItemTimeout.Value; + } - if (_namespaceManager.QueueExists(_queueName) && shouldRecreate) - _namespaceManager.DeleteQueue(_queueName); - - if (!_namespaceManager.QueueExists(_queueName)) + if (autoDeleteOnIdle.HasValue && autoDeleteOnIdle.Value >= TimeSpan.FromMinutes(5)) { - _queueDescription = new QueueDescription(_queueName) - { - MaxDeliveryCount = retries + 1, - LockDuration = _workItemTimeout - }; - _namespaceManager.CreateQueue(_queueDescription); + _autoDeleteOnIdle = autoDeleteOnIdle.Value; } - else { - _queueDescription = _namespaceManager.GetQueue(_queueName); - - bool changes = false; - int newMaxDeliveryCount = retries + 1; - if (_queueDescription.MaxDeliveryCount != newMaxDeliveryCount) - { - _queueDescription.MaxDeliveryCount = newMaxDeliveryCount; - changes = true; - } - - if (_queueDescription.LockDuration != _workItemTimeout) - { - _queueDescription.LockDuration = _workItemTimeout; - changes = true; - } - - if (changes) - { - _namespaceManager.UpdateQueue(_queueDescription); - } + if (defaultMessageTimeToLive.HasValue && defaultMessageTimeToLive.Value > TimeSpan.Zero) + { + _defaultMessageTimeToLive = defaultMessageTimeToLive.Value; } - - _queueClient = QueueClient.CreateFromConnectionString(connectionString, _queueDescription.Path); - if (retryPolicy != null) - _queueClient.RetryPolicy = retryPolicy; } public override async Task DeleteQueueAsync() @@ -93,7 +73,86 @@ public override async Task DeleteQueueAsync() _workerErrorCount = 0; } - public override async Task GetQueueStatsAsync() + protected override async Task EnsureQueueCreatedAsync(CancellationToken cancellationToken = new CancellationToken()) + { + if (_queueClient != null) + { + return; + } + + using (await _lock.LockAsync(cancellationToken)) + { + if (_queueClient != null) + { + return; + } + + QueueDescription queueDescription; + + if (!await _namespaceManager.QueueExistsAsync(_queueName).AnyContext()) + { + try + { + queueDescription = await _namespaceManager.CreateQueueAsync(new QueueDescription(_queueName) + { + MaxDeliveryCount = _retries + 1, + LockDuration = _workItemTimeout, + AutoDeleteOnIdle = _autoDeleteOnIdle, + DefaultMessageTimeToLive = _defaultMessageTimeToLive + }).AnyContext(); + } + catch (MessagingException) + { + queueDescription = await _namespaceManager.GetQueueAsync(_queueName).AnyContext(); + } + } + else + { + queueDescription = await _namespaceManager.GetQueueAsync(_queueName).AnyContext(); + + bool changes = false; + + int newMaxDeliveryCount = _retries + 1; + if (queueDescription.MaxDeliveryCount != newMaxDeliveryCount) + { + queueDescription.MaxDeliveryCount = newMaxDeliveryCount; + changes = true; + } + + if (queueDescription.LockDuration != _workItemTimeout) + { + queueDescription.LockDuration = _workItemTimeout; + changes = true; + } + + if (queueDescription.AutoDeleteOnIdle != _autoDeleteOnIdle) + { + queueDescription.AutoDeleteOnIdle = _autoDeleteOnIdle; + changes = true; + } + + if (queueDescription.DefaultMessageTimeToLive != _defaultMessageTimeToLive) + { + queueDescription.DefaultMessageTimeToLive = _defaultMessageTimeToLive; + changes = true; + } + + if (changes) + { + await _namespaceManager.UpdateQueueAsync(queueDescription).AnyContext(); + } + } + + _queueClient = QueueClient.CreateFromConnectionString(_connectionString, queueDescription.Path); + + if (_retryPolicy != null) + { + _queueClient.RetryPolicy = _retryPolicy; + } + } + } + + protected override async Task GetQueueStatsImplAsync() { var q = await _namespaceManager.GetQueueAsync(_queueName).AnyContext(); return new QueueStats @@ -110,12 +169,12 @@ public override async Task GetQueueStatsAsync() }; } - public override Task> GetDeadletterItemsAsync(CancellationToken cancellationToken = default(CancellationToken)) + protected override Task> GetDeadletterItemsImplAsync(CancellationToken cancellationToken) { throw new NotImplementedException(); } - public override async Task EnqueueAsync(T data) + protected override async Task EnqueueImplAsync(T data) { if (!await OnEnqueuingAsync(data).AnyContext()) return null; @@ -130,7 +189,7 @@ public override async Task EnqueueAsync(T data) return message.MessageId; } - public override void StartWorking(Func, CancellationToken, Task> handler, bool autoComplete = false, CancellationToken cancellationToken = default(CancellationToken)) + protected override void StartWorkingImpl(Func, CancellationToken, Task> handler, bool autoComplete, CancellationToken cancellationToken) { if (handler == null) throw new ArgumentNullException(nameof(handler)); @@ -163,7 +222,7 @@ public override async Task> DequeueAsync(TimeSpan? timeout = null } } - public override Task> DequeueAsync(CancellationToken cancellationToken) + protected override Task> DequeueImplAsync(CancellationToken cancellationToken) { _logger.Warn("Azure Service Bus does not support CancellationTokens - use TimeSpan overload instead. Using default 30 second timeout."); diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/Foundatio.WindowsServerServiceBus.Tests.csproj b/src/Foundatio.WindowsServerServiceBus/Tests/Foundatio.WindowsServerServiceBus.Tests.csproj deleted file mode 100644 index 7455359dc..000000000 --- a/src/Foundatio.WindowsServerServiceBus/Tests/Foundatio.WindowsServerServiceBus.Tests.csproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - Debug - AnyCPU - {350FF062-3935-4263-9CA2-327E8000BC0B} - Library - Properties - Foundatio.WindowsServerServiceBus.Tests - Foundatio.WindowsServerServiceBus.Tests - v4.5.1 - 512 - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\..\packages\Microsoft.Data.Edm.5.7.0\lib\net40\Microsoft.Data.Edm.dll - True - - - ..\..\..\packages\Microsoft.Data.OData.5.7.0\lib\net40\Microsoft.Data.OData.dll - True - - - ..\..\..\packages\Microsoft.Data.Services.Client.5.7.0\lib\net40\Microsoft.Data.Services.Client.dll - True - - - ..\..\..\packages\ServiceBus.v1_1.1.0.5\lib\net40-full\Microsoft.ServiceBus.dll - True - - - ..\..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll - True - - - ..\..\..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - True - - - ..\..\..\packages\Nito.AsyncEx.3.0.1\lib\net45\Nito.AsyncEx.dll - True - - - ..\..\..\packages\Nito.AsyncEx.3.0.1\lib\net45\Nito.AsyncEx.Concurrent.dll - True - - - ..\..\..\packages\Nito.AsyncEx.3.0.1\lib\net45\Nito.AsyncEx.Enlightenment.dll - True - - - ..\..\..\packages\RimDev.Automation.StorageEmulator.0.1.0\lib\net45\RimDev.Automation.StorageEmulator.dll - True - - - - - - - ..\..\..\packages\System.Spatial.5.7.0\lib\net40\System.Spatial.dll - True - - - - - - - - ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll - True - - - ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll - True - - - ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll - True - - - ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll - True - - - - - - - - - - - - Always - - - - - - {f5b6c2b5-485f-4a4b-8e00-d5f77676cd6e} - Foundatio - - - {23002ba4-8663-460b-8d67-3aa941b0322a} - Foundatio.Tests - - - {d9e01fa4-170a-465a-a6e6-6a452485871a} - Foundatio.Logging.Xunit - - - {5cacef55-e509-4043-b9c8-19c28d9154e3} - Foundatio.WindowsServerServiceBus - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/app.config b/src/Foundatio.WindowsServerServiceBus/Tests/app.config deleted file mode 100644 index e30ccbef6..000000000 --- a/src/Foundatio.WindowsServerServiceBus/Tests/app.config +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/packages.config b/src/Foundatio.WindowsServerServiceBus/Tests/packages.config deleted file mode 100644 index 6b76fdd07..000000000 --- a/src/Foundatio.WindowsServerServiceBus/Tests/packages.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/project.json b/src/Foundatio.WindowsServerServiceBus/project.json new file mode 100644 index 000000000..6cf2e5acd --- /dev/null +++ b/src/Foundatio.WindowsServerServiceBus/project.json @@ -0,0 +1,41 @@ +{ + "version": "99.99.99-dev", + "title": "Foundatio Azure ServiceBus Implementations", + "description": "Pluggable foundation blocks for building distributed apps.", + "authors": [ "bniemyjski", "ejsmith" ], + "copyright": "Copyright (c) 2016 Exceptionless. All rights reserved.", + "packOptions": { + "tags": [ "Queue", "Messaging", "Message", "Bus", "Locking", "Lock", "Distributed", "File", "Storage", "Blob", "Jobs", "Metrics", "Stats", "Azure", "Redis", "StatsD", "Amazon", "AWS", "S3", "broker", "Logging", "Log", "pcl", "NETSTANDARD", "Core" ], + "owners": [ "Exceptionless" ], + "projectUrl": "https://github.com/exceptionless/Foundatio", + "releaseNotes": "https://github.com/exceptionless/Foundatio/releases", + "iconUrl": "https://be.exceptionless.io/img/exceptionless-32.png", + "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", + "repository": { + "type": "git", + "url": "https://github.com/exceptionless/Foundatio" + } + }, + "buildOptions": { + "nowarn": [ + "CS1591" + ], + "optimize": true, + "warningsAsErrors": true, + "xmlDoc": true + }, + "dependencies": { + "Foundatio": { + "target": "project" + }, + "Microsoft.WindowsAzure.ConfigurationManager": "3.2.1", + "ServiceBus.v1_1": "1.0.6" + }, + "frameworks": { + "net46": { + "buildOptions": { + "define": [ "NET46" ] + } + } + } +} \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/AzureStorageEmulatorCollection.cs b/test/Foundatio.WindowsServerServiceBus.Tests/AzureStorageEmulatorCollection.cs similarity index 100% rename from src/Foundatio.WindowsServerServiceBus/Tests/AzureStorageEmulatorCollection.cs rename to test/Foundatio.WindowsServerServiceBus.Tests/AzureStorageEmulatorCollection.cs diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/AzureStorageEmulatorFixture.cs b/test/Foundatio.WindowsServerServiceBus.Tests/AzureStorageEmulatorFixture.cs similarity index 100% rename from src/Foundatio.WindowsServerServiceBus/Tests/AzureStorageEmulatorFixture.cs rename to test/Foundatio.WindowsServerServiceBus.Tests/AzureStorageEmulatorFixture.cs diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/Foundatio.WindowsServerServiceBus.Tests.xproj b/test/Foundatio.WindowsServerServiceBus.Tests/Foundatio.WindowsServerServiceBus.Tests.xproj new file mode 100644 index 000000000..e36a93310 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/Foundatio.WindowsServerServiceBus.Tests.xproj @@ -0,0 +1,21 @@ + + + + 14.0.25123 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + dfcfb06a-396d-4d80-adb7-0b4b32e5d1ce + Foundatio.Azure.Tests + .\obj + .\bin\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/Messaging/WindowsServerServiceBusMessageBusTests.cs b/test/Foundatio.WindowsServerServiceBus.Tests/Messaging/AzureServiceBusMessageBusTests.cs similarity index 70% rename from src/Foundatio.WindowsServerServiceBus/Tests/Messaging/WindowsServerServiceBusMessageBusTests.cs rename to test/Foundatio.WindowsServerServiceBus.Tests/Messaging/AzureServiceBusMessageBusTests.cs index e51807fef..dbbc1a1a0 100644 --- a/src/Foundatio.WindowsServerServiceBus/Tests/Messaging/WindowsServerServiceBusMessageBusTests.cs +++ b/test/Foundatio.WindowsServerServiceBus.Tests/Messaging/AzureServiceBusMessageBusTests.cs @@ -7,21 +7,16 @@ using Xunit.Abstractions; namespace Foundatio.Azure.Tests.Messaging { - public class WindowsServerServiceBusMessageBusTests : MessageBusTestBase { - private static IMessageBus _messageBus; + public class AzureServiceBusMessageBusTests : MessageBusTestBase { + protected readonly string _topicName = Guid.NewGuid().ToString("N"); - public WindowsServerServiceBusMessageBusTests(ITestOutputHelper output) : base(output) {} + public AzureServiceBusMessageBusTests(ITestOutputHelper output) : base(output) {} protected override IMessageBus GetMessageBus() { - if (_messageBus != null) - return _messageBus; - - if (String.IsNullOrEmpty(ConnectionStrings.Get("ServiceBusConnectionString"))) + if (String.IsNullOrEmpty(Configuration.GetConnectionString("ServiceBusConnectionString"))) return null; - _messageBus = new WindowsServerServiceBusMessageBus(ConnectionStrings.Get("ServiceBusConnectionString"), Guid.NewGuid().ToString("N"), loggerFactory: Log); - - return _messageBus; + return new AzureServiceBusMessageBus(Configuration.GetConnectionString("ServiceBusConnectionString"), _topicName, loggerFactory: Log); } [Fact] @@ -78,5 +73,15 @@ public class WindowsServerServiceBusMessageBusTests : MessageBusTestBase { public override Task WontKeepMessagesWithNoSubscribers() { return base.WontKeepMessagesWithNoSubscribers(); } + + [Fact] + public override Task CanReceiveFromMultipleSubscribers() { + return base.CanReceiveFromMultipleSubscribers(); + } + + [Fact] + public override void CanDisposeWithNoSubscribersOrPublishers() { + base.CanDisposeWithNoSubscribersOrPublishers(); + } } } \ No newline at end of file diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/Properties/AssemblyInfo.cs b/test/Foundatio.WindowsServerServiceBus.Tests/Properties/AssemblyInfo.cs similarity index 100% rename from src/Foundatio.WindowsServerServiceBus/Tests/Properties/AssemblyInfo.cs rename to test/Foundatio.WindowsServerServiceBus.Tests/Properties/AssemblyInfo.cs diff --git a/src/Foundatio.WindowsServerServiceBus/Tests/Queues/WindowsServerServiceBusQueueTests.cs b/test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureServiceBusQueueTests.cs similarity index 75% rename from src/Foundatio.WindowsServerServiceBus/Tests/Queues/WindowsServerServiceBusQueueTests.cs rename to test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureServiceBusQueueTests.cs index 5b1832a59..b51f458a6 100644 --- a/src/Foundatio.WindowsServerServiceBus/Tests/Queues/WindowsServerServiceBusQueueTests.cs +++ b/test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureServiceBusQueueTests.cs @@ -4,17 +4,18 @@ using Foundatio.Tests.Utility; using Xunit; using System.Threading.Tasks; +using Foundatio.Logging; using Microsoft.ServiceBus; using Xunit.Abstractions; namespace Foundatio.Azure.Tests.Queue { - public class WindowsServerServiceBusQueueTests : QueueTestBase { - private static readonly string QueueName = Guid.NewGuid().ToString("N"); + public class AzureServiceBusQueueTests : QueueTestBase { + private static readonly string _queueName = Guid.NewGuid().ToString("N"); - public WindowsServerServiceBusQueueTests(ITestOutputHelper output) : base(output) {} + public AzureServiceBusQueueTests(ITestOutputHelper output) : base(output) {} protected override IQueue GetQueue(int retries = 1, TimeSpan? workItemTimeout = null, TimeSpan? retryDelay = null, int deadLetterMaxItems = 100, bool runQueueMaintenance = true) { - if (String.IsNullOrEmpty(ConnectionStrings.Get("ServiceBusConnectionString"))) + if (String.IsNullOrEmpty(Configuration.GetConnectionString("ServiceBusConnectionString"))) return null; if (!retryDelay.HasValue) @@ -23,18 +24,11 @@ public class WindowsServerServiceBusQueueTests : QueueTestBase { var maxBackoff = retryDelay.Value > TimeSpan.Zero ? retryDelay.Value + retryDelay.Value : TimeSpan.FromSeconds(1); + var retryPolicy = new RetryExponential(retryDelay.Value, maxBackoff, retries + 1); - var deltaBackoff = retryDelay.Value > TimeSpan.Zero - ? retryDelay.Value + retryDelay.Value - : TimeSpan.FromSeconds(1); - - var terminationTimeBuffer = retryDelay.Value > TimeSpan.Zero - ? TimeSpan.FromMilliseconds(retryDelay.Value.TotalMilliseconds * 2 * retries) - : TimeSpan.FromSeconds(60); - - var retryPolicy = new RetryExponential(retryDelay.Value, maxBackoff, deltaBackoff, terminationTimeBuffer, retries + 1); - return new WindowsServerServiceBusQueue(ConnectionStrings.Get("ServiceBusConnectionString"), - QueueName, retries, workItemTimeout, false, retryPolicy, loggerFactory: Log); + _logger.Debug("Queue Id: {queueId}", _queueName); + return new AzureServiceBusQueue(Configuration.GetConnectionString("ServiceBusConnectionString"), + _queueName, retries, workItemTimeout, retryPolicy, loggerFactory: Log); } [Fact] diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureStorageQueueTests.cs b/test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureStorageQueueTests.cs new file mode 100644 index 000000000..5cb526d51 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/Queues/AzureStorageQueueTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Threading.Tasks; +using Foundatio.Logging; +using Foundatio.Queues; +using Foundatio.Tests.Queue; +using Foundatio.Tests.Utility; +using Microsoft.WindowsAzure.Storage.RetryPolicies; +using Xunit; +using Xunit.Abstractions; + +namespace Foundatio.Azure.Tests.Queue { + [Collection("AzureStorageIntegrationTests")] + public class AzureStorageQueueTests : QueueTestBase { + private static readonly string _queueName = Guid.NewGuid().ToString("N"); + + public AzureStorageQueueTests(ITestOutputHelper output) : base(output) {} + + protected override IQueue GetQueue(int retries = 1, TimeSpan? workItemTimeout = null, TimeSpan? retryDelay = null, int deadLetterMaxItems = 100, bool runQueueMaintenance = true) { + if (String.IsNullOrEmpty(Configuration.GetConnectionString("StorageConnectionString"))) + return null; + + if (!retryDelay.HasValue) + retryDelay = TimeSpan.Zero; + + _logger.Debug("Queue Id: {queueId}", _queueName); + return new AzureStorageQueue(Configuration.GetConnectionString("StorageConnectionString"), _queueName, retries, workItemTimeout, TimeSpan.FromMilliseconds(50), new ExponentialRetry(retryDelay.Value, retries), loggerFactory: Log); + } + + [Fact] + public override Task CanQueueAndDequeueWorkItem() { + return base.CanQueueAndDequeueWorkItem(); + } + + [Fact] + public override Task CanDequeueWithCancelledToken() { + return base.CanDequeueWithCancelledToken(); + } + + [Fact] + public override Task CanQueueAndDequeueMultipleWorkItems() { + return base.CanQueueAndDequeueMultipleWorkItems(); + } + + [Fact] + public override Task WillWaitForItem() { + return base.WillWaitForItem(); + } + + [Fact] + public override Task DequeueWaitWillGetSignaled() { + return base.DequeueWaitWillGetSignaled(); + } + + [Fact] + public override Task CanUseQueueWorker() { + return base.CanUseQueueWorker(); + } + + [Fact] + public override Task CanHandleErrorInWorker() { + return base.CanHandleErrorInWorker(); + } + + [Fact] + public override Task WorkItemsWillTimeout() { + return base.WorkItemsWillTimeout(); + } + + [Fact] + public override Task WorkItemsWillGetMovedToDeadletter() { + return base.WorkItemsWillGetMovedToDeadletter(); + } + + [Fact] + public override Task CanAutoCompleteWorker() { + return base.CanAutoCompleteWorker(); + } + + [Fact] + public override Task CanHaveMultipleQueueInstances() { + return base.CanHaveMultipleQueueInstances(); + } + + [Fact] + public override Task CanRunWorkItemWithMetrics() { + return base.CanRunWorkItemWithMetrics(); + } + + [Fact] + public override Task CanRenewLock() { + return base.CanRenewLock(); + } + + [Fact] + public override Task CanAbandonQueueEntryOnce() { + return base.CanAbandonQueueEntryOnce(); + } + + [Fact] + public override Task CanCompleteQueueEntryOnce() { + return base.CanCompleteQueueEntryOnce(); + } + + // NOTE: Not using this test because you can set specific delay times for storage queue + public override Task CanDelayRetry() { + return base.CanDelayRetry(); + } + } +} \ No newline at end of file diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/Storage/AzureStorageTests.cs b/test/Foundatio.WindowsServerServiceBus.Tests/Storage/AzureStorageTests.cs new file mode 100644 index 000000000..0f2058029 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/Storage/AzureStorageTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Foundatio.Storage; +using Foundatio.Tests.Storage; +using Foundatio.Tests.Utility; +using Xunit; +using Xunit.Abstractions; + +namespace Foundatio.Azure.Tests.Storage { + [Collection("AzureStorageIntegrationTests")] + public class AzureStorageTests : FileStorageTestsBase { + public AzureStorageTests(ITestOutputHelper output) : base(output) {} + + protected override IFileStorage GetStorage() { + if (String.IsNullOrEmpty(Configuration.GetConnectionString("AzureStorageConnectionString"))) + return null; + + return new AzureFileStorage(Configuration.GetConnectionString("AzureStorageConnectionString")); + } + + [Fact] + public override Task CanGetEmptyFileListOnMissingDirectory() { + return base.CanGetEmptyFileListOnMissingDirectory(); + } + + [Fact] + public override Task CanGetFileListForSingleFolder() { + return base.CanGetFileListForSingleFolder(); + } + + [Fact] + public override Task CanSaveFilesAsync() { + return base.CanSaveFilesAsync(); + } + + [Fact] + public override Task CanManageFiles() { + return base.CanManageFiles(); + } + + [Fact] + public override Task CanConcurrentlyManageFiles() { + return base.CanConcurrentlyManageFiles(); + } + } +} diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/appsettings.json b/test/Foundatio.WindowsServerServiceBus.Tests/appsettings.json new file mode 100644 index 000000000..de2cf3139 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/appsettings.json @@ -0,0 +1,6 @@ +{ + "ConnectionStrings": { + "StorageConnectionString": "UseDevelopmentStorage=true;", + "ServiceBusConnectionString": "" + } +} diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/project.json b/test/Foundatio.WindowsServerServiceBus.Tests/project.json new file mode 100644 index 000000000..fddc206a0 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/project.json @@ -0,0 +1,54 @@ +{ + "testRunner": "xunit", + "buildOptions": { + "debugType": "portable", + "warningsAsErrors": true, + "copyToOutput": { + "include": [ "xunit.runner.json" ] + } + }, + "dependencies": { + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Foundatio": { + "target": "project" + }, + "Foundatio.AzureStorage": { + "target": "project" + }, + "Foundatio.Logging.Xunit": { + "target": "project" + }, + "Foundatio.Tests": { + "target": "project" + }, + "Foundatio.WindowsServerServiceBus": "99.99.99-dev", + "Microsoft.Azure.KeyVault.Core": "1.0.0", + "Microsoft.Data.Edm": "5.7.0", + "Microsoft.Data.OData": "5.7.0", + "Microsoft.Data.Services.Client": "5.7.0", + "Microsoft.WindowsAzure.ConfigurationManager": "3.2.1", + "RimDev.Automation.StorageEmulator": "0.1.0", + "System.Spatial": "5.7.0", + "WindowsAzure.ServiceBus": "3.3.2", + "WindowsAzure.Storage": "6.2.0", + "xunit": "2.2.0-beta2-build3300", + "xunit.extensibility.core": "2.2.0-beta2-build3300", + "xunit.extensibility.execution": "2.2.0-beta2-build3300", + "xunit.runner.visualstudio": "2.2.0-beta2-build1149" + }, + "frameworks": { + "NET46": { + "buildOptions": { + "define": [ "NET46" ] + }, + "frameworkAssemblies": { + "System.Threading.Tasks": { + "type": "build" + }, + "System.Runtime": { + "type": "build" + } + } + } + } +} \ No newline at end of file diff --git a/test/Foundatio.WindowsServerServiceBus.Tests/xunit.runner.json b/test/Foundatio.WindowsServerServiceBus.Tests/xunit.runner.json new file mode 100644 index 000000000..1b40892e6 --- /dev/null +++ b/test/Foundatio.WindowsServerServiceBus.Tests/xunit.runner.json @@ -0,0 +1,7 @@ +{ + "diagnosticMessages": true, + "maxParallelThreads": 1, + "methodDisplay": "method", + "parallelizeAssembly": false, + "parallelizetestcollections": false +}