public async Task SelectMigrationsAsync_MigrationNeedNotExistIfAlreadyUpToDate_WithBaseline()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new[]
            {
                new FakeDatabaseMigrationRecord()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1"),
                    IsBaseline = true
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", DatabaseVersion.Parse("1.0.0")) },
                new string[0]);

            migrations.Should().BeEmpty();
        }
        public async Task SelectMigrationsAsync_NoopWhenVersionsMatch()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new[]
            {
                new FakeDatabaseMigrationRecord()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().BeEmpty();
        }
        public async Task SelectMigrationsAsync_AreInOrder()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1")
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(0),
                migrationRegistry.Migrations.ElementAt(1));
        }
        public async Task SelectMigrationsAsync_RepeatablesOnlyRunOnce()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule1",
                    Dependencies = new[] { new DatabaseMigrationSpecifier("baseModule1", null) },
                    Version      = DatabaseVersion.Parse("1.0.0")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule1",
                    Dependencies = new[] { new DatabaseMigrationSpecifier("baseModule1", null) },
                    Version      = DatabaseVersion.Parse("1.0.1")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "baseModule1",
                    IsRepeatable = true,
                    Checksum     = "xyz"
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(2),
                migrationRegistry.Migrations.ElementAt(0),
                migrationRegistry.Migrations.ElementAt(1));
        }
        public async Task SelectMigrationsAsync_BaselineThrowsWhenLatestVersionHasOnlyBaselineMigrationPath()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new[]
            {
                new FakeDatabaseMigrationRecord()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1"),
                    IsBaseline = true
                }
            });

            await sut.Awaiting(async x => await sut.SelectMigrationsAsync(
                                   new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                                   new string[0]))
            .Should()
            .ThrowAsync <DatabaseMigrationException>();
        }
        public async Task SelectMigrationsAsync_RepeatablesNotIfPreviouslyNotRunWhenDependenciesUpdated()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new IDatabaseMigrationRecord[]
            {
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "data",
                    Version    = DatabaseVersion.Parse("1")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "view",
                    IsRepeatable = true,
                    Checksum     = "xyz",
                    Dependencies = new []
                    {
                        new DatabaseMigrationSpecifier("data", null),
                    }
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("data", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("data", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(0));
        }
        public async Task SelectMigrationsAsync_MigrationsToCurrentDependencyVersionsNeedNotExist()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new[]
            {
                new FakeDatabaseMigrationRecord()
                {
                    ModuleName = "baseModule1",
                    Version    = DatabaseVersion.Parse("1.0.0"),
                }
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule1",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new []
                    {
                        new DatabaseMigrationSpecifier("baseModule1", DatabaseVersion.Parse("1.0.0")),
                    }
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(0));
        }
예제 #8
0
        public void SearchModules_QuestionMarkWildcard()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "app-base",
                Version    = DatabaseVersion.Parse("1.0.0")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "app-base",
                Version    = DatabaseVersion.Parse("1.0.1")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "app-module1",
                Version    = DatabaseVersion.Parse("1.0.0")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "foo-another",
                Version    = DatabaseVersion.Parse("1.0.0")
            });

            var result = sut.SearchModules("ap?-base");

            result.Should().BeEquivalentTo("app-base");
        }
        public async Task SelectMigrationsAsync_Tagged()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1"),
                    Tags       = new []
                    {
                        new [] { "DEV", "CI" },
                        new [] { "CUSTOMER2" }
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0"),
                    Tags       = new []
                    {
                        new [] { "DEV", "CI" },
                        new [] { "CUSTOMER3" }
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0"),
                    Tags       = new []
                    {
                        new [] { "DEV", "CI" },
                        new [] { "CUSTOMER1", "CUSTOMER2" }
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0"),
                    Tags       = new []
                    {
                        new [] { "PROD" }
                    }
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new[]
            {
                "CI", "CUSTOMER2"
            });

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(2),
                migrationRegistry.Migrations.ElementAt(0));
        }
