Migration needs to check for completed transitions before accessing (#14174)

* check for completed transitions before accessing target state

* upgrader should be happy with initial and final state being the same value - only an empty final state should throw

* refactor

* reduce complexity

* Don't check for successfull

* Add test that runs migration twice

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
This commit is contained in:
Nathan Woulfe
2023-05-09 20:26:41 +10:00
committed by GitHub
parent 5e9ce916cf
commit 6f3cf6ead5
3 changed files with 74 additions and 14 deletions

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NPoco;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration;
@@ -91,6 +92,26 @@ public class PartialMigrationsTests : UmbracoIntegrationTest
});
}
[Test]
public void CanRunMigrationTwice()
{
Upgrader? upgrader = new(new SimpleMigrationPlan());
Upgrader? upgrader2 = new(new SimpleMigrationPlan());
var result = upgrader.Execute(MigrationPlanExecutor, ScopeProvider, KeyValueService);
var result2 = upgrader2.Execute(MigrationPlanExecutor, ScopeProvider, KeyValueService);
Assert.Multiple(() =>
{
Assert.True(result.Successful);
Assert.AreEqual("SimpleMigrationPlan_InitialState", result.InitialState);
Assert.AreEqual("SimpleMigrationStep", result.FinalState);
Assert.AreEqual(1, result.CompletedTransitions.Count);
Assert.IsNull(result.Exception);
Assert.True(result2.Successful);
Assert.IsNull(result2.Exception);
});
}
[Test]
public void StateIsOnlySavedIfAMigrationSucceeds()
{
@@ -307,4 +328,30 @@ internal class TestUmbracoPlan : UmbracoPlan
To<ErrorMigration>("b");
To<AddColumnMigration>("c");
}
}
internal class SimpleMigrationPlan : MigrationPlan
{
public SimpleMigrationPlan()
: base("SimpleMigrationPlan") => DefinePlan();
public override string InitialState => "SimpleMigrationPlan_InitialState";
private void DefinePlan()
{
MigrationPlan plan = From(InitialState)
.To<SimpleMigrationStep>(nameof(SimpleMigrationStep));
}
}
internal class SimpleMigrationStep : MigrationBase
{
private readonly ILogger<SimpleMigrationStep> _logger;
public SimpleMigrationStep(
IMigrationContext context,
ILogger<SimpleMigrationStep> logger)
: base(context) => _logger = logger;
protected override void Migrate() => _logger.LogDebug("Here be migration");
}