diff --git a/Directory.Build.props b/Directory.Build.props index f2b80f15bd..d6f4df58b2 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -39,7 +39,6 @@ 6.0.* 2.3.* - 4.18.* 17.7.* diff --git a/src/JsonApiDotNetCore/Middleware/JsonApiMiddleware.cs b/src/JsonApiDotNetCore/Middleware/JsonApiMiddleware.cs index b38ad986dd..29774c6eab 100644 --- a/src/JsonApiDotNetCore/Middleware/JsonApiMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/JsonApiMiddleware.cs @@ -23,10 +23,12 @@ public sealed class JsonApiMiddleware private static readonly MediaTypeHeaderValue MediaType = MediaTypeHeaderValue.Parse(HeaderConstants.MediaType); private static readonly MediaTypeHeaderValue AtomicOperationsMediaType = MediaTypeHeaderValue.Parse(HeaderConstants.AtomicOperationsMediaType); - private readonly RequestDelegate _next; + private readonly RequestDelegate? _next; - public JsonApiMiddleware(RequestDelegate next, IHttpContextAccessor httpContextAccessor) + public JsonApiMiddleware(RequestDelegate? next, IHttpContextAccessor httpContextAccessor) { + ArgumentGuard.NotNull(httpContextAccessor); + _next = next; var session = new AspNetCodeTimerSession(httpContextAccessor); @@ -77,9 +79,12 @@ public async Task InvokeAsync(HttpContext httpContext, IControllerResourceMappin httpContext.RegisterJsonApiRequest(); } - using (CodeTimingSessionManager.Current.Measure("Subsequent middleware")) + if (_next != null) { - await _next(httpContext); + using (CodeTimingSessionManager.Current.Measure("Subsequent middleware")) + { + await _next(httpContext); + } } } diff --git a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs index e4f127b725..34fc8971d1 100644 --- a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs +++ b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs @@ -3,5 +3,3 @@ [assembly: InternalsVisibleTo("Benchmarks")] [assembly: InternalsVisibleTo("JsonApiDotNetCoreTests")] [assembly: InternalsVisibleTo("UnitTests")] -[assembly: InternalsVisibleTo("DiscoveryTests")] -[assembly: InternalsVisibleTo("TestBuildingBlocks")] diff --git a/test/DiscoveryTests/DiscoveryTests.csproj b/test/DiscoveryTests/DiscoveryTests.csproj index 0eae11e850..a09e322203 100644 --- a/test/DiscoveryTests/DiscoveryTests.csproj +++ b/test/DiscoveryTests/DiscoveryTests.csproj @@ -12,6 +12,5 @@ - diff --git a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs index 3396aed54b..78c4213e93 100644 --- a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs +++ b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs @@ -1,7 +1,5 @@ using FluentAssertions; using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Middleware; -using JsonApiDotNetCore.Queries; using JsonApiDotNetCore.Repositories; using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Services; @@ -10,7 +8,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Moq; using TestBuildingBlocks; using Xunit; @@ -18,45 +15,26 @@ namespace DiscoveryTests; public sealed class ServiceDiscoveryFacadeTests { - private static readonly ILoggerFactory LoggerFactory = NullLoggerFactory.Instance; - private readonly IServiceCollection _services = new ServiceCollection(); - private readonly ResourceGraphBuilder _resourceGraphBuilder; + private readonly ServiceCollection _services = new(); public ServiceDiscoveryFacadeTests() { - var dbResolverMock = new Mock(); - dbResolverMock.Setup(resolver => resolver.GetContext()).Returns(new Mock().Object); - _services.AddScoped(_ => dbResolverMock.Object); - - IJsonApiOptions options = new JsonApiOptions(); - - _services.AddSingleton(options); - _services.AddSingleton(LoggerFactory); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(typeof(IResourceChangeTracker<>), typeof(ResourceChangeTracker<>)); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - _services.AddScoped(_ => new Mock().Object); - - _resourceGraphBuilder = new ResourceGraphBuilder(options, LoggerFactory); + _services.AddSingleton(_ => NullLoggerFactory.Instance); + _services.AddScoped(_ => new FakeDbContextResolver()); } [Fact] public void Can_add_resources_from_assembly_to_graph() { // Arrange - var facade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, LoggerFactory); - facade.AddAssembly(typeof(Person).Assembly); + Action addAction = facade => facade.AddAssembly(typeof(Person).Assembly); // Act - facade.DiscoverResources(); + _services.AddJsonApi(discovery: facade => addAction(facade)); // Assert - IResourceGraph resourceGraph = _resourceGraphBuilder.Build(); + ServiceProvider serviceProvider = _services.BuildServiceProvider(); + var resourceGraph = serviceProvider.GetRequiredService(); ResourceType? personType = resourceGraph.FindResourceType(typeof(Person)); personType.ShouldNotBeNull(); @@ -69,33 +47,32 @@ public void Can_add_resources_from_assembly_to_graph() public void Can_add_resource_from_current_assembly_to_graph() { // Arrange - var facade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, LoggerFactory); - facade.AddCurrentAssembly(); + Action addAction = facade => facade.AddCurrentAssembly(); // Act - facade.DiscoverResources(); + _services.AddJsonApi(discovery: facade => addAction(facade)); // Assert - IResourceGraph resourceGraph = _resourceGraphBuilder.Build(); + ServiceProvider serviceProvider = _services.BuildServiceProvider(); + var resourceGraph = serviceProvider.GetRequiredService(); - ResourceType? testResourceType = resourceGraph.FindResourceType(typeof(PrivateResource)); - testResourceType.ShouldNotBeNull(); + ResourceType? resourceType = resourceGraph.FindResourceType(typeof(PrivateResource)); + resourceType.ShouldNotBeNull(); } [Fact] public void Can_add_resource_service_from_current_assembly_to_container() { // Arrange - var facade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, LoggerFactory); - facade.AddCurrentAssembly(); + Action addAction = facade => facade.AddCurrentAssembly(); // Act - facade.DiscoverInjectables(); + _services.AddJsonApi(discovery: facade => addAction(facade)); // Assert - ServiceProvider services = _services.BuildServiceProvider(); + ServiceProvider serviceProvider = _services.BuildServiceProvider(); + var resourceService = serviceProvider.GetRequiredService>(); - var resourceService = services.GetRequiredService>(); resourceService.Should().BeOfType(); } @@ -103,16 +80,15 @@ public void Can_add_resource_service_from_current_assembly_to_container() public void Can_add_resource_repository_from_current_assembly_to_container() { // Arrange - var facade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, LoggerFactory); - facade.AddCurrentAssembly(); + Action addAction = facade => facade.AddCurrentAssembly(); // Act - facade.DiscoverInjectables(); + _services.AddJsonApi(discovery: facade => addAction(facade)); // Assert - ServiceProvider services = _services.BuildServiceProvider(); + ServiceProvider serviceProvider = _services.BuildServiceProvider(); + var resourceRepository = serviceProvider.GetRequiredService>(); - var resourceRepository = services.GetRequiredService>(); resourceRepository.Should().BeOfType(); } @@ -120,16 +96,35 @@ public void Can_add_resource_repository_from_current_assembly_to_container() public void Can_add_resource_definition_from_current_assembly_to_container() { // Arrange - var facade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, LoggerFactory); - facade.AddCurrentAssembly(); + Action addAction = facade => facade.AddCurrentAssembly(); // Act - facade.DiscoverInjectables(); + _services.AddJsonApi(discovery: facade => addAction(facade)); // Assert - ServiceProvider services = _services.BuildServiceProvider(); + ServiceProvider serviceProvider = _services.BuildServiceProvider(); + var resourceDefinition = serviceProvider.GetRequiredService>(); - var resourceDefinition = services.GetRequiredService>(); resourceDefinition.Should().BeOfType(); } + + private sealed class FakeDbContextResolver : IDbContextResolver + { + private readonly FakeDbContextOptions _dbContextOptions = new(); + + public DbContext GetContext() + { + return new DbContext(_dbContextOptions); + } + + private sealed class FakeDbContextOptions : DbContextOptions + { + public override Type ContextType => typeof(object); + + public override DbContextOptions WithExtension(TExtension extension) + { + return this; + } + } + } } diff --git a/test/UnitTests/Middleware/JsonApiRequestTests.cs b/test/JsonApiDotNetCoreTests/UnitTests/Middleware/JsonApiMiddlewareTests.cs similarity index 85% rename from test/UnitTests/Middleware/JsonApiRequestTests.cs rename to test/JsonApiDotNetCoreTests/UnitTests/Middleware/JsonApiMiddlewareTests.cs index aad627371d..a57f5ff5b0 100644 --- a/test/UnitTests/Middleware/JsonApiRequestTests.cs +++ b/test/JsonApiDotNetCoreTests/UnitTests/Middleware/JsonApiMiddlewareTests.cs @@ -7,17 +7,17 @@ using JsonApiDotNetCore.Resources.Annotations; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.Extensions.Logging.Abstractions; -using Moq; using TestBuildingBlocks; using Xunit; #pragma warning disable AV1561 // Signature contains too many parameters -namespace UnitTests.Middleware; +namespace JsonApiDotNetCoreTests.UnitTests.Middleware; -public sealed class JsonApiRequestTests +public sealed class JsonApiMiddlewareTests { // @formatter:wrap_lines false [Theory] @@ -65,7 +65,7 @@ public async Task Sets_request_properties_correctly(string requestMethod, string var httpContext = new DefaultHttpContext(); IControllerResourceMapping controllerResourceMapping = SetupRoutes(httpContext, resourceGraph, requestMethod, requestPath); - var middleware = new JsonApiMiddleware(_ => Task.CompletedTask, new HttpContextAccessor + var middleware = new JsonApiMiddleware(null, new HttpContextAccessor { HttpContext = httpContext }); @@ -153,16 +153,10 @@ private static IControllerResourceMapping SetupRoutes(HttpContext httpContext, I ControllerTypeInfo = (TypeInfo)typeof(object) }; - var controllerResourceMappingMock = new Mock(); + httpContext.SetEndpoint(new Endpoint(null, new EndpointMetadataCollection(controllerActionDescriptor), null)); - controllerResourceMappingMock.Setup(mapping => mapping.GetResourceTypeForController(It.IsAny())).Returns(() => - { - return pathSegments.Length > 0 ? resourceGraph.GetResourceTypes().FirstOrDefault(resourceType => resourceType.PublicName == pathSegments[0]) : null; - }); - - httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(controllerActionDescriptor), null)); - - return controllerResourceMappingMock.Object; + string? resourceTypePublicName = pathSegments.Length > 0 ? pathSegments[0] : null; + return new FakeJsonApiRoutingConvention(resourceGraph, resourceTypePublicName); } public enum IsReadOnly @@ -198,4 +192,31 @@ private sealed class TodoItem : Identifiable [HasMany] public ISet Tags { get; set; } = new HashSet(); } + + private sealed class FakeJsonApiRoutingConvention : IJsonApiRoutingConvention + { + private readonly IResourceGraph _resourceGraph; + private readonly string? _resourceTypePublicName; + + public FakeJsonApiRoutingConvention(IResourceGraph resourceGraph, string? resourceTypePublicName) + { + _resourceGraph = resourceGraph; + _resourceTypePublicName = resourceTypePublicName; + } + + public void Apply(ApplicationModel application) + { + throw new NotImplementedException(); + } + + public ResourceType? GetResourceTypeForController(Type? controllerType) + { + return _resourceTypePublicName != null ? _resourceGraph.FindResourceType(_resourceTypePublicName) : null; + } + + public string GetControllerNameForResourceType(ResourceType? resourceType) + { + throw new NotImplementedException(); + } + } } diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index 35ceca88a4..85bcc57484 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -12,6 +12,5 @@ -