예제 #10
0
        private async Task InitializeAsync()
        {
            if (executor != null)
            {
                return;
            }

            LoadModules();

            CreateMigrationProvider();

            executionOptions.EnvironmentTags             = Options.EnvironmentTags?.ToArray() ?? new string[0];
            executionOptions.MigrateOnlySpecifiedModules = Options.Modules?.Count() > 0
                ? Options.Modules.Select(x =>
            {
                string[] parts = x.Split('@', 2);
                if (parts.Length > 1)
                {
                    return(new DatabaseMigrationSearchSpecifier(parts[0], DatabaseVersion.Parse(parts[1])));
                }
                else
                {
                    return(new DatabaseMigrationSearchSpecifier(x, null));
                }
            }).ToArray()
                : null;

            migrationSelector = new DatabaseMigrationSelector(migrationRegistry, migrationProvider,
                                                              executionOptions.MigrationSelectorOptions);

            Regex fileNameRegex = Options.FileNameRegex != null
                ? new Regex(Options.FileNameRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase)
                : null;

            foreach (string path in Options.DirectoryPaths)
            {
                kernel.Bind <FileDatabaseMigrationDiscoveryPath>()
                .ToConstant(new FileDatabaseMigrationDiscoveryPath(path, true, fileNameRegex));
            }

            if (!Options.DirectoryPaths.Any() && !Options.Assemblies.Any())
            {
                Logger.Error("You have not passed any --directoryPaths nor --assemblies to load the migrations from. No migrations will be performed.");
            }

            migrationDiscoveries = new IDatabaseMigrationDiscovery[]
            {
                new FileDatabaseMigrationDiscovery(kernel.GetBindings(typeof(FileDatabaseMigrationDiscoveryPath)).Count() > 0
                        ? kernel.GetAll <FileDatabaseMigrationDiscoveryPath>().ToArray() : new FileDatabaseMigrationDiscoveryPath[0]),
                new ResourceDatabaseMigrationDiscovery(kernel.GetBindings(typeof(ResourceDatabaseMigrationDiscoveryAssembly)).Count() > 0
                        ? kernel.GetAll <ResourceDatabaseMigrationDiscoveryAssembly>().ToArray()
                        : new ResourceDatabaseMigrationDiscoveryAssembly[0])
            };

            executor = new DatabaseMigrationExecutor(new[] { migrationProvider }, migrationRegistry,
                                                     migrationDiscoveries, migrationSelector, executionOptions);
        }
        public async Task SelectMigrationsAsync_OverlappingLevelTwoDependencies()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule1",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new []
                    {
                        new DatabaseMigrationSpecifier("baseModule1", DatabaseVersion.Parse("1.0.0")),
                        new DatabaseMigrationSpecifier("baseModule2", DatabaseVersion.Parse("1.0.0")),
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "baseModule1",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new []
                    {
                        new DatabaseMigrationSpecifier("baseModule3", DatabaseVersion.Parse("1.0.0")),
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "baseModule2",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new []
                    {
                        new DatabaseMigrationSpecifier("baseModule3", DatabaseVersion.Parse("1.0.1")),
                    }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "baseModule3",
                    Version    = DatabaseVersion.Parse("1.0.1")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "baseModule3",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(4),
                migrationRegistry.Migrations.ElementAt(1),
                migrationRegistry.Migrations.ElementAt(3),
                migrationRegistry.Migrations.ElementAt(2),
                migrationRegistry.Migrations.ElementAt(0));
        }
예제 #12
0
 private IDatabaseMigrationRecord ParseMigrationRecord(IDataReader reader, Dictionary <string, int> columnDict)
 {
     return(new DatabaseMigrationRecord(
                reader.GetGuid(columnDict["id"]),
                reader.GetDateTime(columnDict["time_applied"]),
                reader.GetString(columnDict["module_name"]),
                reader.IsDBNull(columnDict["version"]) ? null : DatabaseVersion.Parse(reader.GetString(columnDict["version"])),
                reader.GetString(columnDict["checksum"]),
                reader.IsDBNull(columnDict["file_name"]) ? null : reader.GetString(columnDict["file_name"])));
 }
예제 #13
0
        public void AddMigration()
        {
            var migration = new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0")
            };

            sut.AddMigration(migration);
            sut.Migrations.Should().Contain(migration);
        }
예제 #14
0
        public void Validate_VersionedRepeatableThrows()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName   = "appModule1",
                Version      = DatabaseVersion.Parse("1.0.0"),
                IsRepeatable = true
            });

            sut.Invoking(x => x.ValidateMigrations())
            .Should().Throw <DatabaseMigrationException>();
        }
        public async Task SelectMigrationsAsync_TopModuleDependencies()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule1",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new [] { new DatabaseMigrationSpecifier("baseModule1", DatabaseVersion.Parse("1.0.0")) }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "appModule2",
                    Version      = DatabaseVersion.Parse("1.0.0"),
                    Dependencies = new [] { new DatabaseMigrationSpecifier("baseModule1", DatabaseVersion.Parse("1.0.0")) }
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "baseModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[]
            {
                new DatabaseMigrationSpecifier("appModule1", null),
                new DatabaseMigrationSpecifier("appModule2", null)
            },
                new string[0]);

            migrations.Should().HaveCount(2);
            migrations.Should().Contain(x => x.Specifier.Equals(new DatabaseMigrationSpecifier("appModule1", null)));
            migrations.Should().Contain(x => x.Specifier.Equals(new DatabaseMigrationSpecifier("appModule2", null)));

            var a1 = migrations.First(x => x.Specifier.ModuleName == "appModule1");

            a1.Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(2),
                migrationRegistry.Migrations.ElementAt(0));

            var a2 = migrations.First(x => x.Specifier.ModuleName == "appModule2");

            a2.Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(1));
        }
