diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1e1529f6..e653b6c4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -111,9 +111,8 @@ jobs:
matrix:
arch: [ "win-x64", "win-x86", "win-arm64",
"linux-musl-x64", "linux-musl-arm64", "linux-x64", "linux-arm64",
- "osx-x64", "osx-arm64"
+ "osx-x64"
]
-
steps:
- uses: actions/checkout@v4
- name: Setup .NET 8
@@ -126,24 +125,49 @@ jobs:
env:
VERSION: ${{ needs.set-version-number.outputs.nuGetVersion }}
- - name: Publish .NET 6/7/8 dependent ${{ matrix.arch }}
- run: dotnet publish ./src/grate/grate.csproj -r ${{ matrix.arch }} -c release --no-self-contained -o ./publish/${{ matrix.arch }}/dependent
- env:
- VERSION: ${{ needs.set-version-number.outputs.nuGetVersion }}
- name: Upload self-contained ${{ matrix.arch }}
- if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
+ #if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
uses: actions/upload-artifact@v3
with:
name: grate-${{ matrix.arch }}-self-contained-${{ needs.set-version-number.outputs.nuGetVersion }}
path: ./publish/${{ matrix.arch }}/self-contained/*
- - name: Upload .net dependent ${{ matrix.arch }}
- if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
+
+ build-standalone-mac-arm64:
+ name: Build cli
+ needs: set-version-number
+
+ # Use macos-14 to build osx-arm64, it runs on M1, see
+ # https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/
+ #
+ # I've earlier had problems with that the trimmed, self-contained binary for osx-arm64 that was built on Linux
+ # did not work when opened on an actual mac with arm64.
+
+ runs-on: macos-14
+ strategy:
+ matrix:
+ arch: [ "osx-arm64" ]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Publish self-contained ${{ matrix.arch }}
+ run: dotnet publish ./src/grate/grate.csproj -f net8.0 -r ${{ matrix.arch }} -c release --self-contained -p:SelfContained=true -o ./publish/${{ matrix.arch }}/self-contained
+ env:
+ VERSION: ${{ needs.set-version-number.outputs.nuGetVersion }}
+
+ - name: Upload self-contained ${{ matrix.arch }}
+ #if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
uses: actions/upload-artifact@v3
with:
- name: grate-${{ matrix.arch }}-framework-dependent-${{ needs.set-version-number.outputs.nuGetVersion }}
- path: ./publish/${{ matrix.arch }}/dependent/*
+ name: grate-${{ matrix.arch }}-self-contained-${{ needs.set-version-number.outputs.nuGetVersion }}
+ path: ./publish/${{ matrix.arch }}/self-contained/*
+
build-msi:
name: Build MSI
@@ -248,7 +272,7 @@ jobs:
arch=$(echo ${{ matrix.arch }} | cut -d- -f2 | sed 's/x64/amd64/')
echo "::set-output name=arch::$arch"
- - name: Create dpkg # Linux with powershell script? really?
+ - name: Create dpkg # Linux with powershell script? really? YES! :D
if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
run: ./installers/deb/Create-Package.ps1 -grateExe ./${{ matrix.arch }}/grate -Version "${{ needs.set-version-number.outputs.nuGetVersion }}" -arch ${{ steps.get-arch.outputs.arch}}
env:
@@ -260,33 +284,6 @@ jobs:
name: grate_${{ needs.set-version-number.outputs.nuGetVersion }}-1_${{ steps.get-arch.outputs.arch}}.deb
path: ./installers/deb/grate_${{ needs.set-version-number.outputs.nuGetVersion }}-1_${{ steps.get-arch.outputs.arch }}.deb
- # build-winget:
- # name: Winget - Update package manifest in the OWC
- # needs:
- # - set-version-number
- # - build-msi
- # runs-on: windows-latest
- # if: ${{ needs.set-version-number.outputs.is-release == 'true' }}
-
- # steps:
- # - name: Winget-Create
- # run: |
-
- # $version = "$($env:version)"
-
- # # Download wingetcreate
- # iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
-
- # $packageUrl="https://github.com/erikbra/grate/releases/download/$version/grate-$version.msi"
-
- # echo "Running ./wingetcreate.exe update erikbra.grate -u $packageUrl -v $version -t `"$env:WINGET_GH_PAT`" --submit"
- # ./wingetcreate.exe update erikbra.grate -u $packageUrl -v $version -t "$env:WINGET_GH_PAT" --submit
- # env:
- # WINGET_GH_PAT: ${{ secrets.WINGET_GH_PAT }}
- # #version: "1.4.0"
- # version: "${{ needs.set-version-number.outputs.nuGetVersion }}"
-
-
test:
name: Run tests
@@ -302,12 +299,87 @@ jobs:
with:
dotnet-version: 8.0.x
- name: Test
- run: |
- dotnet test \
- unittests/${{ matrix.category }} \
- --logger:"xunit;LogFilePath=/tmp/test-results/${{ matrix.category }}.xml" -- \
- -MaxCpuCount 2
+ run: >
+ dotnet test
+ unittests/${{ matrix.category }}
+ --logger:"xunit;LogFilePath=/tmp/test-results/${{ matrix.category }}.xml" --
+ -MaxCpuCount 2
+ env:
+ LogLevel: Warning
+ TZ: UTC
+
+ integration-test:
+ name: Tests cli
+ needs:
+ - set-version-number
+ - build-standalone
+
+ strategy:
+ # We could really like to:
+ # - Start each database (on another host, using Docker, or other means, e.g. Azure SQL, etc
+ # - On all architectures available (windows-latest, linux-latest, macos-latest, and macos-14),
+ # - Run command-line tests against each database.
+ #
+ # This way, we can test against all variations of each database too, e.g. Azure SQL, SQL Server "on prem" (in docker),
+ # hosted Oracle databases, aws databases, etc. But we need to find a way to provision these databases both very fast,
+ # and cheap, for each one.
+ matrix:
+ category:
+ - CommandLine.SqlServer
+ - CommandLine.PostgreSQL
+ - CommandLine.MariaDB
+ - CommandLine.Sqlite
+ - CommandLine.Oracle
+ os:
+ # We can only run tests on Linux for now, until we start the database separately somewhere (azure, something)
+ # and run against an external database. Because the commandline tests are also for now _dependent_ on
+ # TestContainers, and running the database in a container using Docker. And Docker is only available on Linux
+ # on Github actions.
+ # - os: windows-latest
+ # executable: grate.exe
+ # - name: windows-latest
+ # arch: win-x64
+ # executable: grate.exe
+ # - os: linux-latest
+ # executable: grate
+ - name: linux-latest
+ arch: linux-x64
+ executable: grate
+ # - os: macos-latest
+ # executable: grate
+ # - name: macos-latest
+ # arch: osx-x64
+ # executable: grate
+ # macos-14 is M1 (arm64)
+ # - name: macos-14
+ # arch: osx-x64
+ # executable: grate
+
+ runs-on: ${{ matrix.os.name }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/download-artifact@v3
+ with:
+ name: grate-${{ matrix.os.arch }}-self-contained-${{ needs.set-version-number.outputs.nuGetVersion }}
+ path: executables/${{ matrix.os.arch }}
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: chmod u+x
+ run: chmod u+x $GrateExecutablePath
+ if: ${{ matrix.os.arch != 'win-x64' }}
+ env:
+ GrateExecutablePath: ${{ github.workspace }}/executables/${{ matrix.os.arch }}/${{ matrix.os.executable }}
+ - name: Test
+ run: >
+ dotnet test
+ unittests/CommandLine/${{ matrix.category }}
+ --logger:"xunit;LogFilePath=/tmp/test-results/${{ matrix.os.arch }}/${{ matrix.category }}.xml" --
+ -MaxCpuCount 2
env:
LogLevel: Warning
+ GrateExecutablePath: ${{ github.workspace }}/executables/${{ matrix.os.arch }}/${{ matrix.os.executable }}
TZ: UTC
diff --git a/.gitignore b/.gitignore
index 303dae0f..e6c0f944 100644
--- a/.gitignore
+++ b/.gitignore
@@ -355,3 +355,5 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
/grate/Properties/launchSettings.json
+
+.DS_Store
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 1cfb7df4..acec9dbf 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -20,6 +20,7 @@
+
diff --git a/grate.sln b/grate.sln
index b1c98c88..d00c30ff 100644
--- a/grate.sln
+++ b/grate.sln
@@ -43,6 +43,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grate.core", "src\grate.cor
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grate", "src\grate\grate.csproj", "{9D3377C2-1E3C-40C9-A5F1-DF41DFDFDD9D}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Command line tests", "Command line tests", "{04731BDA-05F0-4275-AC70-3E60E87F9461}"
+ ProjectSection(SolutionItems) = preProject
+ unittests\CommandLine\IncludeTests.targets = unittests\CommandLine\IncludeTests.targets
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.Common", "unittests\CommandLine\CommandLine.Common\CommandLine.Common.csproj", "{DB220C5D-7B52-4389-B568-793FCD4286AA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.MariaDB", "unittests\CommandLine\CommandLine.MariaDB\CommandLine.MariaDB.csproj", "{088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.Sqlite", "unittests\CommandLine\CommandLine.Sqlite\CommandLine.Sqlite.csproj", "{ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.Oracle", "unittests\CommandLine\CommandLine.Oracle\CommandLine.Oracle.csproj", "{BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.PostgreSQL", "unittests\CommandLine\CommandLine.PostgreSQL\CommandLine.PostgreSQL.csproj", "{89CBE842-BD34-4833-96B4-9E410C5C6AD7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.SqlServer", "unittests\CommandLine\CommandLine.SqlServer\CommandLine.SqlServer.csproj", "{3CD81B8C-9348-4F45-9E50-12713D47B1FB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -233,6 +250,78 @@ Global
{9D3377C2-1E3C-40C9-A5F1-DF41DFDFDD9D}.Release|x64.Build.0 = Release|Any CPU
{9D3377C2-1E3C-40C9-A5F1-DF41DFDFDD9D}.Release|x86.ActiveCfg = Release|Any CPU
{9D3377C2-1E3C-40C9-A5F1-DF41DFDFDD9D}.Release|x86.Build.0 = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|x64.Build.0 = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Debug|x86.Build.0 = Debug|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|x64.ActiveCfg = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|x64.Build.0 = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|x86.ActiveCfg = Release|Any CPU
+ {DB220C5D-7B52-4389-B568-793FCD4286AA}.Release|x86.Build.0 = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|x64.Build.0 = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Debug|x86.Build.0 = Debug|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|x64.ActiveCfg = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|x64.Build.0 = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|x86.ActiveCfg = Release|Any CPU
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE}.Release|x86.Build.0 = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|x64.Build.0 = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Debug|x86.Build.0 = Debug|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|x64.ActiveCfg = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|x64.Build.0 = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|x86.ActiveCfg = Release|Any CPU
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B}.Release|x86.Build.0 = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|x64.Build.0 = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Debug|x86.Build.0 = Debug|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|x64.ActiveCfg = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|x64.Build.0 = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|x86.ActiveCfg = Release|Any CPU
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8}.Release|x86.Build.0 = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|x64.Build.0 = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Debug|x86.Build.0 = Debug|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|x64.ActiveCfg = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|x64.Build.0 = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|x86.ActiveCfg = Release|Any CPU
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7}.Release|x86.Build.0 = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|x64.Build.0 = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Debug|x86.Build.0 = Debug|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|x64.ActiveCfg = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|x64.Build.0 = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|x86.ActiveCfg = Release|Any CPU
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -256,5 +345,12 @@ Global
{69DE6B9D-F937-4AF4-A75E-40F5507B4C83} = {34C2458F-1244-4AF5-B5B5-B349CAEB17A5}
{3BAF5373-6009-405B-AC9D-C8FFFB263E6B} = {34C2458F-1244-4AF5-B5B5-B349CAEB17A5}
{9D3377C2-1E3C-40C9-A5F1-DF41DFDFDD9D} = {34C2458F-1244-4AF5-B5B5-B349CAEB17A5}
+ {04731BDA-05F0-4275-AC70-3E60E87F9461} = {CE4BF96D-E795-49EC-BB36-EDCC7E542685}
+ {DB220C5D-7B52-4389-B568-793FCD4286AA} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
+ {088D2F44-26AE-4DCE-9668-8B8A38EDD5EE} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
+ {ABFC5823-ACCF-4CFC-9EDA-90F7DD8A930B} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
+ {BD31AD42-D1A0-4131-9DD5-7DA83F3F34A8} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
+ {89CBE842-BD34-4833-96B4-9E410C5C6AD7} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
+ {3CD81B8C-9348-4F45-9E50-12713D47B1FB} = {04731BDA-05F0-4275-AC70-3E60E87F9461}
EndGlobalSection
EndGlobal
diff --git a/src/grate.core/Configuration/FoldersConfiguration.cs b/src/grate.core/Configuration/FoldersConfiguration.cs
index c7be5f58..598427a8 100644
--- a/src/grate.core/Configuration/FoldersConfiguration.cs
+++ b/src/grate.core/Configuration/FoldersConfiguration.cs
@@ -26,6 +26,8 @@ public FoldersConfiguration()
public MigrationsFolder? DropDatabase { get; set; }
public static FoldersConfiguration Empty => new();
+
+ public override string ToString() => string.Join(';', Values);
public static IFoldersConfiguration Default(IKnownFolderNames? folderNames = null)
{
diff --git a/src/grate.core/Configuration/MigrationsFolder.cs b/src/grate.core/Configuration/MigrationsFolder.cs
index a1e071df..1821377e 100644
--- a/src/grate.core/Configuration/MigrationsFolder.cs
+++ b/src/grate.core/Configuration/MigrationsFolder.cs
@@ -27,4 +27,6 @@ public MigrationsFolder(
: this(name, name, type, connectionType, transactionHandling)
{ }
+ public override string ToString() =>
+ $"{Name}=path:{Path},type:{Type},connectionType:{ConnectionType},transactionHandling:{TransactionHandling}";
}
diff --git a/src/grate.core/Infrastructure/GrateEnvironment.cs b/src/grate.core/Infrastructure/GrateEnvironment.cs
index d28cb796..acb16f51 100644
--- a/src/grate.core/Infrastructure/GrateEnvironment.cs
+++ b/src/grate.core/Infrastructure/GrateEnvironment.cs
@@ -20,4 +20,5 @@ private bool IsForCurrentEnvironment(string path) =>
public static bool IsEnvironmentFile(string fileName) => fileName.Contains(EnvironmentMarker, InvariantCultureIgnoreCase);
private static string FileName(string path) => new FileInfo(path).Name;
+ public override string ToString() => Current;
}
diff --git a/src/grate.core/grate.core.csproj b/src/grate.core/grate.core.csproj
index 29ce0d8b..270d1000 100644
--- a/src/grate.core/grate.core.csproj
+++ b/src/grate.core/grate.core.csproj
@@ -17,6 +17,11 @@
+
+
+
+
+
diff --git a/src/grate/grate.csproj b/src/grate/grate.csproj
index f60b09de..ca42d5c9 100644
--- a/src/grate/grate.csproj
+++ b/src/grate/grate.csproj
@@ -9,6 +9,12 @@
+
+
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.Common/CommandLine.Common.csproj b/unittests/CommandLine/CommandLine.Common/CommandLine.Common.csproj
new file mode 100644
index 00000000..9347f583
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/CommandLine.Common.csproj
@@ -0,0 +1,40 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ false
+
+ CommandLine.Common.Startup
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_Parameter1>$(MSBuildProjectDirectory)/$(OutputPath)/grate
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.Common/GrateExecutablePathAttribute.cs b/unittests/CommandLine/CommandLine.Common/GrateExecutablePathAttribute.cs
new file mode 100644
index 00000000..761db8c9
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/GrateExecutablePathAttribute.cs
@@ -0,0 +1,8 @@
+namespace CommandLine.Common;
+
+[AttributeUsage(AttributeTargets.Assembly)]
+public class GrateExecutablePathAttribute(string path) : Attribute
+{
+ public string Path { get; set; } = path;
+}
+
diff --git a/unittests/CommandLine/CommandLine.Common/Startup.cs b/unittests/CommandLine/CommandLine.Common/Startup.cs
new file mode 100644
index 00000000..89369daf
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/Startup.cs
@@ -0,0 +1,40 @@
+using CommandLine.Common.TestInfrastructure;
+using grate.Configuration;
+using grate.Migration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Common;
+
+// ReSharper disable once UnusedType.Global
+public abstract class Startup
+{
+ // ReSharper disable once UnusedMember.Global
+ public void ConfigureServices(IServiceCollection services, HostBuilderContext context)
+ {
+ services.AddLogging(
+ lb => lb
+ .AddXUnit()
+ .AddConsole()
+ .SetMinimumLevel(TestConfig.GetLogLevel())
+ );
+
+ services.AddSingleton(new CommandLineGrateMigrator(DatabaseType));
+
+ services.TryAddSingleton(TestContextType);
+ services.TryAddSingleton(TestContainerType);
+
+ services.TryAddTransient(provider =>
+ new CommandLineGrateTestContext(
+ provider.GetRequiredService(),
+ (IGrateTestContext) provider.GetRequiredService(TestContextType)));
+ }
+
+ protected abstract DatabaseType DatabaseType { get; }
+ protected abstract Type TestContainerType { get; }
+ protected abstract Type TestContextType { get; }
+
+}
diff --git a/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineGrateMigrator.cs b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineGrateMigrator.cs
new file mode 100644
index 00000000..4ed7c097
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineGrateMigrator.cs
@@ -0,0 +1,136 @@
+using System.Diagnostics;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using grate.Commands;
+using grate.Configuration;
+using grate.Exceptions;
+using grate.Migration;
+
+namespace CommandLine.Common.TestInfrastructure;
+
+public record CommandLineGrateMigrator(DatabaseType DatabaseType) : IGrateMigrator
+{
+ public DatabaseType DatabaseType { get; set; } = DatabaseType;
+
+ public async Task Migrate()
+ {
+ // Convert configuration to command-line arguments
+ var convertToCommandLineArguments = ConvertToCommandLineArguments(Configuration);
+ var commandLineArguments = convertToCommandLineArguments.ToList();
+
+ // Add the database type
+ commandLineArguments.Add("--databasetype=" + DatabaseType.ToString().ToLowerInvariant());
+
+ // Run the command-line tool with the arguments
+ var processInfo = new ProcessStartInfo(GrateExecutable, commandLineArguments)
+ {
+ RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false,
+ };
+
+ using var process = Process.Start(processInfo);
+ await process!.WaitForExitAsync();
+
+ var output = await process.StandardOutput.ReadToEndAsync();
+ var error = await process.StandardError.ReadToEndAsync();
+
+ var exitCode = process.ExitCode;
+ if (exitCode != 0)
+ {
+ try
+ {
+ throw new Exception($"grate failed with exit code {exitCode}. Output: {output}. Error: {error}");
+ }catch (Exception e)
+ {
+ throw new MigrationFailed(e);
+ }
+ }
+
+ }
+
+ public GrateConfiguration Configuration { get; private init; } = null!;
+
+ public IGrateMigrator WithConfiguration(GrateConfiguration configuration)
+ {
+ return this with { Configuration = configuration };
+ }
+
+ public IGrateMigrator WithConfiguration(Action builder)
+ {
+ var b = GrateConfigurationBuilder.Create(Configuration);
+ builder.Invoke(b);
+ return this with { Configuration = b.Build() };
+ }
+
+ public IGrateMigrator WithDatabase(IDatabase database) => this with { Database = database };
+ public IDatabase? Database { get; set; }
+
+
+ private List ConvertToCommandLineArguments(GrateConfiguration configuration)
+ {
+ List result = new();
+
+ var properties = configuration.GetType().GetProperties();
+
+ var cmd = new MigrateCommand(this);
+
+ foreach (var prop in properties)
+ {
+ // Skip properties with default values
+ var value = prop.GetValue(configuration);
+ var defaultValue = prop.GetValue(GrateConfiguration.Default);
+
+ var serializedValue = JsonSerializer.Serialize(value?.ToString(), SerializerOptions);
+ var serializedDefault = JsonSerializer.Serialize(defaultValue?.ToString(), SerializerOptions);
+
+ if (serializedValue.Equals(serializedDefault))
+ {
+ continue;
+ }
+
+ // Convert IFoldersConfiguration to string
+ if (value is IFoldersConfiguration foldersConfiguration)
+ {
+ value = string.Join(';', foldersConfiguration.Values);
+ }
+
+ var name = prop.Name;
+ var option = cmd.Options.FirstOrDefault(o => string.Equals(o.Name, name, StringComparison.OrdinalIgnoreCase));
+
+ if (option is not null && value is not null)
+ {
+ var optionName = option.Aliases.FirstOrDefault(alias => alias.StartsWith("--"))
+ ?? option.Aliases.First();
+
+ if (value is string[] arr)
+ {
+ result.AddRange(arr.Select(v => $"{optionName}={v}"));
+ }
+ else
+ {
+ result.Add($"{optionName}={value}");
+ }
+ }
+ }
+
+ return result;
+#pragma warning restore CS0162 // Unreachable code detected
+ }
+
+ private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerOptions.Default)
+ {
+ ReferenceHandler = ReferenceHandler.IgnoreCycles
+ };
+
+ private static string GrateExecutable =>
+ Environment.GetEnvironmentVariable("GrateExecutablePath") ??
+ typeof(CommandLineGrateMigrator).Assembly.GetCustomAttribute()?.Path
+ ?? throw new Exception("Grate executable path not found");
+
+
+ public ValueTask DisposeAsync()
+ {
+ return new ValueTask(Task.CompletedTask);
+ }
+
+}
diff --git a/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineTestFramework.cs b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineTestFramework.cs
new file mode 100644
index 00000000..b900c537
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandLineTestFramework.cs
@@ -0,0 +1,48 @@
+// using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+// using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+// using Xunit.Abstractions;
+// using Xunit.Sdk;
+//
+// namespace CommandLine_tests.TestInfrastructure;
+//
+// public class CommandLineTestFramework : XunitTestFramework
+// {
+// public CommandLineTestFramework(IMessageSink messageSink)
+// : base(messageSink)
+// {
+// }
+//
+// protected override ITestFrameworkDiscoverer CreateDiscoverer(
+// IAssemblyInfo assemblyInfo)
+// => new CommandLineTestFrameworkDiscoverer(
+// assemblyInfo,
+// SourceInformationProvider,
+// DiagnosticMessageSink);
+// }
+// public class CommandLineTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer
+// {
+// public CommandLineTestFrameworkDiscoverer(
+// IAssemblyInfo assemblyInfo,
+// ISourceInformationProvider sourceProvider,
+// IMessageSink diagnosticMessageSink,
+// IXunitTestCollectionFactory? collectionFactory = null)
+// : base(
+// assemblyInfo,
+// sourceProvider,
+// diagnosticMessageSink,
+// collectionFactory)
+// {
+// }
+//
+// protected override bool IsValidTestClass(ITypeInfo type)
+// => base.IsValidTestClass(type) &&
+// FilterType(type);
+//
+// protected virtual bool FilterType(ITypeInfo type)
+// {
+// // Insert your custom filter conditions here.
+// return true;
+// }
+// }
+//
+//
diff --git a/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandlineGrateTestContext.cs b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandlineGrateTestContext.cs
new file mode 100644
index 00000000..88755037
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Common/TestInfrastructure/CommandlineGrateTestContext.cs
@@ -0,0 +1,39 @@
+using System.Data;
+using grate.Infrastructure;
+using grate.Migration;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Common.TestInfrastructure;
+
+public class CommandLineGrateTestContext : IGrateTestContext
+{
+ private readonly IGrateTestContext _testContext;
+
+ public CommandLineGrateTestContext(
+ IGrateMigrator migrator,
+ IGrateTestContext testContext)
+ {
+ _testContext = testContext;
+ Migrator = migrator;
+ }
+
+ public IGrateMigrator Migrator { get; }
+
+ public string AdminConnectionString => _testContext.AdminConnectionString;
+ public string ConnectionString(string database) => _testContext.ConnectionString(database);
+ public string UserConnectionString(string database) => _testContext.UserConnectionString(database);
+
+ public IDbConnection GetDbConnection(string connectionString) => _testContext.GetDbConnection(connectionString);
+
+ public ISyntax Syntax => _testContext.Syntax;
+ public Type DbExceptionType => _testContext.DbExceptionType;
+
+ public Type DatabaseType => _testContext.DbExceptionType;
+ public bool SupportsTransaction => _testContext.SupportsTransaction;
+
+ public SqlStatements Sql => _testContext.Sql;
+
+ public string ExpectedVersionPrefix => _testContext.ExpectedVersionPrefix;
+ public bool SupportsCreateDatabase => _testContext.SupportsCreateDatabase;
+ public bool SupportsSchemas => _testContext.SupportsSchemas;
+}
diff --git a/unittests/CommandLine/CommandLine.MariaDB/CommandLine.MariaDB.csproj b/unittests/CommandLine/CommandLine.MariaDB/CommandLine.MariaDB.csproj
new file mode 100644
index 00000000..92070270
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.MariaDB/CommandLine.MariaDB.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+ ../../MariaDB
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/Failing_Scripts.cs b/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/Failing_Scripts.cs
new file mode 100644
index 00000000..97400975
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/Failing_Scripts.cs
@@ -0,0 +1,24 @@
+using MariaDB.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.MariaDB.Running_MigrationScripts;
+
+[Collection(nameof(MariaDbTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class Failing_Scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.Failing_Scripts(testContext, testOutput)
+{
+ protected override string ExpectedErrorMessageForInvalidSql => "Not relevant";
+ protected override IDictionary ExpectedErrorDetails => new Dictionary();
+
+ [Fact(Skip = "Cannot check on the exact error message when running the command line tool. The error message is not available.")]
+ public override Task Aborts_the_run_giving_an_error_message() => Task.CompletedTask;
+
+ [Fact(Skip = "Cannot check on the exact error details when running the command line tool. The error details are not available.")]
+ public override Task Exception_includes_details_on_the_failed_script() => Task.CompletedTask;
+
+ [Fact(Skip =
+ "We do not have the ability to check for transient errors when running the command line tool. The error details are not available.")]
+ public override Task Exception_is_set_to_transient_based_on_inner_exceptions() => Task.CompletedTask;
+
+}
diff --git a/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/One_time_scripts.cs b/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/One_time_scripts.cs
new file mode 100644
index 00000000..7da55a14
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.MariaDB/Running_MigrationScripts/One_time_scripts.cs
@@ -0,0 +1,58 @@
+using Dapper;
+using FluentAssertions;
+using grate.Configuration;
+using grate.Exceptions;
+using MariaDB.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+using static grate.Configuration.KnownFolderKeys;
+
+namespace CommandLine.MariaDB.Running_MigrationScripts;
+
+[Collection(nameof(MariaDbTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class One_time_scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.One_time_scripts(testContext, testOutput)
+{
+
+ [Fact]
+ public override async Task Fails_if_changed_between_runs()
+ {
+ var db = TestConfig.RandomDatabase();
+
+ var parent = CreateRandomTempDirectory();
+ var knownFolders = FoldersConfiguration.Default(null);
+ CreateDummySql(parent, knownFolders[Up]);
+
+ var config = GrateConfigurationBuilder.Create(Context.DefaultConfiguration)
+ .WithConnectionString(Context.ConnectionString(db))
+ .WithFolders(knownFolders)
+ .WithSqlFilesDirectory(parent)
+ .Build();
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ await migrator.Migrate();
+ }
+
+ WriteSomeOtherSql(parent, knownFolders[Up]);
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ var ex = await Assert.ThrowsAsync(() => migrator.Migrate());
+ }
+
+ string[] scripts;
+ string sql = $"SELECT text_of_script FROM {Context.Syntax.TableWithSchema("grate", "ScriptsRun")}";
+
+ using (var conn = Context.CreateDbConnection(db))
+ {
+ scripts = (await conn.QueryAsync(sql)).ToArray();
+ }
+
+ scripts.Should().HaveCount(1);
+ scripts.First().Should().Be(Context.Sql.SelectVersion);
+ }
+
+}
+
+
diff --git a/unittests/CommandLine/CommandLine.MariaDB/Startup.cs b/unittests/CommandLine/CommandLine.MariaDB/Startup.cs
new file mode 100644
index 00000000..197353f7
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.MariaDB/Startup.cs
@@ -0,0 +1,12 @@
+using grate.Configuration;
+using MariaDB.TestInfrastructure;
+
+namespace CommandLine.MariaDB;
+
+// ReSharper disable once UnusedType.Global
+public class Startup: CommandLine.Common.Startup
+{
+ protected override DatabaseType DatabaseType => DatabaseType.MariaDB;
+ protected override Type TestContainerType => typeof(MariaDbTestContainer);
+ protected override Type TestContextType => typeof(MariaDbGrateTestContext);
+}
diff --git a/unittests/CommandLine/CommandLine.Oracle/CommandLine.Oracle.csproj b/unittests/CommandLine/CommandLine.Oracle/CommandLine.Oracle.csproj
new file mode 100644
index 00000000..b4e5ecb9
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Oracle/CommandLine.Oracle.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+ ../../Oracle
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/Failing_Scripts.cs b/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/Failing_Scripts.cs
new file mode 100644
index 00000000..0f593728
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/Failing_Scripts.cs
@@ -0,0 +1,23 @@
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Oracle.Running_MigrationScripts;
+
+[Collection(nameof(OracleTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class Failing_Scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.Failing_Scripts(testContext, testOutput)
+{
+ protected override string ExpectedErrorMessageForInvalidSql => "Not relevant";
+ protected override IDictionary ExpectedErrorDetails => new Dictionary();
+
+ [Fact(Skip = "Cannot check on the exact error message when running the command line tool. The error message is not available.")]
+ public override Task Aborts_the_run_giving_an_error_message() => Task.CompletedTask;
+
+ [Fact(Skip = "Cannot check on the exact error details when running the command line tool. The error details are not available.")]
+ public override Task Exception_includes_details_on_the_failed_script() => Task.CompletedTask;
+
+ [Fact(Skip =
+ "We do not have the ability to check for transient errors when running the command line tool. The error details are not available.")]
+ public override Task Exception_is_set_to_transient_based_on_inner_exceptions() => Task.CompletedTask;
+
+}
diff --git a/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/One_time_scripts.cs b/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/One_time_scripts.cs
new file mode 100644
index 00000000..899cbbdf
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Oracle/Running_MigrationScripts/One_time_scripts.cs
@@ -0,0 +1,59 @@
+using Dapper;
+using FluentAssertions;
+using grate.Configuration;
+using grate.Exceptions;
+using TestCommon.TestInfrastructure;
+using static grate.Configuration.KnownFolderKeys;
+
+namespace CommandLine.Oracle.Running_MigrationScripts;
+
+[Collection(nameof(OracleTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class One_time_scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.One_time_scripts(testContext, testOutput)
+{
+ protected override string CreateView1 => base.CreateView1 + " FROM DUAL";
+ protected override string CreateView2 => base.CreateView2 + " FROM DUAL";
+
+ [Fact]
+ public override async Task Fails_if_changed_between_runs()
+ {
+ var db = TestConfig.RandomDatabase();
+
+ var parent = CreateRandomTempDirectory();
+ var knownFolders = FoldersConfiguration.Default(null);
+ CreateDummySql(parent, knownFolders[Up]);
+
+ var config = GrateConfigurationBuilder.Create(Context.DefaultConfiguration)
+ .WithConnectionString(Context.ConnectionString(db))
+ .WithFolders(knownFolders)
+ .WithSqlFilesDirectory(parent)
+ .Build();
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ await migrator.Migrate();
+ }
+
+ WriteSomeOtherSql(parent, knownFolders[Up]);
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ var ex = await Assert.ThrowsAsync(() => migrator.Migrate());
+ }
+
+ string[] scripts;
+ string sql = $"SELECT text_of_script FROM {Context.Syntax.TableWithSchema("grate", "ScriptsRun")}";
+
+ using (var conn = Context.CreateDbConnection(db))
+ {
+ scripts = (await conn.QueryAsync(sql)).ToArray();
+ }
+
+ scripts.Should().HaveCount(1);
+ scripts.First().Should().Be(Context.Sql.SelectVersion);
+ }
+
+}
+
+
diff --git a/unittests/CommandLine/CommandLine.Oracle/Startup.cs b/unittests/CommandLine/CommandLine.Oracle/Startup.cs
new file mode 100644
index 00000000..249b3c37
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Oracle/Startup.cs
@@ -0,0 +1,13 @@
+using grate.Configuration;
+using Oracle.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Oracle;
+
+// ReSharper disable once UnusedType.Global
+public class Startup: CommandLine.Common.Startup
+{
+ protected override DatabaseType DatabaseType => DatabaseType.Oracle;
+ protected override Type TestContainerType => typeof(OracleTestContainer);
+ protected override Type TestContextType => typeof(OracleGrateTestContext);
+}
diff --git a/unittests/CommandLine/CommandLine.PostgreSQL/CommandLine.PostgreSQL.csproj b/unittests/CommandLine/CommandLine.PostgreSQL/CommandLine.PostgreSQL.csproj
new file mode 100644
index 00000000..e524c1a5
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.PostgreSQL/CommandLine.PostgreSQL.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+ ../../PostgreSQL
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/Failing_Scripts.cs b/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/Failing_Scripts.cs
new file mode 100644
index 00000000..e06cdcde
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/Failing_Scripts.cs
@@ -0,0 +1,23 @@
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.PostgreSQL.Running_MigrationScripts;
+
+[Collection(nameof(PostgreSqlTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class Failing_Scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.Failing_Scripts(testContext, testOutput)
+{
+ protected override string ExpectedErrorMessageForInvalidSql => "Not relevant";
+ protected override IDictionary ExpectedErrorDetails => new Dictionary();
+
+ [Fact(Skip = "Cannot check on the exact error message when running the command line tool. The error message is not available.")]
+ public override Task Aborts_the_run_giving_an_error_message() => Task.CompletedTask;
+
+ [Fact(Skip = "Cannot check on the exact error details when running the command line tool. The error details are not available.")]
+ public override Task Exception_includes_details_on_the_failed_script() => Task.CompletedTask;
+
+ [Fact(Skip =
+ "We do not have the ability to check for transient errors when running the command line tool. The error details are not available.")]
+ public override Task Exception_is_set_to_transient_based_on_inner_exceptions() => Task.CompletedTask;
+
+}
diff --git a/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/One_time_scripts.cs b/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/One_time_scripts.cs
new file mode 100644
index 00000000..9e7f9f8a
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.PostgreSQL/Running_MigrationScripts/One_time_scripts.cs
@@ -0,0 +1,56 @@
+using Dapper;
+using FluentAssertions;
+using grate.Configuration;
+using grate.Exceptions;
+using TestCommon.TestInfrastructure;
+using static grate.Configuration.KnownFolderKeys;
+
+namespace CommandLine.PostgreSQL.Running_MigrationScripts;
+
+[Collection(nameof(PostgreSqlTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class One_time_scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.One_time_scripts(testContext, testOutput)
+{
+ [Fact]
+ public override async Task Fails_if_changed_between_runs()
+ {
+ var db = TestConfig.RandomDatabase();
+
+ var parent = CreateRandomTempDirectory();
+ var knownFolders = FoldersConfiguration.Default(null);
+ CreateDummySql(parent, knownFolders[Up]);
+
+ var config = GrateConfigurationBuilder.Create(Context.DefaultConfiguration)
+ .WithConnectionString(Context.ConnectionString(db))
+ .WithFolders(knownFolders)
+ .WithSqlFilesDirectory(parent)
+ .Build();
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ await migrator.Migrate();
+ }
+
+ WriteSomeOtherSql(parent, knownFolders[Up]);
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ var ex = await Assert.ThrowsAsync(() => migrator.Migrate());
+ }
+
+ string[] scripts;
+ string sql = $"SELECT text_of_script FROM {Context.Syntax.TableWithSchema("grate", "ScriptsRun")}";
+
+ using (var conn = Context.CreateDbConnection(db))
+ {
+ scripts = (await conn.QueryAsync(sql)).ToArray();
+ }
+
+ scripts.Should().HaveCount(1);
+ scripts.First().Should().Be(Context.Sql.SelectVersion);
+ }
+
+}
+
+
diff --git a/unittests/CommandLine/CommandLine.PostgreSQL/Startup.cs b/unittests/CommandLine/CommandLine.PostgreSQL/Startup.cs
new file mode 100644
index 00000000..bd2731ab
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.PostgreSQL/Startup.cs
@@ -0,0 +1,13 @@
+using grate.Configuration;
+using PostgreSQL.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.PostgreSQL;
+
+// ReSharper disable once UnusedType.Global
+public class Startup: CommandLine.Common.Startup
+{
+ protected override DatabaseType DatabaseType => DatabaseType.PostgreSQL;
+ protected override Type TestContainerType => typeof(PostgreSqlTestContainer);
+ protected override Type TestContextType => typeof(PostgreSqlGrateTestContext);
+}
diff --git a/unittests/CommandLine/CommandLine.SqlServer/CommandLine.SqlServer.csproj b/unittests/CommandLine/CommandLine.SqlServer/CommandLine.SqlServer.csproj
new file mode 100644
index 00000000..fe1ef6bf
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.SqlServer/CommandLine.SqlServer.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+ ../../SqlServer
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/Failing_Scripts.cs b/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/Failing_Scripts.cs
new file mode 100644
index 00000000..23b10507
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/Failing_Scripts.cs
@@ -0,0 +1,23 @@
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.SqlServer.Running_MigrationScripts;
+
+[Collection(nameof(SqlServerTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class Failing_Scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.Failing_Scripts(testContext, testOutput)
+{
+ protected override string ExpectedErrorMessageForInvalidSql => "Not relevant";
+ protected override IDictionary ExpectedErrorDetails => new Dictionary();
+
+ [Fact(Skip = "Cannot check on the exact error message when running the command line tool. The error message is not available.")]
+ public override Task Aborts_the_run_giving_an_error_message() => Task.CompletedTask;
+
+ [Fact(Skip = "Cannot check on the exact error details when running the command line tool. The error details are not available.")]
+ public override Task Exception_includes_details_on_the_failed_script() => Task.CompletedTask;
+
+ [Fact(Skip =
+ "We do not have the ability to check for transient errors when running the command line tool. The error details are not available.")]
+ public override Task Exception_is_set_to_transient_based_on_inner_exceptions() => Task.CompletedTask;
+
+}
diff --git a/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/One_time_scripts.cs b/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/One_time_scripts.cs
new file mode 100644
index 00000000..0dbdb2f9
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.SqlServer/Running_MigrationScripts/One_time_scripts.cs
@@ -0,0 +1,56 @@
+using Dapper;
+using FluentAssertions;
+using grate.Configuration;
+using grate.Exceptions;
+using TestCommon.TestInfrastructure;
+using static grate.Configuration.KnownFolderKeys;
+
+namespace CommandLine.SqlServer.Running_MigrationScripts;
+
+[Collection(nameof(SqlServerTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class One_time_scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.One_time_scripts(testContext, testOutput)
+{
+ [Fact]
+ public override async Task Fails_if_changed_between_runs()
+ {
+ var db = TestConfig.RandomDatabase();
+
+ var parent = CreateRandomTempDirectory();
+ var knownFolders = FoldersConfiguration.Default(null);
+ CreateDummySql(parent, knownFolders[Up]);
+
+ var config = GrateConfigurationBuilder.Create(Context.DefaultConfiguration)
+ .WithConnectionString(Context.ConnectionString(db))
+ .WithFolders(knownFolders)
+ .WithSqlFilesDirectory(parent)
+ .Build();
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ await migrator.Migrate();
+ }
+
+ WriteSomeOtherSql(parent, knownFolders[Up]);
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ var ex = await Assert.ThrowsAsync(() => migrator.Migrate());
+ }
+
+ string[] scripts;
+ string sql = $"SELECT text_of_script FROM {Context.Syntax.TableWithSchema("grate", "ScriptsRun")}";
+
+ using (var conn = Context.CreateDbConnection(db))
+ {
+ scripts = (await conn.QueryAsync(sql)).ToArray();
+ }
+
+ scripts.Should().HaveCount(1);
+ scripts.First().Should().Be(Context.Sql.SelectVersion);
+ }
+
+}
+
+
diff --git a/unittests/CommandLine/CommandLine.SqlServer/Startup.cs b/unittests/CommandLine/CommandLine.SqlServer/Startup.cs
new file mode 100644
index 00000000..c6e7d870
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.SqlServer/Startup.cs
@@ -0,0 +1,13 @@
+using grate.Configuration;
+using SqlServer.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.SqlServer;
+
+// ReSharper disable once UnusedType.Global
+public class Startup: CommandLine.Common.Startup
+{
+ protected override DatabaseType DatabaseType => DatabaseType.SQLServer;
+ protected override Type TestContainerType => typeof(SqlServerTestContainer);
+ protected override Type TestContextType => typeof(SqlServerGrateTestContext);
+}
diff --git a/unittests/CommandLine/CommandLine.Sqlite/CommandLine.Sqlite.csproj b/unittests/CommandLine/CommandLine.Sqlite/CommandLine.Sqlite.csproj
new file mode 100644
index 00000000..3550dc0d
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Sqlite/CommandLine.Sqlite.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+ ../../Sqlite
+
+
+
+
diff --git a/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/Failing_Scripts.cs b/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/Failing_Scripts.cs
new file mode 100644
index 00000000..536d9bc0
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/Failing_Scripts.cs
@@ -0,0 +1,23 @@
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Sqlite.Running_MigrationScripts;
+
+[Collection(nameof(SqliteTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class Failing_Scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.Failing_Scripts(testContext, testOutput)
+{
+ protected override string ExpectedErrorMessageForInvalidSql => "Not relevant";
+ protected override IDictionary ExpectedErrorDetails => new Dictionary();
+
+ [Fact(Skip = "Cannot check on the exact error message when running the command line tool. The error message is not available.")]
+ public override Task Aborts_the_run_giving_an_error_message() => Task.CompletedTask;
+
+ [Fact(Skip = "Cannot check on the exact error details when running the command line tool. The error details are not available.")]
+ public override Task Exception_includes_details_on_the_failed_script() => Task.CompletedTask;
+
+ [Fact(Skip =
+ "We do not have the ability to check for transient errors when running the command line tool. The error details are not available.")]
+ public override Task Exception_is_set_to_transient_based_on_inner_exceptions() => Task.CompletedTask;
+
+}
diff --git a/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/One_time_scripts.cs b/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/One_time_scripts.cs
new file mode 100644
index 00000000..408f4553
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Sqlite/Running_MigrationScripts/One_time_scripts.cs
@@ -0,0 +1,56 @@
+using Dapper;
+using FluentAssertions;
+using grate.Configuration;
+using grate.Exceptions;
+using TestCommon.TestInfrastructure;
+using static grate.Configuration.KnownFolderKeys;
+
+namespace CommandLine.Sqlite.Running_MigrationScripts;
+
+[Collection(nameof(SqliteTestContainer))]
+// ReSharper disable once InconsistentNaming
+public class One_time_scripts(IGrateTestContext testContext, ITestOutputHelper testOutput)
+ : TestCommon.Generic.Running_MigrationScripts.One_time_scripts(testContext, testOutput)
+{
+ [Fact]
+ public override async Task Fails_if_changed_between_runs()
+ {
+ var db = TestConfig.RandomDatabase();
+
+ var parent = CreateRandomTempDirectory();
+ var knownFolders = FoldersConfiguration.Default(null);
+ CreateDummySql(parent, knownFolders[Up]);
+
+ var config = GrateConfigurationBuilder.Create(Context.DefaultConfiguration)
+ .WithConnectionString(Context.ConnectionString(db))
+ .WithFolders(knownFolders)
+ .WithSqlFilesDirectory(parent)
+ .Build();
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ await migrator.Migrate();
+ }
+
+ WriteSomeOtherSql(parent, knownFolders[Up]);
+
+ await using (var migrator = Context.Migrator.WithConfiguration(config))
+ {
+ var ex = await Assert.ThrowsAsync(() => migrator.Migrate());
+ }
+
+ string[] scripts;
+ string sql = $"SELECT text_of_script FROM {Context.Syntax.TableWithSchema("grate", "ScriptsRun")}";
+
+ using (var conn = Context.CreateDbConnection(db))
+ {
+ scripts = (await conn.QueryAsync(sql)).ToArray();
+ }
+
+ scripts.Should().HaveCount(1);
+ scripts.First().Should().Be(Context.Sql.SelectVersion);
+ }
+
+}
+
+
diff --git a/unittests/CommandLine/CommandLine.Sqlite/Startup.cs b/unittests/CommandLine/CommandLine.Sqlite/Startup.cs
new file mode 100644
index 00000000..cc2d7a7f
--- /dev/null
+++ b/unittests/CommandLine/CommandLine.Sqlite/Startup.cs
@@ -0,0 +1,13 @@
+using grate.Configuration;
+using Sqlite.TestInfrastructure;
+using TestCommon.TestInfrastructure;
+
+namespace CommandLine.Sqlite;
+
+// ReSharper disable once UnusedType.Global
+public class Startup: CommandLine.Common.Startup
+{
+ protected override DatabaseType DatabaseType => DatabaseType.SQLite;
+ protected override Type TestContainerType => typeof(SqliteTestContainer);
+ protected override Type TestContextType => typeof(SqliteGrateTestContext);
+}
diff --git a/unittests/CommandLine/IncludeTests.targets b/unittests/CommandLine/IncludeTests.targets
new file mode 100644
index 00000000..4d217022
--- /dev/null
+++ b/unittests/CommandLine/IncludeTests.targets
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
\ No newline at end of file
diff --git a/unittests/MariaDB/TestInfrastructure/MariaDbGrateTestContext.cs b/unittests/MariaDB/TestInfrastructure/MariaDbGrateTestContext.cs
index a89ba5c2..66817db5 100644
--- a/unittests/MariaDB/TestInfrastructure/MariaDbGrateTestContext.cs
+++ b/unittests/MariaDB/TestInfrastructure/MariaDbGrateTestContext.cs
@@ -55,4 +55,5 @@ public MariaDbGrateTestContext(
public string ExpectedVersionPrefix => "10.10.7-MariaDB";
public bool SupportsCreateDatabase => true;
+ public bool SupportsSchemas => false;
}
diff --git a/unittests/Oracle/TestInfrastructure/OracleGrateTestContext.cs b/unittests/Oracle/TestInfrastructure/OracleGrateTestContext.cs
index 100d5f74..2ac7bc91 100644
--- a/unittests/Oracle/TestInfrastructure/OracleGrateTestContext.cs
+++ b/unittests/Oracle/TestInfrastructure/OracleGrateTestContext.cs
@@ -50,4 +50,5 @@ public OracleGrateTestContext(
public string ExpectedVersionPrefix => "Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production";
public bool SupportsCreateDatabase => true;
+ public bool SupportsSchemas => false;
}
diff --git a/unittests/PostgreSQL/TestInfrastructure/PostgreSqlGrateTestContext.cs b/unittests/PostgreSQL/TestInfrastructure/PostgreSqlGrateTestContext.cs
index 8405ff20..298e7bcb 100644
--- a/unittests/PostgreSQL/TestInfrastructure/PostgreSqlGrateTestContext.cs
+++ b/unittests/PostgreSQL/TestInfrastructure/PostgreSqlGrateTestContext.cs
@@ -53,5 +53,6 @@ public string UserConnectionString(string database) =>
public string ExpectedVersionPrefix => "PostgreSQL 16.";
public bool SupportsCreateDatabase => true;
+ public bool SupportsSchemas => true;
}
diff --git a/unittests/SqlServer/TestInfrastructure/SqlServerGrateTestContext.cs b/unittests/SqlServer/TestInfrastructure/SqlServerGrateTestContext.cs
index a2179be0..f490084f 100644
--- a/unittests/SqlServer/TestInfrastructure/SqlServerGrateTestContext.cs
+++ b/unittests/SqlServer/TestInfrastructure/SqlServerGrateTestContext.cs
@@ -71,6 +71,7 @@ public string UserConnectionString(string database) =>
public string ExpectedVersionPrefix => "Microsoft SQL Server 2019";
public bool SupportsCreateDatabase => true;
+ public bool SupportsSchemas => true;
public string ServerCollation { get; }
}
diff --git a/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerGrateTestContext.cs b/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerGrateTestContext.cs
index 4631007d..c0891cde 100644
--- a/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerGrateTestContext.cs
+++ b/unittests/SqlServerCaseSensitive/TestInfrastructure/SqlServerGrateTestContext.cs
@@ -53,6 +53,7 @@ public SqlServerGrateTestContext(
public string ExpectedVersionPrefix => "Microsoft SQL Server 2019";
public bool SupportsCreateDatabase => true;
+ public bool SupportsSchemas => true;
public string ServerCollation { get; }
}
diff --git a/unittests/Sqlite/TestInfrastructure/SqliteGrateTestContext.cs b/unittests/Sqlite/TestInfrastructure/SqliteGrateTestContext.cs
index b4b644b5..4287fa73 100644
--- a/unittests/Sqlite/TestInfrastructure/SqliteGrateTestContext.cs
+++ b/unittests/Sqlite/TestInfrastructure/SqliteGrateTestContext.cs
@@ -44,6 +44,7 @@ public SqliteGrateTestContext(
public string ExpectedVersionPrefix => throw new NotSupportedException("Sqlite does not support versioning");
public bool SupportsCreateDatabase => false;
+ public bool SupportsSchemas => false;
public IGrateMigrator Migrator { get; }
}
diff --git a/unittests/TestCommon/Generic/Running_MigrationScripts/Failing_Scripts.cs b/unittests/TestCommon/Generic/Running_MigrationScripts/Failing_Scripts.cs
index d4501dc4..5115c3a3 100644
--- a/unittests/TestCommon/Generic/Running_MigrationScripts/Failing_Scripts.cs
+++ b/unittests/TestCommon/Generic/Running_MigrationScripts/Failing_Scripts.cs
@@ -26,7 +26,7 @@ protected Failing_Scripts(): this(null!, null!)
protected abstract string ExpectedErrorMessageForInvalidSql { get; }
[Fact]
- public async Task Aborts_the_run_giving_an_error_message()
+ public virtual async Task Aborts_the_run_giving_an_error_message()
{
var db = TestConfig.RandomDatabase();
@@ -47,7 +47,7 @@ public async Task Aborts_the_run_giving_an_error_message()
[Fact]
- public async Task Exception_includes_details_on_the_failed_script()
+ public virtual async Task Exception_includes_details_on_the_failed_script()
{
var db = TestConfig.RandomDatabase();
@@ -84,7 +84,7 @@ public async Task Exception_includes_details_on_the_failed_script()
// TODO: Improve this test to throw both transient and non-transient exceptions, and check the result
[Fact]
- public async Task Exception_is_set_to_transient_based_on_inner_exceptions()
+ public virtual async Task Exception_is_set_to_transient_based_on_inner_exceptions()
{
var db = TestConfig.RandomDatabase();
diff --git a/unittests/TestCommon/Generic/Running_MigrationScripts/One_time_scripts.cs b/unittests/TestCommon/Generic/Running_MigrationScripts/One_time_scripts.cs
index db72ebfb..aca0111a 100644
--- a/unittests/TestCommon/Generic/Running_MigrationScripts/One_time_scripts.cs
+++ b/unittests/TestCommon/Generic/Running_MigrationScripts/One_time_scripts.cs
@@ -53,7 +53,7 @@ public async Task Are_not_run_more_than_once_when_unchanged()
}
[Fact]
- public async Task Fails_if_changed_between_runs()
+ public virtual async Task Fails_if_changed_between_runs()
{
var db = TestConfig.RandomDatabase();
diff --git a/unittests/TestCommon/TestInfrastructure/GrateMigratorExtensions.cs b/unittests/TestCommon/TestInfrastructure/GrateMigratorExtensions.cs
index b9ce274e..cb35dc85 100644
--- a/unittests/TestCommon/TestInfrastructure/GrateMigratorExtensions.cs
+++ b/unittests/TestCommon/TestInfrastructure/GrateMigratorExtensions.cs
@@ -8,9 +8,4 @@ public static IDbMigrator GetDbMigrator(this IGrateMigrator migrator)
{
return (migrator as GrateMigrator)!.DbMigrator;
}
-
- public static bool SupportsSchemas(this IGrateMigrator migrator)
- {
- return (migrator as GrateMigrator)!.Database!.SupportsSchemas;
- }
}
diff --git a/unittests/TestCommon/TestInfrastructure/IGrateTestContext.cs b/unittests/TestCommon/TestInfrastructure/IGrateTestContext.cs
index 7a12e373..f1e06e30 100644
--- a/unittests/TestCommon/TestInfrastructure/IGrateTestContext.cs
+++ b/unittests/TestCommon/TestInfrastructure/IGrateTestContext.cs
@@ -36,9 +36,11 @@ public interface IGrateTestContext
public IGrateMigrator Migrator { get; }
- public bool SupportsSchemas => Migrator.SupportsSchemas();
+
+ //public bool SupportsSchemas => Migrator.SupportsSchemas();
bool SupportsCreateDatabase { get; }
+ bool SupportsSchemas { get; }
IDbConnection GetDbConnection(string connectionString);
}
diff --git a/unittests/TestCommon/TestInfrastructure/TestConfig.cs b/unittests/TestCommon/TestInfrastructure/TestConfig.cs
index a6eca76b..e25fec80 100644
--- a/unittests/TestCommon/TestInfrastructure/TestConfig.cs
+++ b/unittests/TestCommon/TestInfrastructure/TestConfig.cs
@@ -15,6 +15,11 @@ public static DirectoryInfo CreateRandomTempDirectory()
var dummyFile = Path.GetTempFileName();
File.Delete(dummyFile);
+ if (Directory.Exists(dummyFile))
+ {
+ Directory.Delete(dummyFile, true);
+ }
+
var scriptsDir = Directory.CreateDirectory(dummyFile);
return scriptsDir;
}