// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Application.Ringtoets.Migration.Core;
using Application.Ringtoets.Storage.TestUtil;
using Core.Common.Base.Storage;
using Core.Common.Gui;
using Core.Common.Gui.TestUtil.Settings;
using Core.Common.TestUtil;
using NUnit.Framework;
using Rhino.Mocks;
using Ringtoets.Common.Utils;
namespace Application.Ringtoets.Migration.Test
{
[TestFixture]
public class RingtoetsProjectMigratorTest
{
private const string testDirectory = nameof(RingtoetsProjectMigratorTest);
private readonly string currentDatabaseVersion = RingtoetsVersionHelper.GetCurrentDatabaseVersion();
private DirectoryDisposeHelper directoryDisposeHelper;
[SetUp]
public void Setup()
{
directoryDisposeHelper = new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), testDirectory);
}
[TearDown]
public void TearDown()
{
directoryDisposeHelper.Dispose();
}
[Test]
public void Constructor_InquiryHelperNull_ThrowsArgumentNullException()
{
// Call
TestDelegate call = () => new RingtoetsProjectMigrator(null);
// Assert
string paramName = Assert.Throws(call).ParamName;
Assert.AreEqual("inquiryHelper", paramName);
}
[Test]
public void Constructor_ReturnsExpectedProperties()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
// Call
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Assert
Assert.IsInstanceOf(migrator);
mocks.VerifyAll();
}
[Test]
public void ShouldMigrate_FilePathNull_ThrowsArgumentNullException()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
TestDelegate call = () => migrator.ShouldMigrate(null);
// Assert
string paramName = Assert.Throws(call).ParamName;
Assert.AreEqual("filePath", paramName);
mocks.VerifyAll();
}
[Test]
[TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))]
public void ShouldMigrate_InvalidFilePath_ThrowsArgumentException(string invalidFilePath)
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
TestDelegate call = () => migrator.ShouldMigrate(invalidFilePath);
// Assert
string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
call, "Bronprojectpad moet een geldig projectpad zijn.")
.ParamName;
Assert.AreEqual("filePath", paramName);
mocks.VerifyAll();
}
[Test]
public void ShouldMigrate_OutdatedProjectUnsupported_ReturnsAbortedAndGeneratesLogMessages()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedUnSupportedProjectFilePath();
var versionedFile = new RingtoetsVersionedFile(sourceFilePath);
string fileVersion = versionedFile.GetVersion();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
var shouldMigrate = MigrationRequired.Yes;
// Call
Action call = () => shouldMigrate = migrator.ShouldMigrate(sourceFilePath);
// Assert
string expectedMessage = $"Het migreren van een projectbestand met versie '{fileVersion}' naar versie '{currentDatabaseVersion}' is niet ondersteund.";
TestHelper.AssertLogMessageIsGenerated(call, expectedMessage);
Assert.AreEqual(MigrationRequired.Aborted, shouldMigrate);
mocks.VerifyAll();
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void ShouldMigrate_OutdatedProjectSupported_AskMigrationConfirmationAndReturnBasedOnConfirmation(bool confirmContinuation)
{
// Setup
string question = "Het project dat u wilt openen is opgeslagen in het formaat van een eerdere versie van Ringtoets." +
$"{Environment.NewLine}{Environment.NewLine}" +
$"Weet u zeker dat u het bestand wilt migreren naar het formaat van uw huidige Ringtoetsversie ({currentDatabaseVersion})?";
var mocks = new MockRepository();
var inquiryHelper = mocks.StrictMock();
inquiryHelper.Expect(h => h.InquireContinuation(question)).Return(confirmContinuation);
mocks.ReplayAll();
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
var shouldMigrate = MigrationRequired.No;
Action call = () => shouldMigrate = migrator.ShouldMigrate(sourceFilePath);
// Assert
var expectedLogMessages = new List>();
if (!confirmContinuation)
{
expectedLogMessages.Add(Tuple.Create($"Het migreren van het projectbestand '{sourceFilePath}' is geannuleerd.",
LogLevelConstant.Warn));
}
TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedLogMessages, expectedLogMessages.Count);
MigrationRequired expectedResult = confirmContinuation ? MigrationRequired.Yes : MigrationRequired.Aborted;
Assert.AreEqual(expectedResult, shouldMigrate);
mocks.VerifyAll();
}
[Test]
public void ShouldMigrate_LatestProjectVersion_ReturnsFalse()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetLatestProjectFilePath();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
MigrationRequired shouldMigrate = migrator.ShouldMigrate(sourceFilePath);
// Assert
Assert.AreEqual(MigrationRequired.No, shouldMigrate);
mocks.VerifyAll();
}
[Test]
public void DetermineMigrationLocation_OriginalFilePathNull_ThrowArgumentNullException()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
TestDelegate call = () => migrator.DetermineMigrationLocation(null);
// Assert
string paramName = Assert.Throws(call).ParamName;
Assert.AreEqual("originalFilePath", paramName);
mocks.VerifyAll();
}
[Test]
[TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))]
public void DetermineMigrationLocation_InvalidOriginalFilePath_ThrowsArgumentException(string invalidFilePath)
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
TestDelegate call = () => migrator.DetermineMigrationLocation(invalidFilePath);
// Assert
string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
call, "Bronprojectpad moet een geldig projectpad zijn.")
.ParamName;
Assert.AreEqual("originalFilePath", paramName);
mocks.VerifyAll();
}
[Test]
public void DetermineMigrationLocation_ValidPath_AsksUserForTargetPathAndReturnsIt()
{
// Setup
const string originalFileName = "Im_a_valid_file_path";
const string expectedFileExtension = "rtd";
string validFilePath = TestHelper.GetScratchPadPath($"{originalFileName}.{expectedFileExtension}");
string versionWithDashes = RingtoetsVersionHelper.GetCurrentDatabaseVersion().Replace('.', '-');
var expectedFileFilter = new FileFilterGenerator(expectedFileExtension, "Ringtoets project");
string expectedSuggestedFileName = $"{originalFileName}_{versionWithDashes}";
string expectedReturnPath = TestHelper.GetScratchPadPath("Im_a_file_path_to_the_migrated_file.rtd");
var mocks = new MockRepository();
var inquiryHelper = mocks.StrictMock();
inquiryHelper.Expect(h => h.GetTargetFileLocation(expectedFileFilter.Filter, expectedSuggestedFileName))
.Return(expectedReturnPath);
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
// Call
string targetFilePath = migrator.DetermineMigrationLocation(validFilePath);
// Assert
Assert.AreEqual(expectedReturnPath, targetFilePath);
mocks.VerifyAll();
}
[Test]
public void DetermineMigrationLocation_TargetFilePathIsEmpty_LogsMessageAndReturnsEmptyTargetPath()
{
// Setup
const string originalFileName = "Im_a_valid_file_path";
const string expectedFileExtension = "rtd";
string validFilePath = TestHelper.GetScratchPadPath($"{originalFileName}.{expectedFileExtension}");
var expectedFileFilter = new FileFilterGenerator(expectedFileExtension, "Ringtoets project");
string versionWithDashes = RingtoetsVersionHelper.GetCurrentDatabaseVersion().Replace('.', '-');
string expectedSuggestedFileName = $"{originalFileName}_{versionWithDashes}";
var mocks = new MockRepository();
var inquiryHelper = mocks.StrictMock();
inquiryHelper.Expect(h => h.GetTargetFileLocation(expectedFileFilter.Filter, expectedSuggestedFileName))
.Return(null);
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
var targetFilePath = "arbitraryPath";
// Call
Action call = () => targetFilePath = migrator.DetermineMigrationLocation(validFilePath);
// Assert
Tuple expectedLogMessage = Tuple.Create($"Het migreren van het projectbestand '{validFilePath}' is geannuleerd.",
LogLevelConstant.Warn);
TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedLogMessage, 1);
Assert.IsNull(targetFilePath);
mocks.VerifyAll();
}
[Test]
public void Migrate_SourcePathNull_ThrowsArgumentNullException()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
string targetFileName = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(Migrate_SourcePathNull_ThrowsArgumentNullException)}.rtd";
string targetFilePath = TestHelper.GetScratchPadPath(targetFileName);
// Call
TestDelegate call = () => migrator.Migrate(null, targetFilePath);
// Assert
string paramName = Assert.Throws(call).ParamName;
Assert.AreEqual("sourceFilePath", paramName);
}
[Test]
public void Migrate_TargetPathNull_ThrowsArgumentNullException()
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
// Call
TestDelegate call = () => migrator.Migrate(sourceFilePath, null);
// Assert
string paramName = Assert.Throws(call).ParamName;
Assert.AreEqual("targetFilePath", paramName);
}
[Test]
[TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))]
public void Migrate_InvalidSourceFilePath_ThrowsArgumentException(string invalidFilePath)
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
string targetFileName = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(Migrate_InvalidSourceFilePath_ThrowsArgumentException)}.rtd";
string targetFilePath = TestHelper.GetScratchPadPath(targetFileName);
// Call
TestDelegate call = () => migrator.Migrate(invalidFilePath, targetFilePath);
// Assert
string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
call, "Bronprojectpad moet een geldig projectpad zijn.")
.ParamName;
Assert.AreEqual("sourceFilePath", paramName);
mocks.VerifyAll();
}
[Test]
[TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))]
public void Migrate_InvalidTargetFilePath_ThrowsArgumentException(string invalidFilePath)
{
// Setup
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
// Call
TestDelegate call = () => migrator.Migrate(sourceFilePath, invalidFilePath);
// Assert
string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
call, "Doelprojectpad moet een geldig projectpad zijn.")
.ParamName;
Assert.AreEqual("targetFilePath", paramName);
mocks.VerifyAll();
}
[Test]
public void GivenMigratorAndSupportedFile_WhenValidTargetLocationGiven_ThenFileSuccessFullyMigrates()
{
// Given
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
string targetFile = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(GivenMigratorAndSupportedFile_WhenValidTargetLocationGiven_ThenFileSuccessFullyMigrates)}.rtd";
string targetFilePath = Path.Combine(TestHelper.GetScratchPadPath(), testDirectory, targetFile);
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string logDirectory = $"{nameof(GivenMigratorAndSupportedFile_WhenValidTargetLocationGiven_ThenFileSuccessFullyMigrates)}_log";
using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), logDirectory))
using (new UseCustomSettingsHelper(new TestSettingsHelper
{
TempPath = TestHelper.GetScratchPadPath(logDirectory)
}))
{
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
var migrationSuccessful = false;
// When
Action call = () => migrationSuccessful = migrator.Migrate(sourceFilePath, targetFilePath);
// Then
string expectedMessage = $"Het projectbestand '{sourceFilePath}' is succesvol gemigreerd naar '{targetFilePath}' " +
$"(versie {currentDatabaseVersion}).";
var migrationLog = new StringBuilder();
migrationLog.AppendLine(@"Door de migratie is het project aangepast. Bekijk het migratierapport door op details te klikken.");
migrationLog.AppendLine(@"Gevolgen van de migratie:");
migrationLog.AppendLine(@"- Alle berekende resultaten zijn verwijderd.");
var expectedLogMessagesAndLevel = new[]
{
Tuple.Create(expectedMessage, LogLevelConstant.Info),
Tuple.Create(migrationLog.ToString(), LogLevelConstant.Info)
};
TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedLogMessagesAndLevel, 2);
Assert.IsTrue(migrationSuccessful);
var toVersionedFile = new RingtoetsVersionedFile(targetFilePath);
Assert.AreEqual(currentDatabaseVersion, toVersionedFile.GetVersion());
}
string logPath = Path.Combine(TestHelper.GetScratchPadPath(), logDirectory, "RingtoetsMigrationLog.sqlite");
Assert.IsFalse(File.Exists(logPath));
mocks.VerifyAll();
}
[Test]
public void Migrate_MigrationLogDatabaseInUse_MigrationFailsAndLogsError()
{
// Setup
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
string targetFile = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(Migrate_MigrationLogDatabaseInUse_MigrationFailsAndLogsError)}.rtd";
string targetFilePath = Path.Combine(TestHelper.GetScratchPadPath(), testDirectory, targetFile);
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string logDirectory = $"{nameof(Migrate_MigrationLogDatabaseInUse_MigrationFailsAndLogsError)}_log";
string logPath = Path.Combine(TestHelper.GetScratchPadPath(), logDirectory, "RingtoetsMigrationLog.sqlite");
using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), logDirectory))
using (new UseCustomSettingsHelper(new TestSettingsHelper
{
TempPath = TestHelper.GetScratchPadPath(logDirectory)
}))
using (var fileDisposeHelper = new FileDisposeHelper(logPath))
{
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
fileDisposeHelper.LockFiles();
var migrationSuccessful = true;
// Call
Action call = () => migrationSuccessful = migrator.Migrate(sourceFilePath, targetFilePath);
// Assert
Tuple logMessage = Tuple.Create(
$"Het is niet mogelijk om het Ringtoets logbestand '{logPath}' aan te maken.",
LogLevelConstant.Error);
TestHelper.AssertLogMessageWithLevelIsGenerated(call, logMessage);
Assert.IsFalse(migrationSuccessful);
Assert.IsTrue(File.Exists(logPath));
}
mocks.VerifyAll();
}
[Test]
public void Migrate_UnableToSaveAtTargetFilePath_MigrationFailsAndLogsError()
{
// Setup
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
string targetFile = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(Migrate_UnableToSaveAtTargetFilePath_MigrationFailsAndLogsError)}.rtd";
string targetFilePath = Path.Combine(TestHelper.GetScratchPadPath(), testDirectory, targetFile);
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string logDirectory = $"{nameof(Migrate_UnableToSaveAtTargetFilePath_MigrationFailsAndLogsError)}_log";
using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), logDirectory))
using (new UseCustomSettingsHelper(new TestSettingsHelper
{
TempPath = TestHelper.GetScratchPadPath(logDirectory)
}))
using (var fileDisposeHelper = new FileDisposeHelper(targetFilePath))
{
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
fileDisposeHelper.LockFiles();
var migrationSuccessful = true;
// Call
Action call = () => migrationSuccessful = migrator.Migrate(sourceFilePath, targetFilePath);
// Assert
TestHelper.AssertLogMessages(call, messages =>
{
string[] msgs = messages.ToArray();
Assert.AreEqual(1, msgs.Length);
StringAssert.StartsWith($"Het migreren van het projectbestand '{sourceFilePath}' is mislukt: ", msgs[0]);
});
Assert.IsFalse(migrationSuccessful);
string logPath = Path.Combine(TestHelper.GetScratchPadPath(), logDirectory, "RingtoetsMigrationLog.sqlite");
Assert.IsFalse(File.Exists(logPath));
}
mocks.VerifyAll();
}
[Test]
public void Migrate_UnsupportedSourceFileVersion_MigrationFailsAndLogsError()
{
// Setup
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedUnSupportedProjectFilePath();
string targetFile = $"{nameof(RingtoetsProjectMigratorTest)}." +
$"{nameof(Migrate_UnsupportedSourceFileVersion_MigrationFailsAndLogsError)}";
string targetFilePath = Path.Combine(TestHelper.GetScratchPadPath(), testDirectory, targetFile);
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string logDirectory = $"{nameof(Migrate_UnsupportedSourceFileVersion_MigrationFailsAndLogsError)}_log";
using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), logDirectory))
using (new UseCustomSettingsHelper(new TestSettingsHelper
{
TempPath = TestHelper.GetScratchPadPath(logDirectory)
}))
{
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
var migrationSuccessful = true;
// Call
Action call = () => migrationSuccessful = migrator.Migrate(sourceFilePath, targetFilePath);
// Assert
TestHelper.AssertLogMessages(call, messages =>
{
string[] msgs = messages.ToArray();
Assert.AreEqual(1, msgs.Length);
StringAssert.StartsWith($"Het migreren van het projectbestand '{sourceFilePath}' is mislukt: ", msgs[0]);
});
Assert.IsFalse(migrationSuccessful);
string logPath = Path.Combine(TestHelper.GetScratchPadPath(logDirectory), "RingtoetsMigrationLog.sqlite");
Assert.IsFalse(File.Exists(logPath));
}
mocks.VerifyAll();
}
[Test]
public void Migrate_TargetFileSameAsSourceFile_MigrationFailsAndLogsError()
{
// Setup
string sourceFilePath = RingtoetsProjectMigrationTestHelper.GetOutdatedSupportedProjectFilePath();
var mocks = new MockRepository();
var inquiryHelper = mocks.Stub();
mocks.ReplayAll();
string logDirectory = $"{nameof(Migrate_TargetFileSameAsSourceFile_MigrationFailsAndLogsError)}_log";
using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), logDirectory))
using (new UseCustomSettingsHelper(new TestSettingsHelper
{
TempPath = TestHelper.GetScratchPadPath(logDirectory)
}))
{
var migrator = new RingtoetsProjectMigrator(inquiryHelper);
var migrationSuccessful = true;
// Call
Action call = () => migrationSuccessful = migrator.Migrate(sourceFilePath, sourceFilePath);
// Assert
TestHelper.AssertLogMessages(call, messages =>
{
string[] msgs = messages.ToArray();
Assert.AreEqual(1, msgs.Length);
StringAssert.StartsWith($"Het migreren van het projectbestand '{sourceFilePath}' is mislukt: ", msgs[0]);
});
Assert.IsFalse(migrationSuccessful);
string logPath = Path.Combine(TestHelper.GetScratchPadPath(), logDirectory, "RingtoetsMigrationLog.sqlite");
Assert.IsFalse(File.Exists(logPath));
}
mocks.VerifyAll();
}
}
}