Index: Application/Riskeer/test/Application.Riskeer.Integration.Test/StorageMigrationIntegrationTest.cs =================================================================== diff -u -r118e48039447bf16cc83a2adba517c20da8e06c8 -r067b62cc6b5541809fa4f3ddf538e237188be738 --- Application/Riskeer/test/Application.Riskeer.Integration.Test/StorageMigrationIntegrationTest.cs (.../StorageMigrationIntegrationTest.cs) (revision 118e48039447bf16cc83a2adba517c20da8e06c8) +++ Application/Riskeer/test/Application.Riskeer.Integration.Test/StorageMigrationIntegrationTest.cs (.../StorageMigrationIntegrationTest.cs) (revision 067b62cc6b5541809fa4f3ddf538e237188be738) @@ -58,7 +58,7 @@ var inquiryHelper = mocks.StrictMock(); mocks.ReplayAll(); - var projectMigrator = new RingtoetsProjectMigrator(inquiryHelper); + var projectMigrator = new ProjectMigrator(inquiryHelper); using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, new RingtoetsProjectFactory(), new GuiCoreSettings())) { @@ -97,7 +97,7 @@ .Return(targetFilePath); mocks.ReplayAll(); - var projectMigrator = new RingtoetsProjectMigrator(inquiryHelper); + var projectMigrator = new ProjectMigrator(inquiryHelper); using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, new RingtoetsProjectFactory(), new GuiCoreSettings())) { @@ -130,7 +130,7 @@ .Return(false); mocks.ReplayAll(); - var projectMigrator = new RingtoetsProjectMigrator(inquiryHelper); + var projectMigrator = new ProjectMigrator(inquiryHelper); using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, new RingtoetsProjectFactory(), new GuiCoreSettings())) { Index: Ringtoets/Migration/src/Riskeer.Migration/ProjectMigrator.cs =================================================================== diff -u --- Ringtoets/Migration/src/Riskeer.Migration/ProjectMigrator.cs (revision 0) +++ Ringtoets/Migration/src/Riskeer.Migration/ProjectMigrator.cs (revision 067b62cc6b5541809fa4f3ddf538e237188be738) @@ -0,0 +1,268 @@ +// Copyright (C) Stichting Deltares 2018. 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.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; +using Core.Common.Base.Storage; +using Core.Common.Gui; +using Core.Common.Util; +using Core.Common.Util.Settings; +using log4net; +using Migration.Scripts.Data.Exceptions; +using Ringtoets.Common.Util; +using Riskeer.Migration.Core; +using Riskeer.Migration.Properties; +using MigrationCoreStorageResources = Migration.Core.Storage.Properties.Resources; + +namespace Riskeer.Migration +{ + /// + /// A GUI implementation to migrate a project database file to a newer version. + /// + public class ProjectMigrator : IMigrateProject + { + private static readonly string currentDatabaseVersion = RingtoetsVersionHelper.GetCurrentDatabaseVersion(); + + private readonly ILog log = LogManager.GetLogger(typeof(ProjectMigrator)); + private readonly RingtoetsSqLiteDatabaseFileMigrator fileMigrator; + private readonly IInquiryHelper inquiryHelper; + private readonly FileFilterGenerator fileFilter; + + private readonly string migrationLogPath; + + /// + /// Creates a new instance of . + /// + /// Object responsible for inquiring the data. + public ProjectMigrator(IInquiryHelper inquiryHelper) + { + if (inquiryHelper == null) + { + throw new ArgumentNullException(nameof(inquiryHelper)); + } + + migrationLogPath = Path.Combine(SettingsHelper.Instance.GetLocalUserTemporaryDirectory(), + "RingtoetsMigrationLog.sqlite"); + + this.inquiryHelper = inquiryHelper; + fileMigrator = new RingtoetsSqLiteDatabaseFileMigrator + { + LogPath = migrationLogPath + }; + fileFilter = new FileFilterGenerator(Resources.RingtoetsProject_FileExtension, + Resources.RingtoetsProject_TypeDescription); + } + + public MigrationRequired ShouldMigrate(string filePath) + { + if (filePath == null) + { + throw new ArgumentNullException(nameof(filePath)); + } + + ValidateProjectPath(filePath, nameof(filePath), Resources.RingtoetsProjectMigrator_Source_Descriptor); + + var versionedFile = new RingtoetsVersionedFile(filePath); + string version = versionedFile.GetVersion(); + + if (version.Equals(currentDatabaseVersion)) + { + return MigrationRequired.No; + } + + if (!fileMigrator.IsVersionSupported(version)) + { + string errorMessage = string.Format(MigrationCoreStorageResources.Migrate_From_Version_0_To_Version_1_Not_Supported, + version, currentDatabaseVersion); + log.Error(errorMessage); + return MigrationRequired.Aborted; + } + + string query = string.Format(Resources.RingtoetsProjectMigrator_Migrate_Outdated_project_file_update_to_current_version_0_inquire, + currentDatabaseVersion); + if (inquiryHelper.InquireContinuation(query)) + { + return MigrationRequired.Yes; + } + + GenerateMigrationCancelledLogMessage(filePath); + return MigrationRequired.Aborted; + } + + public string DetermineMigrationLocation(string originalFilePath) + { + if (originalFilePath == null) + { + throw new ArgumentNullException(nameof(originalFilePath)); + } + + ValidateProjectPath(originalFilePath, nameof(originalFilePath), Resources.RingtoetsProjectMigrator_Source_Descriptor); + + string suggestedFileName = GetSuggestedFileName(originalFilePath); + string migrationLocation = inquiryHelper.GetTargetFileLocation(fileFilter.Filter, suggestedFileName); + if (migrationLocation == null) + { + GenerateMigrationCancelledLogMessage(originalFilePath); + } + + return migrationLocation; + } + + public bool Migrate(string sourceFilePath, string targetFilePath) + { + if (sourceFilePath == null) + { + throw new ArgumentNullException(nameof(sourceFilePath)); + } + + if (targetFilePath == null) + { + throw new ArgumentNullException(nameof(targetFilePath)); + } + + ValidateProjectPath(sourceFilePath, nameof(sourceFilePath), Resources.RingtoetsProjectMigrator_Source_Descriptor); + ValidateProjectPath(targetFilePath, nameof(targetFilePath), Resources.RingtoetsProjectMigrator_Target_Descriptor); + + return MigrateToTargetLocation(sourceFilePath, targetFilePath); + } + + private bool MigrateToTargetLocation(string sourceFilePath, string targetLocation) + { + if (!CreateInitializedDatabaseLogFile()) + { + return false; + } + + try + { + var versionedFile = new RingtoetsVersionedFile(sourceFilePath); + fileMigrator.Migrate(versionedFile, currentDatabaseVersion, targetLocation); + string message = string.Format(Resources.RingtoetsProjectMigrator_MigrateToTargetLocation_Outdated_projectfile_0_succesfully_updated_to_target_filepath_1_version_2_, + sourceFilePath, targetLocation, currentDatabaseVersion); + log.Info(message); + + LogMigrationMessages(); + + return true; + } + catch (CriticalMigrationException e) + { + string errorMessage = string.Format(Resources.RingtoetsProjectMigrator_MigrateToTargetLocation_Updating_outdated_projectfile_0_failed_with_exception_1_, + sourceFilePath, e.Message); + log.Error(errorMessage, e); + return false; + } + finally + { + TryCleanupDatabaseLogFile(); + } + } + + private void LogMigrationMessages() + { + using (var migrationLogDatabase = new MigrationLogDatabaseReader(migrationLogPath)) + { + ReadOnlyCollection migrationLogMessages = migrationLogDatabase.GetMigrationLogMessages(); + if (!migrationLogMessages.Any()) + { + return; + } + + var migrationLog = new StringBuilder(Resources.RingtoetsProjectMigrator_Project_file_modified_click_details_for_migration_report); + foreach (MigrationLogMessage logMessage in migrationLogMessages) + { + migrationLog.AppendLine(logMessage.Message); + } + + log.Info(migrationLog); + } + } + + private bool CreateInitializedDatabaseLogFile() + { + try + { + IOUtils.CreateFileIfNotExists(migrationLogPath); + } + catch (ArgumentException exception) + { + log.Error(string.Format(Resources.RingtoetsProjectMigrator_CreateInitializedDatabaseLogFile_Unable_to_create_migration_log_file_0, migrationLogPath), + exception); + return false; + } + + return true; + } + + private void TryCleanupDatabaseLogFile() + { + try + { + if (File.Exists(migrationLogPath)) + { + File.Delete(migrationLogPath); + } + } + catch (SystemException exception) when (exception is IOException + || exception is UnauthorizedAccessException) + { + string errorMessage = string.Format(Resources.RingtoetsProjectMigrator_Deleting_migration_log_file_0_failed, migrationLogPath); + log.Error(errorMessage, exception); + } + } + + private static string GetSuggestedFileName(string sourceFilePath) + { + string fileName = Path.GetFileNameWithoutExtension(sourceFilePath); + string versionSuffix = currentDatabaseVersion.Replace(".", "-"); + string suggestedFileName = $"{fileName}_{versionSuffix}"; + + return suggestedFileName; + } + + private void GenerateMigrationCancelledLogMessage(string sourceFilePath) + { + string warningMessage = string.Format(Resources.RingtoetsProjectMigrator_GenerateMigrationCancelledLogMessage_Updating_projectfile_0_was_cancelled, sourceFilePath); + log.Warn(warningMessage); + } + + /// + /// Validates a given file path. + /// + /// The file path to be validated. + /// The name of the argument. + /// Prefix, describing the type of file path is being validated. + /// Thrown when the file path argument with the + /// given name is not valid. + private static void ValidateProjectPath(string filePath, string argumentName, string pathDescription) + { + if (!IOUtils.IsValidFilePath(filePath)) + { + string message = string.Format(Resources.RingtoetsProjectMigrator_ValidateProjectPath_TypeDescriptor_0_filepath_must_be_a_valid_path, + pathDescription); + throw new ArgumentException(message, argumentName); + } + } + } +} \ No newline at end of file Fisheye: Tag 067b62cc6b5541809fa4f3ddf538e237188be738 refers to a dead (removed) revision in file `Ringtoets/Migration/src/Riskeer.Migration/RingtoetsProjectMigrator.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Ringtoets/Migration/src/Riskeer.Migration/Riskeer.Migration.csproj =================================================================== diff -u -r81e5c8d7de54c994306ed1401ee411ab96d3db9f -r067b62cc6b5541809fa4f3ddf538e237188be738 --- Ringtoets/Migration/src/Riskeer.Migration/Riskeer.Migration.csproj (.../Riskeer.Migration.csproj) (revision 81e5c8d7de54c994306ed1401ee411ab96d3db9f) +++ Ringtoets/Migration/src/Riskeer.Migration/Riskeer.Migration.csproj (.../Riskeer.Migration.csproj) (revision 067b62cc6b5541809fa4f3ddf538e237188be738) @@ -21,7 +21,7 @@ True Resources.resx - + Index: Ringtoets/Migration/test/Riskeer.Migration.Test/ProjectMigratorTest.cs =================================================================== diff -u --- Ringtoets/Migration/test/Riskeer.Migration.Test/ProjectMigratorTest.cs (revision 0) +++ Ringtoets/Migration/test/Riskeer.Migration.Test/ProjectMigratorTest.cs (revision 067b62cc6b5541809fa4f3ddf538e237188be738) @@ -0,0 +1,721 @@ +// Copyright (C) Stichting Deltares 2018. 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 Core.Common.Base.Storage; +using Core.Common.Gui; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Common.Util.TestUtil.Settings; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Common.Util; +using Riskeer.Migration.Core; +using Riskeer.Migration.Core.TestUtil; + +namespace Riskeer.Migration.Test +{ + [TestFixture] + public class ProjectMigratorTest + { + private const string testDirectory = nameof(ProjectMigratorTest); + 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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(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 ProjectMigrator(inquiryHelper); + + string targetFileName = $"{nameof(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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 ProjectMigrator(inquiryHelper); + + string targetFileName = $"{nameof(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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 van versie 16.4 naar versie 17.1:"); + migrationLog.AppendLine("* Alle berekende resultaten zijn verwijderd."); + migrationLog.AppendLine("* Traject: 'assessmentSection'"); + migrationLog.AppendLine(" + Toetsspoor: 'Grasbekleding erosie kruin en binnentalud'"); + migrationLog.AppendLine(" - De naam van dijkprofiel '1' is veranderd naar '102' en wordt ook gebruikt als ID."); + migrationLog.AppendLine(" - De naam van dijkprofiel '10' is veranderd naar '104' en wordt ook gebruikt als ID."); + migrationLog.AppendLine("Gevolgen van de migratie van versie 17.1 naar versie 17.2:"); + migrationLog.AppendLine("* Traject: 'assessmentSection'"); + migrationLog.AppendLine(" + De ondergrens is gelijk gesteld aan 1/30000."); + migrationLog.AppendLine(" + De signaleringswaarde is gelijk gesteld aan 1/30000 (voorheen de waarde van de norm)."); + migrationLog.AppendLine(" + De norm van het dijktraject is gelijk gesteld aan de signaleringswaarde."); + migrationLog.AppendLine(" + Toetsspoor: 'Hoogte kunstwerk'"); + migrationLog.AppendLine(" - Het ID van kunstwerk 'Id' is veranderd naar 'Id00003'."); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP7'."); + migrationLog.AppendLine(" + Toetsspoor: 'Betrouwbaarheid sluiting kunstwerk'"); + migrationLog.AppendLine(" - Het ID van kunstwerk 'id' is veranderd naar 'id00002'."); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP8'."); + migrationLog.AppendLine(" + Toetsspoor: 'Golfklappen op asfaltbekleding'"); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP9'."); + migrationLog.AppendLine(" + Toetsspoor: 'Grasbekleding erosie buitentalud'"); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP10'."); + migrationLog.AppendLine(" + Toetsspoor: 'Stabiliteit steenzetting'"); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP11'."); + migrationLog.AppendLine(" + Toetsspoor: 'Sterkte en stabiliteit puntconstructies'"); + migrationLog.AppendLine(" - Het ID van kunstwerk 'anId' is veranderd naar 'anId000000002'."); + migrationLog.AppendLine(" - Het ID van voorlandprofiel 'FP' is veranderd naar 'FP12'."); + migrationLog.AppendLine("* Traject: 'Demo traject'"); + migrationLog.AppendLine(" + De ondergrens is gelijk gesteld aan 1/1000."); + migrationLog.AppendLine(" + De signaleringswaarde is gelijk gesteld aan 1/30000 (voorheen de waarde van de norm)."); + migrationLog.AppendLine(" + De norm van het dijktraject is gelijk gesteld aan de signaleringswaarde."); + migrationLog.AppendLine("Gevolgen van de migratie van versie 17.2 naar versie 17.3:"); + migrationLog.AppendLine("* Geen aanpassingen."); + migrationLog.AppendLine("Gevolgen van de migratie van versie 17.3 naar versie 18.1:"); + migrationLog.AppendLine("* Traject: 'assessmentSection'"); + migrationLog.AppendLine(" + Toetsspoor: 'Piping'"); + migrationLog.AppendLine(" - De waarde '3.2' voor de verschuiving van parameter 'Verzadigd gewicht' van ondergrondlaag 'HotPinkLayer' is ongeldig en is veranderd naar NaN."); + migrationLog.AppendLine(" + Toetsspoor: 'Sterkte en stabiliteit langsconstructies'"); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Technische innovaties'"); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Wateroverdruk bij asfaltbekleding'"); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Betrouwbaarheid sluiting kunstwerk'"); + migrationLog.AppendLine(" - De waarde van '0' van parameter 'Aantal identieke doorstroomopeningen' van berekening 'Nieuwe berekening' is ongeldig en is veranderd naar 1."); + migrationLog.AppendLine(" + Toetsspoor: 'Macrostabiliteit buitenwaarts'"); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Golfklappen op asfaltbekleding'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Grasbekleding erosie buitentalud'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Grasbekleding afschuiven binnentalud'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Grasbekleding afschuiven buitentalud'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Microstabiliteit'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Piping bij kunstwerk'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Stabiliteit steenzetting'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" + Toetsspoor: 'Duinafslag'"); + migrationLog.AppendLine(" - Alle resultaten voor de gedetailleerde toets van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine(" - Alle resultaten voor de toets op maat van dit toetsspoor konden niet worden omgezet naar een geldig resultaat en zijn verwijderd."); + migrationLog.AppendLine("Gevolgen van de migratie van versie 18.1 naar versie 19.1:"); + migrationLog.AppendLine("* Traject: 'assessmentSection'"); + migrationLog.AppendLine(" + Er worden standaardwaarden conform WBI2017 voor de HLCD bestand informatie gebruikt."); + migrationLog.AppendLine(" + De waarde voor de transparantie van de achtergrondkaart is aangepast naar 0.60."); + migrationLog.AppendLine("* Traject: 'Demo traject'"); + migrationLog.AppendLine(" + Er worden standaardwaarden conform WBI2017 voor de HLCD bestand informatie gebruikt."); + migrationLog.AppendLine(" + De waarde voor de transparantie van de achtergrondkaart is aangepast naar 0.60."); + + Tuple[] expectedLogMessagesAndLevel = + { + 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(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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(ProjectMigratorTest)}." + + $"{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 ProjectMigrator(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 ProjectMigrator(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(); + } + } +} \ No newline at end of file Fisheye: Tag 067b62cc6b5541809fa4f3ddf538e237188be738 refers to a dead (removed) revision in file `Ringtoets/Migration/test/Riskeer.Migration.Test/RingtoetsProjectMigratorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Ringtoets/Migration/test/Riskeer.Migration.Test/Riskeer.Migration.Test.csproj =================================================================== diff -u -r5da9e26c544c8e3be801086ac660bc787a31b6cf -r067b62cc6b5541809fa4f3ddf538e237188be738 --- Ringtoets/Migration/test/Riskeer.Migration.Test/Riskeer.Migration.Test.csproj (.../Riskeer.Migration.Test.csproj) (revision 5da9e26c544c8e3be801086ac660bc787a31b6cf) +++ Ringtoets/Migration/test/Riskeer.Migration.Test/Riskeer.Migration.Test.csproj (.../Riskeer.Migration.Test.csproj) (revision 067b62cc6b5541809fa4f3ddf538e237188be738) @@ -20,7 +20,7 @@ - +