Search code examples
c#entity-frameworkfluent-migrator

Fluent Migrator Unit Tests: Holding onto Connection


I am trying to create a unit test project to ensure all the migrations made in a project will successfully allow migrations Up and Down.

I am trying to achieve this through creating two unit tests to do this.

Setup:

  • NUnit
  • EntityFramework
  • LocalDB FluentMigrator & Runners

This is my setup for the unit tests. I have a connection string that is a link to a LocalDb database (v11) which all these tests use:

[TestFixture]
public class MigrationTestHandler
{
    private string ConnectionString
    {
        get
        {
            return ConfigurationManager.ConnectionStrings["MigrationDatabase"].ConnectionString;
        }
    }

    [SetUp]
    public void SetUp()
    {
        var blankContext = new DbContext(ConnectionString);
        blankContext.Database.Delete();
        blankContext.Database.Create();
    }

    [TearDown]
    public void TearDown()
    {
        var blankContext = new DbContext(ConnectionString);
        blankContext.Database.Delete();
    }

    [Test]
    public void CanUpgradeDatabase()
    {
        var migrator = new MigrationRunnerHandler(ConnectionString);
        migrator.Migrate(runner => runner.MigrateUp());
    }

    [Test]
    public void CanRollbackDatabase()
    {
        var migrator = new MigrationRunnerHandler(ConnectionString);
        migrator.Migrate(runner => runner.MigrateUp());
        migrator.Migrate(runner => runner.Rollback(int.MaxValue));
    }
}

This is the migration runner handler class I use in order to invoke all the migrations:

public class MigrationRunnerHandler
{
    private readonly string _connectionString;
    private FluentMigrator.Runner.MigrationRunner Runner { get; set; }

    public MigrationRunnerHandler(string connectionString)
    {
        _connectionString = connectionString;
    }

    private class MigrationOptions : IMigrationProcessorOptions
    {
        public bool PreviewOnly { get; set; }
        public int Timeout { get; set; }
        public string ProviderSwitches { get; set; }
    }

    public void Migrate(Action<IMigrationRunner> runnerAction)
    {
        var factory = new SqlServer2008ProcessorFactory();
        var assembly = Assembly.GetExecutingAssembly();

        var announcer = new TextWriterAnnouncer(s => Console.Write(s));
        var migrationContext = new RunnerContext(announcer)
        {
            TransactionPerSession = true,
        };
        var processor = factory.Create(_connectionString, announcer, new MigrationOptions 
        { 
            PreviewOnly = false,
            Timeout = 5
        });
        Runner = new FluentMigrator.Runner.MigrationRunner(assembly, migrationContext, processor);

        runnerAction(Runner);
    }
}

The problem is that upon TearDown of my tests, FluentMigrator seems to be holding onto a connection to the database. Running sp_who on the database shows that there is a "sleeping" process on the database that is "AWAITING COMMAND" that is left on the database. This means that the TearDown of my test will fail to delete the temporary database as "the database is in use".

Looking through the runner I cannot seem to find a way to close this connection down, I have tried to change the timeouts of all the components involved and also attempted to turn "Pooling" off on the connection string but neither have worked.

Is there a way that I can close down this connection or ensure it is closed down?

Thanks


Solution

  • As IMigrationProcessor implements IDisposable, we should use it like that:

    using(var processor = factory.Create(_connectionString, announcer, new MigrationOptions 
    { 
        PreviewOnly = false,
        Timeout = 5
    }))
    {
        Runner = new FluentMigrator.Runner.MigrationRunner(assembly, migrationContext, processor);
    
        runnerAction(Runner);
    }
    

    I also assume, that not disposing the processor is the reason for a hanging connection.