예제 #16
0
        public void Validate_VersionDuplicatesWithDifferentTagsNotThrows()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0"),
                Tags       = new [] { new[] { "ABC" } }
            });

            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0"),
                Tags       = new[] { new[] { "XYZ" } }
            });

            sut.Invoking(x => x.ValidateMigrations())
            .Should().NotThrow <DatabaseMigrationException>();
        }
        public void ParsesVersion()
        {
            var sql =
                @"
-- Hello
/* Multi
line comment */
-- version: 1.5.0

CREATE TABLE abc (
    id int
);

DROP TABLE def;
";

            sut = new TestFileSqlDatabaseMigration("myapp.sql", sql);
            sut.Version.Should().Be(DatabaseVersion.Parse("1.5.0"));
        }
        public async Task SelectMigrationsAsync_RepeatablesRunLast()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new IDatabaseMigrationRecord[]
            {
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "a",
                    Version    = DatabaseVersion.Parse("1")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName   = "b",
                    IsRepeatable = true,
                    Checksum     = "xyz"
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "c",
                    Version    = DatabaseVersion.Parse("1")
                },
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[]
            {
                new DatabaseMigrationSpecifier("a", null),
                new DatabaseMigrationSpecifier("b", null),
                new DatabaseMigrationSpecifier("c", null)
            },
                new string[0]);

            migrations.Should().HaveCount(3);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("a", null));
            migrations.ElementAt(1).Specifier.Should().Be(new DatabaseMigrationSpecifier("c", null));
            migrations.ElementAt(2).Specifier.Should().Be(new DatabaseMigrationSpecifier("b", null));
        }
        public async Task SelectMigrationsAsync_BaselineNotUsedOnExistingDBs()
        {
            migrationProvider.GetMigrationHistoryAsync()
            .Returns(new[]
            {
                new FakeDatabaseMigrationRecord()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1"),
                    IsBaseline = true
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.1")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            var migrations = await sut.SelectMigrationsAsync(
                new[] { new DatabaseMigrationSpecifier("appModule1", null) },
                new string[0]);

            migrations.Should().HaveCount(1);
            migrations.First().Specifier.Should().Be(new DatabaseMigrationSpecifier("appModule1", null));
            migrations.First().Migrations.Should().Equal(
                migrationRegistry.Migrations.ElementAt(1));
        }
예제 #20
0
        public void Validate_MultipleBaselinesDifferentTagsNotThrows()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0"),
                IsBaseline = true,
                Tags       = new [] { new [] { "xyz" } }
            });

            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.1"),
                IsBaseline = true,
                Tags       = new[] { new[] { "abc" } }
            });

            sut.Invoking(x => x.ValidateMigrations())
            .Should().NotThrow <DatabaseMigrationException>();
        }
예제 #21
0
        public void Validate_NotThrows()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.1")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule2",
                Version    = DatabaseVersion.Parse("1.0.0")
            });

            sut.Invoking(x => x.ValidateMigrations())
            .Should().NotThrow <DatabaseMigrationException>();
        }
예제 #22
0
        public void GetAvailableModules()
        {
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.0")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule1",
                Version    = DatabaseVersion.Parse("1.0.1")
            });
            sut.AddMigration(new FakeDatabaseMigration()
            {
                ModuleName = "appModule2",
                Version    = DatabaseVersion.Parse("1.0.0")
            });

            var result = sut.GetAvailableModules();

            result.Should().BeEquivalentTo("appModule1", "appModule2");
        }
        public async Task SelectMigrationsAsync_NonExistentTargetVersionThrows()
        {
            migrationRegistry.Migrations.Returns(new List <IDatabaseMigration>()
            {
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.2")
                },
                new FakeDatabaseMigration()
                {
                    ModuleName = "appModule1",
                    Version    = DatabaseVersion.Parse("1.0.0")
                }
            });

            await sut.Awaiting(async x => await sut.SelectMigrationsAsync(
                                   new[] { new DatabaseMigrationSpecifier("appModule1", DatabaseVersion.Parse("1.0.1")) },
                                   new string[0]))
            .Should()
            .ThrowAsync <DatabaseMigrationException>();
        }
        public void ParsesDependencies()
        {
            var sql =
                @"
-- Hello
/* Multi
line comment */
-- dependency: [email protected]
-- dependency: vendor-module

CREATE TABLE abc (
    id int
);

DROP TABLE def;
";

            sut = new TestFileSqlDatabaseMigration("myapp_1.0.1.sql", sql);
            sut.Dependencies.Should()
            .BeEquivalentTo(
                new DatabaseMigrationSpecifier("myapp-base", DatabaseVersion.Parse("1.2.3")),
                new DatabaseMigrationSpecifier("vendor-module", null));
        }