Commit 9d37dc7f authored by Savorboard's avatar Savorboard

Add unit tests for ConsumerInvoker

parent a7080292
......@@ -22,6 +22,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static class ServiceCollectionExtensions
{
internal static IServiceCollection ServiceCollection;
/// <summary>
/// Adds and configures the consistence services for the consistency.
/// </summary>
......
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
// Copyright (c) .NET Core Community. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using DotNetCore.CAP.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
namespace DotNetCore.CAP.Internal
{
internal class DefaultConsumerInvoker : IConsumerInvoker
{
private readonly ILogger _logger;
private readonly IMessagePacker _messagePacker;
private readonly IModelBinderFactory _modelBinderFactory;
private readonly IServiceProvider _serviceProvider;
public DefaultConsumerInvoker(ILoggerFactory loggerFactory,
IServiceProvider serviceProvider,
IMessagePacker messagePacker,
IModelBinderFactory modelBinderFactory)
{
_modelBinderFactory = modelBinderFactory;
_serviceProvider = serviceProvider;
_messagePacker = messagePacker;
_logger = loggerFactory.CreateLogger<DefaultConsumerInvoker>();
}
public async Task<ConsumerExecutedResult> InvokeAsync(ConsumerContext context)
{
_logger.LogDebug("Executing consumer Topic: {0}", context.ConsumerDescriptor.MethodInfo.Name);
var executor = ObjectMethodExecutor.Create(
context.ConsumerDescriptor.MethodInfo,
context.ConsumerDescriptor.ImplTypeInfo);
using (var scope = _serviceProvider.CreateScope())
{
using System.Threading.Tasks;
using DotNetCore.CAP.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
namespace DotNetCore.CAP.Internal
{
internal class DefaultConsumerInvoker : IConsumerInvoker
{
private readonly ILogger _logger;
private readonly IMessagePacker _messagePacker;
private readonly IModelBinderFactory _modelBinderFactory;
private readonly IServiceProvider _serviceProvider;
public DefaultConsumerInvoker(ILoggerFactory loggerFactory,
IServiceProvider serviceProvider,
IMessagePacker messagePacker,
IModelBinderFactory modelBinderFactory)
{
_modelBinderFactory = modelBinderFactory;
_serviceProvider = serviceProvider;
_messagePacker = messagePacker;
_logger = loggerFactory.CreateLogger<DefaultConsumerInvoker>();
}
public async Task<ConsumerExecutedResult> InvokeAsync(ConsumerContext context)
{
_logger.LogDebug("Executing consumer Topic: {0}", context.ConsumerDescriptor.MethodInfo.Name);
var executor = ObjectMethodExecutor.Create(
context.ConsumerDescriptor.MethodInfo,
context.ConsumerDescriptor.ImplTypeInfo);
using (var scope = _serviceProvider.CreateScope())
{
var provider = scope.ServiceProvider;
var serviceType = context.ConsumerDescriptor.ImplTypeInfo.AsType();
object obj = null;
if (context.ConsumerDescriptor.ServiceTypeInfo != null)
var srvType = context.ConsumerDescriptor.ServiceTypeInfo?.AsType();
var implType = context.ConsumerDescriptor.ImplTypeInfo.AsType();
object obj = null;
if (srvType != null)
{
obj = provider.GetServices(context.ConsumerDescriptor.ServiceTypeInfo.AsType())
.FirstOrDefault(o => o.GetType() == serviceType);
}
obj = provider.GetServices(srvType).FirstOrDefault(o => o.GetType() == implType);
}
if (obj == null)
{
obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, serviceType);
}
var jsonContent = context.DeliverMessage.Content;
var message = _messagePacker.UnPack(jsonContent);
object resultObj;
if (executor.MethodParameters.Length > 0)
{
resultObj = await ExecuteWithParameterAsync(executor, obj, message.Content);
}
else
{
resultObj = await ExecuteAsync(executor, obj);
}
return new ConsumerExecutedResult(resultObj, message.Id, message.CallbackName);
}
}
private async Task<object> ExecuteAsync(ObjectMethodExecutor executor, object @class)
{
if (executor.IsMethodAsync)
{
return await executor.ExecuteAsync(@class);
}
return executor.Execute(@class);
}
private async Task<object> ExecuteWithParameterAsync(ObjectMethodExecutor executor,
object @class, string parameterString)
{
var firstParameter = executor.MethodParameters[0];
try
{
var binder = _modelBinderFactory.CreateBinder(firstParameter);
var bindResult = await binder.BindModelAsync(parameterString);
if (bindResult.IsSuccess)
{
if (executor.IsMethodAsync)
{
return await executor.ExecuteAsync(@class, bindResult.Model);
}
return executor.Execute(@class, bindResult.Model);
}
throw new MethodBindException(
$"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameterString} ");
}
catch (FormatException ex)
{
_logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameterString,
ex);
return null;
}
}
}
obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType);
}
var jsonContent = context.DeliverMessage.Content;
var message = _messagePacker.UnPack(jsonContent);
object resultObj;
if (executor.MethodParameters.Length > 0)
{
resultObj = await ExecuteWithParameterAsync(executor, obj, message.Content);
}
else
{
resultObj = await ExecuteAsync(executor, obj);
}
return new ConsumerExecutedResult(resultObj, message.Id, message.CallbackName);
}
}
private async Task<object> ExecuteAsync(ObjectMethodExecutor executor, object @class)
{
if (executor.IsMethodAsync)
{
return await executor.ExecuteAsync(@class);
}
return executor.Execute(@class);
}
private async Task<object> ExecuteWithParameterAsync(ObjectMethodExecutor executor,
object @class, string parameterString)
{
var firstParameter = executor.MethodParameters[0];
try
{
var binder = _modelBinderFactory.CreateBinder(firstParameter);
var bindResult = await binder.BindModelAsync(parameterString);
if (bindResult.IsSuccess)
{
if (executor.IsMethodAsync)
{
return await executor.ExecuteAsync(@class, bindResult.Model);
}
return executor.Execute(@class, bindResult.Model);
}
throw new MethodBindException(
$"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameterString} ");
}
catch (FormatException ex)
{
_logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameterString,
ex);
return null;
}
}
}
}
\ No newline at end of file
using System;
using System.Reflection;
using System.Threading.Tasks;
using DotNetCore.CAP.Abstractions;
using DotNetCore.CAP.Infrastructure;
using DotNetCore.CAP.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
namespace DotNetCore.CAP.Test
{
public class ConsumerInvokerTest
{
private ILoggerFactory _loggerFactory;
private Mock<IMessagePacker> _mockMessagePacker;
private Mock<IModelBinderFactory> _mockModelBinderFactory;
private MessageContext _messageContext;
public ConsumerInvokerTest()
{
_loggerFactory = new NullLoggerFactory();
_mockMessagePacker = new Mock<IMessagePacker>();
_mockModelBinderFactory = new Mock<IModelBinderFactory>();
}
private Internal.DefaultConsumerInvoker InitDefaultConsumerInvoker(IServiceProvider provider)
{
var invoker = new Internal.DefaultConsumerInvoker(
_loggerFactory,
provider,
_mockMessagePacker.Object,
_mockModelBinderFactory.Object);
var message = new CapReceivedMessage
{
Id = SnowflakeId.Default().NextId(),
Name = "test",
Content = DateTime.Now.ToString(),
StatusName = StatusName.Scheduled,
Group = "Group.Test"
};
_mockMessagePacker
.Setup(x => x.UnPack(It.IsAny<string>()))
.Returns(new CapMessageDto(message.Content));
_messageContext = new MessageContext
{
Group = message.Group,
Name = message.Name,
Content = Helper.ToJson(message)
};
return invoker;
}
[Fact]
public async Task CanInvokeServiceTest()
{
var services = new ServiceCollection();
services.AddSingleton<ITestService, TestService2>();
services.AddSingleton<ITestService, TestService>();
var provider = services.BuildServiceProvider();
var invoker = InitDefaultConsumerInvoker(provider);
var descriptor = new ConsumerExecutorDescriptor
{
ServiceTypeInfo = typeof(ITestService).GetTypeInfo(),
ImplTypeInfo = typeof(TestService).GetTypeInfo(),
MethodInfo = typeof(TestService).GetMethod("Index")
};
descriptor.Attribute = descriptor.MethodInfo.GetCustomAttribute<TopicAttribute>(true);
var context = new Internal.ConsumerContext(descriptor, _messageContext);
var result = await invoker.InvokeAsync(context);
Assert.NotNull(result);
Assert.NotNull(result.Result);
Assert.Equal("test", result.Result.ToString());
}
[Fact]
public async Task CanInvokeControllerTest()
{
var services = new ServiceCollection();
var provider = services.BuildServiceProvider();
var invoker = InitDefaultConsumerInvoker(provider);
var descriptor = new ConsumerExecutorDescriptor
{
ServiceTypeInfo = typeof(HomeController).GetTypeInfo(),
ImplTypeInfo = typeof(HomeController).GetTypeInfo(),
MethodInfo = typeof(HomeController).GetMethod("Index")
};
descriptor.Attribute = descriptor.MethodInfo.GetCustomAttribute<TopicAttribute>(true);
var context = new Internal.ConsumerContext(descriptor, _messageContext);
var result = await invoker.InvokeAsync(context);
Assert.NotNull(result);
Assert.NotNull(result.Result);
Assert.Equal("test", result.Result.ToString());
}
}
public class HomeController
{
[CapSubscribe("test")]
public string Index()
{
return "test";
}
}
public interface ITestService { }
public class TestService : ITestService, ICapSubscribe
{
[CapSubscribe("test")]
public string Index()
{
return "test";
}
}
public class TestService2 : ITestService
{
[CapSubscribe("test")]
public string Index()
{
return "test2";
}
}
public class CapSubscribeAttribute : TopicAttribute
{
public CapSubscribeAttribute(string name) : base(name)
{
}
}
}
\ No newline at end of file
using System;
using DotNetCore.CAP.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace DotNetCore.CAP.Test
{
public class SubscribeFinderTest
{
private IServiceProvider _provider;
public SubscribeFinderTest()
{
var services = new ServiceCollection();
services.AddScoped<ITestService, TestService>();
services.AddCap(x => { });
_provider = services.BuildServiceProvider();
}
[Fact]
public void CanFindControllers()
{
}
[Fact]
public void CanFindSubscribeService()
{
var testService = _provider.GetService<ICapSubscribe>();
Assert.NotNull(testService);
Assert.IsType<TestService>(testService);
}
}
public class HomeController
{
}
public interface ITestService { }
public class TestService : ITestService, ICapSubscribe
{
[CapSubscribe("test")]
public void Index()
{
}
}
public class CapSubscribeAttribute : TopicAttribute
{
public CapSubscribeAttribute(string name) : base(name)
{
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment