diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0c4152f..ad52741 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2023.2.3", + "version": "2023.3.0-eap08", "commands": [ "jb" ] @@ -15,7 +15,7 @@ ] }, "dotnet-reportgenerator-globaltool": { - "version": "5.1.26", + "version": "5.2.0", "commands": [ "reportgenerator" ] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a45d71e..d204896 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,6 @@ --- name: Bug report -about: Create a report to help us improve +about: Create a report to help us improve. title: '' labels: 'bug' assignees: '' diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..8bf0a91 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: true +contact_links: +- name: Documentation + url: https://www.jsonapi.net/usage/resources/index.html + about: Read our comprehensive documentation. +- name: Sponsor JsonApiDotNetCore + url: https://github.com/sponsors/json-api-dotnet + about: Help the continued development. +- name: Ask on Gitter + url: https://gitter.im/json-api-dotnet-core/Lobby + about: Get in touch with the whole community. +- name: Ask on Stack Overflow + url: https://stackoverflow.com/questions/tagged/json-api + about: The best place for asking general-purpose questions. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index f629ca4..019f7a9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,6 @@ --- name: Feature request -about: Suggest an idea for this project +about: Suggest an idea for this project. title: '' labels: 'enhancement' assignees: '' diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 76b3998..2520ad8 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,6 +1,6 @@ --- name: Question -about: Ask a question +about: Ask a question. title: '' labels: 'question' assignees: '' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc41703..881e2ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.x + dotnet-version: | + 6.0.x + 8.0.x - name: Setup PowerShell (Ubuntu) if: matrix.os == 'ubuntu-latest' run: | @@ -118,10 +120,13 @@ jobs: dotnet build --no-restore --configuration Release /p:VersionSuffix=$env:PACKAGE_VERSION_SUFFIX - name: Test run: | - dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" --logger "GitHubActions;summary.includeSkippedTests=true" -- RunConfiguration.CollectSourceInformation=true DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true + dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" --logger "GitHubActions;summary.includeSkippedTests=true" - name: Upload coverage to codecov.io if: matrix.os == 'ubuntu-latest' uses: codecov/codecov-action@v3 + with: + fail_ci_if_error: true + verbose: true - name: Generate packages shell: pwsh run: | @@ -146,7 +151,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.x + dotnet-version: | + 6.0.x + 8.0.x - name: Git checkout uses: actions/checkout@v4 - name: Restore tools @@ -157,7 +164,7 @@ jobs: run: | $inspectCodeOutputPath = Join-Path $env:RUNNER_TEMP 'jetbrains-inspectcode-results.xml' Write-Output "INSPECT_CODE_OUTPUT_PATH=$inspectCodeOutputPath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - dotnet jb inspectcode JsonApiDotNetCore.MongoDb.sln --build --output="$inspectCodeOutputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --properties:ContinuousIntegrationBuild=false --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal + dotnet jb inspectcode JsonApiDotNetCore.MongoDb.sln --build --dotnetcoresdk=$(dotnet --version) --output="$inspectCodeOutputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --properties:ContinuousIntegrationBuild=false --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal - name: Verify outcome shell: pwsh run: | @@ -197,7 +204,9 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.x + dotnet-version: | + 6.0.x + 8.0.x - name: Git checkout uses: actions/checkout@v4 with: @@ -218,13 +227,13 @@ jobs: $baseCommitHash = git rev-parse HEAD~1 Write-Output "Running code cleanup on commit range $baseCommitHash..$headCommitHash in pull request." - dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f commits -a $headCommitHash -b $baseCommitHash --fail-on-diff --print-diff + dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f commits -a $headCommitHash -b $baseCommitHash --fail-on-diff --print-diff - name: CleanupCode (on branch) if: github.event_name == 'push' || github.event_name == 'release' shell: pwsh run: | Write-Output "Running code cleanup on all files." - dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN --fail-on-diff --print-diff + dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN --fail-on-diff --print-diff publish: timeout-minutes: 60 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..5b1868e --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,43 @@ +name: "CodeQL" + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'master', 'release/**' ] + schedule: + - cron: '0 0 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: 'ubuntu-latest' + timeout-minutes: 60 + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + steps: + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 6.0.x + 8.0.x + - name: Git checkout + uses: actions/checkout@v4 + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/deps-review.yml b/.github/workflows/deps-review.yml new file mode 100644 index 0000000..b994508 --- /dev/null +++ b/.github/workflows/deps-review.yml @@ -0,0 +1,14 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 diff --git a/Build.ps1 b/Build.ps1 index 4854651..3abc926 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -10,13 +10,16 @@ Write-Host "$(pwsh --version)" Write-Host "Active .NET SDK: $(dotnet --version)" Write-Host "Using version suffix: $versionSuffix" +Remove-Item -Recurse -Force artifacts -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force * -Include coverage.cobertura.xml + dotnet tool restore VerifySuccessExitCode dotnet build --configuration Release /p:VersionSuffix=$versionSuffix VerifySuccessExitCode -dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true +dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" VerifySuccessExitCode dotnet reportgenerator -reports:**\coverage.cobertura.xml -targetdir:artifacts\coverage -filefilters:-*.g.cs diff --git a/Directory.Build.props b/Directory.Build.props index 2b53cab..dbaf920 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,9 @@ - + $(NoWarn);AV2210 - + $(NoWarn);1591 true true @@ -13,42 +13,20 @@ true - - - net6.0 - 5.4.0 - 2.20.0 - - 4.1.0 - - - 6.0.* - 34.0.* - 3.8.* - 6.0.* - 1.1.* - 6.12.* - 2.3.* - 1.3.* - 2023.3.* - 2.21.* - 1.1.* - 17.8.* - 2.5.* - - - - + + enable + latest enable false false $(MSBuildThisFileDirectory)CodingGuidelines.ruleset - 5.4.1 + $(MSBuildThisFileDirectory)tests.runsettings + 5.5.0 diff --git a/JsonApiDotNetCore.MongoDb.sln b/JsonApiDotNetCore.MongoDb.sln index 0f6c7b7..81b5b78 100644 --- a/JsonApiDotNetCore.MongoDb.sln +++ b/JsonApiDotNetCore.MongoDb.sln @@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution CodingGuidelines.ruleset = CodingGuidelines.ruleset CSharpGuidelinesAnalyzer.config = CSharpGuidelinesAnalyzer.config Directory.Build.props = Directory.Build.props + tests.runsettings = tests.runsettings + package-versions.props = package-versions.props EndProjectSection EndProject Global diff --git a/JsonApiDotNetCore.MongoDb.sln.DotSettings b/JsonApiDotNetCore.MongoDb.sln.DotSettings index 8e89021..d7699ea 100644 --- a/JsonApiDotNetCore.MongoDb.sln.DotSettings +++ b/JsonApiDotNetCore.MongoDb.sln.DotSettings @@ -66,6 +66,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$); WARNING WARNING WARNING + SUGGESTION SUGGESTION SUGGESTION DO_NOT_SHOW @@ -92,7 +93,9 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$); WARNING SUGGESTION SUGGESTION + SUGGESTION WARNING + SUGGESTION <?xml version="1.0" encoding="utf-16"?><Profile name="JADNC Full Cleanup"><XMLReformatCode>True</XMLReformatCode><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CssAlphabetizeProperties>True</CssAlphabetizeProperties><JsInsertSemicolon>True</JsInsertSemicolon><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CorrectVariableKindsDescriptor>True</CorrectVariableKindsDescriptor><VariablesToInnerScopesDescriptor>True</VariablesToInnerScopesDescriptor><StringToTemplatesDescriptor>True</StringToTemplatesDescriptor><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><RemoveRedundantQualifiersTs>True</RemoveRedundantQualifiersTs><OptimizeImportsTs>True</OptimizeImportsTs><OptimizeReferenceCommentsTs>True</OptimizeReferenceCommentsTs><PublicModifierStyleTs>True</PublicModifierStyleTs><ExplicitAnyTs>True</ExplicitAnyTs><TypeAnnotationStyleTs>True</TypeAnnotationStyleTs><RelativePathStyleTs>True</RelativePathStyleTs><AsInsteadOfCastTs>True</AsInsteadOfCastTs><HtmlReformatCode>True</HtmlReformatCode><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CssReformatCode>True</CssReformatCode><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSReformatInactiveBranches>True</CSReformatInactiveBranches></Profile> JADNC Full Cleanup Required @@ -113,6 +116,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$); True True True + INDENT 1 1 False @@ -125,6 +129,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$); False False True + 1 NEVER NEVER False @@ -145,6 +150,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$); True WRAP_IF_LONG 160 + CHOP_IF_LONG WRAP_IF_LONG CHOP_ALWAYS CHOP_ALWAYS diff --git a/WarningSeverities.DotSettings b/WarningSeverities.DotSettings index 96f358d..5c641e6 100644 --- a/WarningSeverities.DotSettings +++ b/WarningSeverities.DotSettings @@ -124,6 +124,7 @@ WARNING WARNING WARNING + WARNING WARNING WARNING WARNING @@ -163,6 +164,7 @@ WARNING WARNING WARNING + WARNING WARNING WARNING WARNING @@ -240,6 +242,7 @@ WARNING WARNING WARNING + WARNING WARNING WARNING WARNING @@ -258,10 +261,12 @@ WARNING WARNING WARNING + WARNING WARNING WARNING WARNING WARNING WARNING WARNING + WARNING \ No newline at end of file diff --git a/cleanupcode.ps1 b/cleanupcode.ps1 index 23f2a36..a593bd9 100644 --- a/cleanupcode.ps1 +++ b/cleanupcode.ps1 @@ -28,17 +28,17 @@ if ($revision) { if ($baseCommitHash -eq $headCommitHash) { Write-Output "Running code cleanup on staged/unstaged files." - dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f staged,modified + dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f staged,modified VerifySuccessExitCode } else { Write-Output "Running code cleanup on commit range $baseCommitHash..$headCommitHash, including staged/unstaged files." - dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f staged,modified,commits -a $headCommitHash -b $baseCommitHash + dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f staged,modified,commits -a $headCommitHash -b $baseCommitHash VerifySuccessExitCode } } else { Write-Output "Running code cleanup on all files." - dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN + dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN VerifySuccessExitCode } diff --git a/inspectcode.ps1 b/inspectcode.ps1 index dc81b09..13f0abb 100644 --- a/inspectcode.ps1 +++ b/inspectcode.ps1 @@ -10,7 +10,7 @@ if ($LastExitCode -ne 0) { $outputPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'jetbrains-inspectcode-results.xml') $resultPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'jetbrains-inspectcode-results.html') -dotnet jb inspectcode JsonApiDotNetCore.MongoDb.sln --build --output="$outputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal +dotnet jb inspectcode JsonApiDotNetCore.MongoDb.sln --dotnetcoresdk=$(dotnet --version) --build --output="$outputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal if ($LastExitCode -ne 0) { throw "Code inspection failed with exit code $LastExitCode" diff --git a/package-versions.props b/package-versions.props new file mode 100644 index 0000000..6d226f5 --- /dev/null +++ b/package-versions.props @@ -0,0 +1,29 @@ + + + + 5.5.0 + 2.20.0 + + + 34.0.* + 6.0.* + 1.1.* + 6.12.* + 2.3.* + 1.3.* + 2.22.* + 8.0.* + 17.8.* + 2.5.* + + + + + 8.0.* + + + + + 6.0.* + + diff --git a/run-docker-mongodb.ps1 b/run-docker-mongodb.ps1 index b1092b4..215b048 100644 --- a/run-docker-mongodb.ps1 +++ b/run-docker-mongodb.ps1 @@ -1,9 +1,6 @@ #Requires -Version 7.0 -# This script starts a docker container with MongoDB database, used for running tests. +# This script starts a MongoDB database in a docker container, which is required for running examples locally. -docker container stop jsonapi-dotnet-core-mongodb-testing - -docker run --rm --name jsonapi-dotnet-core-mongodb-testing ` - -p 27017:27017 ` - mongo:latest +docker container stop jsonapi-mongo-db +docker run --pull always --rm --detach --name jsonapi-mongo-db -p 27017:27017 mongo:latest diff --git a/src/Examples/GettingStarted/GettingStarted.csproj b/src/Examples/GettingStarted/GettingStarted.csproj index a5b25ea..0f6b40f 100644 --- a/src/Examples/GettingStarted/GettingStarted.csproj +++ b/src/Examples/GettingStarted/GettingStarted.csproj @@ -1,8 +1,10 @@ - $(TargetFrameworkName) + net8.0;net6.0 + + diff --git a/src/Examples/GettingStarted/Program.cs b/src/Examples/GettingStarted/Program.cs index e28c933..7deafcc 100644 --- a/src/Examples/GettingStarted/Program.cs +++ b/src/Examples/GettingStarted/Program.cs @@ -2,23 +2,20 @@ using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.MongoDb.Configuration; using JsonApiDotNetCore.MongoDb.Repositories; +using Microsoft.Extensions.DependencyInjection.Extensions; using MongoDB.Driver; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. -builder.Services.AddSingleton(_ => +builder.Services.TryAddSingleton(_ => { var client = new MongoClient(builder.Configuration.GetSection("DatabaseSettings:ConnectionString").Value); return client.GetDatabase(builder.Configuration.GetSection("DatabaseSettings:Database").Value); }); -builder.Services.AddJsonApi(ConfigureJsonApiOptions, resources: resourceGraphBuilder => -{ - resourceGraphBuilder.Add(); -}); - +builder.Services.AddJsonApi(ConfigureJsonApiOptions, resources: resourceGraphBuilder => resourceGraphBuilder.Add()); builder.Services.AddJsonApiMongoDb(); builder.Services.AddResourceRepository>(); diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs b/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs index 61027b4..970a061 100644 --- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs +++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs @@ -5,20 +5,30 @@ using JsonApiDotNetCore.Queries.Expressions; using JsonApiDotNetCore.Resources; using JsonApiDotNetCoreMongoDbExample.Models; +#if NET6_0 using Microsoft.AspNetCore.Authentication; +#endif namespace JsonApiDotNetCoreMongoDbExample.Definitions; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] public sealed class TodoItemDefinition : JsonApiResourceDefinition { - private readonly ISystemClock _systemClock; + private readonly Func _getUtcNow; +#if NET6_0 public TodoItemDefinition(IResourceGraph resourceGraph, ISystemClock systemClock) : base(resourceGraph) { - _systemClock = systemClock; + _getUtcNow = () => systemClock.UtcNow; } +#else + public TodoItemDefinition(IResourceGraph resourceGraph, TimeProvider timeProvider) + : base(resourceGraph) + { + _getUtcNow = timeProvider.GetUtcNow; + } +#endif public override SortExpression OnApplySort(SortExpression? existingSort) { @@ -27,22 +37,21 @@ public override SortExpression OnApplySort(SortExpression? existingSort) private SortExpression GetDefaultSortOrder() { - return CreateSortExpressionFromLambda(new PropertySortOrder - { + return CreateSortExpressionFromLambda([ (todoItem => todoItem.Priority, ListSortDirection.Ascending), (todoItem => todoItem.LastModifiedAt, ListSortDirection.Descending) - }); + ]); } public override Task OnWritingAsync(TodoItem resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) { if (writeOperation == WriteOperationKind.CreateResource) { - resource.CreatedAt = _systemClock.UtcNow; + resource.CreatedAt = _getUtcNow(); } else if (writeOperation == WriteOperationKind.UpdateResource) { - resource.LastModifiedAt = _systemClock.UtcNow; + resource.LastModifiedAt = _getUtcNow(); } return Task.CompletedTask; diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj b/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj index a5b25ea..0f6b40f 100644 --- a/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj +++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj @@ -1,8 +1,10 @@ - $(TargetFrameworkName) + net8.0;net6.0 + + diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs b/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs index 9820cb1..95ec278 100644 --- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs +++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs @@ -4,8 +4,11 @@ using JsonApiDotNetCore.MongoDb.Configuration; using JsonApiDotNetCore.MongoDb.Repositories; using JsonApiDotNetCore.Repositories; -using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection.Extensions; using MongoDB.Driver; +#if NET6_0 +using Microsoft.AspNetCore.Authentication; +#endif [assembly: ExcludeFromCodeCoverage] @@ -13,21 +16,25 @@ // Add services to the container. -builder.Services.AddSingleton(); +#if NET6_0 +builder.Services.TryAddSingleton(); +#else +builder.Services.TryAddSingleton(TimeProvider.System); +#endif -builder.Services.AddSingleton(_ => +builder.Services.TryAddSingleton(_ => { - var client = new MongoClient(builder.Configuration.GetSection("DatabaseSettings:ConnectionString").Value); - return client.GetDatabase(builder.Configuration.GetSection("DatabaseSettings:Database").Value); + var client = new MongoClient(builder.Configuration.GetValue("DatabaseSettings:ConnectionString")); + return client.GetDatabase(builder.Configuration.GetValue("DatabaseSettings:Database")); }); +builder.Services.TryAddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>)); +builder.Services.TryAddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>)); +builder.Services.TryAddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>)); + builder.Services.AddJsonApi(ConfigureJsonApiOptions, facade => facade.AddCurrentAssembly()); builder.Services.AddJsonApiMongoDb(); -builder.Services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>)); -builder.Services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>)); -builder.Services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>)); - WebApplication app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs index 3514e87..3ea882d 100644 --- a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs +++ b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs @@ -35,20 +35,24 @@ public Task AfterProcessOperationAsync(CancellationToken cancellationToken) } /// - public async Task CommitAsync(CancellationToken cancellationToken) + public Task CommitAsync(CancellationToken cancellationToken) { if (_ownsTransaction && _mongoDataAccess.ActiveSession != null) { - await _mongoDataAccess.ActiveSession.CommitTransactionAsync(cancellationToken); + return _mongoDataAccess.ActiveSession.CommitTransactionAsync(cancellationToken); } + + return Task.CompletedTask; } /// - public async ValueTask DisposeAsync() + public ValueTask DisposeAsync() { if (_ownsTransaction) { - await _mongoDataAccess.DisposeAsync(); + return _mongoDataAccess.DisposeAsync(); } + + return ValueTask.CompletedTask; } } diff --git a/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs index 836cf87..d39c8c7 100644 --- a/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using JsonApiDotNetCore.MongoDb.Repositories; using JsonApiDotNetCore.Queries; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace JsonApiDotNetCore.MongoDb.Configuration; @@ -16,7 +17,9 @@ public static class ServiceCollectionExtensions [PublicAPI] public static IServiceCollection AddJsonApiMongoDb(this IServiceCollection services) { - services.AddScoped(); + services.TryAddScoped(); + + // Replace the built-in implementations from JsonApiDotNetCore. services.AddScoped(); services.AddScoped(); diff --git a/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj b/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj index 50df50f..07d7077 100644 --- a/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj +++ b/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj @@ -1,10 +1,12 @@ - $(TargetFrameworkName) + net8.0;net6.0 true true + + $(JsonApiDotNetCoreMongoDbVersionPrefix) jsonapi;json:api;dotnet;asp.net;rest;web-api;MongoDB diff --git a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs index f983cef..c955f8c 100644 --- a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs +++ b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs @@ -173,12 +173,10 @@ public virtual async Task CreateAsync(TResource resourceFromRequest, TResource r await _resourceDefinitionAccessor.OnWritingAsync(resourceForDatabase, WriteOperationKind.CreateResource, cancellationToken); - await SaveChangesAsync(async () => - { - await (_mongoDataAccess.ActiveSession != null + await SaveChangesAsync( + () => _mongoDataAccess.ActiveSession != null ? Collection.InsertOneAsync(_mongoDataAccess.ActiveSession, resourceForDatabase, cancellationToken: cancellationToken) - : Collection.InsertOneAsync(resourceForDatabase, cancellationToken: cancellationToken)); - }, cancellationToken); + : Collection.InsertOneAsync(resourceForDatabase, cancellationToken: cancellationToken), cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(resourceForDatabase, WriteOperationKind.CreateResource, cancellationToken); } @@ -217,12 +215,10 @@ public virtual async Task UpdateAsync(TResource resourceFromRequest, TResource r FilterDefinition filter = Builders.Filter.Eq(resource => resource.Id, resourceFromDatabase.Id); - await SaveChangesAsync(async () => - { - await (_mongoDataAccess.ActiveSession != null + await SaveChangesAsync( + () => _mongoDataAccess.ActiveSession != null ? Collection.ReplaceOneAsync(_mongoDataAccess.ActiveSession, filter, resourceFromDatabase, cancellationToken: cancellationToken) - : Collection.ReplaceOneAsync(filter, resourceFromDatabase, cancellationToken: cancellationToken)); - }, cancellationToken); + : Collection.ReplaceOneAsync(filter, resourceFromDatabase, cancellationToken: cancellationToken), cancellationToken); await _resourceDefinitionAccessor.OnWriteSucceededAsync(resourceFromDatabase, WriteOperationKind.UpdateResource, cancellationToken); } @@ -238,9 +234,9 @@ public virtual async Task DeleteAsync(TResource? resourceFromDatabase, TId id, C FilterDefinition filter = Builders.Filter.Eq(resource => resource.Id, id); DeleteResult result = await SaveChangesAsync( - async () => _mongoDataAccess.ActiveSession != null - ? await Collection.DeleteOneAsync(_mongoDataAccess.ActiveSession, filter, cancellationToken: cancellationToken) - : await Collection.DeleteOneAsync(filter, cancellationToken), cancellationToken); + () => _mongoDataAccess.ActiveSession != null + ? Collection.DeleteOneAsync(_mongoDataAccess.ActiveSession, filter, cancellationToken: cancellationToken) + : Collection.DeleteOneAsync(filter, cancellationToken), cancellationToken); if (!result.IsAcknowledged) { diff --git a/src/JsonApiDotNetCore.MongoDb/Resources/IMongoIdentifiable.cs b/src/JsonApiDotNetCore.MongoDb/Resources/IMongoIdentifiable.cs index 11dbfa2..576cdcc 100644 --- a/src/JsonApiDotNetCore.MongoDb/Resources/IMongoIdentifiable.cs +++ b/src/JsonApiDotNetCore.MongoDb/Resources/IMongoIdentifiable.cs @@ -5,6 +5,4 @@ namespace JsonApiDotNetCore.MongoDb.Resources; /// /// Marker interface to indicate a resource that is stored in MongoDB. /// -public interface IMongoIdentifiable : IIdentifiable -{ -} +public interface IMongoIdentifiable : IIdentifiable; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs index e727573..21db655 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs @@ -1,5 +1,7 @@ using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Meta; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -12,9 +14,17 @@ public sealed class AtomicOperationsFixture : IAsyncLifetime public AtomicOperationsFixture() { + TestContext.UseResourceTypesInNamespace(typeof(MusicTrack).Namespace); + TestContext.UseController(); - TestContext.ConfigureServicesAfterStartup(services => services.AddSingleton()); + TestContext.ConfigureServices(services => + { + services.TryAddSingleton(); + + services.AddResourceDefinition(); + services.AddResourceDefinition(); + }); } public Task InitializeAsync() @@ -22,8 +32,8 @@ public Task InitializeAsync() return Task.CompletedTask; } - public async Task DisposeAsync() + public Task DisposeAsync() { - await TestContext.DisposeAsync(); + return TestContext.DisposeAsync(); } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithClientGeneratedIdTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithClientGeneratedIdTests.cs index bfd4a4e..27813bc 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithClientGeneratedIdTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithClientGeneratedIdTests.cs @@ -58,7 +58,7 @@ public async Task Can_create_resource_with_client_generated_string_ID_having_sid // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); - string isoCode = $"{newLanguage.IsoCode}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingTextLanguageDefinition.Suffix}"; + string isoCode = $"{newLanguage.IsoCode}{ImplicitlyChangingTextLanguageDefinition.Suffix}"; responseDocument.Results.ShouldHaveCount(1); @@ -132,10 +132,10 @@ public async Task Cannot_create_resource_for_existing_client_generated_ID() string newIsoCode = _fakers.TextLanguage.Generate().IsoCode!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.TextLanguages.Add(existingLanguage); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs index 94eabe3..ad022d4 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs @@ -25,10 +25,10 @@ public async Task Cannot_create_ToMany_relationship() string newTitle = _fakers.MusicTrack.Generate().Title; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToOneRelationshipTests.cs index dd7cf9e..209cdea 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToOneRelationshipTests.cs @@ -25,10 +25,10 @@ public async Task Cannot_create_ToOne_relationship() string newLyricText = _fakers.Lyric.Generate().Text; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs index 5721c1b..14f62fb 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs @@ -23,10 +23,10 @@ public async Task Can_delete_existing_resource() // Arrange Performer existingPerformer = _fakers.Performer.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/ImplicitlyChangingTextLanguageDefinition.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/ImplicitlyChangingTextLanguageDefinition.cs index dc5ada1..946bc14 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/ImplicitlyChangingTextLanguageDefinition.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/ImplicitlyChangingTextLanguageDefinition.cs @@ -6,39 +6,34 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations; -[UsedImplicitly] -public sealed class ContainerTypeToHideFromAutoDiscovery +/// +/// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. +/// +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public abstract class ImplicitlyChangingTextLanguageDefinition : HitCountingResourceDefinition { - /// - /// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. - /// - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public abstract class ImplicitlyChangingTextLanguageDefinition : HitCountingResourceDefinition - { - internal const string Suffix = " (changed)"; + internal const string Suffix = " (changed)"; - private readonly IMongoDataAccess _mongoDataAccess; + private readonly IMongoDataAccess _mongoDataAccess; - protected ImplicitlyChangingTextLanguageDefinition(IResourceGraph resourceGraph, ResourceDefinitionHitCounter hitCounter, - IMongoDataAccess mongoDataAccess) - : base(resourceGraph, hitCounter) - { - _mongoDataAccess = mongoDataAccess; - } + protected ImplicitlyChangingTextLanguageDefinition(IResourceGraph resourceGraph, ResourceDefinitionHitCounter hitCounter, IMongoDataAccess mongoDataAccess) + : base(resourceGraph, hitCounter) + { + _mongoDataAccess = mongoDataAccess; + } - public override async Task OnWriteSucceededAsync(TextLanguage resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) - { - await base.OnWriteSucceededAsync(resource, writeOperation, cancellationToken); + public override async Task OnWriteSucceededAsync(TextLanguage resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) + { + await base.OnWriteSucceededAsync(resource, writeOperation, cancellationToken); - if (writeOperation is not WriteOperationKind.DeleteResource) - { - resource.IsoCode += Suffix; + if (writeOperation is not WriteOperationKind.DeleteResource) + { + resource.IsoCode += Suffix; - FilterDefinition filter = Builders.Filter.Eq(item => item.Id, resource.Id); + FilterDefinition filter = Builders.Filter.Eq(item => item.Id, resource.Id); - IMongoCollection collection = _mongoDataAccess.MongoDatabase.GetCollection(nameof(TextLanguage)); - await collection.ReplaceOneAsync(_mongoDataAccess.ActiveSession, filter, resource, cancellationToken: cancellationToken); - } + IMongoCollection collection = _mongoDataAccess.MongoDatabase.GetCollection(nameof(TextLanguage)); + await collection.ReplaceOneAsync(_mongoDataAccess.ActiveSession, filter, resource, cancellationToken: cancellationToken); } } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs index a701256..ed87024 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs @@ -112,10 +112,10 @@ public async Task Returns_resource_meta_in_update_resource_with_side_effects() TextLanguage existingLanguage = _fakers.TextLanguage.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.TextLanguages.Add(existingLanguage); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/TextLanguageMetaDefinition.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/TextLanguageMetaDefinition.cs index ef3db2a..bf1bd66 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/TextLanguageMetaDefinition.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Meta/TextLanguageMetaDefinition.cs @@ -5,7 +5,7 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Meta; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] -public sealed class TextLanguageMetaDefinition : ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingTextLanguageDefinition +public sealed class TextLanguageMetaDefinition : ImplicitlyChangingTextLanguageDefinition { internal const string NoticeText = "See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for ISO 639-1 language codes."; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicRollbackTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicRollbackTests.cs index b9db4b1..26ea797 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicRollbackTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicRollbackTests.cs @@ -26,10 +26,7 @@ public async Task Can_rollback_created_resource_on_error() string newArtistName = _fakers.Performer.Generate().ArtistName!; DateTimeOffset newBornAt = _fakers.Performer.Generate().BornAt; - await _testContext.RunOnDatabaseAsync(async dbContext => - { - await dbContext.ClearTableAsync(); - }); + await _testContext.RunOnDatabaseAsync(dbContext => dbContext.ClearTableAsync()); string unknownPerformerId = Unknown.StringId.For(); @@ -94,10 +91,10 @@ public async Task Can_rollback_updated_resource_on_error() string newArtistName = _fakers.Performer.Generate().ArtistName!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string unknownPerformerId = Unknown.StringId.For(); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicTransactionConsistencyTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicTransactionConsistencyTests.cs index 4d89d74..5475fcb 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicTransactionConsistencyTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/AtomicTransactionConsistencyTests.cs @@ -2,7 +2,7 @@ using FluentAssertions; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Serialization.Objects; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -17,15 +17,17 @@ public AtomicTransactionConsistencyTests(IntegrationTestContext(); - testContext.ConfigureServicesAfterStartup(services => + testContext.ConfigureServices(services => { - services.AddSingleton(); + services.TryAddSingleton(); - services.AddResourceRepository(); - services.AddResourceRepository(); - services.AddResourceRepository(); + services.AddResourceRepository(); + services.AddResourceRepository(); + services.AddResourceRepository(); }); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/LyricRepository.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/LyricRepository.cs index 93e31b2..d738e8d 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/LyricRepository.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/LyricRepository.cs @@ -9,30 +9,25 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Transactions; -[UsedImplicitly] -internal sealed partial class ContainerTypeToHideFromAutoDiscovery +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class LyricRepository : MongoRepository, IAsyncDisposable { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public sealed class LyricRepository : MongoRepository, IAsyncDisposable - { - private readonly IOperationsTransaction _transaction; + private readonly IOperationsTransaction _transaction; - public override string TransactionId => _transaction.TransactionId; + public override string TransactionId => _transaction.TransactionId; - public LyricRepository(IMongoDataAccess mongoDataAccess, ITargetedFields targetedFields, IResourceGraph resourceGraph, IResourceFactory resourceFactory, - IEnumerable constraintProviders, IResourceDefinitionAccessor resourceDefinitionAccessor, - IQueryableBuilder queryableBuilder) - : base(mongoDataAccess, targetedFields, resourceGraph, resourceFactory, constraintProviders, resourceDefinitionAccessor, queryableBuilder) - { - IMongoDataAccess otherDataAccess = new MongoDataAccess(mongoDataAccess.MongoDatabase); + public LyricRepository(IMongoDataAccess mongoDataAccess, ITargetedFields targetedFields, IResourceGraph resourceGraph, IResourceFactory resourceFactory, + IEnumerable constraintProviders, IResourceDefinitionAccessor resourceDefinitionAccessor, IQueryableBuilder queryableBuilder) + : base(mongoDataAccess, targetedFields, resourceGraph, resourceFactory, constraintProviders, resourceDefinitionAccessor, queryableBuilder) + { + IMongoDataAccess otherDataAccess = new MongoDataAccess(mongoDataAccess.MongoDatabase); - var factory = new MongoTransactionFactory(otherDataAccess); - _transaction = factory.BeginTransactionAsync(CancellationToken.None).Result; - } + var factory = new MongoTransactionFactory(otherDataAccess); + _transaction = factory.BeginTransactionAsync(CancellationToken.None).Result; + } - public async ValueTask DisposeAsync() - { - await _transaction.DisposeAsync(); - } + public ValueTask DisposeAsync() + { + return _transaction.DisposeAsync(); } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/MusicTrackRepository.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/MusicTrackRepository.cs index 5d40f37..9595112 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/MusicTrackRepository.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/MusicTrackRepository.cs @@ -7,18 +7,15 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Transactions; -internal sealed partial class ContainerTypeToHideFromAutoDiscovery +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class MusicTrackRepository : MongoRepository { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public sealed class MusicTrackRepository : MongoRepository - { - public override string? TransactionId => null; + public override string? TransactionId => null; - public MusicTrackRepository(IMongoDataAccess mongoDataAccess, ITargetedFields targetedFields, IResourceGraph resourceGraph, - IResourceFactory resourceFactory, IEnumerable constraintProviders, IResourceDefinitionAccessor resourceDefinitionAccessor, - IQueryableBuilder queryableBuilder) - : base(mongoDataAccess, targetedFields, resourceGraph, resourceFactory, constraintProviders, resourceDefinitionAccessor, queryableBuilder) - { - } + public MusicTrackRepository(IMongoDataAccess mongoDataAccess, ITargetedFields targetedFields, IResourceGraph resourceGraph, + IResourceFactory resourceFactory, IEnumerable constraintProviders, IResourceDefinitionAccessor resourceDefinitionAccessor, + IQueryableBuilder queryableBuilder) + : base(mongoDataAccess, targetedFields, resourceGraph, resourceFactory, constraintProviders, resourceDefinitionAccessor, queryableBuilder) + { } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/PerformerRepository.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/PerformerRepository.cs index c4d2e26..2f73d74 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/PerformerRepository.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Transactions/PerformerRepository.cs @@ -6,60 +6,56 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Transactions; -internal sealed partial class ContainerTypeToHideFromAutoDiscovery +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class PerformerRepository : IResourceRepository { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public sealed class PerformerRepository : IResourceRepository + public Task> GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken) { - public Task> GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + throw new NotImplementedException(); + } - public Task CountAsync(FilterExpression? filter, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task CountAsync(FilterExpression? filter, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task GetForCreateAsync(Type resourceClrType, string? id, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task GetForCreateAsync(Type resourceClrType, string? id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task CreateAsync(Performer resourceFromRequest, Performer resourceForDatabase, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task CreateAsync(Performer resourceFromRequest, Performer resourceForDatabase, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task GetForUpdateAsync(QueryLayer queryLayer, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task GetForUpdateAsync(QueryLayer queryLayer, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task UpdateAsync(Performer resourceFromRequest, Performer resourceFromDatabase, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task UpdateAsync(Performer resourceFromRequest, Performer resourceFromDatabase, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task DeleteAsync(Performer? resourceFromDatabase, string? id, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task DeleteAsync(Performer? resourceFromDatabase, string? id, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task SetRelationshipAsync(Performer leftResource, object? rightValue, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task SetRelationshipAsync(Performer leftResource, object? rightValue, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task AddToToManyRelationshipAsync(Performer? leftResource, string? leftId, ISet rightResourceIds, - CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task AddToToManyRelationshipAsync(Performer? leftResource, string? leftId, ISet rightResourceIds, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } - public Task RemoveFromToManyRelationshipAsync(Performer leftResource, ISet rightResourceIds, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task RemoveFromToManyRelationshipAsync(Performer leftResource, ISet rightResourceIds, CancellationToken cancellationToken) + { + throw new NotImplementedException(); } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs index bf4edda..d15f9d0 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_add_to_OneToMany_relationship() MusicTrack existingTrack = _fakers.MusicTrack.Generate(); Performer existingPerformer = _fakers.Performer.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -81,11 +81,11 @@ public async Task Cannot_add_to_ManyToMany_relationship() Playlist existingPlaylist = _fakers.Playlist.Generate(); MusicTrack existingTrack = _fakers.MusicTrack.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); dbContext.Playlists.Add(existingPlaylist); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs index cb17dcd..857f7c5 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_remove_from_OneToMany_relationship() MusicTrack existingTrack = _fakers.MusicTrack.Generate(); existingTrack.Performers = _fakers.Performer.Generate(1); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingTrack.Performers[0]); dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -81,11 +81,11 @@ public async Task Cannot_remove_from_ManyToMany_relationship() Playlist existingPlaylist = _fakers.Playlist.Generate(); existingPlaylist.Tracks = _fakers.MusicTrack.Generate(1); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingPlaylist.Tracks[0]); dbContext.Playlists.Add(existingPlaylist); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs index 27d679a..b716339 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_replace_OneToMany_relationship() MusicTrack existingTrack = _fakers.MusicTrack.Generate(); Performer existingPerformer = _fakers.Performer.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -81,11 +81,11 @@ public async Task Cannot_replace_ManyToMany_relationship() Playlist existingPlaylist = _fakers.Playlist.Generate(); MusicTrack existingTrack = _fakers.MusicTrack.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); dbContext.Playlists.Add(existingPlaylist); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicUpdateToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicUpdateToOneRelationshipTests.cs index 0f80aee..dccab27 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicUpdateToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicUpdateToOneRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_create_ManyToOne_relationship() MusicTrack existingTrack = _fakers.MusicTrack.Generate(); RecordCompany existingCompany = _fakers.RecordCompany.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RecordCompanies.Add(existingCompany); dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs index 162bacb..833bdd3 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_replace_ToMany_relationship() MusicTrack existingTrack = _fakers.MusicTrack.Generate(); Performer existingPerformer = _fakers.Performer.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Performers.Add(existingPerformer); dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateResourceTests.cs index a6cec5b..7ae1426 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateResourceTests.cs @@ -89,10 +89,10 @@ public async Task Can_update_resource_without_attributes_or_relationships() // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -144,10 +144,10 @@ public async Task Can_partially_update_resource_without_side_effects() string newGenre = _fakers.MusicTrack.Generate().Genre!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -202,10 +202,10 @@ public async Task Can_completely_update_resource_without_side_effects() string newGenre = _fakers.MusicTrack.Generate().Genre!; DateTimeOffset newReleasedAt = _fakers.MusicTrack.Generate().ReleasedAt; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -259,10 +259,10 @@ public async Task Can_update_resource_with_side_effects() TextLanguage existingLanguage = _fakers.TextLanguage.Generate(); string newIsoCode = _fakers.TextLanguage.Generate().IsoCode!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.TextLanguages.Add(existingLanguage); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -295,7 +295,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Results.ShouldHaveCount(1); - string isoCode = $"{newIsoCode}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingTextLanguageDefinition.Suffix}"; + string isoCode = $"{newIsoCode}{ImplicitlyChangingTextLanguageDefinition.Suffix}"; responseDocument.Results[0].Data.SingleValue.ShouldNotBeNull().With(resource => { diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateToOneRelationshipTests.cs index 0e0562a..df60664 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateToOneRelationshipTests.cs @@ -24,11 +24,11 @@ public async Task Cannot_create_ToOne_relationship() Lyric existingLyric = _fakers.Lyric.Generate(); MusicTrack existingTrack = _fakers.MusicTrack.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.MusicTracks.Add(existingTrack); dbContext.Lyrics.Add(existingLyric); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/ResourceMetaTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/ResourceMetaTests.cs index 3a3edca..d92419c 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/ResourceMetaTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/ResourceMetaTests.cs @@ -1,7 +1,9 @@ using System.Net; using FluentAssertions; +using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Serialization.Objects; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -16,11 +18,14 @@ public ResourceMetaTests(IntegrationTestContext { _testContext = testContext; + testContext.UseResourceTypesInNamespace(typeof(SupportTicket).Namespace); + testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => + testContext.ConfigureServices(services => { - services.AddSingleton(); + services.TryAddSingleton(); + services.AddResourceDefinition(); }); var hitCounter = _testContext.Factory.Services.GetRequiredService(); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/TopLevelCountTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/TopLevelCountTests.cs index c486d0d..cd122ae 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/TopLevelCountTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/Meta/TopLevelCountTests.cs @@ -4,6 +4,7 @@ using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Serialization.Objects; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -18,13 +19,11 @@ public TopLevelCountTests(IntegrationTestContext { _testContext = testContext; + testContext.UseResourceTypesInNamespace(typeof(SupportTicket).Namespace); + testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => - { - services.AddSingleton(); - services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>)); - }); + testContext.ConfigureServices(services => services.TryAddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>))); var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); options.IncludeTotalResourceCount = true; @@ -60,10 +59,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => public async Task Renders_resource_count_for_empty_collection() { // Arrange - await _testContext.RunOnDatabaseAsync(async dbContext => - { - await dbContext.ClearTableAsync(); - }); + await _testContext.RunOnDatabaseAsync(dbContext => dbContext.ClearTableAsync()); const string route = "/supportTickets"; @@ -115,10 +111,10 @@ public async Task Hides_resource_count_in_update_resource_response() string newDescription = _fakers.SupportTicket.Generate().Description; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.SupportTickets.Add(existingTicket); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDataTypeTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDataTypeTests.cs index 5dc1442..a74e6ee 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDataTypeTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDataTypeTests.cs @@ -19,6 +19,8 @@ public FilterDataTypeTests(IntegrationTestContext(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDepthTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDepthTests.cs index 888cd6c..fccf739 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDepthTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterDepthTests.cs @@ -15,6 +15,8 @@ public FilterDepthTests(IntegrationTestContext(); testContext.UseController(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterOperatorTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterOperatorTests.cs index 60e10e7..efc7075 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterOperatorTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterOperatorTests.cs @@ -39,6 +39,8 @@ public FilterOperatorTests(IntegrationTestContext(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterTests.cs index 9be84ed..c432a77 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Filtering/FilterTests.cs @@ -15,6 +15,8 @@ public FilterTests(IntegrationTestContext { _testContext = testContext; + testContext.UseResourceTypesInNamespace(typeof(Blog).Namespace); + testContext.UseController(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs index 63c5c1f..2fcbfe5 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs @@ -14,6 +14,8 @@ public IncludeTests(IntegrationTestContext(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/PaginationWithTotalCountTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/PaginationWithTotalCountTests.cs index d638555..96e031b 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/PaginationWithTotalCountTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/PaginationWithTotalCountTests.cs @@ -19,6 +19,8 @@ public PaginationWithTotalCountTests(IntegrationTestContext(); var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/RangeValidationTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/RangeValidationTests.cs index 63ec7c6..28a7c06 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/RangeValidationTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Pagination/RangeValidationTests.cs @@ -15,6 +15,8 @@ public RangeValidationTests(IntegrationTestContext(); } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Sorting/SortTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Sorting/SortTests.cs index f0846b7..a5269d7 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Sorting/SortTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/Sorting/SortTests.cs @@ -15,6 +15,8 @@ public SortTests(IntegrationTestContext t { _testContext = testContext; + testContext.UseResourceTypesInNamespace(typeof(Blog).Namespace); + testContext.UseController(); testContext.UseController(); testContext.UseController(); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/ResourceCaptureStore.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/ResourceCaptureStore.cs index 4eeea37..56e7ab9 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/ResourceCaptureStore.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/ResourceCaptureStore.cs @@ -4,7 +4,7 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.QueryStrings.SparseFiel public sealed class ResourceCaptureStore { - internal List Resources { get; } = new(); + internal List Resources { get; } = []; internal void Add(IEnumerable resources) { diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/SparseFieldSetTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/SparseFieldSetTests.cs index dca4609..b61ebac 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/SparseFieldSetTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/QueryStrings/SparseFieldSets/SparseFieldSetTests.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Serialization.Objects; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -17,13 +18,15 @@ public SparseFieldSetTests(IntegrationTestContext(); testContext.UseController(); testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => + testContext.ConfigureServices(services => { - services.AddSingleton(); + services.TryAddSingleton(); services.AddResourceRepository>(); services.AddResourceRepository>(); @@ -82,7 +85,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Data.ManyValue[0].Attributes.ShouldContainKey("caption").With(value => value.Should().Be(post.Caption)); responseDocument.Data.ManyValue[0].Relationships.Should().BeNull(); - var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).And.Subject.Single(); + var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).Which; postCaptured.Caption.Should().Be(post.Caption); postCaptured.Url.Should().BeNull(); } @@ -117,10 +120,10 @@ public async Task Can_select_attribute_in_primary_resource_by_ID() BlogPost post = _fakers.BlogPost.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Posts.Add(post); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/blogPosts/{post.StringId}?fields[blogPosts]=url"; @@ -137,7 +140,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Data.SingleValue.Attributes.ShouldContainKey("url").With(value => value.Should().Be(post.Url)); responseDocument.Data.SingleValue.Relationships.Should().BeNull(); - var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).And.Subject.Single(); + var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).Which; postCaptured.Url.Should().Be(post.Url); postCaptured.Caption.Should().BeNull(); } @@ -148,10 +151,10 @@ public async Task Cannot_select_fields_of_ManyToOne_relationship() // Arrange BlogPost post = _fakers.BlogPost.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Posts.Add(post); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/blogPosts/{post.StringId}?fields[webAccounts]=displayName,emailAddress,preferences"; @@ -177,10 +180,10 @@ public async Task Cannot_select_fields_of_OneToMany_relationship() // Arrange WebAccount account = _fakers.WebAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Accounts.Add(account); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/webAccounts/{account.StringId}?fields[blogPosts]=caption,labels"; @@ -206,10 +209,10 @@ public async Task Cannot_select_fields_of_ManyToMany_relationship() // Arrange BlogPost post = _fakers.BlogPost.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Posts.Add(post); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/blogPosts/{post.StringId}?fields[labels]=color"; @@ -259,7 +262,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Data.ManyValue[0].Attributes.ShouldContainKey("caption").With(value => value.Should().Be(post.Caption)); responseDocument.Data.ManyValue[0].Relationships.Should().BeNull(); - var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).And.Subject.Single(); + var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).Which; postCaptured.Id.Should().Be(post.Id); postCaptured.Caption.Should().Be(post.Caption); postCaptured.Url.Should().BeNull(); @@ -294,7 +297,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Data.ManyValue[0].Attributes.Should().BeNull(); responseDocument.Data.ManyValue[0].Relationships.Should().BeNull(); - var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).And.Subject.Single(); + var postCaptured = (BlogPost)store.Resources.Should().ContainSingle(resource => resource is BlogPost).Which; postCaptured.Id.Should().Be(post.Id); postCaptured.Url.Should().BeNull(); } @@ -309,10 +312,10 @@ public async Task Fetches_all_scalar_properties_when_fieldset_contains_readonly_ Blog blog = _fakers.Blog.Generate(); blog.IsPublished = true; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Blogs.Add(blog); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/blogs/{blog.StringId}?fields[blogs]=showAdvertisements"; @@ -329,7 +332,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.Data.SingleValue.Attributes.ShouldContainKey("showAdvertisements").With(value => value.Should().Be(blog.ShowAdvertisements)); responseDocument.Data.SingleValue.Relationships.Should().BeNull(); - var blogCaptured = (Blog)store.Resources.Should().ContainSingle(resource => resource is Blog).And.Subject.Single(); + var blogCaptured = (Blog)store.Resources.Should().ContainSingle(resource => resource is Blog).Which; blogCaptured.ShowAdvertisements.Should().Be(blog.ShowAdvertisements); blogCaptured.IsPublished.Should().Be(blog.IsPublished); blogCaptured.Title.Should().Be(blog.Title); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs index 7797e79..ccc1ec6 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs @@ -15,6 +15,8 @@ public CreateResourceTests(IntegrationTestContext(); testContext.UseController(); testContext.UseController(); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithClientGeneratedIdTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithClientGeneratedIdTests.cs index 9993e03..c763529 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithClientGeneratedIdTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithClientGeneratedIdTests.cs @@ -17,13 +17,12 @@ public CreateResourceWithClientGeneratedIdTests(IntegrationTestContext(); testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => - { - services.AddResourceDefinition(); - }); + testContext.ConfigureServices(services => services.AddResourceDefinition()); var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); options.ClientIdGeneration = ClientIdGenerationMode.Required; @@ -57,7 +56,7 @@ public async Task Can_create_resource_with_client_generated_string_ID_having_sid // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.Created); - string groupName = $"{newGroup.Name}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; + string groupName = $"{newGroup.Name}{ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; responseDocument.Data.SingleValue.ShouldNotBeNull(); responseDocument.Data.SingleValue.Type.Should().Be("workItemGroups"); @@ -101,7 +100,7 @@ public async Task Can_create_resource_with_client_generated_string_ID_having_sid // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.Created); - string groupName = $"{newGroup.Name}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; + string groupName = $"{newGroup.Name}{ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; responseDocument.Data.SingleValue.ShouldNotBeNull(); responseDocument.Data.SingleValue.Type.Should().Be("workItemGroups"); @@ -203,10 +202,10 @@ public async Task Cannot_create_resource_for_existing_client_generated_ID() string newDisplayName = _fakers.RgbColor.Generate().DisplayName; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RgbColors.Add(existingColor); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs index 626547c..f021d9b 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs @@ -15,6 +15,8 @@ public CreateResourceWithToManyRelationshipTests(IntegrationTestContext(); } @@ -24,10 +26,10 @@ public async Task Cannot_create_resource_with_ToMany_relationship() // Arrange UserAccount? existingUserAccount = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingUserAccount); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToOneRelationshipTests.cs index 337d48a..f02131d 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToOneRelationshipTests.cs @@ -15,6 +15,8 @@ public CreateResourceWithToOneRelationshipTests(IntegrationTestContext(); } @@ -27,11 +29,11 @@ public async Task Cannot_create_resource_with_ToOne_relationship() string newGroupName = _fakers.WorkItemGroup.Generate().Name; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RgbColors.Add(existingGroup.Color); dbContext.Groups.Add(existingGroup); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs index 99cac72..c00fd07 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs @@ -15,6 +15,8 @@ public DeleteResourceTests(IntegrationTestContext(); } @@ -24,10 +26,10 @@ public async Task Can_delete_existing_resource() // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{existingWorkItem.StringId}"; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs index 884349d..a7f74eb 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs @@ -15,6 +15,8 @@ public FetchRelationshipTests(IntegrationTestContext(); testContext.UseController(); } @@ -24,10 +26,10 @@ public async Task Cannot_get_ManyToOne_relationship() { WorkItem workItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(workItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{workItem.StringId}/relationships/assignee"; @@ -53,10 +55,10 @@ public async Task Cannot_get_OneToMany_relationship() // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(userAccount); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/userAccounts/{userAccount.StringId}/relationships/assignedItems"; @@ -82,10 +84,10 @@ public async Task Cannot_get_ManyToMany_relationship() // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(workItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{workItem.StringId}/relationships/tags"; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs index e254772..c8ff584 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs @@ -15,6 +15,8 @@ public FetchResourceTests(IntegrationTestContext(); testContext.UseController(); } @@ -63,10 +65,10 @@ public async Task Can_get_primary_resource_by_ID() // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(workItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{workItem.StringId}"; @@ -114,10 +116,10 @@ public async Task Cannot_get_secondary_ManyToOne_resource() // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(workItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{workItem.StringId}/assignee"; @@ -143,10 +145,10 @@ public async Task Cannot_get_secondary_OneToMany_resources() // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(userAccount); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/userAccounts/{userAccount.StringId}/assignedItems"; @@ -172,10 +174,10 @@ public async Task Cannot_get_secondary_ManyToMany_resources() // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(workItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/workItems/{workItem.StringId}/tags"; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemDefinition.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemDefinition.cs index 4e9f358..61f68e1 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemDefinition.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemDefinition.cs @@ -6,37 +6,35 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.ReadWrite; -[UsedImplicitly] -internal sealed partial class ContainerTypeToHideFromAutoDiscovery +/// +/// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. +/// +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class ImplicitlyChangingWorkItemDefinition : JsonApiResourceDefinition { - /// - /// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. - /// - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public sealed class ImplicitlyChangingWorkItemDefinition : JsonApiResourceDefinition - { - internal const string Suffix = " (changed)"; + internal const string Suffix = " (changed)"; - private readonly ReadWriteDbContext _dbContext; + private readonly ReadWriteDbContext _dbContext; - public ImplicitlyChangingWorkItemDefinition(IResourceGraph resourceGraph, ReadWriteDbContext dbContext) - : base(resourceGraph) - { - _dbContext = dbContext; - } + public ImplicitlyChangingWorkItemDefinition(IResourceGraph resourceGraph, ReadWriteDbContext dbContext) + : base(resourceGraph) + { + _dbContext = dbContext; + } - public override async Task OnWriteSucceededAsync(WorkItem resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) + public override Task OnWriteSucceededAsync(WorkItem resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) + { + if (writeOperation is not WriteOperationKind.DeleteResource) { - if (writeOperation is not WriteOperationKind.DeleteResource) + return _dbContext.WorkItems.ExecuteAsync(async collection => { - await _dbContext.WorkItems.ExecuteAsync(async collection => - { - resource.Description += Suffix; + resource.Description += Suffix; - FilterDefinition filter = Builders.Filter.Eq(item => item.Id, resource.Id); - await collection.ReplaceOneAsync(filter, resource, cancellationToken: cancellationToken); - }); - } + FilterDefinition filter = Builders.Filter.Eq(item => item.Id, resource.Id); + await collection.ReplaceOneAsync(filter, resource, cancellationToken: cancellationToken); + }); } + + return Task.CompletedTask; } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemGroupDefinition.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemGroupDefinition.cs index e9abd46..3d4e846 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemGroupDefinition.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/ImplicitlyChangingWorkItemGroupDefinition.cs @@ -6,36 +6,35 @@ namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.ReadWrite; -internal sealed partial class ContainerTypeToHideFromAutoDiscovery +/// +/// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. +/// +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class ImplicitlyChangingWorkItemGroupDefinition : JsonApiResourceDefinition { - /// - /// Used to simulate side effects that occur in the database while saving, typically caused by database triggers. - /// - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public sealed class ImplicitlyChangingWorkItemGroupDefinition : JsonApiResourceDefinition - { - internal const string Suffix = " (changed)"; + internal const string Suffix = " (changed)"; - private readonly ReadWriteDbContext _dbContext; + private readonly ReadWriteDbContext _dbContext; - public ImplicitlyChangingWorkItemGroupDefinition(IResourceGraph resourceGraph, ReadWriteDbContext dbContext) - : base(resourceGraph) - { - _dbContext = dbContext; - } + public ImplicitlyChangingWorkItemGroupDefinition(IResourceGraph resourceGraph, ReadWriteDbContext dbContext) + : base(resourceGraph) + { + _dbContext = dbContext; + } - public override async Task OnWriteSucceededAsync(WorkItemGroup resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) + public override Task OnWriteSucceededAsync(WorkItemGroup resource, WriteOperationKind writeOperation, CancellationToken cancellationToken) + { + if (writeOperation is not WriteOperationKind.DeleteResource) { - if (writeOperation is not WriteOperationKind.DeleteResource) + return _dbContext.Groups.ExecuteAsync(async collection => { - await _dbContext.Groups.ExecuteAsync(async collection => - { - resource.Name += Suffix; + resource.Name += Suffix; - FilterDefinition filter = Builders.Filter.Eq(group => group.Id, resource.Id); - await collection.ReplaceOneAsync(filter, resource, cancellationToken: cancellationToken); - }); - } + FilterDefinition filter = Builders.Filter.Eq(group => group.Id, resource.Id); + await collection.ReplaceOneAsync(filter, resource, cancellationToken: cancellationToken); + }); } + + return Task.CompletedTask; } } diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs index 7487ca4..970c893 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs @@ -15,6 +15,8 @@ public AddToToManyRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_add_to_OneToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); UserAccount existingSubscriber = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingSubscriber); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -68,11 +70,11 @@ public async Task Cannot_add_to_ManyToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); WorkTag existingTag = _fakers.WorkTag.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkTags.Add(existingTag); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs index 0de1b7b..22dd312 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs @@ -15,6 +15,8 @@ public RemoveFromToManyRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_remove_from_OneToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Subscribers = _fakers.UserAccount.Generate(1).ToHashSet(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingWorkItem.Subscribers.ElementAt(0)); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -68,11 +70,11 @@ public async Task Cannot_remove_from_ManyToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkTags.Add(existingWorkItem.Tags.ElementAt(0)); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs index 2c78ccd..0d623d7 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs @@ -15,6 +15,8 @@ public ReplaceToManyRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_replace_OneToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); UserAccount existingSubscriber = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingSubscriber); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -68,11 +70,11 @@ public async Task Cannot_replace_ManyToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); WorkTag existingTag = _fakers.WorkTag.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkTags.Add(existingTag); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/UpdateToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/UpdateToOneRelationshipTests.cs index 0e76c43..38168eb 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/UpdateToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Relationships/UpdateToOneRelationshipTests.cs @@ -15,6 +15,8 @@ public UpdateToOneRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_replace_ToOne_relationship() WorkItemGroup existingGroup = _fakers.WorkItemGroup.Generate(); RgbColor existingColor = _fakers.RgbColor.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RgbColors.Add(existingColor); dbContext.Groups.Add(existingGroup); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs index ed39b18..fe61fa8 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs @@ -15,6 +15,8 @@ public ReplaceToManyRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_replace_OneToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); UserAccount existingSubscriber = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingSubscriber); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -79,11 +81,11 @@ public async Task Cannot_replace_ManyToMany_relationship() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); WorkTag existingTag = _fakers.WorkTag.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkTags.Add(existingTag); dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs index 4faf659..6163c5e 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs @@ -16,15 +16,17 @@ public UpdateResourceTests(IntegrationTestContext(); testContext.UseController(); testContext.UseController(); testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => + testContext.ConfigureServices(services => { - services.AddResourceDefinition(); - services.AddResourceDefinition(); + services.AddResourceDefinition(); + services.AddResourceDefinition(); }); } @@ -34,10 +36,10 @@ public async Task Can_update_resource_without_attributes_or_relationships() // Arrange UserAccount existingUserAccount = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingUserAccount); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -81,10 +83,10 @@ public async Task Can_partially_update_resource_with_string_ID() WorkItemGroup existingGroup = _fakers.WorkItemGroup.Generate(); string newName = _fakers.WorkItemGroup.Generate().Name; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Groups.Add(existingGroup); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -108,7 +110,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); - string groupName = $"{newName}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; + string groupName = $"{newName}{ImplicitlyChangingWorkItemGroupDefinition.Suffix}"; responseDocument.Data.SingleValue.ShouldNotBeNull(); responseDocument.Data.SingleValue.Type.Should().Be("workItemGroups"); @@ -133,10 +135,10 @@ public async Task Can_completely_update_resource_with_string_ID() RgbColor existingColor = _fakers.RgbColor.Generate(); string newDisplayName = _fakers.RgbColor.Generate().DisplayName; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RgbColors.Add(existingColor); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -177,10 +179,10 @@ public async Task Can_update_resource_without_side_effects() UserAccount existingUserAccount = _fakers.UserAccount.Generate(); UserAccount newUserAccount = _fakers.UserAccount.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.UserAccounts.Add(existingUserAccount); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -223,10 +225,10 @@ public async Task Can_update_resource_with_side_effects() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); string newDescription = _fakers.WorkItem.Generate().Description!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -251,7 +253,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); - string itemDescription = $"{newDescription}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingWorkItemDefinition.Suffix}"; + string itemDescription = $"{newDescription}{ImplicitlyChangingWorkItemDefinition.Suffix}"; responseDocument.Data.SingleValue.ShouldNotBeNull(); responseDocument.Data.SingleValue.Type.Should().Be("workItems"); @@ -279,10 +281,10 @@ public async Task Can_update_resource_with_side_effects_with_primary_fieldset() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); string newDescription = _fakers.WorkItem.Generate().Description!; - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.WorkItems.Add(existingWorkItem); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new @@ -307,7 +309,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // Assert httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); - string itemDescription = $"{newDescription}{ContainerTypeToHideFromAutoDiscovery.ImplicitlyChangingWorkItemDefinition.Suffix}"; + string itemDescription = $"{newDescription}{ImplicitlyChangingWorkItemDefinition.Suffix}"; responseDocument.Data.SingleValue.ShouldNotBeNull(); responseDocument.Data.SingleValue.Type.Should().Be("workItems"); diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateToOneRelationshipTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateToOneRelationshipTests.cs index 2a0faf2..de4ddbc 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateToOneRelationshipTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateToOneRelationshipTests.cs @@ -15,6 +15,8 @@ public UpdateToOneRelationshipTests(IntegrationTestContext(); } @@ -25,11 +27,11 @@ public async Task Cannot_create_ToOne_relationship() WorkItemGroup existingGroup = _fakers.WorkItemGroup.Generate(); RgbColor existingColor = _fakers.RgbColor.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.RgbColors.Add(existingColor); dbContext.Groups.Add(existingGroup); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); var requestBody = new diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs index d9b54c4..69bc808 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Serialization.Objects; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using TestBuildingBlocks; using Xunit; @@ -17,14 +18,20 @@ public ResourceDefinitionReadTests(IntegrationTestContext(); testContext.UseController(); testContext.UseController(); - testContext.ConfigureServicesAfterStartup(services => + testContext.ConfigureServices(services => { - services.AddSingleton(); - services.AddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + services.AddResourceDefinition(); + services.AddResourceDefinition(); + services.AddResourceDefinition(); }); var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); @@ -293,10 +300,10 @@ public async Task Attribute_inclusion_from_resource_definition_is_applied_for_om Star star = _fakers.Star.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Stars.Add(star); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/stars/{star.StringId}"; @@ -333,10 +340,10 @@ public async Task Attribute_inclusion_from_resource_definition_is_applied_for_fi Star star = _fakers.Star.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Stars.Add(star); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/stars/{star.StringId}?fields[stars]=name,solarRadius"; @@ -374,10 +381,10 @@ public async Task Attribute_exclusion_from_resource_definition_is_applied_for_om Star star = _fakers.Star.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Stars.Add(star); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/stars/{star.StringId}"; @@ -414,10 +421,10 @@ public async Task Attribute_exclusion_from_resource_definition_is_applied_for_fi Star star = _fakers.Star.Generate(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Stars.Add(star); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/stars/{star.StringId}?fields[stars]=name,isVisibleFromEarth"; @@ -551,10 +558,10 @@ public async Task Queryable_parameter_handler_from_resource_definition_is_not_ap Planet planet = _fakers.Planet.Generate(); planet.Moons = _fakers.Moon.Generate(1).ToHashSet(); - await _testContext.RunOnDatabaseAsync(async dbContext => + await _testContext.RunOnDatabaseAsync(dbContext => { dbContext.Planets.Add(planet); - await dbContext.SaveChangesAsync(); + return dbContext.SaveChangesAsync(); }); string route = $"/planets/{planet.StringId}/moons?isLargerThanTheSun=false"; diff --git a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/StarDefinition.cs b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/StarDefinition.cs index 5ca6551..46632bd 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/StarDefinition.cs +++ b/test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/ResourceDefinitions/Reading/StarDefinition.cs @@ -26,11 +26,10 @@ public override SortExpression OnApplySort(SortExpression? existingSort) private SortExpression GetDefaultSortOrder() { - return CreateSortExpressionFromLambda(new PropertySortOrder - { + return CreateSortExpressionFromLambda([ (star => star.SolarMass, ListSortDirection.Descending), (star => star.SolarRadius, ListSortDirection.Descending) - }); + ]); } public override PaginationExpression OnApplyPagination(PaginationExpression? existingPagination) diff --git a/test/JsonApiDotNetCoreMongoDbTests/JsonApiDotNetCoreMongoDbTests.csproj b/test/JsonApiDotNetCoreMongoDbTests/JsonApiDotNetCoreMongoDbTests.csproj index b8d099f..d25aea3 100644 --- a/test/JsonApiDotNetCoreMongoDbTests/JsonApiDotNetCoreMongoDbTests.csproj +++ b/test/JsonApiDotNetCoreMongoDbTests/JsonApiDotNetCoreMongoDbTests.csproj @@ -1,8 +1,10 @@ - $(TargetFrameworkName) + net8.0;net6.0 + + diff --git a/test/TestBuildingBlocks/AssemblyInfo.cs b/test/TestBuildingBlocks/AssemblyInfo.cs index 82d1291..2af69d7 100644 --- a/test/TestBuildingBlocks/AssemblyInfo.cs +++ b/test/TestBuildingBlocks/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Diagnostics.CodeAnalysis; -// https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md#excluding-from-coverage +// Justification: This assembly contains building blocks for writing tests. It does not contain code that ships. [assembly: ExcludeFromCodeCoverage] diff --git a/test/TestBuildingBlocks/IntegrationTest.cs b/test/TestBuildingBlocks/IntegrationTest.cs index 50fc3fd..2080a47 100644 --- a/test/TestBuildingBlocks/IntegrationTest.cs +++ b/test/TestBuildingBlocks/IntegrationTest.cs @@ -22,34 +22,34 @@ static IntegrationTest() ThrottleSemaphore = new SemaphoreSlim(maxConcurrentTestRuns); } - public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteGetAsync(string requestUrl, + public Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteGetAsync(string requestUrl, Action? setRequestHeaders = null) { - return await ExecuteRequestAsync(HttpMethod.Get, requestUrl, null, null, setRequestHeaders); + return ExecuteRequestAsync(HttpMethod.Get, requestUrl, null, null, setRequestHeaders); } - public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePostAsync(string requestUrl, + public Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePostAsync(string requestUrl, object requestBody, string contentType = HeaderConstants.MediaType, Action? setRequestHeaders = null) { - return await ExecuteRequestAsync(HttpMethod.Post, requestUrl, requestBody, contentType, setRequestHeaders); + return ExecuteRequestAsync(HttpMethod.Post, requestUrl, requestBody, contentType, setRequestHeaders); } - public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePostAtomicAsync(string requestUrl, + public Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePostAtomicAsync(string requestUrl, object requestBody, string contentType = HeaderConstants.AtomicOperationsMediaType, Action? setRequestHeaders = null) { - return await ExecuteRequestAsync(HttpMethod.Post, requestUrl, requestBody, contentType, setRequestHeaders); + return ExecuteRequestAsync(HttpMethod.Post, requestUrl, requestBody, contentType, setRequestHeaders); } - public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePatchAsync(string requestUrl, + public Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecutePatchAsync(string requestUrl, object requestBody, string contentType = HeaderConstants.MediaType, Action? setRequestHeaders = null) { - return await ExecuteRequestAsync(HttpMethod.Patch, requestUrl, requestBody, contentType, setRequestHeaders); + return ExecuteRequestAsync(HttpMethod.Patch, requestUrl, requestBody, contentType, setRequestHeaders); } - public async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteDeleteAsync(string requestUrl, + public Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteDeleteAsync(string requestUrl, object? requestBody = null, string contentType = HeaderConstants.MediaType, Action? setRequestHeaders = null) { - return await ExecuteRequestAsync(HttpMethod.Delete, requestUrl, requestBody, contentType, setRequestHeaders); + return ExecuteRequestAsync(HttpMethod.Delete, requestUrl, requestBody, contentType, setRequestHeaders); } private async Task<(HttpResponseMessage httpResponse, TResponseDocument responseDocument)> ExecuteRequestAsync(HttpMethod method, @@ -110,9 +110,9 @@ static IntegrationTest() } } - public async Task InitializeAsync() + public Task InitializeAsync() { - await ThrottleSemaphore.WaitAsync(); + return ThrottleSemaphore.WaitAsync(); } public virtual Task DisposeAsync() diff --git a/test/TestBuildingBlocks/IntegrationTestContext.cs b/test/TestBuildingBlocks/IntegrationTestContext.cs index f97fd98..f479821 100644 --- a/test/TestBuildingBlocks/IntegrationTestContext.cs +++ b/test/TestBuildingBlocks/IntegrationTestContext.cs @@ -1,3 +1,4 @@ +using System.Reflection; using System.Text.Json; using EphemeralMongo; using JetBrains.Annotations; @@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using MongoDB.Driver; @@ -33,9 +35,9 @@ public class IntegrationTestContext : Integration { private readonly Lazy _runner; private readonly Lazy> _lazyFactory; + private readonly HashSet _resourceClrTypes = []; private readonly TestControllerProvider _testControllerProvider = new(); - - private Action? _afterServicesConfiguration; + private Action? _configureServices; protected override JsonSerializerOptions SerializerOptions { @@ -59,6 +61,16 @@ private IMongoRunner StartMongoDb() return MongoRunnerProvider.Instance.Get(); } + public void UseResourceTypesInNamespace(string? codeNamespace) + { + Assembly assembly = typeof(TStartup).Assembly; + + foreach (Type resourceClrType in ResourceTypeFinder.GetResourceClrTypesInNamespace(assembly, codeNamespace)) + { + _resourceClrTypes.Add(resourceClrType); + } + } + public void UseController() where TController : ControllerBase { @@ -74,27 +86,34 @@ private WebApplicationFactory CreateFactory() { var factory = new IntegrationTestWebApplicationFactory(); - factory.ConfigureServicesBeforeStartup(services => + factory.ConfigureServices(services => { + _configureServices?.Invoke(services); + services.ReplaceControllers(_testControllerProvider); - services.AddSingleton(_ => + services.TryAddSingleton(_ => { var client = new MongoClient(_runner.Value.ConnectionString); - return client.GetDatabase($"JsonApiDotNetCore_MongoDb_{new Random().Next()}_Test"); + return client.GetDatabase($"JsonApiDotNetCore_MongoDb_{Random.Shared.Next()}_Test"); }); - services.AddJsonApi(ConfigureJsonApiOptions, facade => facade.AddAssembly(typeof(TStartup).Assembly)); - services.AddJsonApiMongoDb(); + services.TryAddScoped(); - services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>)); - services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>)); - services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>)); + services.TryAddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>)); + services.TryAddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>)); + services.TryAddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>)); - services.AddScoped(); - }); + services.AddJsonApi(ConfigureJsonApiOptions, resources: builder => + { + foreach (Type resourceClrType in _resourceClrTypes) + { + builder.Add(resourceClrType); + } + }); - factory.ConfigureServicesAfterStartup(_afterServicesConfiguration); + services.AddJsonApiMongoDb(); + }); // We have placed an appsettings.json in the TestBuildingBlock project folder and set the content root to there. Note that controllers // are not discovered in the content root but are registered manually using IntegrationTestContext.UseController. @@ -108,9 +127,9 @@ private void ConfigureJsonApiOptions(JsonApiOptions options) options.SerializerOptions.WriteIndented = true; } - public void ConfigureServicesAfterStartup(Action servicesConfiguration) + public void ConfigureServices(Action configureServices) { - _afterServicesConfiguration = servicesConfiguration; + _configureServices = configureServices; } public async Task RunOnDatabaseAsync(Func asyncAction) @@ -143,17 +162,11 @@ public override async Task DisposeAsync() private sealed class IntegrationTestWebApplicationFactory : WebApplicationFactory { - private Action? _beforeServicesConfiguration; - private Action? _afterServicesConfiguration; + private Action? _configureServices; - public void ConfigureServicesBeforeStartup(Action? servicesConfiguration) + public void ConfigureServices(Action? configureServices) { - _beforeServicesConfiguration = servicesConfiguration; - } - - public void ConfigureServicesAfterStartup(Action? servicesConfiguration) - { - _afterServicesConfiguration = servicesConfiguration; + _configureServices = configureServices; } protected override IHostBuilder CreateHostBuilder() @@ -165,21 +178,12 @@ protected override IHostBuilder CreateHostBuilder() .CreateDefaultBuilder(null) .ConfigureWebHostDefaults(webBuilder => { - webBuilder.ConfigureServices(services => - { - _beforeServicesConfiguration?.Invoke(services); - }); - + webBuilder.ConfigureServices(services => _configureServices?.Invoke(services)); webBuilder.UseStartup(); - - webBuilder.ConfigureServices(services => - { - _afterServicesConfiguration?.Invoke(services); - }); }); - // @formatter:keep_existing_linebreaks restore // @formatter:wrap_before_first_method_call restore + // @formatter:wrap_chained_method_calls restore } } } diff --git a/test/TestBuildingBlocks/MongoDbContextShim.cs b/test/TestBuildingBlocks/MongoDbContextShim.cs index 323af40..0521914 100644 --- a/test/TestBuildingBlocks/MongoDbContextShim.cs +++ b/test/TestBuildingBlocks/MongoDbContextShim.cs @@ -10,7 +10,7 @@ namespace TestBuildingBlocks; public abstract class MongoDbContextShim { private readonly IMongoDatabase _database; - private readonly List _dbSetShims = new(); + private readonly List _dbSetShims = []; protected MongoDbContextShim(IMongoDatabase database) { @@ -27,10 +27,10 @@ protected MongoDbSetShim Set() return dbSetShim; } - public async Task ClearTableAsync() + public Task ClearTableAsync() where TEntity : IMongoIdentifiable { - await _database.DropCollectionAsync(typeof(TEntity).Name); + return _database.DropCollectionAsync(typeof(TEntity).Name); } public async Task SaveChangesAsync(CancellationToken cancellation = default) diff --git a/test/TestBuildingBlocks/MongoDbSetShim.cs b/test/TestBuildingBlocks/MongoDbSetShim.cs index 7e58223..16e35d5 100644 --- a/test/TestBuildingBlocks/MongoDbSetShim.cs +++ b/test/TestBuildingBlocks/MongoDbSetShim.cs @@ -18,7 +18,7 @@ public sealed class MongoDbSetShim : MongoDbSetShim where TEntity : IMongoIdentifiable { private readonly IMongoCollection _collection; - private readonly List _entitiesToInsert = new(); + private readonly List _entitiesToInsert = []; internal MongoDbSetShim(IMongoCollection collection) { @@ -57,9 +57,9 @@ internal override async Task PersistAsync(CancellationToken cancellationToken) } } - public async Task ExecuteAsync(Func, Task> action) + public Task ExecuteAsync(Func, Task> action) { - await action(_collection); + return action(_collection); } public async Task FirstWithIdAsync(string? id, CancellationToken cancellationToken = default) @@ -79,13 +79,13 @@ public async Task FirstWithIdAsync(string? id, CancellationToken cancel return await _collection.AsQueryable().FirstOrDefaultAsync(document => Equals(document.Id, id), cancellationToken); } - public async Task> ToListAsync(CancellationToken cancellationToken = default) + public Task> ToListAsync(CancellationToken cancellationToken = default) { - return await _collection.AsQueryable().ToListAsync(cancellationToken); + return _collection.AsQueryable().ToListAsync(cancellationToken); } - public async Task> ToListWhereAsync(Expression> predicate, CancellationToken cancellationToken = default) + public Task> ToListWhereAsync(Expression> predicate, CancellationToken cancellationToken = default) { - return await _collection.AsQueryable().Where(predicate).ToListAsync(cancellationToken); + return _collection.AsQueryable().Where(predicate).ToListAsync(cancellationToken); } } diff --git a/test/TestBuildingBlocks/MongoRunnerProvider.cs b/test/TestBuildingBlocks/MongoRunnerProvider.cs index 9565815..c22b8d5 100644 --- a/test/TestBuildingBlocks/MongoRunnerProvider.cs +++ b/test/TestBuildingBlocks/MongoRunnerProvider.cs @@ -1,7 +1,5 @@ using EphemeralMongo; -#pragma warning disable AV1553 // Do not use optional parameters with default value null for strings, collections or tasks - namespace TestBuildingBlocks; // Based on https://gist.github.com/asimmon/612b2d54f1a0d2b4e1115590d456e0be. diff --git a/test/TestBuildingBlocks/ResourceTypeFinder.cs b/test/TestBuildingBlocks/ResourceTypeFinder.cs new file mode 100644 index 0000000..c4d6ecf --- /dev/null +++ b/test/TestBuildingBlocks/ResourceTypeFinder.cs @@ -0,0 +1,31 @@ +using System.Collections.Concurrent; +using System.Reflection; +using JsonApiDotNetCore.Resources; + +#pragma warning disable AV1008 // Class should not be static + +namespace TestBuildingBlocks; + +internal static class ResourceTypeFinder +{ + private static readonly ConcurrentDictionary> ResourceTypesPerAssembly = new(); + private static readonly ConcurrentDictionary> ResourceTypesPerNamespace = new(); + + public static IReadOnlySet GetResourceClrTypesInNamespace(Assembly assembly, string? codeNamespace) + { + IReadOnlySet resourceClrTypesInAssembly = ResourceTypesPerAssembly.GetOrAdd(assembly, GetResourceClrTypesInAssembly); + + string namespaceKey = codeNamespace ?? string.Empty; + return ResourceTypesPerNamespace.GetOrAdd(namespaceKey, _ => FilterTypesInNamespace(resourceClrTypesInAssembly, codeNamespace).ToHashSet()); + } + + private static IReadOnlySet GetResourceClrTypesInAssembly(Assembly assembly) + { + return assembly.GetTypes().Where(type => type.IsAssignableTo(typeof(IIdentifiable))).ToHashSet(); + } + + private static IEnumerable FilterTypesInNamespace(IEnumerable resourceClrTypesInAssembly, string? codeNamespace) + { + return resourceClrTypesInAssembly.Where(resourceClrType => resourceClrType.Namespace == codeNamespace); + } +} diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index 9d30f13..954ef72 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -1,8 +1,10 @@ - $(TargetFrameworkName) + net8.0;net6.0 + + diff --git a/tests.runsettings b/tests.runsettings new file mode 100644 index 0000000..db83eb9 --- /dev/null +++ b/tests.runsettings @@ -0,0 +1,16 @@ + + + + true + + + + + + ObsoleteAttribute,GeneratedCodeAttribute + true + + + + +