// Copyright (C) Stichting Deltares 2017. 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.IO; using System.Linq; using Core.Common.Base; using Core.Common.Base.Service; using Core.Common.TestUtil; using Core.Common.Util; using NUnit.Framework; using Rhino.Mocks; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.TestUtil; using Ringtoets.Common.Service.TestUtil; using Ringtoets.DuneErosion.Data; using Ringtoets.DuneErosion.Data.TestUtil; using Ringtoets.HydraRing.Calculation.Activities; using Ringtoets.HydraRing.Calculation.Calculator.Factory; using Ringtoets.HydraRing.Calculation.Data.Input.Hydraulics; using Ringtoets.HydraRing.Calculation.TestUtil.Calculator; namespace Ringtoets.DuneErosion.Service.Test { [TestFixture] public class DuneErosionBoundaryCalculationActivityTest { private MockRepository mockRepository; private static readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Integration.Service, "HydraRingCalculation"); private static readonly string validFilePath = Path.Combine(testDataPath, "HRD dutch coast south.sqlite"); private static readonly string validPreprocessorDirectory = TestHelper.GetScratchPadPath(); [SetUp] public void SetUp() { mockRepository = new MockRepository(); } [Test] public void Constructor_ExpectedValues() { // Setup var duneLocation = new TestDuneLocation(); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); // Call var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 1.0 / 30000); // Assert Assert.IsInstanceOf(activity); Assert.AreEqual($"Hydraulische randvoorwaarden berekenen voor locatie '{duneLocation.Name}'", activity.Description); Assert.IsNull(activity.ProgressText); Assert.AreEqual(ActivityState.None, activity.State); } [Test] public void Constructor_DuneLocationNull_ThrowArgumentNullException() { // Call TestDelegate test = () => new DuneErosionBoundaryCalculationActivity(null, new DuneLocationCalculation(new TestDuneLocation()), validFilePath, validPreprocessorDirectory, 1.0 / 30000); // Assert var exception = Assert.Throws(test); Assert.AreEqual("duneLocation", exception.ParamName); } [Test] public void Constructor_DuneLocationCalculationNull_ThrowArgumentNullException() { // Call TestDelegate test = () => new DuneErosionBoundaryCalculationActivity(new TestDuneLocation(), null, validFilePath, validPreprocessorDirectory, 1.0 / 30000); // Assert var exception = Assert.Throws(test); Assert.AreEqual("duneLocationCalculation", exception.ParamName); } [Test] public void Run_InvalidHydraulicBoundaryDatabase_PerformValidationAndLogStartAndEndAndError() { // Setup string invalidFilePath = Path.Combine(testDataPath, "notexisting.sqlite"); const string locationName = "testLocation"; var duneLocation = new TestDuneLocation(locationName); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, invalidFilePath, validPreprocessorDirectory, 0.5); // Call Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessages(call, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(4, msgs.Length); Assert.AreEqual($"Hydraulische randvoorwaarden berekenen voor locatie '{locationName}' is gestart.", msgs[0]); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[1]); StringAssert.StartsWith("Herstellen van de verbinding met de hydraulische randvoorwaardendatabase is mislukt. Fout bij het lezen van bestand", msgs[2]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[3]); }); Assert.AreEqual(ActivityState.Failed, activity.State); } [Test] public void Run_InvalidPreprocessorDirectory_PerformValidationAndLogStartAndEndAndError() { // Setup const string invalidPreprocessorDirectory = "NonExistingPreprocessorDirectory"; const string locationName = "testLocation"; var duneLocation = new TestDuneLocation(locationName); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, invalidPreprocessorDirectory, 0.5); // Call Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessages(call, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(4, msgs.Length); Assert.AreEqual($"Hydraulische randvoorwaarden berekenen voor locatie '{locationName}' is gestart.", msgs[0]); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[1]); Assert.AreEqual("De bestandsmap waar de preprocessor bestanden opslaat is ongeldig. De bestandsmap bestaat niet.", msgs[2]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[3]); }); Assert.AreEqual(ActivityState.Failed, activity.State); } [Test] public void Run_ValidHydraulicBoundaryDatabaseAndDuneLocation_PerformValidationValidParameters() { // Setup const double norm = 1.0 / 30; const string locationName = "some name"; var duneLocation = new TestDuneLocation(locationName); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var calculator = new TestDunesBoundaryConditionsCalculator { Converged = true }; var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateDunesBoundaryConditionsCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, norm); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessages(call, m => { string[] messages = m.ToArray(); Assert.AreEqual(6, messages.Length); Assert.AreEqual($"Hydraulische randvoorwaarden berekenen voor locatie '{locationName}' is gestart.", messages[0]); CalculationServiceTestHelper.AssertValidationStartMessage(messages[1]); CalculationServiceTestHelper.AssertValidationEndMessage(messages[2]); CalculationServiceTestHelper.AssertCalculationStartMessage(messages[3]); StringAssert.StartsWith("Hydraulische randvoorwaarden berekening is uitgevoerd op de tijdelijke locatie", messages[4]); CalculationServiceTestHelper.AssertCalculationEndMessage(messages[5]); }); DunesBoundaryConditionsCalculationInput calculationInput = calculator.ReceivedInputs.Single(); Assert.AreEqual(duneLocation.Id, calculationInput.HydraulicBoundaryLocationId); Assert.AreEqual(StatisticsConverter.ProbabilityToReliability(norm), calculationInput.Beta); } Assert.AreEqual(ActivityState.Executed, activity.State); mockRepository.VerifyAll(); } [Test] public void Run_DuneLocationOutputSet_ValidationAndCalculationNotPerformedAndStateSkipped() { // Setup var duneLocation = new TestDuneLocation("locationName"); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()) { Output = new DuneLocationOutput(CalculationConvergence.CalculatedConverged, new DuneLocationOutput.ConstructionProperties()) }; var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 0.5); // Call activity.Run(); // Assert Assert.AreEqual(ActivityState.Skipped, activity.State); } [Test] public void Run_ValidCalculationAndRun_SetsOutput() { // Setup var random = new Random(123); double norm = random.NextDouble(); double expectedWaterLevel = random.NextDouble(); double expectedWaveHeight = random.NextDouble(); double expectedWavePeriod = random.NextDouble(); double expectedReliabilityIndex = random.NextDouble(); var duneLocation = new TestDuneLocation(); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var calculator = new TestDunesBoundaryConditionsCalculator { WaterLevel = expectedWaterLevel, WaveHeight = expectedWaveHeight, WavePeriod = expectedWavePeriod, ReliabilityIndex = expectedReliabilityIndex, Converged = true }; var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateDunesBoundaryConditionsCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, norm); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call activity.Run(); } // Assert DuneLocationOutput duneLocationOutput = duneLocationCalculation.Output; Assert.IsNotNull(duneLocationOutput); Assert.AreEqual(expectedWaterLevel, duneLocationOutput.WaterLevel, duneLocationOutput.WaterLevel.GetAccuracy()); Assert.AreEqual(expectedWaveHeight, duneLocationOutput.WaveHeight, duneLocationOutput.WaveHeight.GetAccuracy()); Assert.AreEqual(expectedWavePeriod, duneLocationOutput.WavePeriod, duneLocationOutput.WavePeriod.GetAccuracy()); Assert.AreEqual(expectedReliabilityIndex, duneLocationOutput.CalculatedReliability, duneLocationOutput.CalculatedReliability.GetAccuracy()); Assert.AreEqual(CalculationConvergence.CalculatedConverged, duneLocationOutput.CalculationConvergence); mockRepository.VerifyAll(); } [Test] [TestCaseSource(typeof(HydraRingCalculatorTestCaseProvider), nameof(HydraRingCalculatorTestCaseProvider.GetCalculatorFailingConditionsWithReportDetails), new object[] { nameof(Run_InvalidCalculation_LogsError) })] public void Run_InvalidCalculation_LogsError(bool endInFailure, string lastErrorFileContent, string detailedReport) { // Setup var calculator = new TestDunesBoundaryConditionsCalculator { EndInFailure = endInFailure, LastErrorFileContent = lastErrorFileContent }; var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateDunesBoundaryConditionsCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); var duneLocation = new TestDuneLocation("dune location"); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 0.5); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call Action call = () => activity.Run(); // Assert string calculationfailedMessage = $"Hydraulische randvoorwaarden berekening voor locatie '{duneLocation.Name}' is mislukt. {detailedReport}"; TestHelper.AssertLogMessageIsGenerated(call, calculationfailedMessage, 7); } mockRepository.VerifyAll(); } [Test] public void Run_CalculationResultingInNoConvergence_LogWarningNoConvergence() { // Setup var calculator = new TestDunesBoundaryConditionsCalculator { Converged = false }; var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateDunesBoundaryConditionsCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); const string locationName = "some name"; var duneLocation = new TestDuneLocation(locationName); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 0.5); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessages(call, messages => { string[] msgs = messages.ToArray(); Assert.AreEqual(7, msgs.Length); Assert.AreEqual($"Hydraulische randvoorwaarden berekenen voor locatie '{locationName}' is gestart.", msgs[0]); CalculationServiceTestHelper.AssertValidationStartMessage(msgs[1]); CalculationServiceTestHelper.AssertValidationEndMessage(msgs[2]); CalculationServiceTestHelper.AssertCalculationStartMessage(msgs[3]); Assert.AreEqual($"Hydraulische randvoorwaarden berekening voor locatie '{duneLocation.Name}' is niet geconvergeerd.", msgs[4]); StringAssert.StartsWith("Hydraulische randvoorwaarden berekening is uitgevoerd op de tijdelijke locatie", msgs[5]); CalculationServiceTestHelper.AssertCalculationEndMessage(msgs[6]); }); Assert.AreEqual(CalculationConvergence.CalculatedNotConverged, duneLocationCalculation.Output.CalculationConvergence); } mockRepository.VerifyAll(); } [Test] [TestCaseSource(typeof(HydraRingCalculatorTestCaseProvider), nameof(HydraRingCalculatorTestCaseProvider.GetCalculatorFailingConditions), new object[] { nameof(Run_ErrorInCalculation_PerformValidationAndCalculationAndError) })] public void Run_ErrorInCalculation_PerformValidationAndCalculationAndError(bool endInFailure, string lastErrorFileContent) { // Setup var duneLocation = new TestDuneLocation(); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var calculator = new TestDunesBoundaryConditionsCalculator { EndInFailure = endInFailure, LastErrorFileContent = lastErrorFileContent }; var calculatorFactory = mockRepository.StrictMock(); calculatorFactory.Expect(cf => cf.CreateDunesBoundaryConditionsCalculator(testDataPath, validPreprocessorDirectory)).Return(calculator); mockRepository.ReplayAll(); var activity = new DuneErosionBoundaryCalculationActivity(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 0.5); using (new HydraRingCalculatorFactoryConfig(calculatorFactory)) { // Call activity.Run(); // Assert Assert.AreEqual(ActivityState.Failed, activity.State); } mockRepository.VerifyAll(); } [Test] [TestCase(ActivityState.Executed)] [TestCase(ActivityState.Failed)] [TestCase(ActivityState.Canceled)] [TestCase(ActivityState.Skipped)] public void Finish_ActivityWithSpecificState_NotifyDuneLocation(ActivityState state) { // Setup var duneLocation = new TestDuneLocation(); var duneLocationCalculation = new DuneLocationCalculation(new TestDuneLocation()); var observer = mockRepository.StrictMock(); observer.Expect(o => o.UpdateObserver()); duneLocation.Attach(observer); mockRepository.ReplayAll(); var activity = new DuneErosionBoundaryCalculationActivityWithState(duneLocation, duneLocationCalculation, validFilePath, validPreprocessorDirectory, 1.0, state); // Call activity.Finish(); // Assert mockRepository.VerifyAll(); } private class DuneErosionBoundaryCalculationActivityWithState : DuneErosionBoundaryCalculationActivity { public DuneErosionBoundaryCalculationActivityWithState(DuneLocation duneLocation, DuneLocationCalculation duneLocationCalculation, string hydraulicBoundaryDatabaseFilePath, string preprocessorDirectory, double norm, ActivityState state) : base(duneLocation, duneLocationCalculation, hydraulicBoundaryDatabaseFilePath, preprocessorDirectory, norm) { State = state; } } } }