diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ISchemaGenerationTraceScope.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ISchemaGenerationTraceScope.cs new file mode 100644 index 0000000000..e9cb25c7ef --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ISchemaGenerationTraceScope.cs @@ -0,0 +1,6 @@ +namespace JsonApiDotNetCore.OpenApi.Swashbuckle; + +internal interface ISchemaGenerationTraceScope : IDisposable +{ + void TraceSucceeded(string schemaId); +} diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs new file mode 100644 index 0000000000..6dbd6bb2f3 --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs @@ -0,0 +1,153 @@ +using JsonApiDotNetCore.Resources.Annotations; +using JsonApiDotNetCore.Serialization.Objects; +using Microsoft.Extensions.Logging; + +namespace JsonApiDotNetCore.OpenApi.Swashbuckle; + +/// +/// Enables to log recursive component schema generation at trace level. +/// +internal sealed partial class SchemaGenerationTracer +{ + private readonly ILoggerFactory _loggerFactory; + + public SchemaGenerationTracer(ILoggerFactory loggerFactory) + { + ArgumentNullException.ThrowIfNull(loggerFactory); + + _loggerFactory = loggerFactory; + } + + public ISchemaGenerationTraceScope TraceStart(object generator) + { + ArgumentNullException.ThrowIfNull(generator); + + return InnerTraceStart(generator, () => "(none)"); + } + + public ISchemaGenerationTraceScope TraceStart(object generator, Type schemaType) + { + ArgumentNullException.ThrowIfNull(generator); + ArgumentNullException.ThrowIfNull(schemaType); + + return InnerTraceStart(generator, () => GetSchemaTypeName(schemaType)); + } + + public ISchemaGenerationTraceScope TraceStart(object generator, AtomicOperationCode operationCode) + { + ArgumentNullException.ThrowIfNull(generator); + + return InnerTraceStart(generator, () => $"{nameof(AtomicOperationCode)}.{operationCode}"); + } + + public ISchemaGenerationTraceScope TraceStart(object generator, RelationshipAttribute relationship) + { + ArgumentNullException.ThrowIfNull(generator); + ArgumentNullException.ThrowIfNull(relationship); + + return InnerTraceStart(generator, + () => $"{GetSchemaTypeName(relationship.GetType())}({GetSchemaTypeName(relationship.LeftType.ClrType)}.{relationship.Property.Name})"); + } + + public ISchemaGenerationTraceScope TraceStart(object generator, Type schemaOpenType, RelationshipAttribute relationship) + { + ArgumentNullException.ThrowIfNull(generator); + ArgumentNullException.ThrowIfNull(schemaOpenType); + ArgumentNullException.ThrowIfNull(relationship); + + return InnerTraceStart(generator, + () => + $"{GetSchemaTypeName(schemaOpenType)} with {GetSchemaTypeName(relationship.GetType())}({GetSchemaTypeName(relationship.LeftType.ClrType)}.{relationship.Property.Name})"); + } + + private ISchemaGenerationTraceScope InnerTraceStart(object generator, Func getSchemaTypeName) + { + ILogger logger = _loggerFactory.CreateLogger(generator.GetType()); + + if (logger.IsEnabled(LogLevel.Trace)) + { + string schemaTypeName = getSchemaTypeName(); + return new SchemaGenerationTraceScope(logger, schemaTypeName); + } + + return DisabledSchemaGenerationTraceScope.Instance; + } + + private static string GetSchemaTypeName(Type type) + { + if (type.IsConstructedGenericType) + { + string typeArguments = string.Join(',', type.GetGenericArguments().Select(GetSchemaTypeName)); + int arityIndex = type.Name.IndexOf('`'); + return $"{type.Name[..arityIndex]}<{typeArguments}>"; + } + + return type.Name; + } + + private sealed partial class SchemaGenerationTraceScope : ISchemaGenerationTraceScope + { + private static readonly AsyncLocal RecursionDepthAsyncLocal = new(); + + private readonly ILogger _logger; + private readonly string _schemaTypeName; + private string? _schemaId; + + public SchemaGenerationTraceScope(ILogger logger, string schemaTypeName) + { + ArgumentNullException.ThrowIfNull(logger); + ArgumentNullException.ThrowIfNull(schemaTypeName); + + _logger = logger; + _schemaTypeName = schemaTypeName; + + RecursionDepthAsyncLocal.Value++; + LogStarted(RecursionDepthAsyncLocal.Value, _schemaTypeName); + } + + public void TraceSucceeded(string schemaId) + { + _schemaId = schemaId; + } + + public void Dispose() + { + if (_schemaId != null) + { + LogSucceeded(RecursionDepthAsyncLocal.Value, _schemaTypeName, _schemaId); + } + else + { + LogFailed(RecursionDepthAsyncLocal.Value, _schemaTypeName); + } + + RecursionDepthAsyncLocal.Value--; + } + + [LoggerMessage(Level = LogLevel.Trace, SkipEnabledCheck = true, Message = "({Depth:D2}) Started for {SchemaTypeName}.")] + private partial void LogStarted(int depth, string schemaTypeName); + + [LoggerMessage(Level = LogLevel.Trace, SkipEnabledCheck = true, Message = "({Depth:D2}) Generated '{SchemaId}' from {SchemaTypeName}.")] + private partial void LogSucceeded(int depth, string schemaTypeName, string schemaId); + + [LoggerMessage(Level = LogLevel.Trace, SkipEnabledCheck = true, Message = "({Depth:D2}) Failed for {SchemaTypeName}.")] + private partial void LogFailed(int depth, string schemaTypeName); + } + + private sealed class DisabledSchemaGenerationTraceScope : ISchemaGenerationTraceScope + { + public static DisabledSchemaGenerationTraceScope Instance { get; } = new(); + + private DisabledSchemaGenerationTraceScope() + { + } + + public void TraceSucceeded(string schemaId) + { + } + + public void Dispose() + { + } + } +} diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs index c4b28c1878..78a25da441 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs @@ -7,12 +7,15 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; internal sealed class AtomicOperationCodeSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly JsonApiSchemaIdSelector _schemaIdSelector; - public AtomicOperationCodeSchemaGenerator(JsonApiSchemaIdSelector schemaIdSelector) + public AtomicOperationCodeSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonApiSchemaIdSelector schemaIdSelector) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(schemaIdSelector); + _schemaGenerationTracer = schemaGenerationTracer; _schemaIdSelector = schemaIdSelector; } @@ -34,6 +37,8 @@ public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRep }; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationCode); + string enumValue = operationCode.ToString().ToLowerInvariant(); var fullSchema = new OpenApiSchema @@ -42,6 +47,9 @@ public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRep Enum = [new OpenApiString(enumValue)] }; - return schemaRepository.AddDefinition(schemaId, fullSchema); + OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + + traceScope.TraceSucceeded(schemaId); + return referenceSchema; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs index 366aa1055d..c4b41dd0f5 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs @@ -12,14 +12,17 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; /// internal sealed class DataContainerSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly DataSchemaGenerator _dataSchemaGenerator; private readonly IResourceGraph _resourceGraph; - public DataContainerSchemaGenerator(DataSchemaGenerator dataSchemaGenerator, IResourceGraph resourceGraph) + public DataContainerSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, DataSchemaGenerator dataSchemaGenerator, IResourceGraph resourceGraph) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(dataSchemaGenerator); ArgumentNullException.ThrowIfNull(resourceGraph); + _schemaGenerationTracer = schemaGenerationTracer; _dataSchemaGenerator = dataSchemaGenerator; _resourceGraph = resourceGraph; } @@ -45,6 +48,13 @@ public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType r Type dataConstructedType = GetElementTypeOfDataProperty(dataContainerSchemaType, resourceType); + if (schemaRepository.TryLookupByType(dataConstructedType, out _)) + { + return referenceSchemaForData; + } + + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, dataConstructedType); + if (canIncludeRelated) { var resourceSchemaType = ResourceSchemaType.Create(dataConstructedType, _resourceGraph); @@ -57,7 +67,9 @@ public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType r } } - return _dataSchemaGenerator.GenerateSchema(dataConstructedType, forRequestSchema, schemaRepository); + referenceSchemaForData = _dataSchemaGenerator.GenerateSchema(dataConstructedType, forRequestSchema, schemaRepository); + traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id); + return referenceSchemaForData; } private static Type GetElementTypeOfDataProperty(Type dataContainerConstructedType, ResourceType resourceType) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs index 66cb83a5c4..4d7783f780 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs @@ -29,6 +29,7 @@ internal sealed class DataSchemaGenerator JsonApiPropertyName.Meta ]; + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly GenerationCacheSchemaGenerator _generationCacheSchemaGenerator; private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator; @@ -42,12 +43,14 @@ internal sealed class DataSchemaGenerator private readonly RelationshipTypeFactory _relationshipTypeFactory; private readonly ResourceDocumentationReader _resourceDocumentationReader; - public DataSchemaGenerator(SchemaGenerator defaultSchemaGenerator, GenerationCacheSchemaGenerator generationCacheSchemaGenerator, - ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, ResourceIdSchemaGenerator resourceIdSchemaGenerator, - LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, MetaSchemaGenerator metaSchemaGenerator, JsonApiSchemaIdSelector schemaIdSelector, - IJsonApiOptions options, IResourceGraph resourceGraph, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider, - RelationshipTypeFactory relationshipTypeFactory, ResourceDocumentationReader resourceDocumentationReader) + public DataSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, + GenerationCacheSchemaGenerator generationCacheSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, + ResourceIdSchemaGenerator resourceIdSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, + MetaSchemaGenerator metaSchemaGenerator, JsonApiSchemaIdSelector schemaIdSelector, IJsonApiOptions options, IResourceGraph resourceGraph, + ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider, RelationshipTypeFactory relationshipTypeFactory, + ResourceDocumentationReader resourceDocumentationReader) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); ArgumentNullException.ThrowIfNull(generationCacheSchemaGenerator); ArgumentNullException.ThrowIfNull(resourceTypeSchemaGenerator); @@ -61,6 +64,7 @@ public DataSchemaGenerator(SchemaGenerator defaultSchemaGenerator, GenerationCac ArgumentNullException.ThrowIfNull(relationshipTypeFactory); ArgumentNullException.ThrowIfNull(resourceDocumentationReader); + _schemaGenerationTracer = schemaGenerationTracer; _defaultSchemaGenerator = defaultSchemaGenerator; _generationCacheSchemaGenerator = generationCacheSchemaGenerator; _resourceTypeSchemaGenerator = resourceTypeSchemaGenerator; @@ -108,6 +112,8 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, return schemaRepository.LookupByType(dataSchemaType); } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, dataSchemaType); + referenceSchemaForData = _defaultSchemaGenerator.GenerateSchema(dataSchemaType, schemaRepository); OpenApiSchema fullSchemaForData = schemaRepository.Schemas[referenceSchemaForData.Reference.Id]; fullSchemaForData.AdditionalPropertiesAllowed = false; @@ -139,6 +145,7 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiBoolean(true); } + traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id); return referenceSchemaForData; } @@ -205,6 +212,8 @@ public OpenApiSchema GenerateSchemaForCommonData(Type commonDataSchemaType, Sche return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonDataSchemaType); + OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); @@ -234,6 +243,7 @@ public OpenApiSchema GenerateSchemaForCommonData(Type commonDataSchemaType, Sche referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(commonDataSchemaType, schemaId); + traceScope.TraceSucceeded(schemaId); return referenceSchema; } @@ -344,7 +354,7 @@ private void SetResourceFields(OpenApiSchema fullSchemaForData, ResourceSchemaTy if (schemaHasFields) { - var fieldSchemaBuilder = new ResourceFieldSchemaBuilder(_defaultSchemaGenerator, this, _linksVisibilitySchemaGenerator, + var fieldSchemaBuilder = new ResourceFieldSchemaBuilder(_schemaGenerationTracer, _defaultSchemaGenerator, this, _linksVisibilitySchemaGenerator, _resourceFieldValidationMetadataProvider, _relationshipTypeFactory, resourceSchemaType); SetFieldSchemaMembers(fullSchemaForData, resourceSchemaType, forRequestSchema, true, fieldSchemaBuilder, schemaRepository); @@ -434,6 +444,8 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonFieldsSchemaType); + OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); var fullSchema = new OpenApiSchema @@ -461,6 +473,7 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(commonFieldsSchemaType, schemaId); + traceScope.TraceSucceeded(schemaId); return referenceSchema; } @@ -557,6 +570,8 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou ResourceSchemaType resourceSchemaTypeForDerived = resourceSchemaType.ChangeResourceType(derivedType); Type derivedSchemaType = resourceSchemaTypeForDerived.SchemaConstructedType; + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, resourceSchemaTypeForDerived.SchemaConstructedType); + OpenApiSchema referenceSchemaForDerived = _defaultSchemaGenerator.GenerateSchema(derivedSchemaType, schemaRepository); OpenApiSchema fullSchemaForDerived = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id]; fullSchemaForDerived.AdditionalPropertiesAllowed = false; @@ -594,6 +609,8 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou } GenerateDataSchemasForDirectlyDerivedTypes(resourceSchemaTypeForDerived, forRequestSchema, schemaRepository); + + traceScope.TraceSucceeded(referenceSchemaForDerived.Reference.Id); } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs index 500250c609..1e1bd07852 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs @@ -6,12 +6,16 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; internal sealed class MetaSchemaGenerator { + private static readonly Type SchemaType = typeof(Meta); + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly JsonApiSchemaIdSelector _schemaIdSelector; - public MetaSchemaGenerator(JsonApiSchemaIdSelector schemaIdSelector) + public MetaSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonApiSchemaIdSelector schemaIdSelector) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(schemaIdSelector); + _schemaGenerationTracer = schemaGenerationTracer; _schemaIdSelector = schemaIdSelector; } @@ -19,11 +23,13 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(typeof(Meta), out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(SchemaType, out OpenApiSchema? referenceSchema)) { return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, SchemaType); + var fullSchema = new OpenApiSchema { Type = "object", @@ -36,8 +42,9 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) string schemaId = _schemaIdSelector.GetMetaSchemaId(); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); - schemaRepository.RegisterType(typeof(Meta), schemaId); + schemaRepository.RegisterType(SchemaType, schemaId); + traceScope.TraceSucceeded(schemaId); return referenceSchema; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs index c4f0ebf556..98f176e8df 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs @@ -8,22 +8,25 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; internal sealed class RelationshipIdentifierSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator; private readonly ResourceIdSchemaGenerator _resourceIdSchemaGenerator; private readonly RelationshipNameSchemaGenerator _relationshipNameSchemaGenerator; private readonly JsonApiSchemaIdSelector _schemaIdSelector; - public RelationshipIdentifierSchemaGenerator(SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, - ResourceIdSchemaGenerator resourceIdSchemaGenerator, RelationshipNameSchemaGenerator relationshipNameSchemaGenerator, - JsonApiSchemaIdSelector schemaIdSelector) + public RelationshipIdentifierSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, + ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, ResourceIdSchemaGenerator resourceIdSchemaGenerator, + RelationshipNameSchemaGenerator relationshipNameSchemaGenerator, JsonApiSchemaIdSelector schemaIdSelector) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); ArgumentNullException.ThrowIfNull(resourceTypeSchemaGenerator); ArgumentNullException.ThrowIfNull(resourceIdSchemaGenerator); ArgumentNullException.ThrowIfNull(relationshipNameSchemaGenerator); ArgumentNullException.ThrowIfNull(schemaIdSelector); + _schemaGenerationTracer = schemaGenerationTracer; _defaultSchemaGenerator = defaultSchemaGenerator; _resourceTypeSchemaGenerator = resourceTypeSchemaGenerator; _resourceIdSchemaGenerator = resourceIdSchemaGenerator; @@ -50,6 +53,8 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe }; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship); + Type relationshipIdentifierConstructedType = typeof(RelationshipIdentifier<>).MakeGenericType(relationship.LeftType.ClrType); ConsistencyGuard.ThrowIf(schemaRepository.TryLookupByType(relationshipIdentifierConstructedType, out _)); @@ -65,6 +70,7 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe schemaRepository.ReplaceSchemaId(relationshipIdentifierConstructedType, schemaId); referenceSchemaForIdentifier.Reference.Id = schemaId; + traceScope.TraceSucceeded(schemaId); return referenceSchemaForIdentifier; } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs index f040a4bad8..7f5c0c5d3a 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs @@ -7,12 +7,15 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; internal sealed class RelationshipNameSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly JsonApiSchemaIdSelector _schemaIdSelector; - public RelationshipNameSchemaGenerator(JsonApiSchemaIdSelector schemaIdSelector) + public RelationshipNameSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonApiSchemaIdSelector schemaIdSelector) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(schemaIdSelector); + _schemaGenerationTracer = schemaGenerationTracer; _schemaIdSelector = schemaIdSelector; } @@ -35,12 +38,17 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe }; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship); + var fullSchema = new OpenApiSchema { Type = "string", Enum = [new OpenApiString(relationship.PublicName)] }; - return schemaRepository.AddDefinition(schemaId, fullSchema); + OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + + traceScope.TraceSucceeded(schemaId); + return referenceSchema; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs index 6a6602088d..21bc5020ed 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs @@ -17,6 +17,8 @@ public ResourceIdSchemaGenerator(SchemaGenerator defaultSchemaGenerator) public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository schemaRepository) { + ArgumentNullException.ThrowIfNull(resourceType); + return GenerateSchema(resourceType.IdentityClrType, schemaRepository); } @@ -26,6 +28,8 @@ public OpenApiSchema GenerateSchema(Type resourceIdClrType, SchemaRepository sch ArgumentNullException.ThrowIfNull(schemaRepository); OpenApiSchema idSchema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository); + ConsistencyGuard.ThrowIf(idSchema.Reference != null); + idSchema.Type = "string"; if (resourceIdClrType != typeof(string)) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs index 9feb84c221..eb933bedbe 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs @@ -8,12 +8,15 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; internal sealed class ResourceTypeSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly JsonApiSchemaIdSelector _schemaIdSelector; - public ResourceTypeSchemaGenerator(JsonApiSchemaIdSelector schemaIdSelector) + public ResourceTypeSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonApiSchemaIdSelector schemaIdSelector) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(schemaIdSelector); + _schemaGenerationTracer = schemaGenerationTracer; _schemaIdSelector = schemaIdSelector; } @@ -27,6 +30,8 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, resourceType.ClrType); + var fullSchema = new OpenApiSchema { Type = "string", @@ -47,6 +52,7 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(resourceType.ClrType, schemaId); + traceScope.TraceSucceeded(schemaId); return referenceSchema; } @@ -66,6 +72,8 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) }; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this); + var fullSchema = new OpenApiSchema { Type = "string", @@ -75,6 +83,9 @@ public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) } }; - return schemaRepository.AddDefinition(schemaId, fullSchema); + OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + + traceScope.TraceSucceeded(schemaId); + return referenceSchema; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs index 49a0002531..f128f89299 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs @@ -20,6 +20,7 @@ internal sealed class AtomicOperationsDocumentSchemaGenerator : DocumentSchemaGe { private static readonly Type AtomicOperationAbstractType = typeof(AtomicOperation); + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly AtomicOperationCodeSchemaGenerator _atomicOperationCodeSchemaGenerator; private readonly DataSchemaGenerator _dataSchemaGenerator; @@ -31,13 +32,13 @@ internal sealed class AtomicOperationsDocumentSchemaGenerator : DocumentSchemaGe private readonly ResourceFieldValidationMetadataProvider _resourceFieldValidationMetadataProvider; private readonly IResourceGraph _resourceGraph; - public AtomicOperationsDocumentSchemaGenerator(SchemaGenerator defaultSchemaGenerator, + public AtomicOperationsDocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, AtomicOperationCodeSchemaGenerator atomicOperationCodeSchemaGenerator, DataSchemaGenerator dataSchemaGenerator, RelationshipIdentifierSchemaGenerator relationshipIdentifierSchemaGenerator, DataContainerSchemaGenerator dataContainerSchemaGenerator, MetaSchemaGenerator metaSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IAtomicOperationFilter atomicOperationFilter, JsonApiSchemaIdSelector schemaIdSelector, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider, IJsonApiOptions options, IResourceGraph resourceGraph) - : base(metaSchemaGenerator, linksVisibilitySchemaGenerator, options) + : base(schemaGenerationTracer, metaSchemaGenerator, linksVisibilitySchemaGenerator, options) { ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); ArgumentNullException.ThrowIfNull(atomicOperationCodeSchemaGenerator); @@ -49,6 +50,7 @@ public AtomicOperationsDocumentSchemaGenerator(SchemaGenerator defaultSchemaGene ArgumentNullException.ThrowIfNull(resourceFieldValidationMetadataProvider); ArgumentNullException.ThrowIfNull(resourceGraph); + _schemaGenerationTracer = schemaGenerationTracer; _defaultSchemaGenerator = defaultSchemaGenerator; _atomicOperationCodeSchemaGenerator = atomicOperationCodeSchemaGenerator; _dataSchemaGenerator = dataSchemaGenerator; @@ -68,6 +70,9 @@ public override bool CanGenerate(Type schemaType) protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) { + ArgumentNullException.ThrowIfNull(schemaType); + ArgumentNullException.ThrowIfNull(schemaRepository); + bool isRequestSchema = schemaType == typeof(OperationsRequestDocument); if (isRequestSchema) @@ -99,6 +104,8 @@ private OpenApiSchema GenerateSchemaForAbstractOperation(SchemaRepository schema return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, AtomicOperationAbstractType); + OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); var fullSchema = new OpenApiSchema @@ -130,6 +137,7 @@ private OpenApiSchema GenerateSchemaForAbstractOperation(SchemaRepository schema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(AtomicOperationAbstractType, schemaId); + traceScope.TraceSucceeded(schemaId); return referenceSchema; } @@ -162,6 +170,9 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource if (IsResourceTypeEnabled(resourceType, writeOperation)) { Type operationConstructedType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType); + + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationConstructedType); + bool needsEmptyDerivedSchema = resourceType.BaseType != null && _atomicOperationFilter.IsEnabled(resourceType.BaseType, writeOperation); if (!needsEmptyDerivedSchema) @@ -197,6 +208,8 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, resourceType); MapInDiscriminator(referenceSchemaForOperation, discriminatorValue, schemaRepository); + + traceScope.TraceSucceeded(referenceSchemaForOperation.Reference.Id); } foreach (ResourceType derivedType in resourceType.DirectlyDerivedTypes) @@ -298,6 +311,8 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela return; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationOpenType, relationship); + RelationshipAttribute? relationshipInAnyBaseResourceType = GetRelationshipEnabledInAnyBase(relationship, writeOperation); OpenApiSchema? referenceSchemaForRelationshipIdentifier; @@ -358,6 +373,8 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, relationship); MapInDiscriminator(referenceSchemaForOperation, discriminatorValue, schemaRepository); + + traceScope.TraceSucceeded(schemaId); } private static WriteOperationKind GetKindOfRelationshipOperation(AtomicOperationCode operationCode) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs index 185fb187ea..740b2fca43 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs @@ -10,17 +10,20 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; /// internal abstract class DocumentSchemaGenerator { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly MetaSchemaGenerator _metaSchemaGenerator; private readonly LinksVisibilitySchemaGenerator _linksVisibilitySchemaGenerator; private readonly IJsonApiOptions _options; - protected DocumentSchemaGenerator(MetaSchemaGenerator metaSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, - IJsonApiOptions options) + protected DocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, MetaSchemaGenerator metaSchemaGenerator, + LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IJsonApiOptions options) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(metaSchemaGenerator); ArgumentNullException.ThrowIfNull(linksVisibilitySchemaGenerator); ArgumentNullException.ThrowIfNull(options); + _schemaGenerationTracer = schemaGenerationTracer; _metaSchemaGenerator = metaSchemaGenerator; _linksVisibilitySchemaGenerator = linksVisibilitySchemaGenerator; _options = options; @@ -38,6 +41,8 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo return referenceSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, schemaType); + _metaSchemaGenerator.GenerateSchema(schemaRepository); referenceSchema = GenerateDocumentSchema(schemaType, schemaRepository); @@ -47,6 +52,7 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo SetJsonApiVersion(fullSchema, schemaRepository); + traceScope.TraceSucceeded(referenceSchema.Reference.Id); return referenceSchema; } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs index 82aa2ccd27..3d305e889b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs @@ -12,15 +12,19 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; /// internal sealed class ErrorResponseDocumentSchemaGenerator : DocumentSchemaGenerator { + private static readonly Type ErrorObjectType = typeof(ErrorObject); + + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly MetaSchemaGenerator _metaSchemaGenerator; - public ErrorResponseDocumentSchemaGenerator(SchemaGenerator defaultSchemaGenerator, MetaSchemaGenerator metaSchemaGenerator, - LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IJsonApiOptions options) - : base(metaSchemaGenerator, linksVisibilitySchemaGenerator, options) + public ErrorResponseDocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, + MetaSchemaGenerator metaSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IJsonApiOptions options) + : base(schemaGenerationTracer, metaSchemaGenerator, linksVisibilitySchemaGenerator, options) { ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); + _schemaGenerationTracer = schemaGenerationTracer; _defaultSchemaGenerator = defaultSchemaGenerator; _metaSchemaGenerator = metaSchemaGenerator; } @@ -32,7 +36,10 @@ public override bool CanGenerate(Type schemaType) protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchemaForErrorObject = _defaultSchemaGenerator.GenerateSchema(typeof(ErrorObject), schemaRepository); + ArgumentNullException.ThrowIfNull(schemaType); + ArgumentNullException.ThrowIfNull(schemaRepository); + + OpenApiSchema referenceSchemaForErrorObject = GenerateSchemaForErrorObject(schemaRepository); OpenApiSchema fullSchemaForErrorObject = schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id]; OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); @@ -40,4 +47,14 @@ protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaR return _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); } + + private OpenApiSchema GenerateSchemaForErrorObject(SchemaRepository schemaRepository) + { + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, ErrorObjectType); + + OpenApiSchema referenceSchema = _defaultSchemaGenerator.GenerateSchema(ErrorObjectType, schemaRepository); + + traceScope.TraceSucceeded(referenceSchema.Reference.Id); + return referenceSchema; + } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs index 289e79e0e0..767f0d0143 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs @@ -37,10 +37,10 @@ internal sealed class ResourceOrRelationshipDocumentSchemaGenerator : DocumentSc private readonly DataContainerSchemaGenerator _dataContainerSchemaGenerator; private readonly IResourceGraph _resourceGraph; - public ResourceOrRelationshipDocumentSchemaGenerator(SchemaGenerator defaultSchemaGenerator, DataContainerSchemaGenerator dataContainerSchemaGenerator, - MetaSchemaGenerator metaSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IJsonApiOptions options, - IResourceGraph resourceGraph) - : base(metaSchemaGenerator, linksVisibilitySchemaGenerator, options) + public ResourceOrRelationshipDocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, + DataContainerSchemaGenerator dataContainerSchemaGenerator, MetaSchemaGenerator metaSchemaGenerator, + LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, IJsonApiOptions options, IResourceGraph resourceGraph) + : base(schemaGenerationTracer, metaSchemaGenerator, linksVisibilitySchemaGenerator, options) { ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); ArgumentNullException.ThrowIfNull(dataContainerSchemaGenerator); @@ -62,17 +62,12 @@ protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaR ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(schemaType, out OpenApiSchema? referenceSchemaForDocument)) - { - return referenceSchemaForDocument; - } - var resourceSchemaType = ResourceSchemaType.Create(schemaType, _resourceGraph); bool isRequestSchema = RequestDocumentSchemaTypes.Contains(resourceSchemaType.SchemaOpenType); _ = _dataContainerSchemaGenerator.GenerateSchema(schemaType, resourceSchemaType.ResourceType, isRequestSchema, !isRequestSchema, schemaRepository); - referenceSchemaForDocument = _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); + OpenApiSchema? referenceSchemaForDocument = _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); OpenApiSchema inlineSchemaForDocument = schemaRepository.Schemas[referenceSchemaForDocument.Reference.Id].UnwrapLastExtendedSchema(); if (JsonApiSchemaFacts.HasNullableDataProperty(resourceSchemaType.SchemaOpenType)) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs index e6d4f4c202..beba632ebf 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs @@ -16,35 +16,41 @@ internal sealed class GenerationCacheSchemaGenerator private const string HasAtomicOperationsEndpointPropertyName = "HasAtomicOperationsEndpoint"; public const string SchemaId = "__JsonApiSchemaGenerationCache__"; + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly IActionDescriptorCollectionProvider _defaultProvider; private readonly JsonApiEndpointMetadataProvider _jsonApiEndpointMetadataProvider; - public GenerationCacheSchemaGenerator(IActionDescriptorCollectionProvider defaultProvider, JsonApiEndpointMetadataProvider jsonApiEndpointMetadataProvider) + public GenerationCacheSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, IActionDescriptorCollectionProvider defaultProvider, + JsonApiEndpointMetadataProvider jsonApiEndpointMetadataProvider) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(defaultProvider); ArgumentNullException.ThrowIfNull(jsonApiEndpointMetadataProvider); + _schemaGenerationTracer = schemaGenerationTracer; _defaultProvider = defaultProvider; _jsonApiEndpointMetadataProvider = jsonApiEndpointMetadataProvider; } public bool HasAtomicOperationsEndpoint(SchemaRepository schemaRepository) { - OpenApiSchema referenceSchema = GenerateFullSchema(schemaRepository); + ArgumentNullException.ThrowIfNull(schemaRepository); + + OpenApiSchema fullSchema = GenerateFullSchema(schemaRepository); - var hasAtomicOperationsEndpoint = (OpenApiBoolean)referenceSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default; + var hasAtomicOperationsEndpoint = (OpenApiBoolean)fullSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default; return hasAtomicOperationsEndpoint.Value; } private OpenApiSchema GenerateFullSchema(SchemaRepository schemaRepository) { - ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.Schemas.TryGetValue(SchemaId, out OpenApiSchema? fullSchema)) { return fullSchema; } + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this); + bool hasAtomicOperationsEndpoint = EvaluateHasAtomicOperationsEndpoint(); fullSchema = new OpenApiSchema @@ -61,7 +67,9 @@ private OpenApiSchema GenerateFullSchema(SchemaRepository schemaRepository) }; schemaRepository.AddDefinition(SchemaId, fullSchema); - return schemaRepository.Schemas[SchemaId]; + + traceScope.TraceSucceeded(SchemaId); + return fullSchema; } private bool EvaluateHasAtomicOperationsEndpoint() diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ServiceCollectionExtensions.cs index f3ef0d189d..5cf4a2da06 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ServiceCollectionExtensions.cs @@ -109,5 +109,7 @@ private static void AddSchemaGenerators(IServiceCollection services) services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); + + services.TryAddSingleton(); } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs index d7dcb25939..31bf7be625 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs @@ -10,6 +10,7 @@ namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; internal sealed class ResourceFieldSchemaBuilder { + private readonly SchemaGenerationTracer _schemaGenerationTracer; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly DataSchemaGenerator _dataSchemaGenerator; private readonly LinksVisibilitySchemaGenerator _linksVisibilitySchemaGenerator; @@ -21,10 +22,12 @@ internal sealed class ResourceFieldSchemaBuilder private readonly ResourceDocumentationReader _resourceDocumentationReader = new(); private readonly IDictionary _schemasForResourceFields; - public ResourceFieldSchemaBuilder(SchemaGenerator defaultSchemaGenerator, DataSchemaGenerator dataSchemaGenerator, - LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider, - RelationshipTypeFactory relationshipTypeFactory, ResourceSchemaType resourceSchemaType) + public ResourceFieldSchemaBuilder(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, + DataSchemaGenerator dataSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, + ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider, RelationshipTypeFactory relationshipTypeFactory, + ResourceSchemaType resourceSchemaType) { + ArgumentNullException.ThrowIfNull(schemaGenerationTracer); ArgumentNullException.ThrowIfNull(defaultSchemaGenerator); ArgumentNullException.ThrowIfNull(dataSchemaGenerator); ArgumentNullException.ThrowIfNull(linksVisibilitySchemaGenerator); @@ -32,6 +35,7 @@ public ResourceFieldSchemaBuilder(SchemaGenerator defaultSchemaGenerator, DataSc ArgumentNullException.ThrowIfNull(resourceFieldValidationMetadataProvider); ArgumentNullException.ThrowIfNull(relationshipTypeFactory); + _schemaGenerationTracer = schemaGenerationTracer; _defaultSchemaGenerator = defaultSchemaGenerator; _dataSchemaGenerator = dataSchemaGenerator; _linksVisibilitySchemaGenerator = linksVisibilitySchemaGenerator; @@ -135,11 +139,15 @@ private void EnsureAttributeSchemaIsExposed(OpenApiSchema referenceSchemaForAttr return; } - string schemaId = referenceSchemaForAttribute.Reference.Id; + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, nonNullableTypeInPropertyType); + string schemaId = referenceSchemaForAttribute.Reference.Id; OpenApiSchema fullSchema = _resourceSchemaRepository.Schemas[schemaId]; + schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(nonNullableTypeInPropertyType, schemaId); + + traceScope.TraceSucceeded(schemaId); } private Type GetRepresentedTypeForAttributeSchema(AttrAttribute attribute) @@ -215,6 +223,8 @@ private Type GetRelationshipSchemaType(RelationshipAttribute relationship, Type private OpenApiSchema CreateReferenceSchemaForRelationship(Type relationshipSchemaType, SchemaRepository schemaRepository) { + using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationshipSchemaType); + OpenApiSchema referenceSchema = _defaultSchemaGenerator.GenerateSchema(relationshipSchemaType, schemaRepository); OpenApiSchema fullSchema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -229,6 +239,7 @@ private OpenApiSchema CreateReferenceSchemaForRelationship(Type relationshipSche _linksVisibilitySchemaGenerator.UpdateSchemaForRelationship(relationshipSchemaType, fullSchema, schemaRepository); } + traceScope.TraceSucceeded(referenceSchema.Reference.Id); return referenceSchema; } diff --git a/test/OpenApiTests/AtomicOperations/OperationsTests.cs b/test/OpenApiTests/AtomicOperations/OperationsTests.cs index 10ca4ac399..f49c10c8a9 100644 --- a/test/OpenApiTests/AtomicOperations/OperationsTests.cs +++ b/test/OpenApiTests/AtomicOperations/OperationsTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.AtomicOperations; @@ -10,16 +11,17 @@ public sealed class OperationsTests : IClassFixture, OperationsDbContext> _testContext; - public OperationsTests(OpenApiTestContext, OperationsDbContext> testContext) + public OperationsTests(OpenApiTestContext, OperationsDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); + testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; + var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); options.IncludeJsonApiVersion = true; - - testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } [Fact] diff --git a/test/OpenApiTests/ClientIdGenerationModes/ClientIdGenerationTests.cs b/test/OpenApiTests/ClientIdGenerationModes/ClientIdGenerationTests.cs index f68dead88a..91f6e20ee4 100644 --- a/test/OpenApiTests/ClientIdGenerationModes/ClientIdGenerationTests.cs +++ b/test/OpenApiTests/ClientIdGenerationModes/ClientIdGenerationTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ClientIdGenerationModes; @@ -8,7 +9,8 @@ public sealed class ClientIdGenerationTests : IClassFixture, ClientIdGenerationDbContext> _testContext; - public ClientIdGenerationTests(OpenApiTestContext, ClientIdGenerationDbContext> testContext) + public ClientIdGenerationTests(OpenApiTestContext, ClientIdGenerationDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -16,6 +18,7 @@ public ClientIdGenerationTests(OpenApiTestContext(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/Documentation/DocumentationTests.cs b/test/OpenApiTests/Documentation/DocumentationTests.cs index 949df2e023..0dfc35d908 100644 --- a/test/OpenApiTests/Documentation/DocumentationTests.cs +++ b/test/OpenApiTests/Documentation/DocumentationTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; // @formatter:max_line_length 250 @@ -17,7 +18,7 @@ public sealed class DocumentationTests : IClassFixture, DocumentationDbContext> _testContext; - public DocumentationTests(OpenApiTestContext, DocumentationDbContext> testContext) + public DocumentationTests(OpenApiTestContext, DocumentationDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -25,6 +26,8 @@ public DocumentationTests(OpenApiTestContext(); testContext.UseController(); testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Fact] diff --git a/test/OpenApiTests/Documentation/ErrorResponseTests.cs b/test/OpenApiTests/Documentation/ErrorResponseTests.cs index 0b72664f5d..0bae066f00 100644 --- a/test/OpenApiTests/Documentation/ErrorResponseTests.cs +++ b/test/OpenApiTests/Documentation/ErrorResponseTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.Documentation; @@ -12,7 +13,8 @@ public sealed class ErrorResponseTests : IClassFixture, DocumentationDbContext> _testContext; - public ErrorResponseTests(OpenApiTestContext, DocumentationDbContext> testContext) + public ErrorResponseTests(OpenApiTestContext, DocumentationDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -20,6 +22,8 @@ public ErrorResponseTests(OpenApiTestContext(); testContext.UseController(); testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Fact] diff --git a/test/OpenApiTests/Headers/HeaderTests.cs b/test/OpenApiTests/Headers/HeaderTests.cs index d900092ad2..4e363b2c89 100644 --- a/test/OpenApiTests/Headers/HeaderTests.cs +++ b/test/OpenApiTests/Headers/HeaderTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.Headers; @@ -9,12 +10,13 @@ public sealed class HeaderTests : IClassFixture, HeaderDbContext> _testContext; - public HeaderTests(OpenApiTestContext, HeaderDbContext> testContext) + public HeaderTests(OpenApiTestContext, HeaderDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/LegacyOpenApi/LegacyTests.cs b/test/OpenApiTests/LegacyOpenApi/LegacyTests.cs index 82a4e80b96..84db211242 100644 --- a/test/OpenApiTests/LegacyOpenApi/LegacyTests.cs +++ b/test/OpenApiTests/LegacyOpenApi/LegacyTests.cs @@ -4,18 +4,20 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.LegacyOpenApi; public sealed class LegacyTests : OpenApiTestContext, LegacyIntegrationDbContext> { - public LegacyTests() + public LegacyTests(ITestOutputHelper testOutputHelper) { UseController(); UseController(); UseController(); UseController(); + SetTestOutputHelper(testOutputHelper); SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/Links/Disabled/LinksDisabledTests.cs b/test/OpenApiTests/Links/Disabled/LinksDisabledTests.cs index 1551866d53..c236ef9b61 100644 --- a/test/OpenApiTests/Links/Disabled/LinksDisabledTests.cs +++ b/test/OpenApiTests/Links/Disabled/LinksDisabledTests.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.Links.Disabled; @@ -12,7 +13,7 @@ public sealed class LinksDisabledTests : IClassFixture, LinkDbContext> _testContext; - public LinksDisabledTests(OpenApiTestContext, LinkDbContext> testContext) + public LinksDisabledTests(OpenApiTestContext, LinkDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -21,6 +22,8 @@ public LinksDisabledTests(OpenApiTestContext, Link testContext.UseController(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); + var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); options.TopLevelLinks = LinkTypes.None; options.ResourceLinks = LinkTypes.NotConfigured; diff --git a/test/OpenApiTests/Links/Enabled/LinksEnabledTests.cs b/test/OpenApiTests/Links/Enabled/LinksEnabledTests.cs index 21b65d07dd..ba476b5756 100644 --- a/test/OpenApiTests/Links/Enabled/LinksEnabledTests.cs +++ b/test/OpenApiTests/Links/Enabled/LinksEnabledTests.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.Resources.Annotations; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.Links.Enabled; @@ -10,7 +11,7 @@ public sealed class LinksEnabledTests : IClassFixture, LinkDbContext> _testContext; - public LinksEnabledTests(OpenApiTestContext, LinkDbContext> testContext) + public LinksEnabledTests(OpenApiTestContext, LinkDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -19,6 +20,7 @@ public LinksEnabledTests(OpenApiTestContext, LinkD testContext.UseController(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/Links/Mixed/LinksMixedTests.cs b/test/OpenApiTests/Links/Mixed/LinksMixedTests.cs index 34b390b88a..3a6be9dc32 100644 --- a/test/OpenApiTests/Links/Mixed/LinksMixedTests.cs +++ b/test/OpenApiTests/Links/Mixed/LinksMixedTests.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.Links.Mixed; @@ -13,7 +14,7 @@ public sealed class LinksMixedTests : IClassFixture, LinkDbContext> _testContext; - public LinksMixedTests(OpenApiTestContext, LinkDbContext> testContext) + public LinksMixedTests(OpenApiTestContext, LinkDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -22,6 +23,7 @@ public LinksMixedTests(OpenApiTestContext, LinkDbC testContext.UseController(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.ConfigureServices(services => services.AddSingleton(CreateResourceGraph)); var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); diff --git a/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs b/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs index e91a7f7f03..3040cb6a26 100644 --- a/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs +++ b/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ModelStateValidation; @@ -16,12 +17,14 @@ public sealed class ModelStateValidationTests : IClassFixture, ModelStateValidationDbContext> _testContext; - public ModelStateValidationTests(OpenApiTestContext, ModelStateValidationDbContext> testContext) + public ModelStateValidationTests(OpenApiTestContext, ModelStateValidationDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index d064c466c9..ac102b673e 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.NamingConventions.CamelCase; @@ -11,7 +12,8 @@ public sealed class CamelCaseTests : IClassFixture, NamingConventionDbContext> _testContext; - public CamelCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public CamelCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -19,6 +21,7 @@ public CamelCaseTests(OpenApiTestContext(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 48a1520a6f..077d7ec5ed 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.NamingConventions.KebabCase; @@ -11,7 +12,8 @@ public sealed class KebabCaseTests : IClassFixture, NamingConventionDbContext> _testContext; - public KebabCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public KebabCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -19,6 +21,7 @@ public KebabCaseTests(OpenApiTestContext(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs index 5cb95663d5..fb5405e6f6 100644 --- a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.NamingConventions.PascalCase; @@ -11,7 +12,8 @@ public sealed class PascalCaseTests : IClassFixture, NamingConventionDbContext> _testContext; - public PascalCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public PascalCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext, + ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -19,6 +21,7 @@ public PascalCaseTests(OpenApiTestContext(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPatchMethodTests.cs b/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPatchMethodTests.cs index b988ebc343..20814f2f80 100644 --- a/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPatchMethodTests.cs +++ b/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPatchMethodTests.cs @@ -1,14 +1,17 @@ using FluentAssertions; using JsonApiDotNetCore.Errors; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.OpenApiGenerationFailures.MissingFromBody; public sealed class MissingFromBodyOnPatchMethodTests : OpenApiTestContext, MissingFromBodyDbContext> { - public MissingFromBodyOnPatchMethodTests() + public MissingFromBodyOnPatchMethodTests(ITestOutputHelper testOutputHelper) { UseController(); + + SetTestOutputHelper(testOutputHelper); } [Fact] diff --git a/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPostMethodTests.cs b/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPostMethodTests.cs index 5725cc732f..a121f058f9 100644 --- a/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPostMethodTests.cs +++ b/test/OpenApiTests/OpenApiGenerationFailures/MissingFromBody/MissingFromBodyOnPostMethodTests.cs @@ -1,14 +1,17 @@ using FluentAssertions; using JsonApiDotNetCore.Errors; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.OpenApiGenerationFailures.MissingFromBody; public sealed class MissingFromBodyOnPostMethodTests : OpenApiTestContext, MissingFromBodyDbContext> { - public MissingFromBodyOnPostMethodTests() + public MissingFromBodyOnPostMethodTests(ITestOutputHelper testOutputHelper) { UseController(); + + SetTestOutputHelper(testOutputHelper); } [Fact] diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index c624f06f2a..7743ab7533 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -1,7 +1,10 @@ using System.Reflection; using System.Text.Json; using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using TestBuildingBlocks; +using Xunit.Abstractions; namespace OpenApiTests; @@ -11,6 +14,7 @@ public class OpenApiTestContext : IntegrationTestContext> _lazySwaggerDocument; + private ITestOutputHelper? _testOutputHelper; internal string? SwaggerDocumentOutputDirectory { get; set; } @@ -39,6 +43,23 @@ private async Task CreateSwaggerDocumentAsync() return rootElement; } + internal void SetTestOutputHelper(ITestOutputHelper testOutputHelper) + { + ArgumentNullException.ThrowIfNull(testOutputHelper); + + _testOutputHelper = testOutputHelper; + ConfigureLogging(AddXUnitProvider); + } + + private void AddXUnitProvider(ILoggingBuilder loggingBuilder) + { + if (_testOutputHelper != null) + { + loggingBuilder.SetMinimumLevel(LogLevel.Trace); + loggingBuilder.Services.AddSingleton(_ => new XUnitLoggerProvider(_testOutputHelper, "JsonApiDotNetCore.OpenApi.Swashbuckle")); + } + } + private static string GetSwaggerDocumentAbsoluteOutputPath(string relativePath) { string testRootDirectory = Path.Combine(Assembly.GetExecutingAssembly().Location, "../../../../../"); diff --git a/test/OpenApiTests/QueryStrings/IncludeTests.cs b/test/OpenApiTests/QueryStrings/IncludeTests.cs index e35ab21621..78c82ad3d8 100644 --- a/test/OpenApiTests/QueryStrings/IncludeTests.cs +++ b/test/OpenApiTests/QueryStrings/IncludeTests.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.QueryStrings; @@ -16,11 +17,13 @@ public sealed class IncludeTests : IClassFixture, QueryStringDbContext> _testContext; - public IncludeTests(OpenApiTestContext, QueryStringDbContext> testContext) + public IncludeTests(OpenApiTestContext, QueryStringDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Fact] diff --git a/test/OpenApiTests/QueryStrings/QueryStringTests.cs b/test/OpenApiTests/QueryStrings/QueryStringTests.cs index 61ffc007ab..f74f773796 100644 --- a/test/OpenApiTests/QueryStrings/QueryStringTests.cs +++ b/test/OpenApiTests/QueryStrings/QueryStringTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.QueryStrings; @@ -9,13 +10,14 @@ public sealed class QueryStringTests : IClassFixture, QueryStringDbContext> _testContext; - public QueryStringTests(OpenApiTestContext, QueryStringDbContext> testContext) + public QueryStringTests(OpenApiTestContext, QueryStringDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/NullabilityTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/NullabilityTests.cs index fb73500b5f..aae027360a 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/NullabilityTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/NullabilityTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOff; @@ -9,11 +10,13 @@ public sealed class NullabilityTests : IClassFixture, NrtOffDbContext> _testContext; - public NullabilityTests(OpenApiTestContext, NrtOffDbContext> testContext) + public NullabilityTests(OpenApiTestContext, NrtOffDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/RequiredTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/RequiredTests.cs index 3d8bc4542c..ece2c6174a 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/RequiredTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/RequiredTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOff; @@ -8,11 +9,13 @@ public sealed class RequiredTests : IClassFixture, NrtOffDbContext> _testContext; - public RequiredTests(OpenApiTestContext, NrtOffDbContext> testContext) + public RequiredTests(OpenApiTestContext, NrtOffDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Theory] diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/NullabilityTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/NullabilityTests.cs index bdb8fdb84e..32c9e93779 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/NullabilityTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/NullabilityTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOn; @@ -9,11 +10,13 @@ public sealed class NullabilityTests : IClassFixture, NrtOffDbContext> _testContext; - public NullabilityTests(OpenApiTestContext, NrtOffDbContext> testContext) + public NullabilityTests(OpenApiTestContext, NrtOffDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/RequiredTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/RequiredTests.cs index 42e2efc614..46a45ac2fd 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/RequiredTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/RequiredTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOn; @@ -8,11 +9,13 @@ public sealed class RequiredTests : IClassFixture, NrtOffDbContext> _testContext; - public RequiredTests(OpenApiTestContext, NrtOffDbContext> testContext) + public RequiredTests(OpenApiTestContext, NrtOffDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Theory] diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/NullabilityTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/NullabilityTests.cs index 5c795c8cad..084cb85fde 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/NullabilityTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/NullabilityTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOff; @@ -9,11 +10,13 @@ public sealed class NullabilityTests : IClassFixture, NrtOnDbContext> _testContext; - public NullabilityTests(OpenApiTestContext, NrtOnDbContext> testContext) + public NullabilityTests(OpenApiTestContext, NrtOnDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/RequiredTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/RequiredTests.cs index c4512e4cfd..64ee1c433e 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/RequiredTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/RequiredTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOff; @@ -8,11 +9,13 @@ public sealed class RequiredTests : IClassFixture, NrtOnDbContext> _testContext; - public RequiredTests(OpenApiTestContext, NrtOnDbContext> testContext) + public RequiredTests(OpenApiTestContext, NrtOnDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Theory] diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/NullabilityTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/NullabilityTests.cs index 6a0bbac52c..8617f3cd28 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/NullabilityTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/NullabilityTests.cs @@ -2,6 +2,7 @@ using FluentAssertions; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOn; @@ -9,11 +10,13 @@ public sealed class NullabilityTests : IClassFixture, NrtOnDbContext> _testContext; - public NullabilityTests(OpenApiTestContext, NrtOnDbContext> testContext) + public NullabilityTests(OpenApiTestContext, NrtOnDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; } diff --git a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/RequiredTests.cs b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/RequiredTests.cs index 11d9e02bca..ad70bcfdeb 100644 --- a/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/RequiredTests.cs +++ b/test/OpenApiTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/RequiredTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOn; @@ -8,11 +9,13 @@ public sealed class RequiredTests : IClassFixture, NrtOnDbContext> _testContext; - public RequiredTests(OpenApiTestContext, NrtOnDbContext> testContext) + public RequiredTests(OpenApiTestContext, NrtOnDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); } [Theory] diff --git a/test/OpenApiTests/ResourceInheritance/Everything/EverythingInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/Everything/EverythingInheritanceTests.cs index 57240b59e5..09ff3fb81a 100644 --- a/test/OpenApiTests/ResourceInheritance/Everything/EverythingInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/Everything/EverythingInheritanceTests.cs @@ -1,13 +1,15 @@ using JsonApiDotNetCore.Controllers; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format namespace OpenApiTests.ResourceInheritance.Everything; -public sealed class EverythingInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : ResourceInheritanceTests(testContext, true, false) +public sealed class EverythingInheritanceTests( + OpenApiTestContext, ResourceInheritanceDbContext> testContext, ITestOutputHelper testOutputHelper) + : ResourceInheritanceTests(testContext, testOutputHelper, true, false) { [Theory] [InlineData(typeof(District), JsonApiEndpoints.All)] diff --git a/test/OpenApiTests/ResourceInheritance/NoOperations/NoOperationsInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/NoOperations/NoOperationsInheritanceTests.cs index 47666a3550..c057fdacc7 100644 --- a/test/OpenApiTests/ResourceInheritance/NoOperations/NoOperationsInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/NoOperations/NoOperationsInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -11,8 +12,9 @@ namespace OpenApiTests.ResourceInheritance.NoOperations; public sealed class NoOperationsInheritanceTests : ResourceInheritanceTests { - public NoOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, true) + public NoOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, true) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/OnlyAbstract/OnlyAbstractInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/OnlyAbstract/OnlyAbstractInheritanceTests.cs index ddcb24baaf..5efacb7f17 100644 --- a/test/OpenApiTests/ResourceInheritance/OnlyAbstract/OnlyAbstractInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/OnlyAbstract/OnlyAbstractInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -11,8 +12,9 @@ namespace OpenApiTests.ResourceInheritance.OnlyAbstract; public sealed class OnlyAbstractInheritanceTests : ResourceInheritanceTests { - public OnlyAbstractInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, false) + public OnlyAbstractInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, false) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/OnlyConcrete/OnlyConcreteInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/OnlyConcrete/OnlyConcreteInheritanceTests.cs index 0e8e30f499..6a0f9742df 100644 --- a/test/OpenApiTests/ResourceInheritance/OnlyConcrete/OnlyConcreteInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/OnlyConcrete/OnlyConcreteInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -11,8 +12,9 @@ namespace OpenApiTests.ResourceInheritance.OnlyConcrete; public sealed class OnlyConcreteInheritanceTests : ResourceInheritanceTests { - public OnlyConcreteInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, false) + public OnlyConcreteInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, false) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/OnlyOperations/OnlyOperationsInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/OnlyOperations/OnlyOperationsInheritanceTests.cs index f13e5f8c08..94ada069cc 100644 --- a/test/OpenApiTests/ResourceInheritance/OnlyOperations/OnlyOperationsInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/OnlyOperations/OnlyOperationsInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -11,8 +12,9 @@ namespace OpenApiTests.ResourceInheritance.OnlyOperations; public sealed class OnlyOperationsInheritanceTests : ResourceInheritanceTests { - public OnlyOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, false) + public OnlyOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, false) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/OnlyRelationships/OnlyRelationshipsInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/OnlyRelationships/OnlyRelationshipsInheritanceTests.cs index 49d5d48333..8d41ebaf68 100644 --- a/test/OpenApiTests/ResourceInheritance/OnlyRelationships/OnlyRelationshipsInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/OnlyRelationships/OnlyRelationshipsInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -14,8 +15,9 @@ public sealed class OnlyRelationshipsInheritanceTests : ResourceInheritanceTests private const JsonApiEndpoints OnlyRelationshipEndpoints = JsonApiEndpoints.GetRelationship | JsonApiEndpoints.PostRelationship | JsonApiEndpoints.PatchRelationship | JsonApiEndpoints.DeleteRelationship; - public OnlyRelationshipsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, true) + public OnlyRelationshipsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, true) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/ResourceInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/ResourceInheritanceTests.cs index f2c05660f6..7455c0c899 100644 --- a/test/OpenApiTests/ResourceInheritance/ResourceInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/ResourceInheritanceTests.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; #pragma warning disable AV1755 // Name of async method should end with Async or TaskAsync @@ -16,11 +17,12 @@ public abstract class ResourceInheritanceTests : IClassFixture, ResourceInheritanceDbContext> _testContext; protected ResourceInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, - bool hasOperationsController, bool writeToDisk) + ITestOutputHelper testOutputHelper, bool hasOperationsController, bool writeToDisk) { _testContext = testContext; testContext.UseInheritanceControllers(hasOperationsController); + testContext.SetTestOutputHelper(testOutputHelper); if (writeToDisk) { diff --git a/test/OpenApiTests/ResourceInheritance/SubsetOfOperations/SubsetOfOperationsInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/SubsetOfOperations/SubsetOfOperationsInheritanceTests.cs index 5496f98956..7d49d6b2ea 100644 --- a/test/OpenApiTests/ResourceInheritance/SubsetOfOperations/SubsetOfOperationsInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/SubsetOfOperations/SubsetOfOperationsInheritanceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; #pragma warning disable format @@ -11,8 +12,9 @@ namespace OpenApiTests.ResourceInheritance.SubsetOfOperations; public sealed class SubsetOfOperationsInheritanceTests : ResourceInheritanceTests { - public SubsetOfOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, true, true) + public SubsetOfOperationsInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, true, true) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/ResourceInheritance/SubsetOfVarious/SubsetOfVariousInheritanceTests.cs b/test/OpenApiTests/ResourceInheritance/SubsetOfVarious/SubsetOfVariousInheritanceTests.cs index 069d4be369..24de06c72a 100644 --- a/test/OpenApiTests/ResourceInheritance/SubsetOfVarious/SubsetOfVariousInheritanceTests.cs +++ b/test/OpenApiTests/ResourceInheritance/SubsetOfVarious/SubsetOfVariousInheritanceTests.cs @@ -4,13 +4,15 @@ using Microsoft.Extensions.DependencyInjection; using OpenApiTests.ResourceInheritance.Models; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.ResourceInheritance.SubsetOfVarious; public sealed class SubsetOfVariousInheritanceTests : ResourceInheritanceTests { - public SubsetOfVariousInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext) - : base(testContext, false, true) + public SubsetOfVariousInheritanceTests(OpenApiTestContext, ResourceInheritanceDbContext> testContext, + ITestOutputHelper testOutputHelper) + : base(testContext, testOutputHelper, false, true) { testContext.ConfigureServices(services => { diff --git a/test/OpenApiTests/RestrictedControllers/RestrictionTests.cs b/test/OpenApiTests/RestrictedControllers/RestrictionTests.cs index 2938f6867e..061b6b4733 100644 --- a/test/OpenApiTests/RestrictedControllers/RestrictionTests.cs +++ b/test/OpenApiTests/RestrictedControllers/RestrictionTests.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using TestBuildingBlocks; using Xunit; +using Xunit.Abstractions; namespace OpenApiTests.RestrictedControllers; @@ -12,7 +13,7 @@ public sealed class RestrictionTests : IClassFixture, RestrictionDbContext> _testContext; - public RestrictionTests(OpenApiTestContext, RestrictionDbContext> testContext) + public RestrictionTests(OpenApiTestContext, RestrictionDbContext> testContext, ITestOutputHelper testOutputHelper) { _testContext = testContext; @@ -22,6 +23,7 @@ public RestrictionTests(OpenApiTestContext, testContext.UseController(); testContext.UseController(); + testContext.SetTestOutputHelper(testOutputHelper); testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; }