added DatabaseInitializer + Tests
This commit is contained in:
parent
e54eebc9b5
commit
8708a529d6
6 changed files with 322 additions and 21 deletions
|
@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Domain.Tests",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Pipeline.Tests", "Tests\BirdsiteLive.Pipeline.Tests\BirdsiteLive.Pipeline.Tests.csproj", "{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Pipeline.Tests", "Tests\BirdsiteLive.Pipeline.Tests\BirdsiteLive.Pipeline.Tests.csproj", "{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdsiteLive.DAL.Tests", "Tests\BirdsiteLive.DAL.Tests\BirdsiteLive.DAL.Tests.csproj", "{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -101,6 +103,10 @@ Global
|
||||||
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Release|Any CPU.Build.0 = Release|Any CPU
|
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -119,6 +125,7 @@ Global
|
||||||
{2A8CC30D-D775-47D1-9388-F72A5C32DE2A} = {DA3C160C-4811-4E26-A5AD-42B81FAF2D7C}
|
{2A8CC30D-D775-47D1-9388-F72A5C32DE2A} = {DA3C160C-4811-4E26-A5AD-42B81FAF2D7C}
|
||||||
{F544D745-89A8-4DEA-B61C-A7E6C53C1D63} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
{F544D745-89A8-4DEA-B61C-A7E6C53C1D63} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
{BF51CA81-5A7A-46F8-B4FB-861C6BE59298} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
|
{5A1E3EB5-6CBB-470D-8A0D-10F8C18353D5} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {69E8DCAD-4C37-4010-858F-5F94E6FBABCE}
|
SolutionGuid = {69E8DCAD-4C37-4010-858F-5F94E6FBABCE}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.DAL;
|
||||||
using BirdsiteLive.DAL.Contracts;
|
using BirdsiteLive.DAL.Contracts;
|
||||||
using BirdsiteLive.Pipeline;
|
using BirdsiteLive.Pipeline;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
@ -9,36 +11,21 @@ namespace BirdsiteLive.Services
|
||||||
{
|
{
|
||||||
public class FederationService : BackgroundService
|
public class FederationService : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly IDbInitializerDal _dbInitializerDal;
|
private readonly IDatabaseInitializer _databaseInitializer;
|
||||||
private readonly IStatusPublicationPipeline _statusPublicationPipeline;
|
private readonly IStatusPublicationPipeline _statusPublicationPipeline;
|
||||||
|
|
||||||
#region Ctor
|
#region Ctor
|
||||||
public FederationService(IDbInitializerDal dbInitializerDal, IStatusPublicationPipeline statusPublicationPipeline)
|
public FederationService(IDatabaseInitializer databaseInitializer, IStatusPublicationPipeline statusPublicationPipeline)
|
||||||
{
|
{
|
||||||
_dbInitializerDal = dbInitializerDal;
|
_databaseInitializer = databaseInitializer;
|
||||||
_statusPublicationPipeline = statusPublicationPipeline;
|
_statusPublicationPipeline = statusPublicationPipeline;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
await DbInitAsync();
|
await _databaseInitializer.DbInitAsync();
|
||||||
await _statusPublicationPipeline.ExecuteAsync(stoppingToken);
|
await _statusPublicationPipeline.ExecuteAsync(stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DbInitAsync()
|
|
||||||
{
|
|
||||||
var currentVersion = await _dbInitializerDal.GetCurrentDbVersionAsync();
|
|
||||||
var mandatoryVersion = _dbInitializerDal.GetMandatoryDbVersion();
|
|
||||||
|
|
||||||
if (currentVersion == null)
|
|
||||||
{
|
|
||||||
await _dbInitializerDal.InitDbAsync();
|
|
||||||
}
|
|
||||||
else if (currentVersion != mandatoryVersion)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ namespace BirdsiteLive.DAL.Contracts
|
||||||
Task<Version> GetCurrentDbVersionAsync();
|
Task<Version> GetCurrentDbVersionAsync();
|
||||||
Version GetMandatoryDbVersion();
|
Version GetMandatoryDbVersion();
|
||||||
Tuple<Version, Version>[] GetMigrationPatterns();
|
Tuple<Version, Version>[] GetMigrationPatterns();
|
||||||
Task MigrateDbAsync(Version from, Version to);
|
Task<Version> MigrateDbAsync(Version from, Version to);
|
||||||
Task InitDbAsync();
|
Task<Version> InitDbAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
46
src/DataAccessLayers/BirdsiteLive.DAL/DatabaseInitializer.cs
Normal file
46
src/DataAccessLayers/BirdsiteLive.DAL/DatabaseInitializer.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.DAL.Contracts;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.DAL
|
||||||
|
{
|
||||||
|
public interface IDatabaseInitializer
|
||||||
|
{
|
||||||
|
Task DbInitAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DatabaseInitializer : IDatabaseInitializer
|
||||||
|
{
|
||||||
|
private readonly IDbInitializerDal _dbInitializerDal;
|
||||||
|
|
||||||
|
#region Ctor
|
||||||
|
public DatabaseInitializer(IDbInitializerDal dbInitializerDal)
|
||||||
|
{
|
||||||
|
_dbInitializerDal = dbInitializerDal;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public async Task DbInitAsync()
|
||||||
|
{
|
||||||
|
var currentVersion = await _dbInitializerDal.GetCurrentDbVersionAsync();
|
||||||
|
var mandatoryVersion = _dbInitializerDal.GetMandatoryDbVersion();
|
||||||
|
|
||||||
|
if (currentVersion == mandatoryVersion) return;
|
||||||
|
|
||||||
|
// Init Db
|
||||||
|
var migrationPatterns = _dbInitializerDal.GetMigrationPatterns();
|
||||||
|
if (currentVersion == null)
|
||||||
|
currentVersion = await _dbInitializerDal.InitDbAsync();
|
||||||
|
|
||||||
|
// Migrate Db
|
||||||
|
while (migrationPatterns.Any(x => x.Item1 == currentVersion))
|
||||||
|
{
|
||||||
|
var migration = migrationPatterns.First(x => x.Item1 == currentVersion);
|
||||||
|
currentVersion = await _dbInitializerDal.MigrateDbAsync(migration.Item1, migration.Item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentVersion != mandatoryVersion) throw new Exception("Migrating DB failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||||
|
<PackageReference Include="Moq" Version="4.14.5" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\DataAccessLayers\BirdsiteLive.DAL\BirdsiteLive.DAL.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
240
src/Tests/BirdsiteLive.DAL.Tests/DatabaseInitializerTests.cs
Normal file
240
src/Tests/BirdsiteLive.DAL.Tests/DatabaseInitializerTests.cs
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BirdsiteLive.DAL.Contracts;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.DAL.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DatabaseInitializerTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DbInitAsync_UpToDate_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var current = new Version(2, 3);
|
||||||
|
var mandatory = new Version(2, 3);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var dbInitializerDal = new Mock<IDbInitializerDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetCurrentDbVersionAsync())
|
||||||
|
.ReturnsAsync(current);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMandatoryDbVersion())
|
||||||
|
.Returns(mandatory);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var dbInitializer = new DatabaseInitializer(dbInitializerDal.Object);
|
||||||
|
await dbInitializer.DbInitAsync();
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
dbInitializerDal.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DbInitAsync_NoDb_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var current = (Version)null;
|
||||||
|
var mandatory = new Version(1, 0);
|
||||||
|
|
||||||
|
var migrationPatterns = new Tuple<Version, Version>[0];
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var dbInitializerDal = new Mock<IDbInitializerDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetCurrentDbVersionAsync())
|
||||||
|
.ReturnsAsync(current);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMandatoryDbVersion())
|
||||||
|
.Returns(mandatory);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.InitDbAsync())
|
||||||
|
.ReturnsAsync(new Version(1, 0));
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMigrationPatterns())
|
||||||
|
.Returns(migrationPatterns);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var dbInitializer = new DatabaseInitializer(dbInitializerDal.Object);
|
||||||
|
await dbInitializer.DbInitAsync();
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
dbInitializerDal.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DbInitAsync_NoDb_Migration_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var current = (Version)null;
|
||||||
|
var mandatory = new Version(2, 3);
|
||||||
|
|
||||||
|
var migrationPatterns = new Tuple<Version, Version>[]
|
||||||
|
{
|
||||||
|
new Tuple<Version, Version>(new Version(1,0), new Version(1,7)),
|
||||||
|
new Tuple<Version, Version>(new Version(1,7), new Version(2,0)),
|
||||||
|
new Tuple<Version, Version>(new Version(2,0), new Version(2,3))
|
||||||
|
};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var dbInitializerDal = new Mock<IDbInitializerDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetCurrentDbVersionAsync())
|
||||||
|
.ReturnsAsync(current);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMandatoryDbVersion())
|
||||||
|
.Returns(mandatory);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.InitDbAsync())
|
||||||
|
.ReturnsAsync(new Version(1, 0));
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMigrationPatterns())
|
||||||
|
.Returns(migrationPatterns);
|
||||||
|
|
||||||
|
foreach (var m in migrationPatterns)
|
||||||
|
{
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.MigrateDbAsync(
|
||||||
|
It.Is<Version>(y => y == m.Item1),
|
||||||
|
It.Is<Version>(y => y == m.Item2)
|
||||||
|
))
|
||||||
|
.ReturnsAsync(m.Item2);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var dbInitializer = new DatabaseInitializer(dbInitializerDal.Object);
|
||||||
|
await dbInitializer.DbInitAsync();
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
dbInitializerDal.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task DbInitAsync_HasDb_Migration_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var current = new Version(1, 7);
|
||||||
|
var mandatory = new Version(2, 3);
|
||||||
|
|
||||||
|
var migrationPatterns = new Tuple<Version, Version>[]
|
||||||
|
{
|
||||||
|
new Tuple<Version, Version>(new Version(1,0), new Version(1,7)),
|
||||||
|
new Tuple<Version, Version>(new Version(1,7), new Version(2,0)),
|
||||||
|
new Tuple<Version, Version>(new Version(2,0), new Version(2,3))
|
||||||
|
};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var dbInitializerDal = new Mock<IDbInitializerDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetCurrentDbVersionAsync())
|
||||||
|
.ReturnsAsync(current);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMandatoryDbVersion())
|
||||||
|
.Returns(mandatory);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMigrationPatterns())
|
||||||
|
.Returns(migrationPatterns);
|
||||||
|
|
||||||
|
foreach (var m in migrationPatterns.Skip(1))
|
||||||
|
{
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.MigrateDbAsync(
|
||||||
|
It.Is<Version>(y => y == m.Item1),
|
||||||
|
It.Is<Version>(y => y == m.Item2)
|
||||||
|
))
|
||||||
|
.ReturnsAsync(m.Item2);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var dbInitializer = new DatabaseInitializer(dbInitializerDal.Object);
|
||||||
|
await dbInitializer.DbInitAsync();
|
||||||
|
|
||||||
|
#region Validations
|
||||||
|
dbInitializerDal.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(Exception))]
|
||||||
|
public async Task DbInitAsync_NoDb_Migration_Error_Test()
|
||||||
|
{
|
||||||
|
#region Stubs
|
||||||
|
var current = (Version)null;
|
||||||
|
var mandatory = new Version(2, 3);
|
||||||
|
|
||||||
|
var migrationPatterns = new Tuple<Version, Version>[]
|
||||||
|
{
|
||||||
|
new Tuple<Version, Version>(new Version(1,0), new Version(1,7)),
|
||||||
|
new Tuple<Version, Version>(new Version(1,7), new Version(2,0)),
|
||||||
|
new Tuple<Version, Version>(new Version(2,0), new Version(2,2))
|
||||||
|
};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Mocks
|
||||||
|
var dbInitializerDal = new Mock<IDbInitializerDal>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetCurrentDbVersionAsync())
|
||||||
|
.ReturnsAsync(current);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMandatoryDbVersion())
|
||||||
|
.Returns(mandatory);
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.InitDbAsync())
|
||||||
|
.ReturnsAsync(new Version(1, 0));
|
||||||
|
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.GetMigrationPatterns())
|
||||||
|
.Returns(migrationPatterns);
|
||||||
|
|
||||||
|
foreach (var m in migrationPatterns)
|
||||||
|
{
|
||||||
|
dbInitializerDal
|
||||||
|
.Setup(x => x.MigrateDbAsync(
|
||||||
|
It.Is<Version>(y => y == m.Item1),
|
||||||
|
It.Is<Version>(y => y == m.Item2)
|
||||||
|
))
|
||||||
|
.ReturnsAsync(m.Item2);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var dbInitializer = new DatabaseInitializer(dbInitializerDal.Object);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await dbInitializer.DbInitAsync();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
#region Validations
|
||||||
|
dbInitializerDal.VerifyAll();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue