diff --git a/CHANGELOG.md b/CHANGELOG.md index 286040a34b..72bc376563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,6 +136,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed `CHANGELOG` entry for issue ([#103](https://github.com/ie3-institute/simona/issues/103)) [#941](https://github.com/ie3-institute/simona/issues/941) - Fix grammar and spelling in docs and comments [#1022](https://github.com/ie3-institute/simona/issues/1022) - Fix some minor issues and findings from inspections [#1019](https://github.com/ie3-institute/simona/issues/1019) +- Fix initialisation freezing on empty primary data [#981](https://github.com/ie3-institute/simona/issues/981) ## [3.0.0] - 2023-08-07 diff --git a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala index efb4150814..927007bb47 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -139,9 +139,8 @@ protected trait ParticipantAgentFundamentals[ /* Confirm final initialization */ releaseTick() - senderToMaybeTick._2.foreach { tick => - scheduler ! Completion(self.toTyped, Some(tick)) - } + scheduler ! Completion(self.toTyped, senderToMaybeTick._2) + goto(Idle) using stateData } diff --git a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala index bd09c0b81b..b20fdd834c 100644 --- a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala +++ b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala @@ -20,6 +20,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.RichValue import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.SqlParams import edu.ie3.simona.exceptions.InitializationException import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException +import edu.ie3.simona.exceptions.agent.ServiceRegistrationException import edu.ie3.simona.ontology.messages.services.ServiceMessage import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage import edu.ie3.simona.service.ServiceStateData.{ @@ -131,32 +132,47 @@ final case class PrimaryServiceWorker[V <: Value]( s"Provided init data '${unsupported.getClass.getSimpleName}' for primary service are invalid!" ) ) - }).map { case (source, simulationStart) => + }).flatMap { case (source, simulationStart) => implicit val startDateTime: ZonedDateTime = simulationStart val (maybeNextTick, furtherActivationTicks) = SortedDistinctSeq( // Note: The whole data set is used here, which might be inefficient depending on the source implementation. source.getTimeSeries.getEntries.asScala - .filter { timeBasedValue => - val dateTime = timeBasedValue.getTime - dateTime.isEqual(simulationStart) || dateTime.isAfter( - simulationStart - ) - } .map(timeBasedValue => timeBasedValue.getTime.toTick) + .filter(_ >= 0L) .toSeq .sorted ).pop - /* Set up the state data and determine the next activation tick. */ - val initializedStateData = - PrimaryServiceInitializedStateData( - maybeNextTick, - furtherActivationTicks, - simulationStart, - source, - ) - (initializedStateData, maybeNextTick) + (maybeNextTick, furtherActivationTicks) match { + case (Some(tick), furtherActivationTicks) if tick == 0L => + /* Set up the state data and determine the next activation tick. */ + val initializedStateData = + PrimaryServiceInitializedStateData( + maybeNextTick, + furtherActivationTicks, + simulationStart, + source, + ) + + Success(initializedStateData, maybeNextTick) + + case (Some(tick), _) if tick > 0L => + /* The start of the data needs to be at the first tick of the simulation. */ + Failure( + new ServiceRegistrationException( + s"The data for the timeseries '${source.getTimeSeries.getUuid}' starts after the start of this simulation (tick: $tick)! This is not allowed!" + ) + ) + + case _ => + /* No data for the simulation. */ + Failure( + new ServiceRegistrationException( + s"No appropriate data found within simulation time range in timeseries '${source.getTimeSeries.getUuid}'!" + ) + ) + } } } diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala index db7e9abdea..c08f189b79 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala @@ -105,6 +105,32 @@ class PrimaryServiceWorkerSpec } } + "fail to init, if time series ends with delay before simulation start" in { + val initData = validInitData.copy( + simulationStart = validInitData.simulationStart.plusHours(1) + ) + + service.init(initData) match { + case Failure(exception) => + exception.getMessage shouldBe "No appropriate data found within simulation time range in timeseries '9185b8c1-86ba-4a16-8dea-5ac898e8caa5'!" + case Success(_) => + fail("Initialisation with unsupported init data is meant to fail.") + } + } + + "fail to init, if time series starts with delay after simulation start" in { + val initData = validInitData.copy( + simulationStart = validInitData.simulationStart.minusHours(1) + ) + + service.init(initData) match { + case Failure(exception) => + exception.getMessage shouldBe "The data for the timeseries '9185b8c1-86ba-4a16-8dea-5ac898e8caa5' starts after the start of this simulation (tick: 3600)! This is not allowed!" + case Success(_) => + fail("Initialisation with unsupported init data is meant to fail.") + } + } + "fail, if pointed to the wrong file" in { // time series exists, but is malformed val tsUuid = UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c27")