Skip to content

Commit

Permalink
Bug #524: Scripts in internal Grate migration tables are always regis…
Browse files Browse the repository at this point in the history
…tered as "run" (#566)

* Bug #524: Scripts in internal Grate migration tables are always registered as "run"

The running of the scripts to create the grate tables ScriptsRun, ScriptsRunErrors and Version were always run
in baseline mode, even after the scripts had been registered as run, so they were registered as run every time
(even if they were only run once).

* Check that the internal tables exist before trying to select from them

* Improved silly test in unit test
  • Loading branch information
erikbra authored Jul 23, 2024
1 parent 7898ef6 commit 8b45ba0
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 2 deletions.
15 changes: 15 additions & 0 deletions src/grate.core/Migration/AnsiSqlDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,21 @@ protected async Task WaitUntilDatabaseIsReady()
var prefix = SupportsSchemas ? string.Empty : _syntax.TableWithSchema(schemaName, string.Empty);
return name?[prefix.Length..];
}

public async Task<bool> GrateInternalTablesAreProperlyLogged()
{
const string tableName = "GrateScriptsRun";

string existsSql = $"SELECT 1 FROM {_syntax.TableWithSchema(SchemaName, tableName)} WHERE script_name = '02_create_scripts_run_table.sql'";

if (await ExistingTable(SchemaName, tableName) is { })
{
var res = await ExecuteScalarAsync<int?>(ActiveConnection, existsSql);
return res is 1;
}
return false;
}


protected virtual string ExistsSql(string tableSchema, string fullTableName)
{
Expand Down
10 changes: 8 additions & 2 deletions src/grate.core/Migration/GrateMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,14 @@ private async Task<GrateConfiguration> GetInternalGrateConfiguration(string inte

var internalMigrationFolders = await WriteInternalScriptsToTemporaryFolders(internalFolderName, sqlFolderNamePrefix);

// Check if the tables already exist or not. If they do, run in baseline mode.
var baseline = internalFolderName == "Baseline" && await this.Database.VersionTableExists();
// Check if the internal grate tables already exist or not.
// If they do, check if the tables are already logged as run in their own tables.
// If they are, the tables are already known to grate. If they are not, the tables are created by RoundhousE, or
// an earlier version of grate, and we need to run in baseline mode, to register the scripts as run, without
// actually running them.
var baseline = internalFolderName == "Baseline"
&& await this.Database.VersionTableExists()
&& !(await this.Database.GrateInternalTablesAreProperlyLogged());

// We might consider supporting other sources of the SQL scripts than the file system,
// but for now, we write the internal scripts to file system before running them
Expand Down
1 change: 1 addition & 0 deletions src/grate.core/Migration/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Task InsertScriptRun(string scriptName, string? sql, string hash, bool runOnce,
TransactionHandling transactionHandling);
Task InsertScriptRunError(string scriptName, string? sql, string errorSql, string errorMessage, long versionId);
Task<bool> VersionTableExists();
Task<bool> GrateInternalTablesAreProperlyLogged();
Task ChangeVersionStatus(string status, long versionId);
Task DeleteVersionRecord(long versionId);
void SetDefaultConnectionActive();
Expand Down
9 changes: 9 additions & 0 deletions unittests/MariaDB/Bootstrapping/Grate_Internal_Scripts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MariaDB.TestInfrastructure;

namespace MariaDB.Bootstrapping;

[Collection(nameof(MariaDbGrateTestContext))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(MariaDbGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
9 changes: 9 additions & 0 deletions unittests/Oracle/Bootstrapping/Grate_Internal_Scripts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Oracle.TestInfrastructure;

namespace Oracle.Bootstrapping;

[Collection(nameof(OracleGrateTestContext))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(OracleGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
9 changes: 9 additions & 0 deletions unittests/PostgreSQL/Bootstrapping/Grate_Internal_Scripts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using PostgreSQL.TestInfrastructure;

namespace PostgreSQL.Bootstrapping;

[Collection(nameof(PostgreSqlGrateTestContext))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(PostgreSqlGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
9 changes: 9 additions & 0 deletions unittests/SqlServer/Bootstrapping/Grate_Internal_Scripts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SqlServer.TestInfrastructure;

namespace SqlServer.Bootstrapping;

[Collection(nameof(SqlServerGrateTestContext))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(SqlServerGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SqlServerCaseSensitive.TestInfrastructure;

namespace SqlServerCaseSensitive.Bootstrapping;

[Collection(nameof(SqlServerGrateTestContext))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(SqlServerGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
11 changes: 11 additions & 0 deletions unittests/Sqlite/Bootstrapping/Grate_Internal_Scripts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Sqlite.TestInfrastructure;
using TestCommon.TestInfrastructure;

namespace Sqlite.Bootstrapping;


[Collection(nameof(SqliteTestDatabase))]
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public class Grate_Internal_Scripts(SqliteGrateTestContext testContext, ITestOutputHelper testOutput)
: TestCommon.Generic.Bootstrapping.Grate_Internal_Scripts(testContext, testOutput);
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Dapper;
using FluentAssertions;
using grate.Configuration;
using TestCommon.Generic.Running_MigrationScripts;
using TestCommon.TestInfrastructure;
using Xunit.Abstractions;
using static grate.Configuration.KnownFolderKeys;

namespace TestCommon.Generic.Bootstrapping;

//[TestFixture]
// ReSharper disable once InconsistentNaming
public abstract class Grate_Internal_Scripts(IGrateTestContext context, ITestOutputHelper testOutput)
: MigrationsScriptsBase(context, testOutput)
{
[Fact]
public async Task Are_only_run_once()
{
var db = TestConfig.RandomDatabase();

var parent = CreateRandomTempDirectory();
var knownFolders = Folders.Default;
CreateDummySql(parent, knownFolders[Sprocs]);

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();
}
await using (var migrator = Context.Migrator.WithConfiguration(config))
{
await migrator.Migrate();
}

string[] scripts;
string sql = $"""
SELECT script_name
FROM {Context.Syntax.TableWithSchema("grate", "GrateScriptsRun")}
WHERE script_name = '02_create_scripts_run_table.sql'
""";

using (var conn = Context.External.CreateDbConnection(db))
{
scripts = (await conn.QueryAsync<string>(sql)).ToArray();
}

scripts.Should().HaveCount(1);
}
}

0 comments on commit 8b45ba0

Please sign in to comment.