diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index f6b7fcec..0c47e892 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -483,7 +483,7 @@ jobs: exit 2 } exit 0 - - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 3 - Non-Query)' + - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 3 - Non-Query, excluding CompiledModel)' if: always() && env.skipTests != 'true' shell: pwsh run: | @@ -495,7 +495,52 @@ jobs: } $env:EFCoreJet_DefaultConnection = '${{ env.defaultConnection }}' - & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName!~.FunctionalTests.Query." + & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName!~.FunctionalTests.Query.&FullyQualifiedName!~CompiledModel" + + # + # Check for test runner crashes: + # + + $currentTestRunTrx = Get-ChildItem $shardDir -Filter '*.trx' | Sort-Object LastWriteTime | Select-Object -Last 1 + if ($null -eq $currentTestRunTrx) { + echo 'Test runner log file is missing.' + exit 3 + } + + $currentTestRunDir = Join-Path $shardDir $currentTestRunTrx.BaseName + if (Test-Path $currentTestRunDir) { + if ($null -ne (Get-ChildItem $currentTestRunDir -Filter 'Sequence_*' -Recurse)) { + # Split string because searching the log for that phrase should only show actual crashes and not this line. + echo ('Test runner cras' + 'hed.') + continue + } + } + + echo 'Test runner ran until the end.' + break + } + + $establishedGreenTestsFilePath = ".\test\EFCore.Jet.FunctionalTests\GreenTests\ace_${{ matrix.aceVersion }}_$('${{ matrix.dataAccessProviderType }}'.Replace(' ', '').ToLowerInvariant())_${{ matrix.aceArchitecture }}.txt" + $failIfKeepsCrashing = Test-Path $establishedGreenTestsFilePath + + if ($i -ge 3 -and $failIfKeepsCrashing) { + echo 'Test runner keeps crashing.' + exit 2 + } + exit 0 + - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 4 - CompiledModel)' + if: always() && env.skipTests != 'true' + shell: pwsh + run: | + $shardDir = '.\test\EFCore.Jet.FunctionalTests\TestResults\shard4' + + for ($i = 0; $i -lt 3; $i++) { + if (Test-Path $shardDir -PathType Container) { + Get-ChildItem $shardDir | Remove-Item -Recurse -Force + } + + $env:EFCoreJet_DefaultConnection = '${{ env.defaultConnection }}' + & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName~CompiledModel" # # Check for test runner crashes: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 9ef44c20..8296ec1d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -492,7 +492,7 @@ jobs: exit 2 } exit 0 - - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 3 - Non-Query)' + - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 3 - Non-Query, excluding CompiledModel)' if: always() && env.skipTests != 'true' shell: pwsh run: | @@ -504,7 +504,52 @@ jobs: } $env:EFCoreJet_DefaultConnection = '${{ env.defaultConnection }}' - & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName!~.FunctionalTests.Query." + & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName!~.FunctionalTests.Query.&FullyQualifiedName!~CompiledModel" + + # + # Check for test runner crashes: + # + + $currentTestRunTrx = Get-ChildItem $shardDir -Filter '*.trx' | Sort-Object LastWriteTime | Select-Object -Last 1 + if ($null -eq $currentTestRunTrx) { + echo 'Test runner log file is missing.' + exit 3 + } + + $currentTestRunDir = Join-Path $shardDir $currentTestRunTrx.BaseName + if (Test-Path $currentTestRunDir) { + if ($null -ne (Get-ChildItem $currentTestRunDir -Filter 'Sequence_*' -Recurse)) { + # Split string because searching the log for that phrase should only show actual crashes and not this line. + echo ('Test runner cras' + 'hed.') + continue + } + } + + echo 'Test runner ran until the end.' + break + } + + $establishedGreenTestsFilePath = ".\test\EFCore.Jet.FunctionalTests\GreenTests\ace_${{ matrix.aceVersion }}_$('${{ matrix.dataAccessProviderType }}'.Replace(' ', '').ToLowerInvariant())_${{ matrix.aceArchitecture }}.txt" + $failIfKeepsCrashing = Test-Path $establishedGreenTestsFilePath + + if ($i -ge 3 -and $failIfKeepsCrashing) { + echo 'Test runner keeps crashing.' + exit 2 + } + exit 0 + - name: 'Run Tests: EFCore.Jet.FunctionalTests (Shard 4 - CompiledModel)' + if: always() && env.skipTests != 'true' + shell: pwsh + run: | + $shardDir = '.\test\EFCore.Jet.FunctionalTests\TestResults\shard4' + + for ($i = 0; $i -lt 3; $i++) { + if (Test-Path $shardDir -PathType Container) { + Get-ChildItem $shardDir | Remove-Item -Recurse -Force + } + + $env:EFCoreJet_DefaultConnection = '${{ env.defaultConnection }}' + & '${{ env.dotnetExecutable }}' test .\test\EFCore.Jet.FunctionalTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --logger trx --blame-hang-timeout 3m --results-directory $shardDir --filter "FullyQualifiedName~CompiledModel" # # Check for test runner crashes: diff --git a/AGENTS.md b/AGENTS.md index eddc9d01..a639b6fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ It is kept in sync with `CLAUDE.md`; if you change guidance in one, check whethe EntityFrameworkCore.Jet is an EF Core provider for Microsoft Jet/ACE databases (Microsoft Access `.mdb`/`.accdb` files). The **Jet** provider runs **Windows only** and bridges EF Core to the Access database engine via either ODBC or OLE DB. Alongside it, **LibRed** (also in this repo, on `master`) is a from-scratch managed engine that reads/writes the file format directly and is **cross-platform** — see the LibRed section below. -Current version: `11.0.0-alpha.1` (`Version.props`) targeting EF Core 11 and `net11.0`; `global.json` pins an 11.0.100 preview SDK with `rollForward: latestFeature`. The test projects use **xunit v3**. +Current version: `11.0.0-alpha.1` (`Version.props`) targeting EF Core 11 and `net11.0`; `global.json` pins the 11.0.100 RC1 SDK with `rollForward: latestFeature`. The test projects use **xunit v3**. ### Which layer am I touching? @@ -167,7 +167,7 @@ shared type subclassing or branching — see `LibRedConventionSetBuilder`, `LibR `LibRedCodeGenerator`, `LibRedDesignTimeServices`. The types below are named where they live today: - `JetServiceCollectionExtensions.AddEntityFrameworkJet()` registers all provider services. - `JetQuerySqlGenerator` extends `QuerySqlGenerator` to produce Jet-compatible SQL — converts `CAST` to Jet VBA functions (`CBOOL`, `CINT`, `CLNG`, etc.), handles boolean/numeric null semantics. -- `JetQueryTranslationPostprocessor` applies Jet-specific query rewrites in this order: skip/take transformation → base postprocessing → **append the query's last identifier column to `ORDER BY`** (deterministic tie-breaking, only when the query already orders) → optional millisecond support → ORDER BY lifting. `JetSkipTakePostprocessor` emulates `SKIP`/`OFFSET` since Jet only supports `SELECT TOP n`. Note it reaches `SelectExpression._identifier` by reflection, so an EF Core update can break it at runtime rather than at compile time. +- `JetQueryTranslationPostprocessor` applies Jet-specific query rewrites in this order: skip/take transformation → base postprocessing → ORDER BY lifting. `JetSkipTakePostprocessor` emulates `SKIP`/`OFFSET` since Jet only supports `SELECT TOP n`. LibRed's copy runs the same two steps but gates both on `LibRedSqlMode.Compatible`. - `JetMigrationsSqlGenerator` generates DDL for Access. It **does** emit `ALTER TABLE … ALTER COLUMN` (Jet's form folds the default value into the `ALTER COLUMN` rather than taking a separate operation); constraint support is still limited. - `JetHistoryRepository` implements migration locking via a `__EFMigrationsLock` table with `LockReleaseBehavior.Explicit`. - `JetRelationalConnection` creates an "empty" (masterless) connection for database creation/drop operations. diff --git a/CLAUDE.md b/CLAUDE.md index 4ccbe089..ae230437 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co EntityFrameworkCore.Jet is an EF Core provider for Microsoft Jet/ACE databases (Microsoft Access `.mdb`/`.accdb` files). The **Jet** provider runs **Windows only** and bridges EF Core to the Access database engine via either ODBC or OLE DB. Alongside it, **LibRed** (also in this repo, on `master`) is a from-scratch managed engine that reads/writes the file format directly and is **cross-platform** — see the LibRed section below. -Current version: `11.0.0-alpha.1` (`Version.props`) targeting EF Core 11 and `net11.0`; `global.json` pins an 11.0.100 preview SDK with `rollForward: latestFeature`. The test projects use **xunit v3**. +Current version: `11.0.0-alpha.1` (`Version.props`) targeting EF Core 11 and `net11.0`; `global.json` pins the 11.0.100 RC1 SDK with `rollForward: latestFeature`. The test projects use **xunit v3**. ### Which layer am I touching? @@ -179,7 +179,7 @@ shared type subclassing or branching — see `LibRedConventionSetBuilder`, `LibR `LibRedCodeGenerator`, `LibRedDesignTimeServices`. The types below are named where they live today: - `JetServiceCollectionExtensions.AddEntityFrameworkJet()` registers all provider services. - `JetQuerySqlGenerator` extends `QuerySqlGenerator` to produce Jet-compatible SQL — converts `CAST` to Jet VBA functions (`CBOOL`, `CINT`, `CLNG`, etc.), handles boolean/numeric null semantics. -- `JetQueryTranslationPostprocessor` applies Jet-specific query rewrites in this order: skip/take transformation → base postprocessing → **append the query's last identifier column to `ORDER BY`** (deterministic tie-breaking, only when the query already orders) → optional millisecond support → ORDER BY lifting. `JetSkipTakePostprocessor` emulates `SKIP`/`OFFSET` since Jet only supports `SELECT TOP n`. Note it reaches `SelectExpression._identifier` by reflection, so an EF Core update can break it at runtime rather than at compile time. +- `JetQueryTranslationPostprocessor` applies Jet-specific query rewrites in this order: skip/take transformation → base postprocessing → ORDER BY lifting. `JetSkipTakePostprocessor` emulates `SKIP`/`OFFSET` since Jet only supports `SELECT TOP n`. LibRed's copy runs the same two steps but gates both on `LibRedSqlMode.Compatible`. - `JetMigrationsSqlGenerator` generates DDL for Access. It **does** emit `ALTER TABLE … ALTER COLUMN` (Jet's form folds the default value into the `ALTER COLUMN` rather than taking a separate operation); constraint support is still limited. - `JetHistoryRepository` implements migration locking via a `__EFMigrationsLock` table with `LockReleaseBehavior.Explicit`. - `JetRelationalConnection` creates an "empty" (masterless) connection for database creation/drop operations. diff --git a/Dependencies.targets b/Dependencies.targets index 079dea98..adf32fed 100644 --- a/Dependencies.targets +++ b/Dependencies.targets @@ -1,8 +1,8 @@ - [11.0.0-preview.7.26381.103] - [11.0.0-preview.7.26381.103] - [11.0.0-preview.7.26381.103] + [11.0.0-rc.1.26425.128] + [11.0.0-rc.1.26425.128] + [11.0.0-rc.1.26425.128] @@ -12,7 +12,7 @@ - + @@ -25,27 +25,27 @@ - + - - - + + + - - - - + + + + - + diff --git a/Version.props b/Version.props index 90881e7a..18997bbd 100644 --- a/Version.props +++ b/Version.props @@ -17,7 +17,7 @@ --> 11.0.0 alpha - 1 + 2