From 971c9db90517c6ea723ce7b340240ce44d9ed2cd Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 17:28:55 +0800 Subject: [PATCH] Add fake transport fot unit tests --- .../ConsumerInvokerTest.cs | 56 ++++++++++++++ .../DotNetCore.CAP.Test.csproj | 10 +-- .../CAP.FakeQueueOptionsExtension.cs | 18 +++++ .../CAP.Options.Extensions.cs | 11 +++ .../ITransport.FakeInMemory.cs | 41 ++++++++++ .../InMemoryConsumerClient.cs | 75 +++++++++++++++++++ .../InMemoryConsumerClientFactory.cs | 23 ++++++ .../FakeInMemoryQueue/InMemoryQueue.cs | 67 +++++++++++++++++ test/DotNetCore.CAP.Test/HelperTest.cs | 2 +- test/DotNetCore.CAP.Test/OperateResultTest.cs | 26 ------- 10 files changed, 297 insertions(+), 32 deletions(-) create mode 100644 test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs delete mode 100644 test/DotNetCore.CAP.Test/OperateResultTest.cs diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs new file mode 100644 index 0000000..aa14448 --- /dev/null +++ b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class ConsumerInvokerTest + { + private readonly IServiceProvider _serviceProvider; + + public ConsumerInvokerTest() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + private IConsumerInvoker ConsumerInvoker => _serviceProvider.GetService(); + + [Fact] + public async Task InvokeTest() + { + var descriptor = new ConsumerExecutorDescriptor() + { + Attribute = new CandidatesTopic("fake.output.integer"), + ServiceTypeInfo = typeof(FakeSubscriber).GetTypeInfo(), + ImplTypeInfo = typeof(FakeSubscriber).GetTypeInfo(), + MethodInfo = typeof(FakeSubscriber).GetMethod(nameof(FakeSubscriber.OutputIntegerSub)), + Parameters = new List() + }; + + var header = new Dictionary(); + var message = new Message(header, null); + var context = new ConsumerContext(descriptor, message); + + var ret = await ConsumerInvoker.InvokeAsync(context); + Assert.Equal(int.MaxValue, ret.Result); + } + } + + public class FakeSubscriber : ICapSubscribe + { + [CapSubscribe("fake.output.integer")] + public int OutputIntegerSub() + { + return int.MaxValue; + } + } +} diff --git a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj index 838166d..e3d1d65 100644 --- a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj +++ b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj @@ -6,20 +6,20 @@ - - + + + + all runtime; build; native; contentfiles; analyzers - - - + diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs new file mode 100644 index 0000000..23ba908 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs @@ -0,0 +1,18 @@ +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class FakeQueueOptionsExtension : ICapOptionsExtension + { + + public void AddServices(IServiceCollection services) + { + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs new file mode 100644 index 0000000..24852f0 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs @@ -0,0 +1,11 @@ +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + public static class CapOptionsExtensions + { + public static CapOptions UseFakeTransport(this CapOptions options) + { + options.RegisterExtension(new FakeQueueOptionsExtension()); + return options; + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs new file mode 100644 index 0000000..0647ff4 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal class FakeInMemoryQueueTransport : ITransport + { + private readonly InMemoryQueue _queue; + private readonly ILogger _logger; + + public FakeInMemoryQueueTransport(InMemoryQueue queue, ILogger logger) + { + _queue = queue; + _logger = logger; + } + + public string Address { get; } = string.Empty; + + public Task SendAsync(TransportMessage message) + { + try + { + _queue.Send(message.GetName(), message); + + _logger.LogDebug($"Event message [{message.GetName()}] has been published."); + + return Task.FromResult(OperateResult.Success); + } + catch (Exception ex) + { + var wrapperEx = new PublisherSentFailedException(ex.Message, ex); + + return Task.FromResult(OperateResult.Failed(wrapperEx)); + } + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs new file mode 100644 index 0000000..6879916 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class InMemoryConsumerClient : IConsumerClient + { + private readonly ILogger _logger; + private readonly InMemoryQueue _queue; + private readonly string _subscriptionName; + + public InMemoryConsumerClient( + ILogger logger, + InMemoryQueue queue, + string subscriptionName) + { + _logger = logger; + _queue = queue; + _subscriptionName = subscriptionName; + } + + public event EventHandler OnMessageReceived; + + public event EventHandler OnLog; + + public string ServersAddress => string.Empty; + + public void Subscribe(IEnumerable topics) + { + if (topics == null) throw new ArgumentNullException(nameof(topics)); + + foreach (var topic in topics) + { + _queue.Subscribe(_subscriptionName, OnConsumerReceived, topic); + + _logger.LogInformation($"InMemory message queue initialize the topic: {topic}"); + } + } + + public void Listening(TimeSpan timeout, CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + cancellationToken.WaitHandle.WaitOne(timeout); + } + } + + public void Commit() + { + // ignore + } + + public void Reject() + { + // ignore + } + + public void Dispose() + { + _queue.ClearSubscriber(); + } + + #region private methods + + private void OnConsumerReceived(TransportMessage e) + { + OnMessageReceived?.Invoke(null, e); + } + #endregion private methods + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs new file mode 100644 index 0000000..3e3c216 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs @@ -0,0 +1,23 @@ +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class InMemoryConsumerClientFactory : IConsumerClientFactory + { + private readonly ILoggerFactory _loggerFactory; + private readonly InMemoryQueue _queue; + + public InMemoryConsumerClientFactory(ILoggerFactory loggerFactory, InMemoryQueue queue) + { + _loggerFactory = loggerFactory; + _queue = queue; + } + + public IConsumerClient Create(string groupId) + { + var logger = _loggerFactory.CreateLogger(typeof(InMemoryConsumerClient)); + return new InMemoryConsumerClient(logger, _queue, groupId); + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs new file mode 100644 index 0000000..deab65a --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using DotNetCore.CAP.Messages; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal class InMemoryQueue + { + private readonly ILogger _logger; + private static readonly object Lock = new object(); + + private readonly Dictionary, List)> _groupTopics; + + public Dictionary Messages { get; } + + public InMemoryQueue(ILogger logger) + { + _logger = logger; + _groupTopics = new Dictionary, List)>(); + Messages = new Dictionary(); + } + + public void Subscribe(string groupId, Action received, string topic) + { + lock (Lock) + { + if (_groupTopics.ContainsKey(groupId)) + { + var topics = _groupTopics[groupId]; + if (!topics.Item2.Contains(topic)) + { + topics.Item2.Add(topic); + } + } + else + { + _groupTopics.Add(groupId, (received, new List { topic })); + } + } + } + + public void ClearSubscriber() + { + _groupTopics.Clear(); + } + + public void Send(string topic, TransportMessage message) + { + Messages.Add(topic, message); + foreach (var groupTopic in _groupTopics) + { + if (groupTopic.Value.Item2.Contains(topic)) + { + try + { + groupTopic.Value.Item1?.Invoke(message); + } + catch (Exception e) + { + _logger.LogError(e, $"Consumption message raises an exception. Group-->{groupTopic.Key} Name-->{topic}"); + } + } + } + } + } +} diff --git a/test/DotNetCore.CAP.Test/HelperTest.cs b/test/DotNetCore.CAP.Test/HelperTest.cs index e179193..2b2b3b1 100644 --- a/test/DotNetCore.CAP.Test/HelperTest.cs +++ b/test/DotNetCore.CAP.Test/HelperTest.cs @@ -72,7 +72,7 @@ namespace DotNetCore.CAP.Test } } - class HomeController + public class HomeController { } diff --git a/test/DotNetCore.CAP.Test/OperateResultTest.cs b/test/DotNetCore.CAP.Test/OperateResultTest.cs deleted file mode 100644 index 5788f19..0000000 --- a/test/DotNetCore.CAP.Test/OperateResultTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Linq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class OperateResultTest - { - [Fact] - public void VerifyDefaultConstructor() - { - var result = new OperateResult(); - - Assert.False(result.Succeeded); - Assert.Empty(result.Errors); - } - - [Fact] - public void NullFaildUsesEmptyErrors() - { - var result = OperateResult.Failed(); - - Assert.False(result.Succeeded); - Assert.Empty(result.Errors); - } - } -} \ No newline at end of file