From ede35638a1bda18e4953bf69facc130bdd2ab73a Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Wed, 18 Dec 2024 21:04:01 +0100 Subject: [PATCH 1/2] Converting services to pekko typed. --- CHANGELOG.md | 1 + .../ie3/simona/agent/EnvironmentRefs.scala | 12 +- .../agent/grid/GridAgentController.scala | 28 +- .../agent/participant/ParticipantAgent.scala | 24 +- .../ParticipantAgentFundamentals.scala | 51 +- .../participant/ServiceRegistration.scala | 28 +- .../agent/participant/data/DataService.scala | 7 +- .../data/primary/PrimaryDataService.scala | 12 +- .../data/secondary/SecondaryDataService.scala | 30 +- .../agent/participant/evcs/EvcsAgent.scala | 2 +- .../evcs/EvcsAgentFundamentals.scala | 26 +- .../FixedFeedInAgentFundamentals.scala | 5 +- .../simona/agent/participant/hp/HpAgent.scala | 2 +- .../participant/hp/HpAgentFundamentals.scala | 5 +- .../load/LoadAgentFundamentals.scala | 5 +- .../simona/agent/participant/pv/PvAgent.scala | 2 +- .../participant/pv/PvAgentFundamentals.scala | 5 +- .../participant/statedata/BaseStateData.scala | 18 +- .../statedata/DataCollectionStateData.scala | 3 +- .../statedata/ParticipantStateData.scala | 44 +- .../storage/StorageAgentFundamentals.scala | 5 +- .../agent/participant/wec/WecAgent.scala | 2 +- .../wec/WecAgentFundamentals.scala | 5 +- .../edu/ie3/simona/api/ExtSimAdapter.scala | 2 +- .../messages/services/EvMessage.scala | 20 +- .../services/PrimaryDataMessage.scala | 59 +- .../messages/services/ServiceMessage.scala | 56 +- .../services/ServiceMessageUniversal.scala | 73 +++ .../messages/services/WeatherMessage.scala | 15 +- .../services/WholeSalePriceMessage.scala | 15 + .../ie3/simona/service/ExtDataSupport.scala | 35 +- .../ie3/simona/service/ServiceStateData.scala | 7 + .../ie3/simona/service/SimonaService.scala | 169 ++--- .../simona/service/ev/ExtEvDataService.scala | 108 +++- .../service/primary/PrimaryServiceProxy.scala | 422 ++++++------ .../primary/PrimaryServiceWorker.scala | 367 +++++------ .../service/weather/WeatherService.scala | 128 ++-- .../scala/edu/ie3/simona/sim/SimonaSim.scala | 8 +- .../simona/sim/setup/ExtSimSetupData.scala | 12 +- .../ie3/simona/sim/setup/SimonaSetup.scala | 9 +- .../sim/setup/SimonaStandaloneSetup.scala | 64 +- .../edu/ie3/simona/agent/em/EmAgentIT.scala | 35 +- .../agent/grid/DBFSAlgorithmCenGridSpec.scala | 14 +- .../DBFSAlgorithmFailedPowerFlowSpec.scala | 13 +- .../grid/DBFSAlgorithmParticipantSpec.scala | 33 +- .../agent/grid/DBFSAlgorithmSupGridSpec.scala | 23 +- .../EvcsAgentModelCalculationSpec.scala | 168 ++--- ...FixedFeedInAgentModelCalculationSpec.scala | 21 +- .../HpAgentModelCalculationSpec.scala | 80 ++- .../LoadAgentFixedModelCalculationSpec.scala | 21 +- ...LoadAgentProfileModelCalculationSpec.scala | 14 +- .../ParticipantAgent2ListenerSpec.scala | 14 +- .../ParticipantAgentExternalSourceSpec.scala | 96 +-- .../ParticipantAgentFundamentalsSpec.scala | 19 +- .../participant/ParticipantAgentMock.scala | 5 +- .../PvAgentModelCalculationSpec.scala | 83 ++- .../StorageAgentModelCalculationSpec.scala | 21 +- .../WecAgentModelCalculationSpec.scala | 72 ++- .../ie3/simona/api/ExtSimAdapterSpec.scala | 2 +- .../service/ev/ExtEvDataServiceSpec.scala | 606 +++++++++--------- .../primary/PrimaryServiceProxySpec.scala | 380 +++++------ .../primary/PrimaryServiceProxySqlIT.scala | 106 ++- .../primary/PrimaryServiceWorkerSpec.scala | 169 ++--- .../primary/PrimaryServiceWorkerSqlIT.scala | 100 ++- .../service/weather/WeatherServiceSpec.scala | 158 +++-- .../edu/ie3/simona/sim/SimonaSimSpec.scala | 13 +- .../simona/sim/setup/SimonaSetupSpec.scala | 13 +- .../ie3/simona/test/common/AgentSpec.scala | 4 +- .../simona/test/common/AgentTypedSpec.scala | 26 + 69 files changed, 2306 insertions(+), 1894 deletions(-) create mode 100644 src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessageUniversal.scala create mode 100644 src/main/scala/edu/ie3/simona/ontology/messages/services/WholeSalePriceMessage.scala create mode 100644 src/test/scala/edu/ie3/simona/test/common/AgentTypedSpec.scala diff --git a/CHANGELOG.md b/CHANGELOG.md index a3b29efcb9..3358efbfca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -111,6 +111,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactor thermal calcRelevantData [#1051](https://github.com/ie3-institute/simona/issues/1051) - Removed Deployment stage from Jenkinsfile [#1063](https://github.com/ie3-institute/simona/issues/1063) - Prepare 'ChpModelSpec' and 'CylindricalThermalStorageSpec' for Storage without storageVolumeLvlMin [#1012](https://github.com/ie3-institute/simona/issues/1012) +- Converted services to pekko typed [#1069](https://github.com/ie3-institute/simona/issues/1069) ### Fixed - Fix rendering of references in documentation [#505](https://github.com/ie3-institute/simona/issues/505) diff --git a/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala b/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala index 4b5c6c920d..cd3cdce1fd 100644 --- a/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala +++ b/src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala @@ -8,8 +8,12 @@ package edu.ie3.simona.agent import edu.ie3.simona.event.RuntimeEvent import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + PrimaryDataMessage, + WeatherMessage, +} import org.apache.pekko.actor.typed.ActorRef -import org.apache.pekko.actor.{ActorRef => ClassicRef} /** Container class, that gather together reference to relevant entities, that * represent the environment in the simulation @@ -28,7 +32,7 @@ import org.apache.pekko.actor.{ActorRef => ClassicRef} final case class EnvironmentRefs( scheduler: ActorRef[SchedulerMessage], runtimeEventListener: ActorRef[RuntimeEvent], - primaryServiceProxy: ClassicRef, - weather: ClassicRef, - evDataService: Option[ClassicRef], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + weather: ActorRef[WeatherMessage], + evDataService: Option[ActorRef[EvMessage]], ) diff --git a/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala b/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala index 8d615ec3af..f48eec3c06 100644 --- a/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala +++ b/src/main/scala/edu/ie3/simona/agent/grid/GridAgentController.scala @@ -33,13 +33,17 @@ import edu.ie3.simona.exceptions.CriticalFailureException import edu.ie3.simona.exceptions.agent.GridAgentInitializationException import edu.ie3.simona.ontology.messages.SchedulerMessage.ScheduleActivation import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.FlexResponse +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.util.ConfigUtil import edu.ie3.simona.util.ConfigUtil._ import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import org.apache.pekko.actor.typed.ActorRef import org.apache.pekko.actor.typed.scaladsl.ActorContext import org.apache.pekko.actor.typed.scaladsl.adapter._ -import org.apache.pekko.actor.{ActorRef => ClassicRef} import org.slf4j.Logger import java.time.ZonedDateTime @@ -472,7 +476,7 @@ class GridAgentController( private def buildFixedFeedIn( fixedFeedInInput: FixedFeedInInput, modelConfiguration: FixedFeedInRuntimeConfig, - primaryServiceProxy: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -529,7 +533,7 @@ class GridAgentController( private def buildLoad( loadInput: LoadInput, modelConfiguration: LoadRuntimeConfig, - primaryServiceProxy: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -588,8 +592,8 @@ class GridAgentController( private def buildPv( pvInput: PvInput, modelConfiguration: PvRuntimeConfig, - primaryServiceProxy: ClassicRef, - weatherService: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], + weatherService: ActorRef[WeatherMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -648,8 +652,8 @@ class GridAgentController( private def buildEvcs( evcsInput: EvcsInput, modelConfiguration: EvcsRuntimeConfig, - primaryServiceProxy: ClassicRef, - evMovementsService: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], + evMovementsService: ActorRef[EvMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -708,8 +712,8 @@ class GridAgentController( hpInput: HpInput, thermalGrid: ThermalGrid, modelConfiguration: HpRuntimeConfig, - primaryServiceProxy: ClassicRef, - weatherService: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], + weatherService: ActorRef[WeatherMessage], requestVoltageDeviationThreshold: Double, outputConfig: NotifierConfig, maybeControllingEm: Option[ActorRef[FlexResponse]], @@ -766,8 +770,8 @@ class GridAgentController( private def buildWec( wecInput: WecInput, modelConfiguration: WecRuntimeConfig, - primaryServiceProxy: ClassicRef, - weatherService: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], + weatherService: ActorRef[WeatherMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -824,7 +828,7 @@ class GridAgentController( private def buildStorage( storageInput: StorageInput, modelConfiguration: SimonaConfig.StorageRuntimeConfig, - primaryServiceProxy: ClassicRef, + primaryServiceProxy: ActorRef[PrimaryDataMessage], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgent.scala b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgent.scala index 19eff90211..15a80f0fb8 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgent.scala @@ -16,7 +16,7 @@ import edu.ie3.simona.agent.participant.ParticipantAgent.{ import edu.ie3.simona.agent.participant.data.Data import edu.ie3.simona.agent.participant.data.Data.PrimaryData.PrimaryDataWithApparentPower import edu.ie3.simona.agent.participant.data.Data.{PrimaryData, SecondaryData} -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FromOutsideBaseStateData, ParticipantModelBaseStateData, @@ -47,18 +47,17 @@ import edu.ie3.simona.model.participant.{ } import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.{ + FlexActivation, FlexResponse, IssueFlexControl, - FlexActivation, -} -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ - PrimaryServiceRegistrationMessage, - ProvisionMessage, - RegistrationResponseMessage, } +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ProvisionMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.scala.quantities.ReactivePower +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import org.apache.pekko.actor.typed.{ActorRef => TypedActorRef} import org.apache.pekko.actor.{ActorRef, FSM} import squants.{Dimensionless, Power} @@ -129,7 +128,8 @@ abstract class ParticipantAgent[ * that will confirm, otherwise, a failed registration is announced. */ holdTick(INIT_SIM_TICK) initStateData.primaryServiceProxy ! PrimaryServiceRegistrationMessage( - initStateData.inputModel.electricalInputModel.getUuid + self, + initStateData.inputModel.electricalInputModel.getUuid, ) goto(HandleInformation) using ParticipantInitializingStateData( initStateData.inputModel, @@ -442,7 +442,7 @@ abstract class ParticipantAgent[ participantStateData.receivedSecondaryDataStore, currentTick, nonEmptyData.collect { case (actorRef, Some(data: SecondaryData)) => - actorRef -> data + actorRef.toClassic -> data }, ) case _ => participantStateData.receivedSecondaryDataStore @@ -515,7 +515,7 @@ abstract class ParticipantAgent[ resolution: Long, requestVoltageDeviationThreshold: Double, outputConfig: NotifierConfig, - senderToMaybeTick: (ActorRef, Option[Long]), + senderToMaybeTick: (TypedActorRef[_], Option[Long]), scheduler: ActorRef, ): FSM.State[AgentState, ParticipantStateData[PD]] @@ -547,7 +547,7 @@ abstract class ParticipantAgent[ def initializeParticipantForModelCalculation( inputModel: InputModelContainer[I], modelConfig: MC, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, 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 a505696943..6022f9efeb 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -30,6 +30,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ } import edu.ie3.simona.agent.participant.data.Data.{PrimaryData, SecondaryData} import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FromOutsideBaseStateData, ParticipantModelBaseStateData, @@ -75,16 +76,18 @@ import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage._ import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions -import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ - ProvisionMessage, - RegistrationResponseMessage, -} +import edu.ie3.simona.ontology.messages.services.ServiceMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ProvisionMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage import edu.ie3.simona.util.TickUtil._ import edu.ie3.util.quantities.PowerSystemUnits._ import edu.ie3.util.quantities.QuantityUtils.RichQuantityDouble import edu.ie3.util.scala.quantities.DefaultQuantities._ import edu.ie3.util.scala.quantities.{Megavars, QuantityUtil, ReactivePower} -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.typed.scaladsl.adapter.{ + ClassicActorRefOps, + TypedActorRefOps, +} import org.apache.pekko.actor.typed.{ActorRef => TypedActorRef} import org.apache.pekko.actor.{ActorRef, FSM, PoisonPill} import org.apache.pekko.event.LoggingAdapter @@ -123,7 +126,7 @@ protected trait ParticipantAgentFundamentals[ resolution: Long, requestVoltageDeviationThreshold: Double, outputConfig: NotifierConfig, - senderToMaybeTick: (ActorRef, Option[Long]), + senderToMaybeTick: (TypedActorRef[_], Option[Long]), scheduler: ActorRef, ): FSM.State[AgentState, ParticipantStateData[PD]] = { val stateData = determineFromOutsideBaseStateData( @@ -175,7 +178,7 @@ protected trait ParticipantAgentFundamentals[ resolution: Long, requestVoltageDeviationThreshold: Double, outputConfig: NotifierConfig, - senderToMaybeTick: (ActorRef, Option[Long]), + senderToMaybeTick: (TypedActorRef[_], Option[Long]), ): FromOutsideBaseStateData[M, PD] = { val model = buildModel( inputModel, @@ -257,7 +260,7 @@ protected trait ParticipantAgentFundamentals[ override def initializeParticipantForModelCalculation( inputModel: InputModelContainer[I], modelConfig: MC, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -337,7 +340,7 @@ protected trait ParticipantAgentFundamentals[ def determineModelBaseStateData( inputModel: InputModelContainer[I], modelConfig: MC, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -622,7 +625,7 @@ protected trait ParticipantAgentFundamentals[ modelStateData.receivedSecondaryDataStore, tick, stateData.data.map { case (actorRef, Some(data: SecondaryData)) => - actorRef -> data + actorRef.toClassic -> data }, ) @@ -987,7 +990,7 @@ protected trait ParticipantAgentFundamentals[ * A trial to get and process the needed data */ def prepareData( - data: Map[ActorRef, Option[_ <: Data]], + data: Map[TypedActorRef[_], Option[_ <: Data]], reactivePowerFunction: Power => ReactivePower, ): Try[PD] = data.headOption @@ -1943,27 +1946,17 @@ protected trait ParticipantAgentFundamentals[ * @param services * the services used in * [[edu.ie3.simona.agent.participant.statedata.BaseStateData.ModelBaseStateData]] - * @param tag - * ClassTag of T - * @tparam T - * the type of secondary service to return + * @tparam S + * the type of the messages of the secondary service to return * @return * secondary service of given type */ - protected def getService[T <: SecondaryDataService[_]]( - services: Iterable[SecondaryDataService[_ <: SecondaryData]] - )(implicit tag: ClassTag[T]): ActorRef = - services - .find { - case _: T => true - case _ => false - } - .getOrElse( - throw new InconsistentStateException( - s"No $tag provided by ParticipantModelBaseStateData." - ) - ) - .actorRef + protected def getService[S <: ServiceMessage]( + services: Iterable[SecondaryServiceType] + ): Option[TypedActorRef[S]] = + services.collectFirst { case service: SecondaryDataService[_, S] => + service.actorRef + } } object ParticipantAgentFundamentals { diff --git a/src/main/scala/edu/ie3/simona/agent/participant/ServiceRegistration.scala b/src/main/scala/edu/ie3/simona/agent/participant/ServiceRegistration.scala index 5308b4e768..89110d37c9 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ServiceRegistration.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ServiceRegistration.scala @@ -6,7 +6,6 @@ package edu.ie3.simona.agent.participant -import org.apache.pekko.actor.ActorRef import edu.ie3.datamodel.models.input.system.{EvcsInput, SystemParticipantInput} import edu.ie3.simona.agent.participant.data.Data.PrimaryData.PrimaryDataWithApparentPower import edu.ie3.simona.agent.participant.data.Data.SecondaryData @@ -26,6 +25,12 @@ import edu.ie3.simona.model.participant.{ } import edu.ie3.simona.ontology.messages.services.EvMessage.RegisterForEvDataMessage import edu.ie3.simona.ontology.messages.services.WeatherMessage.RegisterForWeatherMessage +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + ServiceMessage, + WeatherMessage, +} +import org.apache.pekko.actor.typed.ActorRef trait ServiceRegistration[ PD <: PrimaryDataWithApparentPower[PD], @@ -50,8 +55,10 @@ trait ServiceRegistration[ */ def registerForServices( inputModel: I, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], - ): Iterable[ActorRef] = + services: Iterable[ + SecondaryDataService[_ <: SecondaryData, _ <: ServiceMessage] + ], + ): Iterable[ActorRef[_]] = services.flatMap(service => registerForSecondaryService(service, inputModel) ) @@ -69,11 +76,12 @@ trait ServiceRegistration[ * supported at the moment */ private def registerForSecondaryService[ - S <: SecondaryData + S <: SecondaryData, + M <: ServiceMessage, ]( - serviceDefinition: SecondaryDataService[S], + serviceDefinition: SecondaryDataService[S, M], inputModel: I, - ): Option[ActorRef] = serviceDefinition match { + ): Option[ActorRef[_]] = serviceDefinition match { case SecondaryDataService.ActorPriceService(_) => log.debug( s"Attempt to register for {}. This is currently not supported.", @@ -97,7 +105,7 @@ trait ServiceRegistration[ * @return */ private def registerForWeather( - actorRef: ActorRef, + actorRef: ActorRef[WeatherMessage], inputModel: I, ): Unit = { /* If we are asked to register for weather, determine the proper geo position */ @@ -113,7 +121,7 @@ trait ServiceRegistration[ s"is invalid." ) } - actorRef ! RegisterForWeatherMessage(lat, lon) + actorRef ! RegisterForWeatherMessage(self, lat, lon) } /** Register for the EV movement service @@ -125,12 +133,12 @@ trait ServiceRegistration[ * @return */ private def registerForEvData( - serviceRef: ActorRef, + serviceRef: ActorRef[EvMessage], inputModel: I, ): Unit = { inputModel match { case evcsInput: EvcsInput => - serviceRef ! RegisterForEvDataMessage(evcsInput.getUuid) + serviceRef ! RegisterForEvDataMessage(self, evcsInput.getUuid) case _ => throw new ServiceRegistrationException( s"Cannot register for EV movements information at node ${inputModel.getNode.getId} " + diff --git a/src/main/scala/edu/ie3/simona/agent/participant/data/DataService.scala b/src/main/scala/edu/ie3/simona/agent/participant/data/DataService.scala index 7d07c317a5..11b869bccc 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/data/DataService.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/data/DataService.scala @@ -6,15 +6,16 @@ package edu.ie3.simona.agent.participant.data -import org.apache.pekko.actor.ActorRef +import edu.ie3.simona.ontology.messages.services.ServiceMessage +import org.apache.pekko.actor.typed.ActorRef /** Common properties to all data sources providing data from the outside of a * SystemParticipant model but not necessarily from the outside of the * simulation (but could be). */ -trait DataService[+D <: Data] { +trait DataService[+D <: Data, M <: ServiceMessage] { /** A reference to the actor */ - val actorRef: ActorRef + val actorRef: ActorRef[M] } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/data/primary/PrimaryDataService.scala b/src/main/scala/edu/ie3/simona/agent/participant/data/primary/PrimaryDataService.scala index 92c4e510d3..3aff5c6185 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/data/primary/PrimaryDataService.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/data/primary/PrimaryDataService.scala @@ -9,11 +9,14 @@ package edu.ie3.simona.agent.participant.data.primary import edu.ie3.simona.agent.participant.data.Data.PrimaryData import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ComplexPower import edu.ie3.simona.agent.participant.data.DataService -import org.apache.pekko.actor.ActorRef +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage +import org.apache.pekko.actor.typed.ActorRef /** Enum-like trait to denote possible external data sources for systems */ -sealed trait PrimaryDataService[+D <: PrimaryData] extends DataService[D] +@deprecated +sealed trait PrimaryDataService[+D <: PrimaryData] + extends DataService[D, PrimaryDataMessage] object PrimaryDataService { @@ -22,6 +25,7 @@ object PrimaryDataService { * @param actorRef * actor reference of the actual source */ - final case class DummyPrimaryService(override val actorRef: ActorRef) - extends PrimaryDataService[ComplexPower] + final case class DummyPrimaryService( + override val actorRef: ActorRef[PrimaryDataMessage] + ) extends PrimaryDataService[ComplexPower] } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/data/secondary/SecondaryDataService.scala b/src/main/scala/edu/ie3/simona/agent/participant/data/secondary/SecondaryDataService.scala index ebac2ad136..a7489acb78 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/data/secondary/SecondaryDataService.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/data/secondary/SecondaryDataService.scala @@ -6,24 +6,38 @@ package edu.ie3.simona.agent.participant.data.secondary -import org.apache.pekko.actor.ActorRef import edu.ie3.simona.agent.participant.data.Data.SecondaryData import edu.ie3.simona.agent.participant.data.Data.SecondaryData.WholesalePrice import edu.ie3.simona.agent.participant.data.DataService import edu.ie3.simona.ontology.messages.services.EvMessage.EvData import edu.ie3.simona.ontology.messages.services.WeatherMessage.WeatherData +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + ServiceMessage, + WeatherMessage, + WholeSalePriceMessage, +} +import org.apache.pekko.actor.typed.ActorRef /** Common properties to all secondary data services */ -sealed trait SecondaryDataService[+D <: SecondaryData] extends DataService[D] +sealed trait SecondaryDataService[+D <: SecondaryData, M <: ServiceMessage] + extends DataService[D, M] object SecondaryDataService { - final case class ActorPriceService(override val actorRef: ActorRef) - extends SecondaryDataService[WholesalePrice] - final case class ActorWeatherService(override val actorRef: ActorRef) - extends SecondaryDataService[WeatherData] + type SecondaryServiceType = + SecondaryDataService[_ <: SecondaryData, _ <: ServiceMessage] + + final case class ActorPriceService( + override val actorRef: ActorRef[WholeSalePriceMessage] + ) extends SecondaryDataService[WholesalePrice, WholeSalePriceMessage] + + final case class ActorWeatherService( + override val actorRef: ActorRef[WeatherMessage] + ) extends SecondaryDataService[WeatherData, WeatherMessage] - final case class ActorExtEvDataService(override val actorRef: ActorRef) - extends SecondaryDataService[EvData] + final case class ActorExtEvDataService( + override val actorRef: ActorRef[EvMessage] + ) extends SecondaryDataService[EvData, EvMessage] } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgent.scala b/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgent.scala index 5b37ae70e3..3fcbb036d3 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgent.scala @@ -58,7 +58,7 @@ object EvcsAgent { ) ) - val neededServices: Vector[Class[_ <: SecondaryDataService[_]]] = Vector( + val neededServices: Vector[Class[_ <: SecondaryDataService[_, _]]] = Vector( classOf[ActorExtEvDataService] ) } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgentFundamentals.scala index 9cf2f747d8..d7da8047a2 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/evcs/EvcsAgentFundamentals.scala @@ -17,9 +17,7 @@ import edu.ie3.simona.agent.grid.GridAgentMessages.AssetPowerChangedMessage import edu.ie3.simona.agent.participant.ParticipantAgent.getAndCheckNodalVoltage import edu.ie3.simona.agent.participant.ParticipantAgentFundamentals import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ComplexPower -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.ActorExtEvDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.evcs.EvcsAgent.neededServices import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, @@ -35,6 +33,7 @@ import edu.ie3.simona.agent.state.AgentState.Idle import edu.ie3.simona.config.SimonaConfig.EvcsRuntimeConfig import edu.ie3.simona.event.ResultEvent.ParticipantResultEvent import edu.ie3.simona.event.notifier.NotifierConfig +import edu.ie3.simona.exceptions.ServiceException import edu.ie3.simona.exceptions.agent.{ AgentInitializationException, InconsistentStateException, @@ -51,6 +50,7 @@ import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.{ FlexRequest, FlexResponse, } +import edu.ie3.simona.ontology.messages.services.EvMessage import edu.ie3.simona.ontology.messages.services.EvMessage._ import edu.ie3.simona.util.SimonaConstants import edu.ie3.simona.util.TickUtil.RichZonedDateTime @@ -109,7 +109,7 @@ protected trait EvcsAgentFundamentals override def determineModelBaseStateData( inputModel: InputModelContainer[EvcsInput], modelConfig: EvcsRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -359,9 +359,12 @@ protected trait EvcsAgentFundamentals EvcsModel, ], ): Unit = { - val evServiceRef = getService[ActorExtEvDataService]( - modelBaseStateData.services - ) + val evServiceRef = getService[EvMessage](modelBaseStateData.services) + .getOrElse( + throw ServiceException( + s"No suitable service was provided by ParticipantModelBaseStateData." + ) + ) val lastState = getLastOrInitialStateData(modelBaseStateData, tick - 1) @@ -398,9 +401,12 @@ protected trait EvcsAgentFundamentals EvcsState, EvcsModel, ] = { - val evServiceRef = getService[ActorExtEvDataService]( - baseStateData.services - ) + val evServiceRef = getService[EvMessage](baseStateData.services) + .getOrElse( + throw ServiceException( + s"No suitable service was provided by ParticipantModelBaseStateData." + ) + ) // we don't take the state at the current tick, since // that one cannot contain the departing EVs anymore diff --git a/src/main/scala/edu/ie3/simona/agent/participant/fixedfeedin/FixedFeedInAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/fixedfeedin/FixedFeedInAgentFundamentals.scala index 2ed0495610..68ff429077 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/fixedfeedin/FixedFeedInAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/fixedfeedin/FixedFeedInAgentFundamentals.scala @@ -19,8 +19,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, ParticipantModelBaseStateData, @@ -105,7 +104,7 @@ protected trait FixedFeedInAgentFundamentals override def determineModelBaseStateData( inputModel: InputModelContainer[FixedFeedInInput], modelConfig: FixedFeedInRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgent.scala b/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgent.scala index 7861575ef5..912e21ba2a 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgent.scala @@ -36,7 +36,7 @@ object HpAgent { ) ) - val neededServices: Vector[Class[_ <: SecondaryDataService[_]]] = Vector( + val neededServices: Vector[Class[_ <: SecondaryDataService[_, _]]] = Vector( classOf[ActorWeatherService] ) } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala index 534126b986..3ad05b12db 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala @@ -14,9 +14,8 @@ import edu.ie3.datamodel.models.result.system.{ import edu.ie3.simona.agent.ValueStore import edu.ie3.simona.agent.participant.ParticipantAgent.getAndCheckNodalVoltage import edu.ie3.simona.agent.participant.ParticipantAgentFundamentals -import edu.ie3.simona.agent.participant.data.Data import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ComplexPowerAndHeat -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.hp.HpAgent.neededServices import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, @@ -323,7 +322,7 @@ trait HpAgentFundamentals override def determineModelBaseStateData( inputModel: InputModelContainer[HpInput], modelConfig: HpRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: Data.SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/load/LoadAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/load/LoadAgentFundamentals.scala index e01c463115..afa9415574 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/load/LoadAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/load/LoadAgentFundamentals.scala @@ -19,8 +19,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, ParticipantModelBaseStateData, @@ -116,7 +115,7 @@ protected trait LoadAgentFundamentals[LD <: LoadRelevantData, LM <: LoadModel[ override def determineModelBaseStateData( inputModel: InputModelContainer[LoadInput], modelConfig: LoadRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgent.scala b/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgent.scala index a46f7478a8..2378c0df34 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgent.scala @@ -37,7 +37,7 @@ object PvAgent { ) ) - val neededServices: Vector[Class[_ <: SecondaryDataService[_]]] = Vector( + val neededServices: Vector[Class[_ <: SecondaryDataService[_, _]]] = Vector( classOf[ActorWeatherService] ) } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgentFundamentals.scala index b7107d6233..49a7e35513 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/pv/PvAgentFundamentals.scala @@ -19,8 +19,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.pv.PvAgent.neededServices import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, @@ -107,7 +106,7 @@ protected trait PvAgentFundamentals override def determineModelBaseStateData( inputModel: InputModelContainer[PvInput], modelConfig: PvRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/statedata/BaseStateData.scala b/src/main/scala/edu/ie3/simona/agent/participant/statedata/BaseStateData.scala index 04650f4763..2852a59bc6 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/statedata/BaseStateData.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/statedata/BaseStateData.scala @@ -10,6 +10,7 @@ import edu.ie3.simona.agent.ValueStore import edu.ie3.simona.agent.participant.data.Data.PrimaryData.PrimaryDataWithApparentPower import edu.ie3.simona.agent.participant.data.Data.SecondaryData import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.{ CalcRelevantData, @@ -21,6 +22,7 @@ import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.{ FlexResponse, ProvideFlexOptions, } +import edu.ie3.simona.ontology.messages.services.ServiceMessage import org.apache.pekko.actor.typed.ActorRef import org.apache.pekko.actor.{ActorRef => ClassicActorRef} import squants.Dimensionless @@ -61,7 +63,7 @@ trait BaseStateData[+PD <: PrimaryDataWithApparentPower[PD]] /** A mapping from service reference to it's foreseen next availability of * data */ - val foreseenDataTicks: Map[ClassicActorRef, Option[Long]] + val foreseenDataTicks: Map[ActorRef[_ <: ServiceMessage], Option[Long]] /** A store, holding a map from tick to active / reactive power */ @@ -110,7 +112,9 @@ object BaseStateData { /** The services, the physical model depends on */ - val services: Iterable[SecondaryDataService[_ <: SecondaryData]] + val services: Iterable[ + SecondaryDataService[_ <: SecondaryData, _ <: ServiceMessage] + ] /** Stores all data that are relevant to model calculation */ @@ -162,7 +166,7 @@ object BaseStateData { override val endDate: ZonedDateTime, override val outputConfig: NotifierConfig, override val additionalActivationTicks: SortedSet[Long], - override val foreseenDataTicks: Map[ClassicActorRef, Option[Long]], + override val foreseenDataTicks: Map[ActorRef[_], Option[Long]], fillUpReactivePowerWithModelFunc: Boolean = false, requestVoltageDeviationThreshold: Double, override val voltageValueStore: ValueStore[ @@ -215,10 +219,12 @@ object BaseStateData { override val startDate: ZonedDateTime, override val endDate: ZonedDateTime, override val model: M, - override val services: Iterable[SecondaryDataService[_ <: SecondaryData]], + override val services: Iterable[SecondaryServiceType], override val outputConfig: NotifierConfig, override val additionalActivationTicks: SortedSet[Long], - override val foreseenDataTicks: Map[ClassicActorRef, Option[Long]], + override val foreseenDataTicks: Map[ActorRef[_ <: ServiceMessage], Option[ + Long + ]], requestVoltageDeviationThreshold: Double, override val voltageValueStore: ValueStore[ Dimensionless @@ -278,7 +284,7 @@ object BaseStateData { updatedRequestValueStore: ValueStore[PD], updatedVoltageValueStore: ValueStore[Dimensionless], updatedAdditionalActivationTicks: SortedSet[Long], - updatedForeseenTicks: Map[ClassicActorRef, Option[Long]], + updatedForeseenTicks: Map[ActorRef[_], Option[Long]], ): BaseStateData[PD] = { baseStateData match { case external: FromOutsideBaseStateData[_, PD] => diff --git a/src/main/scala/edu/ie3/simona/agent/participant/statedata/DataCollectionStateData.scala b/src/main/scala/edu/ie3/simona/agent/participant/statedata/DataCollectionStateData.scala index 1ce8cf9352..e238c98198 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/statedata/DataCollectionStateData.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/statedata/DataCollectionStateData.scala @@ -9,6 +9,7 @@ package edu.ie3.simona.agent.participant.statedata import org.apache.pekko.actor.ActorRef import edu.ie3.simona.agent.participant.data.Data import edu.ie3.simona.agent.participant.data.Data.PrimaryData.PrimaryDataWithApparentPower +import org.apache.pekko.actor.typed.{ActorRef => TypedActorRef} import scala.reflect.{ClassTag, classTag} @@ -31,7 +32,7 @@ final case class DataCollectionStateData[+PD <: PrimaryDataWithApparentPower[ PD ]]( baseStateData: BaseStateData[PD], - data: Map[ActorRef, Option[_ <: Data]], + data: Map[TypedActorRef[_], Option[_ <: Data]], yetTriggered: Boolean, ) extends ParticipantStateData[PD] { diff --git a/src/main/scala/edu/ie3/simona/agent/participant/statedata/ParticipantStateData.scala b/src/main/scala/edu/ie3/simona/agent/participant/statedata/ParticipantStateData.scala index 786caf63b0..979ebb48e3 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/statedata/ParticipantStateData.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/statedata/ParticipantStateData.scala @@ -8,14 +8,17 @@ package edu.ie3.simona.agent.participant.statedata import edu.ie3.datamodel.models.input.container.ThermalGrid import edu.ie3.datamodel.models.input.system.SystemParticipantInput +import edu.ie3.simona.agent.participant.data.Data.PrimaryData import edu.ie3.simona.agent.participant.data.Data.PrimaryData.PrimaryDataWithApparentPower -import edu.ie3.simona.agent.participant.data.Data.{PrimaryData, SecondaryData} -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.config.SimonaConfig import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.FlexResponse +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + ServiceMessage, +} import org.apache.pekko.actor.typed.ActorRef -import org.apache.pekko.actor.{ActorRef => ClassicActorRef} import java.time.ZonedDateTime @@ -71,7 +74,7 @@ object ParticipantStateData { ]( inputModel: InputModelContainer[I], modelConfig: C, - secondaryDataServices: Iterable[SecondaryDataService[_ <: SecondaryData]], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -115,8 +118,8 @@ object ParticipantStateData { ]( inputModel: InputModelContainer[I], modelConfig: C, - primaryServiceProxy: ClassicActorRef, - secondaryDataServices: Iterable[SecondaryDataService[_ <: SecondaryData]], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -134,10 +137,8 @@ object ParticipantStateData { ]( inputModel: I, modelConfig: C, - primaryServiceProxy: ClassicActorRef, - secondaryDataServices: Iterable[ - SecondaryDataService[_ <: SecondaryData] - ], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -163,10 +164,8 @@ object ParticipantStateData { ]( inputModel: I, modelConfig: C, - primaryServiceProxy: ClassicActorRef, - secondaryDataServices: Iterable[ - SecondaryDataService[_ <: SecondaryData] - ], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -195,10 +194,8 @@ object ParticipantStateData { inputModel: I, thermalGrid: ThermalGrid, modelConfig: C, - primaryServiceProxy: ClassicActorRef, - secondaryDataServices: Iterable[ - SecondaryDataService[_ <: SecondaryData] - ], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -226,10 +223,8 @@ object ParticipantStateData { inputModel: I, thermalGrid: ThermalGrid, modelConfig: C, - primaryServiceProxy: ClassicActorRef, - secondaryDataServices: Iterable[ - SecondaryDataService[_ <: SecondaryData] - ], + primaryServiceProxy: ActorRef[PrimaryDataMessage], + secondaryDataServices: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, @@ -268,8 +263,9 @@ object ParticipantStateData { +PD <: PrimaryDataWithApparentPower[PD] ]( baseStateData: BaseStateData[PD], - pendingResponses: Iterable[ClassicActorRef], - foreseenNextDataTicks: Map[ClassicActorRef, Long] = Map.empty, + pendingResponses: Iterable[ActorRef[_]], + foreseenNextDataTicks: Map[ActorRef[_ <: ServiceMessage], Long] = + Map.empty, ) extends ParticipantStateData[PD] sealed trait InputModelContainer[+I <: SystemParticipantInput] { diff --git a/src/main/scala/edu/ie3/simona/agent/participant/storage/StorageAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/storage/StorageAgentFundamentals.scala index bfa312e68a..27ca20b085 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/storage/StorageAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/storage/StorageAgentFundamentals.scala @@ -15,12 +15,11 @@ import edu.ie3.datamodel.models.result.system.{ import edu.ie3.simona.agent.ValueStore import edu.ie3.simona.agent.participant.ParticipantAgent.getAndCheckNodalVoltage import edu.ie3.simona.agent.participant.ParticipantAgentFundamentals -import edu.ie3.simona.agent.participant.data.Data import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.{ FlexControlledData, ParticipantModelBaseStateData, @@ -85,7 +84,7 @@ trait StorageAgentFundamentals override def determineModelBaseStateData( inputModel: ParticipantStateData.InputModelContainer[StorageInput], modelConfig: StorageRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: Data.SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgent.scala b/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgent.scala index f8858ded76..3aad97321c 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgent.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgent.scala @@ -37,7 +37,7 @@ object WecAgent { ) ) - val neededServices: Vector[Class[_ <: SecondaryDataService[_]]] = Vector( + val neededServices: Vector[Class[_ <: SecondaryDataService[_, _]]] = Vector( classOf[ActorWeatherService] ) } diff --git a/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgentFundamentals.scala index 1cbe2e7cf3..4ef5cda5cd 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/wec/WecAgentFundamentals.scala @@ -19,8 +19,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData._ import edu.ie3.simona.agent.participant.statedata.ParticipantStateData import edu.ie3.simona.agent.participant.statedata.ParticipantStateData.InputModelContainer @@ -102,7 +101,7 @@ protected trait WecAgentFundamentals override def determineModelBaseStateData( inputModel: InputModelContainer[WecInput], modelConfig: WecRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala index b71adf4a30..2432a143de 100644 --- a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala +++ b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala @@ -22,7 +22,7 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.ScheduleServiceActivation import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala index 1e8ae341a9..b779a13827 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/EvMessage.scala @@ -10,24 +10,31 @@ import edu.ie3.simona.agent.participant.data.Data.SecondaryData import edu.ie3.simona.model.participant.evcs.EvModelWrapper import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ ProvisionMessage, - ServiceRegistrationMessage, + ServiceInternal, } -import org.apache.pekko.actor.ActorRef +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.ServiceRegistrationMessage +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.util.UUID -sealed trait EvMessage +sealed trait EvMessage extends ServiceInternal object EvMessage { + private[services] trait EvInternal extends EvMessage + /** Indicate the [[edu.ie3.simona.service.ev.ExtEvDataService]] that the * requesting agent wants to receive EV movements * + * @param actorRef + * actor ref for the agent to be registered * @param evcs * the charging station */ final case class RegisterForEvDataMessage( - evcs: UUID + actorRef: ClassicRef, + evcs: UUID, ) extends EvMessage with ServiceRegistrationMessage @@ -45,7 +52,7 @@ object EvMessage { */ final case class ProvideEvDataMessage( override val tick: Long, - override val serviceRef: ActorRef, + override val serviceRef: ActorRef[EvMessage], override val data: EvData, override val nextDataTick: Option[Long], ) extends EvMessage @@ -56,7 +63,7 @@ object EvMessage { * @param tick * The latest tick that the data is requested for */ - final case class EvFreeLotsRequest(tick: Long) + final case class EvFreeLotsRequest(tick: Long) extends EvMessage /** Requests EV models of departing EVs with given UUIDs * @@ -66,6 +73,7 @@ object EvMessage { * The UUIDs of EVs that are requested */ final case class DepartingEvsRequest(tick: Long, departingEvs: Seq[UUID]) + extends EvMessage /** Holds arrivals for one charging station * diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/PrimaryDataMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/PrimaryDataMessage.scala index f78e1f5fe4..444bfdbb87 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/PrimaryDataMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/PrimaryDataMessage.scala @@ -6,14 +6,65 @@ package edu.ie3.simona.ontology.messages.services +import edu.ie3.simona.agent.participant.data.Data.PrimaryData import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ComplexPower -import edu.ie3.simona.ontology.messages.services.ServiceMessage.ProvisionMessage -import org.apache.pekko.actor.ActorRef +import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ + ProvisionMessage, + ServiceInternal, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.ServiceRegistrationMessage +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.{ActorRef => ClassicRef} + +import java.util.UUID -sealed trait PrimaryDataMessage +sealed trait PrimaryDataMessage extends ServiceInternal object PrimaryDataMessage { + private[services] trait PrimaryInternal extends PrimaryDataMessage + + /** Provide primary data to subscribes + * + * @param tick + * Current tick + * @param data + * The payload + * @param nextDataTick + * The next tick, when data is available + */ + final case class ProvidePrimaryDataMessage( + override val tick: Long, + override val serviceRef: ActorRef[PrimaryDataMessage], + override val data: PrimaryData, + override val nextDataTick: Option[Long], + ) extends ServiceMessage.ProvisionMessage[PrimaryData] + with PrimaryDataMessage + + /** Message to register with a primary data service. + * + * @param actorRef + * actor ref for the agent to be registered + * @param inputModelUuid + * Identifier of the input model + */ + final case class PrimaryServiceRegistrationMessage( + actorRef: ClassicRef, + inputModelUuid: UUID, + ) extends ServiceRegistrationMessage + with PrimaryDataMessage + + /** This message can be sent from a proxy to a subordinate worker in order to + * forward the original registration request. This message may only be used, + * if no further information are needed. + * + * @param requestingActor + * Reference to the requesting actor + */ + final case class WorkerRegistrationMessage(requestingActor: ClassicRef) + extends ServiceRegistrationMessage + with PrimaryDataMessage + /** Provides primary data in the form of [[ComplexPower]] * * @param tick @@ -26,7 +77,7 @@ object PrimaryDataMessage { @deprecated final case class ApparentPowerProvisionMessage( override val tick: Long, - override val serviceRef: ActorRef, + override val serviceRef: ActorRef[PrimaryDataMessage], override val data: ComplexPower, override val nextDataTick: Option[Long], ) extends ProvisionMessage[ComplexPower] diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala index d7444454fd..e0de69d1e9 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala @@ -6,11 +6,12 @@ package edu.ie3.simona.ontology.messages.services -import org.apache.pekko.actor.ActorRef - -import java.util.UUID import edu.ie3.simona.agent.participant.data.Data +import edu.ie3.simona.api.data.ontology.DataMessageFromExt +import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey +import edu.ie3.simona.service.ServiceStateData.InitializeServiceStateData +import org.apache.pekko.actor.typed.ActorRef /** Collections of all messages, that are send to and from the different * services @@ -19,52 +20,7 @@ sealed trait ServiceMessage object ServiceMessage { - /** Message used to register for a service - */ - trait ServiceRegistrationMessage extends ServiceMessage - - /** Message to register with a primary data service. - * - * @param inputModelUuid - * Identifier of the input model - */ - final case class PrimaryServiceRegistrationMessage(inputModelUuid: UUID) - extends ServiceRegistrationMessage - - /** This message can be sent from a proxy to a subordinate worker in order to - * forward the original registration request. This message may only be used, - * if no further information are needed. - * - * @param requestingActor - * Reference to the requesting actor - */ - final case class WorkerRegistrationMessage(requestingActor: ActorRef) - extends ServiceRegistrationMessage - - sealed trait RegistrationResponseMessage extends ServiceMessage { - val serviceRef: ActorRef - } - - object RegistrationResponseMessage { - - /** Message, that is used to confirm a successful registration - */ - final case class RegistrationSuccessfulMessage( - override val serviceRef: ActorRef, - nextDataTick: Option[Long], - ) extends RegistrationResponseMessage - - /** Message, that is used to announce a failed registration - */ - final case class RegistrationFailedMessage( - override val serviceRef: ActorRef - ) extends RegistrationResponseMessage - - final case class ScheduleServiceActivation( - tick: Long, - unlockKey: ScheduleKey, - ) - } + private[services] trait ServiceInternal extends ServiceMessage /** Actual provision of data * @@ -73,7 +29,7 @@ object ServiceMessage { */ trait ProvisionMessage[D <: Data] extends ServiceMessage { val tick: Long - val serviceRef: ActorRef + val serviceRef: ActorRef[_] val data: D /** Next tick at which data could arrive. If None, no data is expected for diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessageUniversal.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessageUniversal.scala new file mode 100644 index 0000000000..b731a5ca37 --- /dev/null +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessageUniversal.scala @@ -0,0 +1,73 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.ontology.messages.services + +import edu.ie3.simona.api.data.ontology.{ + DataMessageFromExt, + ScheduleDataServiceMessage, +} +import edu.ie3.simona.ontology.messages.Activation +import edu.ie3.simona.ontology.messages.services.EvMessage.EvInternal +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryInternal +import edu.ie3.simona.ontology.messages.services.WeatherMessage.WeatherInternal +import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey +import edu.ie3.simona.service.ServiceStateData.InitializeServiceStateData +import org.apache.pekko.actor.typed.ActorRef + +sealed trait ServiceMessageUniversal + extends PrimaryInternal + with EvInternal + with WeatherInternal + +object ServiceMessageUniversal { + + final case class WrappedActivation(activation: Activation) + extends ServiceMessageUniversal + + final case class WrappedExternalMessage( + extMsg: DataMessageFromExt + ) extends ServiceMessageUniversal + + /** Service initialization data can sometimes only be constructed once the + * service actor is created (e.g. + * [[edu.ie3.simona.service.ev.ExtEvDataService]]). Thus, we need an extra + * initialization message. + */ + final case class Create[+I <: InitializeServiceStateData]( + initializeStateData: I, + unlockKey: ScheduleKey, + ) extends ServiceMessageUniversal + + /** Message used to register for a service + */ + trait ServiceRegistrationMessage extends ServiceMessageUniversal + + sealed trait RegistrationResponseMessage extends ServiceMessageUniversal { + val serviceRef: ActorRef[_ <: ServiceMessage] + } + + object RegistrationResponseMessage { + + /** Message, that is used to confirm a successful registration + */ + final case class RegistrationSuccessfulMessage( + override val serviceRef: ActorRef[_ <: ServiceMessage], + nextDataTick: Option[Long], + ) extends RegistrationResponseMessage + + /** Message, that is used to announce a failed registration + */ + final case class RegistrationFailedMessage( + override val serviceRef: ActorRef[_ <: ServiceMessage] + ) extends RegistrationResponseMessage + + final case class ScheduleServiceActivation( + tick: Long, + unlockKey: ScheduleKey, + ) extends ServiceMessageUniversal + } +} diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/WeatherMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/WeatherMessage.scala index cb9e8349ba..57b1fb4c6f 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/WeatherMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/WeatherMessage.scala @@ -9,13 +9,15 @@ package edu.ie3.simona.ontology.messages.services import edu.ie3.simona.agent.participant.data.Data.SecondaryData import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ ProvisionMessage, - ServiceRegistrationMessage, + ServiceInternal, } +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.ServiceRegistrationMessage import edu.ie3.util.scala.quantities.Irradiance -import org.apache.pekko.actor.ActorRef +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.{ActorRef => ClassicRef} import squants.{Temperature, Velocity} -sealed trait WeatherMessage +sealed trait WeatherMessage extends ServiceInternal /** Declares all messages sent and received by the weather service and weather * data provided through these messages @@ -25,15 +27,20 @@ sealed trait WeatherMessage */ object WeatherMessage { + private[services] trait WeatherInternal extends WeatherMessage + /** Indicate the [[edu.ie3.simona.service.weather.WeatherService]] that the * requesting agent wants to receive weather for the provided coordinates * + * @param actorRef + * actor ref for the agent to be registered * @param latitude * Latitude of the requested location * @param longitude * Longitude of the requested location */ final case class RegisterForWeatherMessage( + actorRef: ClassicRef, latitude: Double, longitude: Double, ) extends WeatherMessage @@ -50,7 +57,7 @@ object WeatherMessage { */ final case class ProvideWeatherMessage( override val tick: Long, - override val serviceRef: ActorRef, + override val serviceRef: ActorRef[WeatherMessage], override val data: WeatherData, override val nextDataTick: Option[Long], ) extends WeatherMessage diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/WholeSalePriceMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/WholeSalePriceMessage.scala new file mode 100644 index 0000000000..d3d43473da --- /dev/null +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/WholeSalePriceMessage.scala @@ -0,0 +1,15 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.ontology.messages.services + +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceInternal + +sealed trait WholeSalePriceMessage extends ServiceInternal + +object WholeSalePriceMessage { + final class Dummy extends WholeSalePriceMessage +} diff --git a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala index 31800da210..77faa4bfa1 100644 --- a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala +++ b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala @@ -8,22 +8,41 @@ package edu.ie3.simona.service import edu.ie3.simona.api.data.ontology.DataMessageFromExt import edu.ie3.simona.ontology.messages.services.EvMessage.EvResponseMessage -import edu.ie3.simona.service.ServiceStateData.ServiceBaseStateData +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.WrappedExternalMessage +import edu.ie3.simona.service.ServiceStateData.{ + ServiceBaseStateData, + ServiceConstantStateData, +} +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.typed.scaladsl.{Behaviors, StashBuffer} trait ExtDataSupport[ - S <: ServiceBaseStateData + S <: ServiceBaseStateData, + T >: ServiceMessageUniversal, ] { - this: SimonaService[S] => + this: SimonaService[S, T] => - override def idleExternal(implicit stateData: S): Receive = { - case extMsg: DataMessageFromExt => + override private[service] def idleExternal(implicit + stateData: S, + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = Behaviors.receive { + case (_, WrappedExternalMessage(extMsg)) => val updatedStateData = handleDataMessage(extMsg)(stateData) - context become idle(updatedStateData) - case extResponseMsg: EvResponseMessage => + buffer.unstashAll(idleInternal(updatedStateData, constantData, buffer)) + + case (_, extResponseMsg: EvResponseMessage) => val updatedStateData = handleDataResponseMessage(extResponseMsg)(stateData) - context become idle(updatedStateData) + + buffer.unstashAll(idleInternal(updatedStateData, constantData, buffer)) + + case (ctx, unsupported) => + ctx.log.warn(s"Received unsupported message: $unsupported!") + buffer.stash(unsupported) + Behaviors.unhandled } /** Handle a message from outside the simulation diff --git a/src/main/scala/edu/ie3/simona/service/ServiceStateData.scala b/src/main/scala/edu/ie3/simona/service/ServiceStateData.scala index b8075a6e87..2ca34fbef0 100644 --- a/src/main/scala/edu/ie3/simona/service/ServiceStateData.scala +++ b/src/main/scala/edu/ie3/simona/service/ServiceStateData.scala @@ -6,7 +6,9 @@ package edu.ie3.simona.service +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq +import org.apache.pekko.actor.typed.ActorRef trait ServiceStateData @@ -18,6 +20,11 @@ object ServiceStateData { trait ServiceBaseStateData extends ServiceStateData + case class ServiceConstantStateData( + scheduler: ActorRef[SchedulerMessage], + activationAdapter: ActorRef[Activation], + ) extends ServiceStateData + /** Indicate that the service is initialized */ trait ServiceActivationBaseStateData extends ServiceBaseStateData { diff --git a/src/main/scala/edu/ie3/simona/service/SimonaService.scala b/src/main/scala/edu/ie3/simona/service/SimonaService.scala index 310c7f0b32..b4c36de856 100644 --- a/src/main/scala/edu/ie3/simona/service/SimonaService.scala +++ b/src/main/scala/edu/ie3/simona/service/SimonaService.scala @@ -6,55 +6,45 @@ package edu.ie3.simona.service -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorContext, ActorRef, Stash} -import edu.ie3.simona.logging.SimonaActorLogging import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation -import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + ServiceRegistrationMessage, + WrappedActivation, +} import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.service.ServiceStateData.{ InitializeServiceStateData, ServiceBaseStateData, + ServiceConstantStateData, } -import edu.ie3.simona.service.SimonaService.Create import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.Behavior +import org.apache.pekko.actor.typed.scaladsl.{ + ActorContext, + Behaviors, + StashBuffer, +} +import scala.language.implicitConversions import scala.util.{Failure, Success, Try} -object SimonaService { - - /** Service initialization data can sometimes only be constructed once the - * service actor is created (e.g. - * [[edu.ie3.simona.service.ev.ExtEvDataService]]). Thus, we need an extra - * initialization message. - */ - final case class Create[+I <: InitializeServiceStateData]( - initializeStateData: I, - unlockKey: ScheduleKey, - ) -} - /** Abstract description of a service agent, that is able to announce new * information to registered participants * - * @param scheduler - * actor reference of the scheduler * @tparam S * the service specific type of the [[ServiceStateData]] */ abstract class SimonaService[ - S <: ServiceBaseStateData -](protected val scheduler: ActorRef) - extends Actor - with Stash - with SimonaActorLogging { - - override def receive: Receive = uninitialized + S <: ServiceBaseStateData, + T >: ServiceMessageUniversal, +] { /** Receive method that is used before the service is initialized. Represents * the state "Uninitialized". @@ -62,43 +52,53 @@ abstract class SimonaService[ * @return * idleInternal methods for the uninitialized state */ - private def uninitialized: Receive = { - - case Create( - initializeStateData: InitializeServiceStateData, - unlockKey: ScheduleKey, + def uninitialized(implicit + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = Behaviors.receive { + case ( + _, + Create( + initializeStateData: InitializeServiceStateData, + unlockKey: ScheduleKey, + ), ) => - scheduler ! ScheduleActivation( - self.toTyped, + constantData.scheduler ! ScheduleActivation( + constantData.activationAdapter, INIT_SIM_TICK, Some(unlockKey), ) - context become initializing(initializeStateData) + initializing(initializeStateData) // not ready yet to handle registrations, stash request away - case _: ServiceRegistrationMessage => - stash() + case (_, msg: ServiceRegistrationMessage) => + buffer.stash(msg) + Behaviors.same } private def initializing( initializeStateData: InitializeServiceStateData - ): Receive = { - - case Activation(INIT_SIM_TICK) => + )(implicit + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = Behaviors.receive { + case (ctx, WrappedActivation(Activation(INIT_SIM_TICK))) => // init might take some time and could go wrong if invalid initialize service data is received // execute complete and unstash only if init is carried out successfully init( initializeStateData ) match { case Success((serviceStateData, maybeNewTick)) => - scheduler ! Completion(self.toTyped, maybeNewTick) - unstashAll() - context become idle(serviceStateData) + constantData.scheduler ! Completion( + constantData.activationAdapter, + maybeNewTick, + ) + buffer.unstashAll(idle(serviceStateData, constantData, buffer)) case Failure(exception) => // initialize service trigger with invalid data - log.error( + ctx.log.error( "Error during service initialization." + s"\nReceivedData: {}" + s"\nException: {}", @@ -109,14 +109,18 @@ abstract class SimonaService[ } // not ready yet to handle registrations, stash request away - case _: ServiceRegistrationMessage | _: Activation => - stash() + case (_, msg: ServiceRegistrationMessage) => + buffer.stash(msg) + Behaviors.same - // unhandled message - case x => - log.error(s"Received unhandled message: $x") - unhandled(x) + case (_, msg: WrappedActivation) => + buffer.stash(msg) + Behaviors.same + // unhandled message + case (ctx, x) => + ctx.log.error(s"Received unhandled message: $x") + Behaviors.unhandled } /** Default receive method when the service is initialized. Requires the @@ -127,45 +131,58 @@ abstract class SimonaService[ * @return * default idleInternal method when the service is initialized */ - final protected def idle(implicit stateData: S): Receive = - idleExternal.applyOrElse(_, idleInternal(stateData)) - - private def idleInternal(implicit stateData: S): Receive = { + final protected def idle(implicit + stateData: S, + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = idleExternal + + private[service] def idleInternal(implicit + stateData: S, + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = Behaviors.receive { // agent registration process - case registrationMsg: ServiceRegistrationMessage => + case (ctx, registrationMsg: ServiceRegistrationMessage) => /* Someone asks to register for information from the service */ - handleRegistrationRequest(registrationMsg) match { - case Success(stateData) => context become idle(stateData) + handleRegistrationRequest(registrationMsg)(stateData, ctx) match { + case Success(stateData) => idleInternal(stateData, constantData, buffer) case Failure(exception) => - log.error( + ctx.log.error( "Error during registration." + "\nMsg: {}" + "\nException: {}", registrationMsg, exception, ) - unhandled(registrationMsg) + Behaviors.unhandled } - case ScheduleServiceActivation(tick, unlockKey) => - scheduler ! ScheduleActivation( - self.toTyped, + case (_, ScheduleServiceActivation(tick, unlockKey)) => + constantData.scheduler ! ScheduleActivation( + constantData.activationAdapter, tick, Some(unlockKey), ) + buffer.unstashAll(idleInternal) + // activity start trigger for this service - case Activation(tick) => + case (ctx, WrappedActivation(Activation(tick))) => /* The scheduler sends out an activity start trigger. Announce new data to all registered recipients. */ val (updatedStateData, maybeNewTriggers) = - announceInformation(tick)(stateData, context) - scheduler ! Completion(self.toTyped, maybeNewTriggers) - context become idle(updatedStateData) + announceInformation(tick)(stateData, ctx) + constantData.scheduler ! Completion( + constantData.activationAdapter, + maybeNewTriggers, + ) + + buffer.unstashAll(idle(updatedStateData, constantData, buffer)) // unhandled message - case x => - log.error("Unhandled message received:{}", x) - unhandled(x) + case (ctx, x) => + ctx.log.error("Unhandled message received:{}", x) + Behaviors.unhandled } /** Internal api method that allows handling incoming messages from external @@ -176,8 +193,11 @@ abstract class SimonaService[ * @return * empty behavior to ensure it only is called if it is overridden */ - private[service] def idleExternal(implicit stateData: S): Receive = - Actor.emptyBehavior + private[service] def idleExternal(implicit + stateData: S, + constantData: ServiceConstantStateData, + buffer: StashBuffer[T], + ): Behavior[T] = idleInternal /** Initialize the concrete service implementation using the provided * initialization data. This method should perform all heavyweight tasks @@ -210,7 +230,8 @@ abstract class SimonaService[ protected def handleRegistrationRequest( registrationMessage: ServiceRegistrationMessage )(implicit - serviceStateData: S + serviceStateData: S, + ctx: ActorContext[T], ): Try[S] /** Send out the information to all registered recipients @@ -226,7 +247,7 @@ abstract class SimonaService[ */ protected def announceInformation(tick: Long)(implicit serviceStateData: S, - ctx: ActorContext, + ctx: ActorContext[T], ): (S, Option[Long]) } diff --git a/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala b/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala index 680c6050b1..50183ca9c1 100644 --- a/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala +++ b/src/main/scala/edu/ie3/simona/service/ev/ExtEvDataService.scala @@ -17,12 +17,19 @@ import edu.ie3.simona.exceptions.{ ServiceException, } import edu.ie3.simona.model.participant.evcs.EvModelWrapper +import edu.ie3.simona.ontology.messages.services.EvMessage import edu.ie3.simona.ontology.messages.services.EvMessage._ -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + ServiceRegistrationMessage, + WrappedActivation, + WrappedExternalMessage, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.service.ServiceStateData.{ InitializeServiceStateData, ServiceBaseStateData, + ServiceConstantStateData, } import edu.ie3.simona.service.ev.ExtEvDataService.{ ExtEvStateData, @@ -31,23 +38,22 @@ import edu.ie3.simona.service.ev.ExtEvDataService.{ import edu.ie3.simona.service.{ExtDataSupport, ServiceStateData, SimonaService} import edu.ie3.simona.util.ReceiveDataMap import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK -import org.apache.pekko.actor.{ActorContext, ActorRef, Props} +import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.slf4j.Logger import java.util.UUID +import scala.concurrent.Future import scala.jdk.CollectionConverters._ import scala.jdk.OptionConverters._ import scala.util.{Failure, Success, Try} object ExtEvDataService { - def props(scheduler: ActorRef): Props = - Props( - new ExtEvDataService(scheduler: ActorRef) - ) - final case class ExtEvStateData( extEvData: ExtEvData, - uuidToActorRef: Map[UUID, ActorRef] = Map.empty[UUID, ActorRef], + uuidToActorRef: Map[UUID, ClassicRef] = Map.empty[UUID, ClassicRef], extEvMessage: Option[EvDataMessageFromExt] = None, freeLots: ReceiveDataMap[UUID, Int] = ReceiveDataMap.empty, departingEvResponses: ReceiveDataMap[UUID, Seq[EvModelWrapper]] = @@ -58,12 +64,48 @@ object ExtEvDataService { extEvData: ExtEvData ) extends InitializeServiceStateData -} + def adapter(evService: ActorRef[EvMessage]): Behavior[DataMessageFromExt] = + Behaviors.receiveMessagePartial { extMsg => + evService ! WrappedExternalMessage(extMsg) + Behaviors.same + } -class ExtEvDataService(override val scheduler: ActorRef) - extends SimonaService[ExtEvStateData](scheduler) - with ExtDataSupport[ExtEvStateData] { + def apply( + scheduler: ActorRef[SchedulerMessage] + ): Behavior[EvMessage] = Behaviors.withStash[EvMessage](100) { buffer => + Behaviors.setup { ctx => + val activationAdapter: ActorRef[Activation] = + ctx.messageAdapter[Activation](msg => WrappedActivation(msg)) + + implicit val constantData: ServiceConstantStateData = + ServiceConstantStateData( + scheduler, + activationAdapter, + ) + + new ExtEvDataService().uninitialized(constantData, buffer) + } + } +} +private final class ExtEvDataService + extends SimonaService[ExtEvStateData, EvMessage] + with ExtDataSupport[ExtEvStateData, EvMessage] { + + /** Initialize the concrete service implementation using the provided + * initialization data. This method should perform all heavyweight tasks + * before the actor becomes ready. The return values are a) the state data of + * the initialized service and b) optional triggers that should be sent to + * the [[edu.ie3.simona.scheduler.Scheduler]] together with the completion + * message that is sent in response to the trigger that is sent to start the + * initialization process + * + * @param initServiceData + * the data that should be used for initialization + * @return + * the state data of this service and optional tick that should be included + * in the completion message + */ override def init( initServiceData: ServiceStateData.InitializeServiceStateData ): Try[ @@ -104,11 +146,12 @@ class ExtEvDataService(override val scheduler: ActorRef) override def handleRegistrationRequest( registrationMessage: ServiceRegistrationMessage )(implicit - serviceStateData: ExtEvStateData + serviceStateData: ExtEvStateData, + ctx: ActorContext[EvMessage], ): Try[ExtEvStateData] = registrationMessage match { - case RegisterForEvDataMessage(evcs) => - Success(handleRegistrationRequest(sender(), evcs)) + case RegisterForEvDataMessage(actorRef, evcs) => + Success(handleRegistrationRequest(actorRef, evcs)) case invalidMessage => Failure( InvalidRegistrationRequestException( @@ -132,12 +175,13 @@ class ExtEvDataService(override val scheduler: ActorRef) * information if the registration has been carried out successfully */ private def handleRegistrationRequest( - agentToBeRegistered: ActorRef, + agentToBeRegistered: ClassicRef, evcs: UUID, )(implicit - serviceStateData: ExtEvStateData + serviceStateData: ExtEvStateData, + ctx: ActorContext[EvMessage], ): ExtEvStateData = { - log.debug( + ctx.log.debug( "Received ev movement service registration from {} for [Evcs:{}]", agentToBeRegistered.path.name, evcs, @@ -154,7 +198,7 @@ class ExtEvDataService(override val scheduler: ActorRef) ) case Some(_) => // actor is already registered, do nothing - log.warning( + ctx.log.warn( "Sending actor {} is already registered", agentToBeRegistered, ) @@ -170,12 +214,15 @@ class ExtEvDataService(override val scheduler: ActorRef) * the current state data of this service * @return * the service stata data that should be used in the next state (normally - * with updated values) together with the completion message that is sent + * with updated values) together with the message that is sent * in response to the trigger that was sent to start this announcement */ override protected def announceInformation( tick: Long - )(implicit serviceStateData: ExtEvStateData, ctx: ActorContext): ( + )(implicit + serviceStateData: ExtEvStateData, + ctx: ActorContext[EvMessage], + ): ( ExtEvStateData, Option[Long], ) = { @@ -183,6 +230,8 @@ class ExtEvDataService(override val scheduler: ActorRef) : java.util.Map[UUID, java.util.List[E]] => Map[UUID, Seq[E]] = map => map.asScala.view.mapValues(_.asScala.toSeq).toMap + implicit val log: Logger = ctx.log + serviceStateData.extEvMessage.getOrElse( throw ServiceException( "ExtEvDataService was triggered without ExtEvMessage available" @@ -200,7 +249,8 @@ class ExtEvDataService(override val scheduler: ActorRef) asScala(arrivingEvsProvision.arrivals), arrivingEvsProvision.maybeNextTick.toScala.map(Long2long), )( - serviceStateData + serviceStateData, + ctx, ) } } @@ -254,7 +304,8 @@ class ExtEvDataService(override val scheduler: ActorRef) tick: Long, requestedDepartingEvs: Map[UUID, Seq[UUID]], )(implicit - serviceStateData: ExtEvStateData + serviceStateData: ExtEvStateData, + log: Logger, ): (ExtEvStateData, Option[Long]) = { val departingEvResponses = @@ -266,7 +317,7 @@ class ExtEvDataService(override val scheduler: ActorRef) Some(evcs) case None => - log.warning( + log.warn( "A corresponding actor ref for UUID {} could not be found", evcs, ) @@ -294,7 +345,8 @@ class ExtEvDataService(override val scheduler: ActorRef) allArrivingEvs: Map[UUID, Seq[EvModel]], maybeNextTick: Option[Long], )(implicit - serviceStateData: ExtEvStateData + serviceStateData: ExtEvStateData, + ctx: ActorContext[EvMessage], ): (ExtEvStateData, Option[Long]) = { if (tick == INIT_SIM_TICK) { @@ -307,7 +359,7 @@ class ExtEvDataService(override val scheduler: ActorRef) serviceStateData.uuidToActorRef.foreach { case (_, actor) => actor ! RegistrationSuccessfulMessage( - self, + ctx.self, maybeNextTick, ) } @@ -319,7 +371,7 @@ class ExtEvDataService(override val scheduler: ActorRef) actor ! ProvideEvDataMessage( tick, - self, + ctx.self, ArrivingEvs(evs.map(EvModelWrapper.apply)), maybeNextTick, ) diff --git a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala index 45de3bae63..8a1d46be09 100644 --- a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala +++ b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala @@ -6,8 +6,6 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import edu.ie3.datamodel.io.connectors.SqlConnector import edu.ie3.datamodel.io.csv.CsvIndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation @@ -38,21 +36,26 @@ import edu.ie3.simona.exceptions.{ InitializationException, InvalidConfigParameterException, } -import edu.ie3.simona.logging.SimonaActorLogging -import edu.ie3.simona.ontology.messages.Activation -import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ +import edu.ie3.simona.ontology.messages.SchedulerMessage.{ + Completion, + ScheduleActivation, +} +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ PrimaryServiceRegistrationMessage, WorkerRegistrationMessage, } +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock -import edu.ie3.simona.service.{ServiceStateData, SimonaService} -import edu.ie3.simona.service.ServiceStateData.InitializeServiceStateData -import edu.ie3.simona.service.primary.PrimaryServiceProxy.{ - InitPrimaryServiceProxyStateData, - PrimaryServiceStateData, - SourceRef, +import edu.ie3.simona.service.ServiceStateData +import edu.ie3.simona.service.ServiceStateData.{ + InitializeServiceStateData, + ServiceConstantStateData, } import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ CsvInitPrimaryServiceStateData, @@ -60,6 +63,10 @@ import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ SqlInitPrimaryServiceStateData, } import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.slf4j.Logger import java.nio.file.Paths import java.text.SimpleDateFormat @@ -68,6 +75,7 @@ import java.util.UUID import scala.Option.when import scala.jdk.CollectionConverters._ import scala.jdk.OptionConverters.RichOptional +import scala.language.implicitConversions import scala.util.{Failure, Success, Try} /** This actor has information on which models can be replaced by precalculated @@ -75,54 +83,174 @@ import scala.util.{Failure, Success, Try} * register for a certain model. If data is available, a child actor is spun * of, that will do the actual provision and the requesting agent is informed * accordingly. - * - * @param scheduler - * Reference to the scheduler of the simulation - * @param startDateTime - * Simulation time of the first instant in simulation */ -case class PrimaryServiceProxy( - scheduler: ActorRef, - initStateData: InitPrimaryServiceProxyStateData, - private implicit val startDateTime: ZonedDateTime, -) extends Actor - with SimonaActorLogging { - - /** Start receiving without knowing specifics about myself +object PrimaryServiceProxy { + + /** State data with needed information to initialize this primary service + * provider proxy * - * @return - * How receiving should be handled + * @param primaryConfig + * Configuration for the primary source + * @param simulationStart + * Simulation time of the first instant in simulation + */ + final case class InitPrimaryServiceProxyStateData( + primaryConfig: PrimaryConfig, + simulationStart: ZonedDateTime, + private[primary] val timeSeriesToSourceRef: Map[UUID, SourceRef] = + Map.empty, + ) extends InitializeServiceStateData + + /** Holding the state of an initialized proxy. + * + * @param modelToTimeSeries + * Mapping from models' to time series unique identifiers + * @param timeSeriesToSourceRef + * Mapping from time series identifier to [[SourceRef]] + * @param simulationStart + * Simulation time of the first instant in simulation + * @param primaryConfig + * The configuration for the sources + * @param mappingSource + * The mapping source + */ + final case class PrimaryServiceStateData( + modelToTimeSeries: Map[UUID, UUID], + timeSeriesToSourceRef: Map[UUID, SourceRef], + simulationStart: ZonedDateTime, + primaryConfig: PrimaryConfig, + mappingSource: TimeSeriesMappingSource, + ) extends ServiceStateData + + /** Giving reference to the target time series and source worker. + * + * @param metaInformation + * Meta information (including column scheme) of the time series + * @param worker + * Optional reference to an already existing worker providing information + * on that time series */ - override def receive: Receive = uninitialized + final case class SourceRef( + metaInformation: IndividualTimeSeriesMetaInformation, + worker: Option[ActorRef[PrimaryDataMessage]], + ) + + /** Check if the config holds correct information to instantiate a mapping + * source + * + * @param primaryConfig + * Config entries for primary source + */ + def checkConfig(primaryConfig: PrimaryConfig): Unit = { + + def checkTimePattern(dtfPattern: String): Unit = + Try { + new SimpleDateFormat(dtfPattern) + } match { + case Failure(exception) => + throw new InvalidConfigParameterException( + s"Invalid timePattern '$dtfPattern' for a time series source. Please provide a valid pattern!" + + s"\nException: $exception" + ) + case Success(_) => + // this is fine + } + + val supportedSources = + Set("csv", "sql") + + val sourceConfigs = Seq( + primaryConfig.couchbaseParams, + primaryConfig.csvParams, + primaryConfig.influxDb1xParams, + primaryConfig.sqlParams, + ).filter(_.isDefined).flatten + if (sourceConfigs.size > 1) + throw new InvalidConfigParameterException( + s"${sourceConfigs.size} time series source types defined. " + + s"Please define only one type!\nAvailable types:\n\t${supportedSources.mkString("\n\t")}" + ) + else if (sourceConfigs.isEmpty) + throw new InvalidConfigParameterException( + s"No time series source type defined. Please define exactly one type!" + + s"\nAvailable types:\n\t${supportedSources.mkString("\n\t")}" + ) + else { + sourceConfigs.headOption match { + case Some(csvParams: PrimaryDataCsvParams) => + // note: if inheritance is supported by tscfg, + // the following method should be called for all different supported sources! + checkTimePattern(csvParams.timePattern) + case Some(sqlParams: SqlParams) => + checkTimePattern(sqlParams.timePattern) + case Some(x) => + throw new InvalidConfigParameterException( + s"Invalid configuration '$x' for a time series source.\nAvailable types:\n\t${supportedSources + .mkString("\n\t")}" + ) + case None => + throw new InvalidConfigParameterException( + s"No configuration for a time series mapping source provided.\nPlease provide one of the available sources:\n\t${supportedSources + .mkString("\n\t")}" + ) + } + } + } + + def apply( + scheduler: ActorRef[SchedulerMessage], + initStateData: InitPrimaryServiceProxyStateData, + ): Behavior[PrimaryDataMessage] = Behaviors.setup { ctx => + val activationAdapter: ActorRef[Activation] = + ctx.messageAdapter[Activation](msg => WrappedActivation(msg)) + + implicit val constantData: ServiceConstantStateData = + ServiceConstantStateData( + scheduler, + activationAdapter, + ) + + scheduler ! ScheduleActivation( + activationAdapter, + INIT_SIM_TICK, + ) + + uninitialized(initStateData) + } /** Handle all messages, when the actor isn't initialized, yet. * * @return * How receiving should be handled with gained insight of myself */ - private def uninitialized: Receive = { - case Activation(INIT_SIM_TICK) => + private def uninitialized( + initStateData: InitPrimaryServiceProxyStateData + )(implicit + constantData: ServiceConstantStateData + ): Behavior[PrimaryDataMessage] = Behaviors.receive { + case (ctx, WrappedActivation(Activation(INIT_SIM_TICK))) => /* The proxy is asked to initialize itself. If that happened successfully, change the logic of receiving * messages */ prepareStateData( initStateData.primaryConfig, initStateData.simulationStart, - ) match { + )(ctx.log) match { case Success(stateData) => - scheduler ! Completion(self.toTyped) - context become onMessage(stateData) + constantData.scheduler ! Completion(constantData.activationAdapter) + onMessage(stateData) case Failure(exception) => - log.error( + ctx.log.error( + s"Unable to initialize the ${ctx.self.path}. Shut it down.", exception, - s"Unable to initialize the $actorName. Shut it down.", ) - self ! PoisonPill + + Behaviors.stopped } - case x => + case (ctx, x) => /* Unhandled message */ - log.error("Received unhandled message: {}", x) - unhandled(x) + ctx.log.error("Received unhandled message: {}", x) + Behaviors.same } /** Prepare the needed state data by building a @@ -136,10 +264,10 @@ case class PrimaryServiceProxy( * @return * State data, containing the known model and time series identifiers */ - private def prepareStateData( + private[service] def prepareStateData( primaryConfig: PrimaryConfig, simulationStart: ZonedDateTime, - ): Try[PrimaryServiceStateData] = { + )(implicit log: Logger): Try[PrimaryServiceStateData] = { createSources(primaryConfig).map { case (mappingSource, metaInformationSource) => val modelToTimeSeries = mappingSource.getMapping.asScala.toMap @@ -159,7 +287,7 @@ case class PrimaryServiceProxy( timeSeriesUuid -> SourceRef(metaInformation, None) } case None => - log.warning( + log.warn( "Unable to acquire meta information for time series '{}'. Leave that out.", timeSeriesUuid, ) @@ -243,8 +371,10 @@ case class PrimaryServiceProxy( * @return * Message handling routine */ - private def onMessage(stateData: PrimaryServiceStateData): Receive = { - case PrimaryServiceRegistrationMessage(modelUuid) => + private def onMessage(stateData: PrimaryServiceStateData)(implicit + constantData: ServiceConstantStateData + ): Behavior[PrimaryDataMessage] = Behaviors.receive { + case (ctx, PrimaryServiceRegistrationMessage(actorRef, modelUuid)) => /* Try to register for this model */ stateData.modelToTimeSeries.get(modelUuid) match { case Some(timeSeriesUuid) => @@ -253,20 +383,22 @@ case class PrimaryServiceProxy( modelUuid, timeSeriesUuid, stateData, - sender(), - ) + actorRef, + )(constantData, ctx) case None => - log.debug( + ctx.log.debug( s"There is no time series apparent for the model with uuid '{}'.", modelUuid, ) - sender() ! RegistrationFailedMessage(self) + actorRef ! RegistrationFailedMessage(ctx.self) } - case x => - log.error( + + Behaviors.same + case (ctx, x) => + ctx.log.error( s"Received message '$x', but I'm only able to handle registration requests." ) - unhandled(x) + Behaviors.same } /** Handle the registration request for a covered model. First, try to get an @@ -280,11 +412,14 @@ case class PrimaryServiceProxy( * @param stateData * Current state data of the actor */ - protected def handleCoveredModel( + protected[service] def handleCoveredModel( modelUuid: UUID, timeSeriesUuid: UUID, stateData: PrimaryServiceStateData, - requestingActor: ActorRef, + requestingActor: ClassicRef, + )(implicit + constantData: ServiceConstantStateData, + ctx: ActorContext[_], ): Unit = { val timeSeriesToSourceRef = stateData.timeSeriesToSourceRef timeSeriesToSourceRef.get(timeSeriesUuid) match { @@ -304,24 +439,24 @@ case class PrimaryServiceProxy( workerRef ! WorkerRegistrationMessage(requestingActor) /* Register the new worker within the state data and change the context */ - context become onMessage( + onMessage( updateStateData(stateData, timeSeriesUuid, workerRef) ) case Failure(exception) => - log.warning( + ctx.log.warn( s"A failure occurred during spin-off of a primary source for time series '$timeSeriesUuid'. " + s"Will inform the requesting actor, that registration is not possible.", exception, ) - requestingActor ! RegistrationFailedMessage(self) + requestingActor ! RegistrationFailedMessage(ctx.self) } case None => - log.warning( + ctx.log.warn( s"There is no source information for time series '$timeSeriesUuid' (requested for model " + s"'$modelUuid'), although the mapping contains information about it." ) - requestingActor ! RegistrationFailedMessage(self) + requestingActor ! RegistrationFailedMessage(ctx.self) } } @@ -337,28 +472,31 @@ case class PrimaryServiceProxy( * @return * The [[ActorRef]] to the worker */ - protected def initializeWorker( + protected[service] def initializeWorker( metaInformation: IndividualTimeSeriesMetaInformation, simulationStart: ZonedDateTime, primaryConfig: PrimaryConfig, - ): Try[ActorRef] = { - val workerRef = classToWorkerRef( - metaInformation.getColumnScheme.getValueClass, - metaInformation.getUuid.toString, - ) + )(implicit + constantData: ServiceConstantStateData, + ctx: ActorContext[_], + ): Try[ActorRef[PrimaryDataMessage]] = { + val valueClass = metaInformation.getColumnScheme.getValueClass + + val workerRef = classToWorkerRef(metaInformation.getUuid.toString) toInitData( metaInformation, simulationStart, primaryConfig, + valueClass, ) match { case Success(initData) => - workerRef ! SimonaService.Create( + workerRef ! Create( initData, - ScheduleLock.singleKey(context, scheduler.toTyped, INIT_SIM_TICK), + ScheduleLock.singleKey(ctx, constantData.scheduler, INIT_SIM_TICK), ) Success(workerRef) case Failure(cause) => - workerRef ! PoisonPill + ctx.stop(workerRef) Failure( new InitializationException( "Unable to build init data for worker. Kill the uninitialized worker. Goodbye my friend!", @@ -371,25 +509,21 @@ case class PrimaryServiceProxy( /** Build a primary source worker and type it to the foreseen value class to * come * - * @param valueClass - * Class of the values to provide later on * @param timeSeriesUuid * uuid of the time series the actor processes - * @tparam V - * Type of the class to provide * @return * The [[ActorRef]] to the spun off actor */ - protected def classToWorkerRef[V <: Value]( - valueClass: Class[V], - timeSeriesUuid: String, - ): ActorRef = { - import edu.ie3.simona.actor.SimonaActorNaming._ - context.simonaActorOf( - PrimaryServiceWorker.props(scheduler, valueClass), + protected[service] def classToWorkerRef( + timeSeriesUuid: String + )(implicit + constantData: ServiceConstantStateData, + ctx: ActorContext[_], + ): ActorRef[PrimaryDataMessage] = + ctx.spawn( + PrimaryServiceWorker(constantData.scheduler), timeSeriesUuid, ) - } /** Building proper init data for the worker * @@ -401,11 +535,12 @@ case class PrimaryServiceProxy( * Configuration for the primary config * @return */ - private def toInitData( + private[service] def toInitData[V <: Value]( metaInformation: IndividualTimeSeriesMetaInformation, simulationStart: ZonedDateTime, primaryConfig: PrimaryConfig, - ): Try[InitPrimaryServiceStateData] = + valueClass: Class[V], + ): Try[InitPrimaryServiceStateData[V]] = primaryConfig match { case PrimaryConfig( None, @@ -420,6 +555,7 @@ case class PrimaryServiceProxy( CsvInitPrimaryServiceStateData( csvMetaData.getUuid, simulationStart, + valueClass, csvSep, Paths.get(directoryPath), csvMetaData.getFullFilePath, @@ -445,6 +581,7 @@ case class PrimaryServiceProxy( SqlInitPrimaryServiceStateData( metaInformation.getUuid, simulationStart, + valueClass, sqlParams, new DatabaseNamingStrategy(), ) @@ -472,7 +609,7 @@ case class PrimaryServiceProxy( private def updateStateData( stateData: PrimaryServiceStateData, timeSeriesUuid: UUID, - workerRef: ActorRef, + workerRef: ActorRef[PrimaryDataMessage], ): PrimaryServiceStateData = { val timeSeriesToSourceRef = stateData.timeSeriesToSourceRef val sourceRef = timeSeriesToSourceRef.getOrElse( @@ -487,124 +624,5 @@ case class PrimaryServiceProxy( ) stateData.copy(timeSeriesToSourceRef = updatedTimeSeriesToSourceRef) } -} - -object PrimaryServiceProxy { - - def props( - scheduler: ActorRef, - initStateData: InitPrimaryServiceProxyStateData, - startDateTime: ZonedDateTime, - ): Props = Props( - new PrimaryServiceProxy(scheduler, initStateData, startDateTime) - ) - - /** State data with needed information to initialize this primary service - * provider proxy - * - * @param primaryConfig - * Configuration for the primary source - * @param simulationStart - * Simulation time of the first instant in simulation - */ - final case class InitPrimaryServiceProxyStateData( - primaryConfig: PrimaryConfig, - simulationStart: ZonedDateTime, - ) extends InitializeServiceStateData - - /** Holding the state of an initialized proxy. - * - * @param modelToTimeSeries - * Mapping from models' to time series unique identifiers - * @param timeSeriesToSourceRef - * Mapping from time series identifier to [[SourceRef]] - * @param simulationStart - * Simulation time of the first instant in simulation - * @param primaryConfig - * The configuration for the sources - * @param mappingSource - * The mapping source - */ - final case class PrimaryServiceStateData( - modelToTimeSeries: Map[UUID, UUID], - timeSeriesToSourceRef: Map[UUID, SourceRef], - simulationStart: ZonedDateTime, - primaryConfig: PrimaryConfig, - mappingSource: TimeSeriesMappingSource, - ) extends ServiceStateData - /** Giving reference to the target time series and source worker. - * - * @param metaInformation - * Meta information (including column scheme) of the time series - * @param worker - * Optional reference to an already existing worker providing information - * on that time series - */ - final case class SourceRef( - metaInformation: IndividualTimeSeriesMetaInformation, - worker: Option[ActorRef], - ) - - /** Check if the config holds correct information to instantiate a mapping - * source - * - * @param primaryConfig - * Config entries for primary source - */ - def checkConfig(primaryConfig: PrimaryConfig): Unit = { - - def checkTimePattern(dtfPattern: String): Unit = - Try { - new SimpleDateFormat(dtfPattern) - } match { - case Failure(exception) => - throw new InvalidConfigParameterException( - s"Invalid timePattern '$dtfPattern' for a time series source. Please provide a valid pattern!" + - s"\nException: $exception" - ) - case Success(_) => - // this is fine - } - - val supportedSources = - Set("csv", "sql") - - val sourceConfigs = Seq( - primaryConfig.couchbaseParams, - primaryConfig.csvParams, - primaryConfig.influxDb1xParams, - primaryConfig.sqlParams, - ).filter(_.isDefined).flatten - if (sourceConfigs.size > 1) - throw new InvalidConfigParameterException( - s"${sourceConfigs.size} time series source types defined. " + - s"Please define only one type!\nAvailable types:\n\t${supportedSources.mkString("\n\t")}" - ) - else if (sourceConfigs.isEmpty) - throw new InvalidConfigParameterException( - s"No time series source type defined. Please define exactly one type!" + - s"\nAvailable types:\n\t${supportedSources.mkString("\n\t")}" - ) - else { - sourceConfigs.headOption match { - case Some(csvParams: PrimaryDataCsvParams) => - // note: if inheritance is supported by tscfg, - // the following method should be called for all different supported sources! - checkTimePattern(csvParams.timePattern) - case Some(sqlParams: SqlParams) => - checkTimePattern(sqlParams.timePattern) - case Some(x) => - throw new InvalidConfigParameterException( - s"Invalid configuration '$x' for a time series source.\nAvailable types:\n\t${supportedSources - .mkString("\n\t")}" - ) - case None => - throw new InvalidConfigParameterException( - s"No configuration for a time series mapping source provided.\nPlease provide one of the available sources:\n\t${supportedSources - .mkString("\n\t")}" - ) - } - } - } } 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 f61974392d..277b7ebb90 100644 --- a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala +++ b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceWorker.scala @@ -6,7 +6,6 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.{ActorContext, ActorRef, Props} import edu.ie3.datamodel.io.connectors.SqlConnector import edu.ie3.datamodel.io.factory.timeseries.TimeBasedSimpleValueFactory import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme @@ -21,19 +20,30 @@ 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.ontology.messages.services.PrimaryDataMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ + ProvidePrimaryDataMessage, + WorkerRegistrationMessage, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + ServiceRegistrationMessage, + WrappedActivation, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.service.ServiceStateData.{ InitializeServiceStateData, ServiceActivationBaseStateData, + ServiceConstantStateData, } -import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ - PrimaryServiceInitializedStateData, - ProvidePrimaryDataMessage, -} -import edu.ie3.simona.service.{ServiceStateData, SimonaService} +import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.service.primary.PrimaryServiceWorker.PrimaryServiceInitializedStateData import edu.ie3.simona.util.TickUtil.{RichZonedDateTime, TickLong} import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq +import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.{ActorRef => ClassicRef} +import org.slf4j.Logger import java.nio.file.Path import java.time.ZonedDateTime @@ -43,10 +53,129 @@ import scala.jdk.CollectionConverters._ import scala.jdk.OptionConverters.RichOptional import scala.util.{Failure, Success, Try} -final case class PrimaryServiceWorker[V <: Value]( - override protected val scheduler: ActorRef, - valueClass: Class[V], -) extends SimonaService[PrimaryServiceInitializedStateData[V]](scheduler) { +object PrimaryServiceWorker { + + /** List of supported column schemes aka. column schemes, that belong to + * primary data + */ + val supportedColumnSchemes: Vector[ColumnScheme] = Vector( + ColumnScheme.ACTIVE_POWER, + ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND, + ColumnScheme.APPARENT_POWER, + ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, + ) + + /** Abstract class pattern for specific [[InitializeServiceStateData]]. + * Different implementations are needed, because the [[PrimaryServiceProxy]] + * already has detailed information about different source types, that can be + * handed over instead of being acquired once again. + */ + abstract class InitPrimaryServiceStateData[V <: Value] + extends InitializeServiceStateData { + val timeSeriesUuid: UUID + val simulationStart: ZonedDateTime + val valueClass: Class[V] + } + + /** Specific implementation of [[InitPrimaryServiceStateData]], if the source + * to use utilizes csv files. + * + * @param timeSeriesUuid + * Unique identifier of the time series to read + * @param simulationStart + * Simulation time of the beginning of simulation time + * @param csvSep + * Column separation character of the csv files + * @param directoryPath + * Base directory path, where all input information are given + * @param filePath + * Path of the file to read with respect to the given folder path (Without + * ending!) + * @param fileNamingStrategy + * [[FileNamingStrategy]], the input files follow + * @param timePattern + * the time format pattern of the time series + */ + final case class CsvInitPrimaryServiceStateData[V <: Value]( + override val timeSeriesUuid: UUID, + override val simulationStart: ZonedDateTime, + override val valueClass: Class[V], + csvSep: String, + directoryPath: Path, + filePath: Path, + fileNamingStrategy: FileNamingStrategy, + timePattern: String, + ) extends InitPrimaryServiceStateData[V] + + /** Specific implementation of [[InitPrimaryServiceStateData]], if the source + * to use utilizes an SQL database. + * + * @param timeSeriesUuid + * Unique identifier of the time series to read + * @param simulationStart + * Simulation time of the beginning of simulation time + * @param sqlParams + * Parameters regarding SQL connection and table selection + * @param databaseNamingStrategy + * Strategy of naming database entities, such as tables + */ + final case class SqlInitPrimaryServiceStateData[V <: Value]( + override val timeSeriesUuid: UUID, + override val simulationStart: ZonedDateTime, + override val valueClass: Class[V], + sqlParams: SqlParams, + databaseNamingStrategy: DatabaseNamingStrategy, + ) extends InitPrimaryServiceStateData[V] + + /** Class carrying the state of a fully initialized [[PrimaryServiceWorker]] + * + * @param maybeNextActivationTick + * the next tick, when this actor is triggered by scheduler + * @param activationTicks + * Linked collection of ticks, in which data is available + * @param startDateTime + * Simulation time of the first instant in simulation + * @param source + * Implementation of [[TimeSeriesSource]] to use for actual acquisition of + * data + * @param subscribers + * Collection of interested actors + * @tparam V + * Type of value to get from source + */ + final case class PrimaryServiceInitializedStateData[V <: Value]( + override val maybeNextActivationTick: Option[Long], + override val activationTicks: SortedDistinctSeq[Long] = + SortedDistinctSeq.empty, + startDateTime: ZonedDateTime, + source: TimeSeriesSource[V], + subscribers: Vector[ClassicRef] = Vector.empty[ClassicRef], + ) extends ServiceActivationBaseStateData + + def apply( + scheduler: ActorRef[SchedulerMessage] + ): Behavior[PrimaryDataMessage] = + Behaviors.withStash(100) { buffer => + Behaviors.setup { ctx => + val activationAdapter: ActorRef[Activation] = + ctx.messageAdapter[Activation](msg => WrappedActivation(msg)) + + implicit val constantData: ServiceConstantStateData = + ServiceConstantStateData( + scheduler, + activationAdapter, + ) + + new PrimaryServiceWorker().uninitialized(constantData, buffer) + } + } + +} + +private final class PrimaryServiceWorker + extends SimonaService[PrimaryServiceInitializedStateData[ + _ <: Value + ], PrimaryDataMessage] { /** Initialize the actor with the given information. Try to figure out the * initialized state data and the next activation ticks, that will then be @@ -59,17 +188,13 @@ final case class PrimaryServiceWorker[V <: Value]( * included in the completion message */ override def init( - initServiceData: ServiceStateData.InitializeServiceStateData - ): Try[ - ( - PrimaryServiceInitializedStateData[V], - Option[Long], - ) - ] = { + initServiceData: InitializeServiceStateData + ): Try[(PrimaryServiceInitializedStateData[_ <: Value], Option[Long])] = { (initServiceData match { case PrimaryServiceWorker.CsvInitPrimaryServiceStateData( timeSeriesUuid, simulationStart, + valueClass, csvSep, directoryPath, filePath, @@ -97,6 +222,7 @@ final case class PrimaryServiceWorker[V <: Value]( case PrimaryServiceWorker.SqlInitPrimaryServiceStateData( timeSeriesUuid: UUID, simulationStart: ZonedDateTime, + valueClass, sqlParams: SqlParams, namingStrategy: DatabaseNamingStrategy, ) => @@ -147,7 +273,7 @@ final case class PrimaryServiceWorker[V <: Value]( (maybeNextTick, furtherActivationTicks) match { case (Some(tick), furtherActivationTicks) if tick == 0L => /* Set up the state data and determine the next activation tick. */ - val initializedStateData = + val initializedStateData: PrimaryServiceInitializedStateData[Value] = PrimaryServiceInitializedStateData( maybeNextTick, furtherActivationTicks, @@ -176,35 +302,27 @@ final case class PrimaryServiceWorker[V <: Value]( } } - /** Handle a request to register for information from this service - * - * @param registrationMessage - * registration message to handle - * @param serviceStateData - * current state data of the actor - * @return - * the service stata data that should be used in the next state (normally - * with updated values) - */ override protected def handleRegistrationRequest( - registrationMessage: ServiceMessage.ServiceRegistrationMessage + registrationMessage: ServiceRegistrationMessage )(implicit - serviceStateData: PrimaryServiceInitializedStateData[V] - ): Try[PrimaryServiceInitializedStateData[V]] = registrationMessage match { - case ServiceMessage.WorkerRegistrationMessage(requestingActor) => - requestingActor ! RegistrationSuccessfulMessage( - self, - serviceStateData.maybeNextActivationTick, - ) - val subscribers = serviceStateData.subscribers :+ requestingActor - Success(serviceStateData.copy(subscribers = subscribers)) - case unsupported => - Failure( - InvalidRegistrationRequestException( - s"A primary service provider is not able to handle registration request '$unsupported'." + serviceStateData: PrimaryServiceInitializedStateData[_ <: Value], + ctx: ActorContext[PrimaryDataMessage], + ): Try[PrimaryServiceInitializedStateData[_ <: Value]] = + registrationMessage match { + case WorkerRegistrationMessage(requestingActor) => + requestingActor ! RegistrationSuccessfulMessage( + ctx.self, + serviceStateData.maybeNextActivationTick, ) - ) - } + val subscribers = serviceStateData.subscribers :+ requestingActor + Success(serviceStateData.copy(subscribers = subscribers)) + case unsupported => + Failure( + InvalidRegistrationRequestException( + s"A primary service provider is not able to handle registration request '$unsupported'." + ) + ) + } /** Send out the information to all registered recipients * @@ -221,20 +339,23 @@ final case class PrimaryServiceWorker[V <: Value]( override protected def announceInformation( tick: Long )(implicit - serviceBaseStateData: PrimaryServiceInitializedStateData[V], - ctx: ActorContext, + serviceBaseStateData: PrimaryServiceInitializedStateData[_ <: Value], + ctx: ActorContext[PrimaryDataMessage], ): ( - PrimaryServiceInitializedStateData[V], + PrimaryServiceInitializedStateData[_ <: Value], Option[Long], ) = { /* Get the information to distribute */ val simulationTime = tick.toDateTime(serviceBaseStateData.startDateTime) serviceBaseStateData.source.getValue(simulationTime).toScala match { case Some(value) => - processDataAndAnnounce(tick, value, serviceBaseStateData) + processDataAndAnnounce(tick, value, serviceBaseStateData)( + ctx.self, + ctx.log, + ) case None => /* There is no data available in the source. */ - log.warning( + ctx.log.warn( s"I expected to get data for tick '{}' ({}), but data is not available", tick, simulationTime, @@ -253,9 +374,9 @@ final case class PrimaryServiceWorker[V <: Value]( * messages */ private def updateStateDataAndBuildTriggerMessages( - baseStateData: PrimaryServiceInitializedStateData[V] + baseStateData: PrimaryServiceInitializedStateData[_ <: Value] ): ( - PrimaryServiceInitializedStateData[V], + PrimaryServiceInitializedStateData[_ <: Value], Option[Long], ) = { val (maybeNextActivationTick, remainderActivationTicks) = @@ -281,19 +402,22 @@ final case class PrimaryServiceWorker[V <: Value]( * updated state data as well as an optional sequence of triggers to be * sent to scheduler */ - private def processDataAndAnnounce( + private[service] def processDataAndAnnounce( tick: Long, - value: V, - serviceBaseStateData: PrimaryServiceInitializedStateData[V], + value: Value, + serviceBaseStateData: PrimaryServiceInitializedStateData[_ <: Value], + )(implicit + self: ActorRef[PrimaryDataMessage], + log: Logger, ): ( - PrimaryServiceInitializedStateData[V], + PrimaryServiceInitializedStateData[_ <: Value], Option[Long], ) = value.toPrimaryData match { case Success(primaryData) => announcePrimaryData(tick, primaryData, serviceBaseStateData) case Failure(exception) => /* Processing of data failed */ - log.warning( + log.warn( "Unable to convert received value to primary data. Skipped that data." + "\nException: {}", exception, @@ -313,12 +437,12 @@ final case class PrimaryServiceWorker[V <: Value]( * updated state data as well as an optional sequence of triggers to be * sent to scheduler */ - private def announcePrimaryData( + private[service] def announcePrimaryData( tick: Long, primaryData: PrimaryData, - serviceBaseStateData: PrimaryServiceInitializedStateData[V], - ): ( - PrimaryServiceInitializedStateData[V], + serviceBaseStateData: PrimaryServiceInitializedStateData[_ <: Value], + )(implicit self: ActorRef[PrimaryDataMessage]): ( + PrimaryServiceInitializedStateData[_ <: Value], Option[Long], ) = { val (maybeNextTick, remainderActivationTicks) = @@ -335,122 +459,3 @@ final case class PrimaryServiceWorker[V <: Value]( (updatedStateData, maybeNextTick) } } - -object PrimaryServiceWorker { - - /** List of supported column schemes aka. column schemes, that belong to - * primary data - */ - val supportedColumnSchemes: Vector[ColumnScheme] = Vector( - ColumnScheme.ACTIVE_POWER, - ColumnScheme.ACTIVE_POWER_AND_HEAT_DEMAND, - ColumnScheme.APPARENT_POWER, - ColumnScheme.APPARENT_POWER_AND_HEAT_DEMAND, - ) - - def props[V <: Value]( - scheduler: ActorRef, - valueClass: Class[V], - ): Props = - Props(new PrimaryServiceWorker(scheduler, valueClass)) - - /** Abstract class pattern for specific [[InitializeServiceStateData]]. - * Different implementations are needed, because the [[PrimaryServiceProxy]] - * already has detailed information about different source types, that can be - * handed over instead of being acquired once again. - */ - abstract class InitPrimaryServiceStateData - extends InitializeServiceStateData { - val timeSeriesUuid: UUID - val simulationStart: ZonedDateTime - } - - /** Specific implementation of [[InitPrimaryServiceStateData]], if the source - * to use utilizes csv files. - * - * @param timeSeriesUuid - * Unique identifier of the time series to read - * @param simulationStart - * Simulation time of the beginning of simulation time - * @param csvSep - * Column separation character of the csv files - * @param directoryPath - * Base directory path, where all input information are given - * @param filePath - * Path of the file to read with respect to the given folder path (Without - * ending!) - * @param fileNamingStrategy - * [[FileNamingStrategy]], the input files follow - * @param timePattern - * the time format pattern of the time series - */ - final case class CsvInitPrimaryServiceStateData( - override val timeSeriesUuid: UUID, - override val simulationStart: ZonedDateTime, - csvSep: String, - directoryPath: Path, - filePath: Path, - fileNamingStrategy: FileNamingStrategy, - timePattern: String, - ) extends InitPrimaryServiceStateData - - /** Specific implementation of [[InitPrimaryServiceStateData]], if the source - * to use utilizes an SQL database. - * - * @param timeSeriesUuid - * Unique identifier of the time series to read - * @param simulationStart - * Simulation time of the beginning of simulation time - * @param sqlParams - * Parameters regarding SQL connection and table selection - * @param databaseNamingStrategy - * Strategy of naming database entities, such as tables - */ - final case class SqlInitPrimaryServiceStateData( - override val timeSeriesUuid: UUID, - override val simulationStart: ZonedDateTime, - sqlParams: SqlParams, - databaseNamingStrategy: DatabaseNamingStrategy, - ) extends InitPrimaryServiceStateData - - /** Class carrying the state of a fully initialized [[PrimaryServiceWorker]] - * - * @param maybeNextActivationTick - * the next tick, when this actor is triggered by scheduler - * @param activationTicks - * Linked collection of ticks, in which data is available - * @param startDateTime - * Simulation time of the first instant in simulation - * @param source - * Implementation of [[TimeSeriesSource]] to use for actual acquisition of - * data - * @param subscribers - * Collection of interested actors - * @tparam V - * Type of value to get from source - */ - final case class PrimaryServiceInitializedStateData[V <: Value]( - override val maybeNextActivationTick: Option[Long], - override val activationTicks: SortedDistinctSeq[Long] = - SortedDistinctSeq.empty, - startDateTime: ZonedDateTime, - source: TimeSeriesSource[V], - subscribers: Vector[ActorRef] = Vector.empty[ActorRef], - ) extends ServiceActivationBaseStateData - - /** Provide primary data to subscribes - * - * @param tick - * Current tick - * @param data - * The payload - * @param nextDataTick - * The next tick, when data is available - */ - final case class ProvidePrimaryDataMessage( - override val tick: Long, - override val serviceRef: ActorRef, - override val data: PrimaryData, - override val nextDataTick: Option[Long], - ) extends ServiceMessage.ProvisionMessage[PrimaryData] -} diff --git a/src/main/scala/edu/ie3/simona/service/weather/WeatherService.scala b/src/main/scala/edu/ie3/simona/service/weather/WeatherService.scala index a31a217eb0..321b13cfb7 100644 --- a/src/main/scala/edu/ie3/simona/service/weather/WeatherService.scala +++ b/src/main/scala/edu/ie3/simona/service/weather/WeatherService.scala @@ -6,21 +6,26 @@ package edu.ie3.simona.service.weather -import org.apache.pekko.actor.{ActorContext, ActorRef, Props} -import edu.ie3.simona.exceptions.InitializationException import edu.ie3.simona.config.SimonaConfig +import edu.ie3.simona.exceptions.InitializationException import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + ServiceRegistrationMessage, + WrappedActivation, +} +import edu.ie3.simona.ontology.messages.services.WeatherMessage import edu.ie3.simona.ontology.messages.services.WeatherMessage._ -import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.service.ServiceStateData.{ InitializeServiceStateData, ServiceActivationBaseStateData, + ServiceConstantStateData, } +import edu.ie3.simona.service.SimonaService import edu.ie3.simona.service.weather.WeatherService.{ InitWeatherServiceStateData, WeatherInitializedStateData, @@ -32,27 +37,21 @@ import edu.ie3.simona.service.weather.WeatherSource.{ import edu.ie3.simona.util.SimonaConstants import edu.ie3.simona.util.TickUtil.RichZonedDateTime import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq +import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.time.ZonedDateTime import scala.util.{Failure, Success, Try} +/** Weather Service is responsible to register other actors that require weather + * information and provide weather information when requested + * + * @version 0.1 + * @since 2019-07-28 + */ object WeatherService { - def props( - scheduler: ActorRef, - startDateTime: ZonedDateTime, - simulationEnd: ZonedDateTime, - amountOfInterpolationCoordinates: Int = 4, - ): Props = - Props( - new WeatherService( - scheduler, - startDateTime, - simulationEnd, - amountOfInterpolationCoordinates, - ) - ) - /** @param weatherSource * weather source to receive information from * @param coordsToActorRefMap @@ -68,13 +67,14 @@ object WeatherService { */ final case class WeatherInitializedStateData( weatherSource: WeatherSource, - coordsToActorRefMap: Map[AgentCoordinates, Vector[ActorRef]] = - Map.empty[AgentCoordinates, Vector[ActorRef]], + coordsToActorRefMap: Map[AgentCoordinates, Vector[ClassicRef]] = + Map.empty[AgentCoordinates, Vector[ClassicRef]], weightedWeatherCoordinates: Map[AgentCoordinates, WeightedCoordinates] = Map.empty[AgentCoordinates, WeightedCoordinates], override val maybeNextActivationTick: Option[Long], override val activationTicks: SortedDistinctSeq[Long] = SortedDistinctSeq.empty, + amountOfInterpolationCoords: Int = 4, ) extends ServiceActivationBaseStateData /** Weather service state data used for initialization of the weather service @@ -83,26 +83,35 @@ object WeatherService { * the definition of the source to use */ final case class InitWeatherServiceStateData( - sourceDefinition: SimonaConfig.Simona.Input.Weather.Datasource + sourceDefinition: SimonaConfig.Simona.Input.Weather.Datasource, + startDateTime: ZonedDateTime, + simulationEnd: ZonedDateTime, ) extends InitializeServiceStateData val FALLBACK_WEATHER_STEM_DISTANCE = 3600L + + def apply( + scheduler: ActorRef[SchedulerMessage] + ): Behavior[WeatherMessage] = + Behaviors.withStash(100) { buffer => + Behaviors.setup { ctx => + val activationAdapter: ActorRef[Activation] = + ctx.messageAdapter[Activation](msg => WrappedActivation(msg)) + + implicit val constantData: ServiceConstantStateData = + ServiceConstantStateData( + scheduler, + activationAdapter, + ) + + new WeatherService().uninitialized(constantData, buffer) + } + } + } -/** Weather Service is responsible to register other actors that require weather - * information and provide weather information when requested - * - * @version 0.1 - * @since 2019-07-28 - */ -final case class WeatherService( - override val scheduler: ActorRef, - private implicit val simulationStart: ZonedDateTime, - simulationEnd: ZonedDateTime, - private val amountOfInterpolationCoords: Int, -) extends SimonaService[ - WeatherInitializedStateData - ](scheduler) { +private final class WeatherService + extends SimonaService[WeatherInitializedStateData, WeatherMessage] { /** Initialize the concrete service implementation using the provided * initialization data. This method should perform all heavyweight tasks @@ -122,7 +131,13 @@ final case class WeatherService( initServiceData: InitializeServiceStateData ): Try[(WeatherInitializedStateData, Option[Long])] = initServiceData match { - case InitWeatherServiceStateData(sourceDefinition) => + case InitWeatherServiceStateData( + sourceDefinition, + startDateTime, + simulationEnd, + ) => + implicit val simulationStart: ZonedDateTime = startDateTime + val weatherSource = WeatherSource(sourceDefinition) /* What is the first tick to be triggered for? And what are further activation ticks */ @@ -167,11 +182,12 @@ final case class WeatherService( override def handleRegistrationRequest( registrationMessage: ServiceRegistrationMessage )(implicit - serviceStateData: WeatherInitializedStateData + serviceStateData: WeatherInitializedStateData, + ctx: ActorContext[WeatherMessage], ): Try[WeatherInitializedStateData] = registrationMessage match { - case RegisterForWeatherMessage(latitude, longitude) => - Success(handleRegistrationRequest(sender(), latitude, longitude)) + case RegisterForWeatherMessage(sender, latitude, longitude) => + Success(handleRegistrationRequest(sender, latitude, longitude)) case invalidMessage => Failure( InvalidRegistrationRequestException( @@ -197,15 +213,16 @@ final case class WeatherService( * information if the registration has been carried out successfully */ private def handleRegistrationRequest( - agentToBeRegistered: ActorRef, + agentToBeRegistered: ClassicRef, latitude: Double, longitude: Double, )(implicit - serviceStateData: WeatherInitializedStateData + serviceStateData: WeatherInitializedStateData, + ctx: ActorContext[_], ): WeatherInitializedStateData = { - log.debug( + ctx.log.debug( "Received weather registration from {} for [Lat:{}, Long:{}]", - agentToBeRegistered.path.name, + agentToBeRegistered, latitude, longitude, ) @@ -221,11 +238,11 @@ final case class WeatherService( /* The coordinate itself is not known yet. Try to figure out, which weather coordinates are relevant */ serviceStateData.weatherSource.getWeightedCoordinates( agentCoord, - amountOfInterpolationCoords, + serviceStateData.amountOfInterpolationCoords, ) match { case Success(weightedCoordinates) => agentToBeRegistered ! RegistrationSuccessfulMessage( - self, + ctx.self, serviceStateData.maybeNextActivationTick, ) @@ -240,18 +257,18 @@ final case class WeatherService( serviceStateData.weightedWeatherCoordinates + (agentCoord -> weightedCoordinates), ) case Failure(exception) => - log.error( - exception, + ctx.log.error( s"Unable to obtain necessary information to register for coordinate $agentCoord.", + exception, ) - sender() ! RegistrationFailedMessage(self) + agentToBeRegistered ! RegistrationFailedMessage(ctx.self) serviceStateData } case Some(actorRefs) if !actorRefs.contains(agentToBeRegistered) => // coordinate is already known (= we have data for it), but this actor is not registered yet agentToBeRegistered ! RegistrationSuccessfulMessage( - self, + ctx.self, serviceStateData.maybeNextActivationTick, ) @@ -262,7 +279,7 @@ final case class WeatherService( case Some(actorRefs) if actorRefs.contains(agentToBeRegistered) => // actor is already registered, do nothing - log.warning( + ctx.log.warn( "Sending actor {} is already registered", agentToBeRegistered, ) @@ -271,7 +288,7 @@ final case class WeatherService( case _ => // actor is not registered, and we don't have data for it // inform the agentToBeRegistered that the registration failed as we don't have data for it - agentToBeRegistered ! RegistrationFailedMessage(self) + agentToBeRegistered ! RegistrationFailedMessage(ctx.self) serviceStateData } } @@ -289,7 +306,7 @@ final case class WeatherService( */ override protected def announceInformation(tick: Long)(implicit serviceStateData: WeatherInitializedStateData, - ctx: ActorContext, + ctx: ActorContext[WeatherMessage], ): (WeatherInitializedStateData, Option[Long]) = { /* Pop the next activation tick and update the state data */ @@ -313,7 +330,7 @@ final case class WeatherService( recipients.foreach( _ ! ProvideWeatherMessage( tick, - self, + ctx.self, weatherResult, maybeNextTick, ) @@ -326,5 +343,4 @@ final case class WeatherService( maybeNextTick, ) } - } diff --git a/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala b/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala index c8196aaf30..693b9f0c62 100644 --- a/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala +++ b/src/main/scala/edu/ie3/simona/sim/SimonaSim.scala @@ -93,7 +93,7 @@ object SimonaSim { val environmentRefs = EnvironmentRefs( scheduler, - runtimeEventListener.toClassic, + runtimeEventListener, primaryServiceProxy, weatherService, extSimulationData.evDataService, @@ -109,11 +109,11 @@ object SimonaSim { val otherActors = Iterable[ActorRef[_]]( timeAdvancer, scheduler, - primaryServiceProxy.toTyped, - weatherService.toTyped, + primaryServiceProxy, + weatherService, ) ++ gridAgents ++ - extSimulationData.extDataServices.values.map(_.toTyped) + extSimulationData.extDataServices.values /* watch all actors */ resultEventListeners.foreach(ctx.watch) diff --git a/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala b/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala index 3209fb706d..ff06c4bd7e 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/ExtSimSetupData.scala @@ -6,14 +6,18 @@ package edu.ie3.simona.sim.setup -import org.apache.pekko.actor.{ActorRef => ClassicRef} +import edu.ie3.simona.ontology.messages.services.EvMessage import edu.ie3.simona.service.ev.ExtEvDataService +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.{ActorRef => ClassicRef} final case class ExtSimSetupData( extSimAdapters: Iterable[ClassicRef], - extDataServices: Map[Class[_], ClassicRef], + extDataServices: Map[Class[_], ActorRef[_]], ) { - def evDataService: Option[ClassicRef] = - extDataServices.get(classOf[ExtEvDataService]) + def evDataService: Option[ActorRef[EvMessage]] = + extDataServices + .get(classOf[ExtEvDataService.type]) + .asInstanceOf[Option[ActorRef[EvMessage]]] } diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala index 4c452a4c3c..1dac0cfcea 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaSetup.scala @@ -13,13 +13,16 @@ import edu.ie3.simona.agent.grid.GridAgent import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.scheduler.TimeAdvancer import edu.ie3.simona.scheduler.core.Core.CoreFactory import edu.ie3.simona.scheduler.core.RegularSchedulerCore import edu.ie3.simona.sim.SimonaSim import org.apache.pekko.actor.typed.ActorRef import org.apache.pekko.actor.typed.scaladsl.ActorContext -import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.nio.file.Path @@ -80,7 +83,7 @@ trait SimonaSetup { def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef + ): ActorRef[PrimaryDataMessage] /** Creates a weather service * @@ -95,7 +98,7 @@ trait SimonaSetup { def weatherService( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef + ): ActorRef[WeatherMessage] /** Loads external simulations and provides corresponding actors and init data * diff --git a/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala b/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala index 55848d2ced..0775d4aa1c 100644 --- a/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala +++ b/src/main/scala/edu/ie3/simona/sim/setup/SimonaStandaloneSetup.scala @@ -18,6 +18,7 @@ import edu.ie3.simona.agent.grid.GridAgentMessages.CreateGridAgent import edu.ie3.simona.api.ExtSimAdapter import edu.ie3.simona.api.data.ExtData import edu.ie3.simona.api.data.ev.{ExtEvData, ExtEvSimulation} +import edu.ie3.simona.api.data.ontology.DataMessageFromExt import edu.ie3.simona.api.simulation.ExtSimAdapterData import edu.ie3.simona.config.{ArgsParser, RefSystemParser, SimonaConfig} import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} @@ -25,11 +26,18 @@ import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} import edu.ie3.simona.exceptions.agent.GridAgentInitializationException import edu.ie3.simona.io.grid.GridProvider import edu.ie3.simona.ontology.messages.SchedulerMessage -import edu.ie3.simona.ontology.messages.SchedulerMessage.ScheduleActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedExternalMessage, +} +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.scheduler.core.Core.CoreFactory import edu.ie3.simona.scheduler.core.RegularSchedulerCore import edu.ie3.simona.scheduler.{ScheduleLock, Scheduler, TimeAdvancer} -import edu.ie3.simona.service.SimonaService import edu.ie3.simona.service.ev.ExtEvDataService import edu.ie3.simona.service.ev.ExtEvDataService.InitExtEvData import edu.ie3.simona.service.primary.PrimaryServiceProxy @@ -48,7 +56,6 @@ import org.apache.pekko.actor.typed.scaladsl.adapter.{ TypedActorContextOps, TypedActorRefOps, } -import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.nio.file.Path import java.util.UUID @@ -149,43 +156,41 @@ class SimonaStandaloneSetup( override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = { + ): ActorRef[PrimaryDataMessage] = { val simulationStart = TimeUtil.withDefaults.toZonedDateTime( simonaConfig.simona.time.startDateTime ) - val primaryServiceProxy = context.toClassic.simonaActorOf( - PrimaryServiceProxy.props( - scheduler.toClassic, + val primaryServiceProxy = context.spawn( + PrimaryServiceProxy( + scheduler, InitPrimaryServiceProxyStateData( simonaConfig.simona.input.primary, simulationStart, ), - simulationStart, ), "primaryServiceProxyAgent", ) - - scheduler ! ScheduleActivation(primaryServiceProxy.toTyped, INIT_SIM_TICK) primaryServiceProxy } override def weatherService( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = { - val weatherService = context.toClassic.simonaActorOf( - WeatherService.props( - scheduler.toClassic, - TimeUtil.withDefaults - .toZonedDateTime(simonaConfig.simona.time.startDateTime), - TimeUtil.withDefaults - .toZonedDateTime(simonaConfig.simona.time.endDateTime), + ): ActorRef[WeatherMessage] = { + val weatherService = context.spawn( + WeatherService( + scheduler ), "weatherAgent", ) - weatherService ! SimonaService.Create( + + weatherService ! Create( InitWeatherServiceStateData( - simonaConfig.simona.input.weather.datasource + simonaConfig.simona.input.weather.datasource, + TimeUtil.withDefaults + .toZonedDateTime(simonaConfig.simona.time.startDateTime), + TimeUtil.withDefaults + .toZonedDateTime(simonaConfig.simona.time.endDateTime), ), ScheduleLock.singleKey(context, scheduler, INIT_SIM_TICK), ) @@ -221,17 +226,24 @@ class SimonaStandaloneSetup( // setup data services that belong to this external simulation val (extData, extDataInit): ( Iterable[ExtData], - Iterable[(Class[_ <: SimonaService[_]], ClassicRef)], + Iterable[(Class[_], ActorRef[_])], ) = extLink.getExtDataSimulations.asScala.zipWithIndex.map { case (_: ExtEvSimulation, dIndex) => - val extEvDataService = context.toClassic.simonaActorOf( - ExtEvDataService.props(scheduler.toClassic), + val extEvDataService = context.spawn( + ExtEvDataService(scheduler), s"$index-$dIndex", ) - val extEvData = new ExtEvData(extEvDataService, extSimAdapter) - extEvDataService ! SimonaService.Create( + val extEvServiceAdapter = context.spawn( + ExtEvDataService.adapter(extEvDataService), + s"$index-$dIndex-adapter", + ) + + val extEvData = + new ExtEvData(extEvServiceAdapter.toClassic, extSimAdapter) + + extEvDataService ! Create( InitExtEvData(extEvData), ScheduleLock.singleKey( context, @@ -240,7 +252,7 @@ class SimonaStandaloneSetup( ), ) - (extEvData, (classOf[ExtEvDataService], extEvDataService)) + (extEvData, (classOf[ExtEvDataService.type], extEvDataService)) }.unzip extLink.getExtSimulation.setup( diff --git a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala index 09f6acb019..a4bab08933 100644 --- a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala @@ -21,9 +21,8 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } @@ -32,6 +31,11 @@ import edu.ie3.simona.ontology.messages.services.WeatherMessage.{ RegisterForWeatherMessage, WeatherData, } +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + ServiceMessage, + WeatherMessage, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.test.common.input.EmInputTestData import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK @@ -101,8 +105,8 @@ class EmAgentIT "be initialized correctly and run through some activations" in { val resultListener = TestProbe[ResultEvent]("ResultListener") val primaryServiceProxy = - TestProbe[ServiceMessage]("PrimaryServiceProxy") - val weatherService = TestProbe[ServiceMessage]("WeatherService") + TestProbe[PrimaryDataMessage]("PrimaryServiceProxy") + val weatherService = TestProbe[WeatherMessage]("WeatherService") val scheduler = TestProbe[SchedulerMessage]("Scheduler") val emAgent = spawn( @@ -200,7 +204,7 @@ class EmAgentIT loadAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(loadInput.getUuid) + PrimaryServiceRegistrationMessage(loadAgent.ref, loadInput.getUuid) ) loadAgent ! RegistrationFailedMessage(primaryServiceProxy.ref.toClassic) @@ -227,13 +231,14 @@ class EmAgentIT pvAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(pvInput.getUuid) + PrimaryServiceRegistrationMessage(pvAgent.ref, pvInput.getUuid) ) pvAgent ! RegistrationFailedMessage(primaryServiceProxy.ref.toClassic) // deal with weather service registration weatherService.expectMessage( RegisterForWeatherMessage( + pvAgent.ref, pvInput.getNode.getGeoPosition.getY, pvInput.getNode.getGeoPosition.getX, ) @@ -250,7 +255,10 @@ class EmAgentIT storageAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(householdStorageInput.getUuid) + PrimaryServiceRegistrationMessage( + storageAgent.ref, + householdStorageInput.getUuid, + ) ) storageAgent ! RegistrationFailedMessage( primaryServiceProxy.ref.toClassic @@ -485,7 +493,7 @@ class EmAgentIT loadAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(loadInput.getUuid) + PrimaryServiceRegistrationMessage(loadAgent.ref, loadInput.getUuid) ) loadAgent ! RegistrationFailedMessage(primaryServiceProxy.ref.toClassic) @@ -512,13 +520,14 @@ class EmAgentIT pvAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(pvInput.getUuid) + PrimaryServiceRegistrationMessage(pvAgent.ref, pvInput.getUuid) ) pvAgent ! RegistrationFailedMessage(primaryServiceProxy.ref.toClassic) // deal with weather service registration weatherService.expectMessage( RegisterForWeatherMessage( + pvAgent.ref, pvInput.getNode.getGeoPosition.getY, pvInput.getNode.getGeoPosition.getX, ) @@ -535,7 +544,10 @@ class EmAgentIT heatPumpAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(adaptedHpInputModel.getUuid) + PrimaryServiceRegistrationMessage( + heatPumpAgent.ref, + adaptedHpInputModel.getUuid, + ) ) heatPumpAgent ! RegistrationFailedMessage( primaryServiceProxy.ref.toClassic @@ -543,6 +555,7 @@ class EmAgentIT weatherService.expectMessage( RegisterForWeatherMessage( + heatPumpAgent.ref, hpInputModel.getNode.getGeoPosition.getY, hpInputModel.getNode.getGeoPosition.getX, ) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmCenGridSpec.scala b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmCenGridSpec.scala index 8d23af9c46..9fa55af1fa 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmCenGridSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmCenGridSpec.scala @@ -21,6 +21,10 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.test.common.model.grid.DbfsTestGrid @@ -31,7 +35,6 @@ import org.apache.pekko.actor.testkit.typed.scaladsl.{ ScalaTestWithActorTestKit, TestProbe, } -import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import squants.electro.Kilovolts import squants.energy.Megawatts @@ -55,8 +58,9 @@ class DBFSAlgorithmCenGridSpec private val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") private val runtimeEvents: TestProbe[RuntimeEvent] = TestProbe("runtimeEvents") - private val primaryService = TestProbe("primaryService") - private val weatherService = TestProbe("weatherService") + private val primaryService = TestProbe[PrimaryDataMessage]("primaryService") + private val weatherService = + TestProbe[WeatherMessage]("weatherService") private val superiorGridAgent = SuperiorGA( TestProbe("superiorGridAgent_1000"), @@ -77,8 +81,8 @@ class DBFSAlgorithmCenGridSpec private val environmentRefs = EnvironmentRefs( scheduler = scheduler.ref, runtimeEventListener = runtimeEvents.ref, - primaryServiceProxy = primaryService.ref.toClassic, - weather = weatherService.ref.toClassic, + primaryServiceProxy = primaryService.ref, + weather = weatherService.ref, evDataService = None, ) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmFailedPowerFlowSpec.scala b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmFailedPowerFlowSpec.scala index a1047edeff..0e54c2f756 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmFailedPowerFlowSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmFailedPowerFlowSpec.scala @@ -20,6 +20,10 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.test.common.model.grid.DbfsTestGrid @@ -48,8 +52,9 @@ class DBFSAlgorithmFailedPowerFlowSpec private val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") private val runtimeEvents: TestProbe[RuntimeEvent] = TestProbe("runtimeEvents") - private val primaryService = TestProbe("primaryService") - private val weatherService = TestProbe("weatherService") + private val primaryService = TestProbe[PrimaryDataMessage]("primaryService") + private val weatherService = + TestProbe[WeatherMessage]("weatherService") private val superiorGridAgent = SuperiorGA( TestProbe("superiorGridAgent_1000"), @@ -62,8 +67,8 @@ class DBFSAlgorithmFailedPowerFlowSpec private val environmentRefs = EnvironmentRefs( scheduler = scheduler.ref, runtimeEventListener = runtimeEvents.ref, - primaryServiceProxy = primaryService.ref.toClassic, - weather = weatherService.ref.toClassic, + primaryServiceProxy = primaryService.ref, + weather = weatherService.ref, evDataService = None, ) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmParticipantSpec.scala b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmParticipantSpec.scala index fa43ee2d1e..813a8c6f6f 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmParticipantSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmParticipantSpec.scala @@ -20,9 +20,12 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.test.common.model.grid.DbfsTestGridWithParticipants @@ -48,17 +51,20 @@ class DBFSAlgorithmParticipantSpec with TestSpawnerTyped { private val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") - private val runtimeEvents: TestProbe[RuntimeEvent] = - TestProbe("runtimeEvents") - private val primaryService: TestProbe[ServiceMessage] = - TestProbe("primaryService") - private val weatherService = TestProbe("weatherService") + private val runtimeEvents: TestProbe[RuntimeEvent] = TestProbe( + "runtimeEvents" + ) + private val primaryService: TestProbe[PrimaryDataMessage] = TestProbe( + "primaryService" + ) + private val weatherService = + TestProbe[WeatherMessage]("weatherService") private val environmentRefs = EnvironmentRefs( scheduler = scheduler.ref, runtimeEventListener = runtimeEvents.ref, - primaryServiceProxy = primaryService.ref.toClassic, - weather = weatherService.ref.toClassic, + primaryServiceProxy = primaryService.ref, + weather = weatherService.ref, evDataService = None, ) @@ -119,11 +125,14 @@ class DBFSAlgorithmParticipantSpec loadAgent ! Activation(INIT_SIM_TICK) primaryService.expectMessage( - PrimaryServiceRegistrationMessage(load1.getUuid) + PrimaryServiceRegistrationMessage( + loadAgent.ref.toClassic, + load1.getUuid, + ) ) loadAgent.toClassic ! RegistrationFailedMessage( - primaryService.ref.toClassic + primaryService.ref ) scheduler.expectMessage(Completion(loadAgent, Some(0))) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmSupGridSpec.scala b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmSupGridSpec.scala index beb1408270..fb9fa13655 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmSupGridSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/DBFSAlgorithmSupGridSpec.scala @@ -19,7 +19,10 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.test.common.model.grid.DbfsTestGrid @@ -31,7 +34,6 @@ import org.apache.pekko.actor.testkit.typed.scaladsl.{ TestProbe, } import org.apache.pekko.actor.typed.ActorRef -import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import squants.energy.Megawatts import java.util.UUID @@ -51,18 +53,21 @@ class DBFSAlgorithmSupGridSpec with TestSpawnerTyped { private val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") - private val runtimeEvents: TestProbe[RuntimeEvent] = - TestProbe("runtimeEvents") - private val primaryService: TestProbe[ServiceMessage] = - TestProbe("primaryService") - private val weatherService = TestProbe("weatherService") + private val runtimeEvents: TestProbe[RuntimeEvent] = TestProbe( + "runtimeEvents" + ) + private val primaryService: TestProbe[PrimaryDataMessage] = TestProbe( + "primaryService" + ) + private val weatherService = + TestProbe[WeatherMessage]("weatherService") private val hvGrid: TestProbe[GridAgent.Request] = TestProbe("hvGrid") private val environmentRefs = EnvironmentRefs( scheduler = scheduler.ref, runtimeEventListener = runtimeEvents.ref, - primaryServiceProxy = primaryService.ref.toClassic, - weather = weatherService.ref.toClassic, + primaryServiceProxy = primaryService.ref, + weather = weatherService.ref, evDataService = None, ) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/EvcsAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/EvcsAgentModelCalculationSpec.scala index 4d3c444156..6a9706c63d 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/EvcsAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/EvcsAgentModelCalculationSpec.scala @@ -44,8 +44,8 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage._ import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions import edu.ie3.simona.ontology.messages.services.EvMessage._ -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } @@ -132,7 +132,7 @@ class EvcsAgentModelCalculationSpec resolution = resolution, requestVoltageDeviationThreshold = requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -173,7 +173,7 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) deathProbe.expectTerminated(evcsAgent.ref) @@ -191,14 +191,14 @@ class EvcsAgentModelCalculationSpec inputModel = evcsInputModel, modelConfig = modelConfig, secondaryDataServices = Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ), simulationStartDate = simulationStartDate, simulationEndDate = simulationEndDate, resolution = resolution, requestVoltageDeviationThreshold = requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -234,7 +234,7 @@ class EvcsAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(evcsInputModel.getUuid) + PrimaryServiceRegistrationMessage(evcsAgent.ref, evcsInputModel.getUuid) ) /* State should be information handling and having correct state data */ evcsAgent.stateName shouldBe HandleInformation @@ -253,7 +253,7 @@ class EvcsAgentModelCalculationSpec inputModel shouldBe SimpleInputContainer(evcsInputModel) modelConfig shouldBe modelConfig secondaryDataServices shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) simulationStartDate shouldBe simulationStartDate simulationEndDate shouldBe simulationEndDate @@ -268,11 +268,13 @@ class EvcsAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ - evService.expectMsg(RegisterForEvDataMessage(evcsInputModel.getUuid)) + evService.expectMsg( + RegisterForEvDataMessage(evcsAgent.ref, evcsInputModel.getUuid) + ) /* ... as well as corresponding state and state data */ evcsAgent.stateName shouldBe HandleInformation @@ -301,7 +303,7 @@ class EvcsAgentModelCalculationSpec startDate shouldBe simulationStartDate endDate shouldBe simulationEndDate services shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) outputConfig shouldBe NotifierConfig( simulationResultInfo = false, @@ -318,7 +320,9 @@ class EvcsAgentModelCalculationSpec requestValueStore shouldBe ValueStore[ComplexPower](resolution) /* Additional information */ - awaitRegistrationResponsesFrom shouldBe Iterable(evService.ref) + awaitRegistrationResponsesFrom shouldBe Iterable( + evService.ref.toTyped + ) foreseenNextDataTicks shouldBe Map.empty case _ => fail( @@ -329,7 +333,7 @@ class EvcsAgentModelCalculationSpec /* Reply, that registration was successful */ evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, None), + RegistrationSuccessfulMessage(evService.ref.toTyped, None), ) /* Expect a completion message */ @@ -340,7 +344,9 @@ class EvcsAgentModelCalculationSpec evcsAgent.stateData match { case baseStateData: ParticipantModelBaseStateData[_, _, _, _] => /* Only check the awaited next data ticks, as the rest has yet been checked */ - baseStateData.foreseenDataTicks shouldBe Map(evService.ref -> None) + baseStateData.foreseenDataTicks shouldBe Map( + evService.ref.toTyped -> None + ) case _ => fail( s"Did not find expected state data $ParticipantModelBaseStateData, but ${evcsAgent.stateData}" @@ -363,14 +369,16 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ - evService.expectMsg(RegisterForEvDataMessage(evcsInputModel.getUuid)) + evService.expectMsg( + RegisterForEvDataMessage(evcsAgent.ref, evcsInputModel.getUuid) + ) evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(900L)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -429,14 +437,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) /* I'm not interested in the content of the Completion */ @@ -452,7 +460,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0L, - evService.ref, + evService.ref.toTyped, arrivingEvsData, Some(900), ), @@ -468,12 +476,12 @@ class EvcsAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - evService.ref -> Some(900) + evService.ref.toTyped -> Some(900) ) /* The yet sent data is also registered */ expectedSenders shouldBe Map( - evService.ref -> Some(arrivingEvsData) + evService.ref.toTyped -> Some(arrivingEvsData) ) /* It is not yet triggered */ @@ -563,14 +571,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) /* I'm not interested in the content of the Completion */ @@ -593,10 +601,12 @@ class EvcsAgentModelCalculationSpec isYetTriggered, ) => /* The next data tick is already registered */ - baseStateData.foreseenDataTicks shouldBe Map(evService.ref -> Some(0)) + baseStateData.foreseenDataTicks shouldBe Map( + evService.ref.toTyped -> Some(0) + ) /* The yet sent data is also registered */ - expectedSenders shouldBe Map(evService.ref -> None) + expectedSenders shouldBe Map(evService.ref.toTyped -> None) /* It is not yet triggered */ isYetTriggered shouldBe true @@ -614,7 +624,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0L, - evService.ref, + evService.ref.toTyped, arrivingEvsData, Some(900), ), @@ -694,14 +704,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(10800)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(10800)), ) /* I'm not interested in the content of the Completion */ @@ -739,14 +749,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) /* I'm not interested in the content of the CompletionM */ @@ -773,7 +783,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(EvModelWrapper(evA))), Some(900), ), @@ -820,14 +830,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) /* I'm not interested in the content of the Completion */ @@ -839,7 +849,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(EvModelWrapper(evA))), Some(900), ), @@ -856,7 +866,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 900, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq.empty), Some(1800), ), @@ -878,14 +888,14 @@ class EvcsAgentModelCalculationSpec inputModel = evcsInputModelQv, modelConfig = modelConfig, secondaryDataServices = Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ), simulationStartDate = simulationStartDate, simulationEndDate = simulationEndDate, resolution = resolution, requestVoltageDeviationThreshold = requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ), listener = systemListener, ) @@ -898,14 +908,14 @@ class EvcsAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ evService.expectMsgType[RegisterForEvDataMessage] evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) /* I'm not interested in the content of the Completion */ @@ -918,7 +928,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0, - evService.ref, + evService.ref.toTyped, ArrivingEvs( Seq(EvModelWrapper(evA.copyWithDeparture(3600))) ), @@ -952,7 +962,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 3600, - evService.ref, + evService.ref.toTyped, ArrivingEvs( Seq(EvModelWrapper(evB.copyWithDeparture(7200))) ), @@ -986,7 +996,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 7200, - evService.ref, + evService.ref.toTyped, ArrivingEvs( Seq(EvModelWrapper(evA.copyWithDeparture(10800))) ), @@ -1060,14 +1070,14 @@ class EvcsAgentModelCalculationSpec inputModel = evcsInputModelQv, modelConfig = modelConfig, secondaryDataServices = Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ), simulationStartDate = simulationStartDate, simulationEndDate = simulationEndDate, resolution = resolution, requestVoltageDeviationThreshold = requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, maybeEmAgent = Some(emAgent.ref.toTyped), ), listener = Iterable.empty, @@ -1078,7 +1088,10 @@ class EvcsAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(evcsInputModelQv.getUuid) + PrimaryServiceRegistrationMessage( + evcsAgent.ref, + evcsInputModelQv.getUuid, + ) ) /* State should be information handling and having correct state data */ evcsAgent.stateName shouldBe HandleInformation @@ -1097,7 +1110,7 @@ class EvcsAgentModelCalculationSpec inputModel shouldBe SimpleInputContainer(evcsInputModelQv) modelConfig shouldBe modelConfig secondaryDataServices shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) simulationStartDate shouldBe simulationStartDate simulationEndDate shouldBe simulationEndDate @@ -1112,7 +1125,7 @@ class EvcsAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) emAgent.expectMsg( @@ -1125,10 +1138,12 @@ class EvcsAgentModelCalculationSpec // only receive registration message. ScheduleFlexRequest after secondary service initialized emAgent.expectNoMessage() - evService.expectMsg(RegisterForEvDataMessage(evcsInputModelQv.getUuid)) + evService.expectMsg( + RegisterForEvDataMessage(evcsAgent.ref, evcsInputModelQv.getUuid) + ) evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) emAgent.expectMsg( @@ -1160,11 +1175,11 @@ class EvcsAgentModelCalculationSpec startDate shouldBe simulationStartDate endDate shouldBe simulationEndDate services shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) outputConfig shouldBe defaultOutputConfig additionalActivationTicks shouldBe empty - foreseenDataTicks shouldBe Map(evService.ref -> Some(0)) + foreseenDataTicks shouldBe Map(evService.ref.toTyped -> Some(0)) voltageValueStore shouldBe ValueStore( resolution, SortedMap(0L -> Each(1.0)), @@ -1194,7 +1209,7 @@ class EvcsAgentModelCalculationSpec inputModel = SimpleInputContainer(evcsInputModelQv), modelConfig = modelConfig, secondaryDataServices = Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ), simulationStartDate = simulationStartDate, simulationEndDate = simulationEndDate, @@ -1205,7 +1220,7 @@ class EvcsAgentModelCalculationSpec powerRequestReply = false, flexResult = true, ), - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, maybeEmAgent = Some(emAgent.ref.toTyped), ), listener = Iterable(resultListener.ref), @@ -1216,7 +1231,10 @@ class EvcsAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(evcsInputModelQv.getUuid) + PrimaryServiceRegistrationMessage( + evcsAgent.ref, + evcsInputModelQv.getUuid, + ) ) /* State should be information handling and having correct state data */ evcsAgent.stateName shouldBe HandleInformation @@ -1235,7 +1253,7 @@ class EvcsAgentModelCalculationSpec inputModel shouldBe SimpleInputContainer(evcsInputModelQv) modelConfig shouldBe modelConfig secondaryDataServices shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) simulationStartDate shouldBe simulationStartDate simulationEndDate shouldBe simulationEndDate @@ -1254,7 +1272,7 @@ class EvcsAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) emAgent.expectMsg( @@ -1266,10 +1284,12 @@ class EvcsAgentModelCalculationSpec ) emAgent.expectNoMessage() - evService.expectMsg(RegisterForEvDataMessage(evcsInputModelQv.getUuid)) + evService.expectMsg( + RegisterForEvDataMessage(evcsAgent.ref, evcsInputModelQv.getUuid) + ) evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(900)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(900)), ) emAgent.expectMsg( @@ -1339,7 +1359,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 900, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev900)), Some(4500), ), @@ -1456,7 +1476,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 4500, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev4500)), Some(11700), ), @@ -1586,7 +1606,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 11700, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev11700)), None, ), @@ -2023,7 +2043,7 @@ class EvcsAgentModelCalculationSpec evcsInputModel, modelConfig = modelConfig, secondaryDataServices = Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ), simulationStartDate = simulationStartDate, simulationEndDate = simulationEndDate, @@ -2034,7 +2054,7 @@ class EvcsAgentModelCalculationSpec powerRequestReply = false, flexResult = true, ), - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) val evcsAgent = TestFSMRef( new EvcsAgent( @@ -2048,7 +2068,7 @@ class EvcsAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(inputModelUuid) + PrimaryServiceRegistrationMessage(evcsAgent.ref, inputModelUuid) ) /* State should be information handling and having correct state data */ evcsAgent.stateName shouldBe HandleInformation @@ -2067,7 +2087,7 @@ class EvcsAgentModelCalculationSpec inputModel shouldBe SimpleInputContainer(evcsInputModel) modelConfig shouldBe modelConfig secondaryDataServices shouldBe Iterable( - ActorExtEvDataService(evService.ref) + ActorExtEvDataService(evService.ref.toTyped) ) simulationStartDate shouldBe simulationStartDate simulationEndDate shouldBe simulationEndDate @@ -2086,13 +2106,15 @@ class EvcsAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( evcsAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) - evService.expectMsg(RegisterForEvDataMessage(evcsInputModel.getUuid)) + evService.expectMsg( + RegisterForEvDataMessage(evcsAgent.ref, evcsInputModel.getUuid) + ) evService.send( evcsAgent, - RegistrationSuccessfulMessage(evService.ref, Some(0)), + RegistrationSuccessfulMessage(evService.ref.toTyped, Some(0)), ) scheduler.expectMsg(Completion(evcsAgent.toTyped, Some(0))) @@ -2106,7 +2128,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 0, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq.empty), Some(900), ), @@ -2126,7 +2148,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 900, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev900)), Some(1800), ), @@ -2154,7 +2176,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 1800, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev1800)), Some(2700), ), @@ -2193,7 +2215,7 @@ class EvcsAgentModelCalculationSpec evcsAgent, ProvideEvDataMessage( 2700, - evService.ref, + evService.ref.toTyped, ArrivingEvs(Seq(ev2700)), None, ), diff --git a/src/test/scala/edu/ie3/simona/agent/participant/FixedFeedInAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/FixedFeedInAgentModelCalculationSpec.scala index c8bcdd13b5..9255ee0769 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/FixedFeedInAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/FixedFeedInAgentModelCalculationSpec.scala @@ -32,8 +32,8 @@ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.input.FixedFeedInputTestData import edu.ie3.simona.util.ConfigUtil @@ -116,7 +116,7 @@ class FixedFeedInAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -152,7 +152,10 @@ class FixedFeedInAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(voltageSensitiveInput.getUuid) + PrimaryServiceRegistrationMessage( + fixedFeedAgent.ref, + voltageSensitiveInput.getUuid, + ) ) /* State should be information handling and having correct state data */ fixedFeedAgent.stateName shouldBe HandleInformation @@ -184,7 +187,7 @@ class FixedFeedInAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( fixedFeedAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a completion notification */ @@ -246,7 +249,7 @@ class FixedFeedInAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( fixedFeedAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the Completion */ @@ -302,7 +305,7 @@ class FixedFeedInAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( fixedFeedAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I am not interested in the Completion */ @@ -354,7 +357,7 @@ class FixedFeedInAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( fixedFeedAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(fixedFeedAgent.toTyped, Some(0))) @@ -397,7 +400,7 @@ class FixedFeedInAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( fixedFeedAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(fixedFeedAgent.toTyped, Some(0))) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala index 68ff601380..8a978c7ea4 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala @@ -30,8 +30,8 @@ import edu.ie3.simona.model.participant.HpModel.HpState import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseState import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } @@ -113,7 +113,7 @@ class HpAgentModelCalculationSpec ) private val noServices = Iterable.empty private val services = Iterable( - ActorWeatherService(weatherService.ref) + ActorWeatherService(weatherService.ref.toTyped) ) private val resolution = simonaConfig.simona.powerflow.resolution.getSeconds @@ -132,7 +132,7 @@ class HpAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, maybeEmAgent = None, ) @@ -175,7 +175,7 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) deathProbe.expectTerminated(hpAgent) @@ -198,7 +198,7 @@ class HpAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, maybeEmAgent = None, ) @@ -235,7 +235,7 @@ class HpAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(hpInput.getUuid) + PrimaryServiceRegistrationMessage(hpAgent.ref, hpInput.getUuid) ) /* State should be information handling and having correct state data */ hpAgent.stateName shouldBe HandleInformation @@ -269,12 +269,12 @@ class HpAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(52.02083574, 7.40110716) + RegisterForWeatherMessage(hpAgent.ref, 52.02083574, 7.40110716) ) /* ... as well as corresponding state and state data */ @@ -304,7 +304,7 @@ class HpAgentModelCalculationSpec startDate shouldBe defaultSimulationStart endDate shouldBe defaultSimulationEnd services shouldBe Iterable( - ActorWeatherService(weatherService.ref) + ActorWeatherService(weatherService.ref.toTyped) ) outputConfig shouldBe NotifierConfig( simulationResultInfo = true, @@ -323,7 +323,9 @@ class HpAgentModelCalculationSpec ) /* Additional information */ - awaitRegistrationResponsesFrom shouldBe Iterable(weatherService.ref) + awaitRegistrationResponsesFrom shouldBe Iterable( + weatherService.ref.toTyped + ) foreseenNextDataTicks shouldBe Map.empty case _ => fail( @@ -334,7 +336,7 @@ class HpAgentModelCalculationSpec /* Reply, that registration was successful */ weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(4711L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(4711L)), ) /* Expect a completion message */ @@ -346,7 +348,7 @@ class HpAgentModelCalculationSpec case baseStateData: ParticipantModelBaseStateData[_, _, _, _] => /* Only check the awaited next data ticks, as the rest has yet been checked */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(4711L) + weatherService.ref.toTyped -> Some(4711L) ) case _ => fail( @@ -370,16 +372,16 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(52.02083574, 7.40110716) + RegisterForWeatherMessage(hpAgent.ref, 52.02083574, 7.40110716) ) weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -436,14 +438,14 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -461,7 +463,12 @@ class HpAgentModelCalculationSpec weatherService.send( hpAgent, - ProvideWeatherMessage(0L, weatherService.ref, weatherData, Some(3600L)), + ProvideWeatherMessage( + 0L, + weatherService.ref.toTyped, + weatherData, + Some(3600L), + ), ) /* Find yourself in corresponding state and state data */ @@ -474,12 +481,12 @@ class HpAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(3600L) + weatherService.ref.toTyped -> Some(3600L) ) /* The yet sent data is also registered */ expectedSenders shouldBe Map( - weatherService.ref -> Some(weatherData) + weatherService.ref.toTyped -> Some(weatherData) ) /* It is not yet triggered */ @@ -567,14 +574,14 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -594,11 +601,11 @@ class HpAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(0L) + weatherService.ref.toTyped -> Some(0L) ) /* The yet sent data is also registered */ - expectedSenders shouldBe Map(weatherService.ref -> None) + expectedSenders shouldBe Map(weatherService.ref.toTyped -> None) /* It is yet triggered */ isYetTriggered shouldBe true @@ -618,7 +625,12 @@ class HpAgentModelCalculationSpec weatherService.send( hpAgent, - ProvideWeatherMessage(0L, weatherService.ref, weatherData, Some(3600L)), + ProvideWeatherMessage( + 0L, + weatherService.ref.toTyped, + weatherData, + Some(3600L), + ), ) /* Expect confirmation */ @@ -696,14 +708,14 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(3600L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(3600L)), ) /* I'm not interested in the content of the Completion */ @@ -730,7 +742,7 @@ class HpAgentModelCalculationSpec hpAgent, ProvideWeatherMessage( 3600L, - weatherService.ref, + weatherService.ref.toTyped, weatherData, Some(7200L), ), @@ -767,14 +779,14 @@ class HpAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( hpAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( hpAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -787,7 +799,7 @@ class HpAgentModelCalculationSpec hpAgent, ProvideWeatherMessage( 0L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0), WattsPerSquareMeter(0), @@ -805,7 +817,7 @@ class HpAgentModelCalculationSpec hpAgent, ProvideWeatherMessage( 3600L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0), WattsPerSquareMeter(0), @@ -823,7 +835,7 @@ class HpAgentModelCalculationSpec hpAgent, ProvideWeatherMessage( 7200L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0), WattsPerSquareMeter(0), diff --git a/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentFixedModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentFixedModelCalculationSpec.scala index ddb97cd27b..d4275bd24d 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentFixedModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentFixedModelCalculationSpec.scala @@ -32,8 +32,8 @@ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.model.participant.LoadTestData import edu.ie3.simona.util.ConfigUtil @@ -110,7 +110,7 @@ class LoadAgentFixedModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -146,7 +146,10 @@ class LoadAgentFixedModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(voltageSensitiveInput.getUuid) + PrimaryServiceRegistrationMessage( + loadAgent.ref, + voltageSensitiveInput.getUuid, + ) ) /* State should be information handling and having correct state data */ loadAgent.stateName shouldBe HandleInformation @@ -178,7 +181,7 @@ class LoadAgentFixedModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a completion notification */ @@ -240,7 +243,7 @@ class LoadAgentFixedModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the Completion */ @@ -296,7 +299,7 @@ class LoadAgentFixedModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I am not interested in the Completion */ @@ -348,7 +351,7 @@ class LoadAgentFixedModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(loadAgent.toTyped, Some(0))) @@ -391,7 +394,7 @@ class LoadAgentFixedModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(loadAgent.toTyped, Some(0))) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentProfileModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentProfileModelCalculationSpec.scala index 6615308552..707ff1c6d7 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentProfileModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/LoadAgentProfileModelCalculationSpec.scala @@ -32,8 +32,8 @@ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.model.participant.LoadTestData import edu.ie3.simona.util.ConfigUtil @@ -110,7 +110,7 @@ class LoadAgentProfileModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -177,7 +177,7 @@ class LoadAgentProfileModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a completion notification */ @@ -240,7 +240,7 @@ class LoadAgentProfileModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the Completion */ @@ -296,7 +296,7 @@ class LoadAgentProfileModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I am not interested in the Completion */ @@ -348,7 +348,7 @@ class LoadAgentProfileModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( loadAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(loadAgent.toTyped, Some(0))) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgent2ListenerSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgent2ListenerSpec.scala index dcfa3b2cb1..aeec0f8e9f 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgent2ListenerSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgent2ListenerSpec.scala @@ -26,8 +26,8 @@ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.DefaultTestData import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK @@ -103,7 +103,7 @@ class ParticipantAgent2ListenerSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = outputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "inform listeners about new simulation results, when asked to do" in { @@ -129,7 +129,7 @@ class ParticipantAgent2ListenerSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(mockAgent.toTyped)) @@ -181,7 +181,7 @@ class ParticipantAgent2ListenerSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(mockAgent.toTyped)) @@ -217,7 +217,7 @@ class ParticipantAgent2ListenerSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(mockAgent.toTyped)) @@ -278,7 +278,7 @@ class ParticipantAgent2ListenerSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) scheduler.expectMsg(Completion(mockAgent.toTyped)) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentExternalSourceSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentExternalSourceSpec.scala index 041052ee5f..ca6149ca9a 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentExternalSourceSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentExternalSourceSpec.scala @@ -6,10 +6,6 @@ package edu.ie3.simona.agent.participant -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{ActorRef, ActorSystem} -import org.apache.pekko.testkit.TestFSMRef -import org.apache.pekko.util.Timeout import breeze.numerics.{acos, tan} import com.typesafe.config.ConfigFactory import edu.ie3.datamodel.models.input.NodeInput @@ -20,6 +16,7 @@ import edu.ie3.simona.agent.grid.GridAgentMessages.{ AssetPowerUnchangedMessage, } import edu.ie3.simona.agent.participant.ParticipantAgent.RequestAssetPowerMessage +import edu.ie3.simona.agent.participant.data.Data import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ActivePower, ActivePowerAndHeat, @@ -45,19 +42,26 @@ import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.model.participant.{CalcRelevantData, SystemParticipant} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage -import edu.ie3.simona.service.primary.PrimaryServiceWorker.ProvidePrimaryDataMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ + PrimaryServiceRegistrationMessage, + ProvidePrimaryDataMessage, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.DefaultTestData import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.scala.quantities.{Kilovars, Megavars, ReactivePower, Vars} +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.typed.{ActorRef => TypedActorRef} +import org.apache.pekko.testkit.TestFSMRef +import org.apache.pekko.util.Timeout import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.when import org.scalatestplus.mockito.MockitoSugar -import squants.{Each, Power} import squants.energy.{Kilowatts, Megawatts, Watts} +import squants.{Each, Power} import tech.units.indriya.quantity.Quantities import java.util.UUID @@ -139,7 +143,7 @@ class ParticipantAgentExternalSourceSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -173,7 +177,7 @@ class ParticipantAgentExternalSourceSpec /* Expect a registration message */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(testUUID) + PrimaryServiceRegistrationMessage(mockAgent.ref, testUUID) ) /* ... as well as corresponding state and state data */ @@ -206,7 +210,10 @@ class ParticipantAgentExternalSourceSpec /* Reply, that registration was successful */ primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(4711L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(4711L), + ), ) scheduler.expectMsg(Completion(mockAgent.toTyped, Some(4711L))) @@ -221,7 +228,7 @@ class ParticipantAgentExternalSourceSpec ], ComplexPower] => /* Only check the awaited next data ticks, as the rest has yet been checked */ baseStateData.foreseenDataTicks shouldBe Map( - primaryServiceProxy.ref -> Some(4711L) + primaryServiceProxy.ref.toTyped -> Some(4711L) ) case _ => fail( @@ -244,7 +251,10 @@ class ParticipantAgentExternalSourceSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(900L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(900L), + ), ) /* I'm not interested in the content of the Completion */ @@ -309,7 +319,10 @@ class ParticipantAgentExternalSourceSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(900L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(900L), + ), ) /* I'm not interested in the content of the Completion */ @@ -321,7 +334,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 900L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(0.0), Kilovars(900.0), @@ -344,12 +357,12 @@ class ParticipantAgentExternalSourceSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - primaryServiceProxy.ref -> Some(1800L) + primaryServiceProxy.ref.toTyped -> Some(1800L) ) /* The yet sent data is also registered */ expectedSenders shouldBe Map( - primaryServiceProxy.ref -> Some( + primaryServiceProxy.ref.toTyped -> Some( ComplexPower( Kilowatts(0.0), Kilovars(900.0), @@ -410,7 +423,10 @@ class ParticipantAgentExternalSourceSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(900L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(900L), + ), ) /* I'm not interested in the content of the Completion */ @@ -434,11 +450,11 @@ class ParticipantAgentExternalSourceSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - primaryServiceProxy.ref -> Some(900L) + primaryServiceProxy.ref.toTyped -> Some(900L) ) /* The yet sent data is also registered */ - expectedSenders shouldBe Map(primaryServiceProxy.ref -> None) + expectedSenders shouldBe Map(primaryServiceProxy.ref.toTyped -> None) /* It is yet triggered */ isYetTriggered shouldBe true @@ -453,7 +469,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 900L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(0.0), Kilovars(900.0), @@ -505,7 +521,10 @@ class ParticipantAgentExternalSourceSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(900L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(900L), + ), ) /* I'm not interested in the content of the Completion */ @@ -526,7 +545,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 900L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(0.0), Kilovars(900.0), @@ -566,7 +585,7 @@ class ParticipantAgentExternalSourceSpec defaultSimulationEnd, defaultOutputConfig, SortedSet.empty, - Map.empty[ActorRef, Option[Long]], + Map.empty[TypedActorRef[_], Option[Long]], fillUpReactivePowerWithModelFunc = false, 1e-4, ValueStore.forVoltage( @@ -597,7 +616,7 @@ class ParticipantAgentExternalSourceSpec defaultSimulationEnd, defaultOutputConfig, SortedSet.empty, - Map.empty[ActorRef, Option[Long]], + Map.empty[TypedActorRef[_], Option[Long]], fillUpReactivePowerWithModelFunc = true, 1e-4, ValueStore.forVoltage( @@ -621,7 +640,10 @@ class ParticipantAgentExternalSourceSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( mockAgent, - RegistrationSuccessfulMessage(primaryServiceProxy.ref, Some(900L)), + RegistrationSuccessfulMessage( + primaryServiceProxy.ref.toTyped, + Some(900L), + ), ) /* I'm not interested in the content of the Completion */ @@ -634,7 +656,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 900L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(100.0), Kilovars(33.0), @@ -650,7 +672,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 1800L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(150.0), Kilovars(49.0), @@ -666,7 +688,7 @@ class ParticipantAgentExternalSourceSpec mockAgent, ProvidePrimaryDataMessage( 2700L, - primaryServiceProxy.ref, + primaryServiceProxy.ref.toTyped, ComplexPower( Kilowatts(200.0), Kilovars(66.0), @@ -736,8 +758,8 @@ class ParticipantAgentExternalSourceSpec "sending unsupported data" should { "fail" in { - val data = Map( - primaryServiceProxy.ref -> Some( + val data: Map[TypedActorRef[_], Option[_ <: Data]] = Map( + primaryServiceProxy.ref.toTyped -> Some( ComplexPowerAndHeat( Kilowatts(0.0), Kilovars(0.0), @@ -758,8 +780,8 @@ class ParticipantAgentExternalSourceSpec "sending enhanceable data" should { "fail, if enhanced data are not supported" in { - val data = Map( - primaryServiceProxy.ref -> Some( + val data: Map[TypedActorRef[_], Option[_ <: Data]] = Map( + primaryServiceProxy.ref.toTyped -> Some( ActivePowerAndHeat( Kilowatts(0.0), Kilowatts(0.0), @@ -777,8 +799,8 @@ class ParticipantAgentExternalSourceSpec } "lead to proper enriched data, if supported" in { - val data = Map( - primaryServiceProxy.ref -> Some( + val data: Map[TypedActorRef[_], Option[_ <: Data]] = Map( + primaryServiceProxy.ref.toTyped -> Some( ActivePower(Kilowatts(0.0)) ) ) @@ -798,8 +820,8 @@ class ParticipantAgentExternalSourceSpec } "lead to proper enriched data, if supported and utilizing a active to reactive power function" in { - val data = Map( - primaryServiceProxy.ref -> Some( + val data: Map[TypedActorRef[_], Option[_ <: Data]] = Map( + primaryServiceProxy.ref.toTyped -> Some( ActivePower(Kilowatts(100.0)) ) ) diff --git a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentalsSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentalsSpec.scala index 26058683b3..b402f6f739 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentalsSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentalsSpec.scala @@ -38,8 +38,9 @@ import edu.ie3.util.scala.quantities.{ ReactivePower, Vars, } -import org.apache.pekko.actor.ActorRef.noSender -import org.apache.pekko.actor.{ActorRef, ActorSystem} +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps import org.apache.pekko.testkit.TestFSMRef import org.apache.pekko.util.Timeout import org.mockito.Mockito.when @@ -257,8 +258,8 @@ class ParticipantAgentFundamentalsSpec val baseStateData = ParticipantAgentFundamentalsSpec.mockBaseStateData( SortedSet(100L, 200L, 300L), Map( - self -> Some(10L), - noSender -> Some(0L), + self.toTyped -> Some(10L), + noSender.ref.toTyped -> Some(0L), ), ) @@ -276,8 +277,8 @@ class ParticipantAgentFundamentalsSpec val baseStateData = ParticipantAgentFundamentalsSpec.mockBaseStateData( SortedSet(0L, 10L, 20L), Map( - self -> Some(200L), - noSender -> Some(100L), + self.toTyped -> Some(200L), + noSender.toTyped -> Some(100L), ), ) @@ -298,8 +299,8 @@ class ParticipantAgentFundamentalsSpec val baseStateData = ParticipantAgentFundamentalsSpec.mockBaseStateData( SortedSet(0L, 10L, 20L), Map( - self -> Some(20L), - noSender -> Some(0L), + self.toTyped -> Some(20L), + noSender.toTyped -> Some(0L), ), ) @@ -618,7 +619,7 @@ case object ParticipantAgentFundamentalsSpec extends MockitoSugar { */ def mockBaseStateData( additionalActivationTicks: SortedSet[Long], - foreseenDataTicks: Map[ActorRef, Option[Long]], + foreseenDataTicks: Map[ActorRef[_], Option[Long]], ): ParticipantModelBaseStateData[ ComplexPower, FixedRelevantData.type, diff --git a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentMock.scala b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentMock.scala index 3e17e76ccb..205aa69f58 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentMock.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/ParticipantAgentMock.scala @@ -14,8 +14,7 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPower, ZERO_POWER, } -import edu.ie3.simona.agent.participant.data.Data.SecondaryData -import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.SecondaryServiceType import edu.ie3.simona.agent.participant.statedata.BaseStateData.ParticipantModelBaseStateData import edu.ie3.simona.agent.participant.statedata.ParticipantStateData.{ InputModelContainer, @@ -193,7 +192,7 @@ class ParticipantAgentMock( override def determineModelBaseStateData( inputModel: InputModelContainer[SystemParticipantInput], modelConfig: SimonaConfig.BaseRuntimeConfig, - services: Iterable[SecondaryDataService[_ <: SecondaryData]], + services: Iterable[SecondaryServiceType], simulationStartDate: ZonedDateTime, simulationEndDate: ZonedDateTime, resolution: Long, diff --git a/src/test/scala/edu/ie3/simona/agent/participant/PvAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/PvAgentModelCalculationSpec.scala index 071a5fa2c7..de2d00d0a1 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/PvAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/PvAgentModelCalculationSpec.scala @@ -29,8 +29,8 @@ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } @@ -111,7 +111,7 @@ class PvAgentModelCalculationSpec ) private val noServices = Iterable.empty private val withServices = Iterable( - ActorWeatherService(weatherService.ref) + ActorWeatherService(weatherService.ref.toTyped) ) private val resolution = simonaConfig.simona.powerflow.resolution.getSeconds @@ -133,7 +133,7 @@ class PvAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -175,7 +175,7 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) deathProbe.expectTerminated(pvAgent.ref) @@ -197,7 +197,7 @@ class PvAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = defaultOutputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, ) "be instantiated correctly" in { @@ -233,7 +233,10 @@ class PvAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(voltageSensitiveInput.getUuid) + PrimaryServiceRegistrationMessage( + pvAgent.ref, + voltageSensitiveInput.getUuid, + ) ) /* State should be information handling and having correct state data */ pvAgent.stateName shouldBe HandleInformation @@ -265,12 +268,12 @@ class PvAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(52.02083574, 7.40110716) + RegisterForWeatherMessage(pvAgent.ref, 52.02083574, 7.40110716) ) /* ... as well as corresponding state and state data */ @@ -300,7 +303,7 @@ class PvAgentModelCalculationSpec startDate shouldBe simulationStartDate endDate shouldBe simulationEndDate services shouldBe Iterable( - ActorWeatherService(weatherService.ref) + ActorWeatherService(weatherService.ref.toTyped) ) outputConfig shouldBe NotifierConfig( simulationResultInfo = false, @@ -317,7 +320,9 @@ class PvAgentModelCalculationSpec requestValueStore shouldBe ValueStore[ComplexPower](resolution) /* Additional information */ - awaitRegistrationResponsesFrom shouldBe Iterable(weatherService.ref) + awaitRegistrationResponsesFrom shouldBe Iterable( + weatherService.ref.toTyped + ) foreseenNextDataTicks shouldBe Map.empty case _ => fail( @@ -328,7 +333,7 @@ class PvAgentModelCalculationSpec /* Reply, that registration was successful */ weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(4711L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(4711L)), ) /* Expect a completion message */ @@ -340,7 +345,7 @@ class PvAgentModelCalculationSpec case baseStateData: ParticipantModelBaseStateData[_, _, _, _] => /* Only check the awaited next data ticks, as the rest has yet been checked */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(4711L) + weatherService.ref.toTyped -> Some(4711L) ) case _ => fail( @@ -364,16 +369,16 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(52.02083574, 7.40110716) + RegisterForWeatherMessage(pvAgent.ref, 52.02083574, 7.40110716) ) weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -429,14 +434,14 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -454,7 +459,12 @@ class PvAgentModelCalculationSpec weatherService.send( pvAgent, - ProvideWeatherMessage(0L, weatherService.ref, weatherData, Some(3600L)), + ProvideWeatherMessage( + 0L, + weatherService.ref.toTyped, + weatherData, + Some(3600L), + ), ) /* Find yourself in corresponding state and state data */ @@ -467,12 +477,12 @@ class PvAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(3600L) + weatherService.ref.toTyped -> Some(3600L) ) /* The yet sent data is also registered */ expectedSenders shouldBe Map( - weatherService.ref -> Some(weatherData) + weatherService.ref.toTyped -> Some(weatherData) ) /* It is not yet triggered */ @@ -536,14 +546,14 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -563,11 +573,11 @@ class PvAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(0L) + weatherService.ref.toTyped -> Some(0L) ) /* The yet sent data is also registered */ - expectedSenders shouldBe Map(weatherService.ref -> None) + expectedSenders shouldBe Map(weatherService.ref.toTyped -> None) /* It is yet triggered */ isYetTriggered shouldBe true @@ -587,7 +597,12 @@ class PvAgentModelCalculationSpec weatherService.send( pvAgent, - ProvideWeatherMessage(0L, weatherService.ref, weatherData, Some(3600L)), + ProvideWeatherMessage( + 0L, + weatherService.ref.toTyped, + weatherData, + Some(3600L), + ), ) /* Expect confirmation */ @@ -641,14 +656,14 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(3600L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(3600L)), ) /* I'm not interested in the content of the Completion */ @@ -675,7 +690,7 @@ class PvAgentModelCalculationSpec pvAgent, ProvideWeatherMessage( 3600L, - weatherService.ref, + weatherService.ref.toTyped, weatherData, Some(7200L), ), @@ -712,14 +727,14 @@ class PvAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( pvAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( pvAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(0L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(0L)), ) /* I'm not interested in the content of the Completion */ @@ -732,7 +747,7 @@ class PvAgentModelCalculationSpec pvAgent, ProvideWeatherMessage( 0L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0d), WattsPerSquareMeter(0d), @@ -750,7 +765,7 @@ class PvAgentModelCalculationSpec pvAgent, ProvideWeatherMessage( 3600L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0d), WattsPerSquareMeter(0d), @@ -768,7 +783,7 @@ class PvAgentModelCalculationSpec pvAgent, ProvideWeatherMessage( 7200L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(0d), WattsPerSquareMeter(0d), diff --git a/src/test/scala/edu/ie3/simona/agent/participant/StorageAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/StorageAgentModelCalculationSpec.scala index aa4d1984e5..995020d3f5 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/StorageAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/StorageAgentModelCalculationSpec.scala @@ -32,11 +32,11 @@ import edu.ie3.simona.event.ResultEvent.{ import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation +import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage._ import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions -import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage import edu.ie3.simona.test.ParticipantAgentSpec import edu.ie3.simona.test.common.input.StorageInputTestData import edu.ie3.simona.util.ConfigUtil @@ -49,8 +49,8 @@ import edu.ie3.util.scala.quantities.{Megavars, ReactivePower, Vars} import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps import org.apache.pekko.actor.{ActorRef, ActorSystem} import org.apache.pekko.testkit.{TestFSMRef, TestProbe} -import squants.{Each, Power} import squants.energy.{Kilowatts, Megawatts, Watts} +import squants.{Each, Power} import java.time.ZonedDateTime import scala.collection.SortedMap @@ -121,7 +121,7 @@ class StorageAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, outputConfig = outputConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, maybeEmAgent = Some(emAgent.ref.toTyped), ) @@ -138,7 +138,10 @@ class StorageAgentModelCalculationSpec /* Actor should ask for registration with primary service */ primaryServiceProxy.expectMsg( - PrimaryServiceRegistrationMessage(storageInputQv.getUuid) + PrimaryServiceRegistrationMessage( + storageAgent.ref, + storageInputQv.getUuid, + ) ) /* State should be information handling and having correct state data */ storageAgent.stateName shouldBe HandleInformation @@ -170,7 +173,7 @@ class StorageAgentModelCalculationSpec /* Refuse registration */ primaryServiceProxy.send( storageAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) emAgent.expectMsg( @@ -244,7 +247,7 @@ class StorageAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( storageAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) emAgent.expectMsgType[RegisterParticipant] @@ -305,7 +308,7 @@ class StorageAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( storageAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) emAgent.expectMsgType[RegisterParticipant] diff --git a/src/test/scala/edu/ie3/simona/agent/participant/WecAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/WecAgentModelCalculationSpec.scala index 01d8e24c29..bf3fc9b2ca 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/WecAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/WecAgentModelCalculationSpec.scala @@ -36,8 +36,8 @@ import edu.ie3.simona.model.participant.WecModel.WecRelevantData import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } @@ -114,7 +114,9 @@ class WecAgentModelCalculationSpec voltageSensitiveInput.getUuid ) - private val withServices = Iterable(ActorWeatherService(weatherService.ref)) + private val withServices = Iterable( + ActorWeatherService(weatherService.ref.toTyped) + ) private val resolution = simonaConfig.simona.powerflow.resolution.getSeconds @@ -134,7 +136,7 @@ class WecAgentModelCalculationSpec requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, modelConfig = modelConfig, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, secondaryDataServices = Iterable.empty, outputConfig = NotifierConfig( simulationResultInfo = false, @@ -182,7 +184,7 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) deathProbe.expectTerminated(wecAgent.ref) @@ -202,7 +204,7 @@ class WecAgentModelCalculationSpec resolution = resolution, requestVoltageDeviationThreshold = simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, - primaryServiceProxy = primaryServiceProxy.ref, + primaryServiceProxy = primaryServiceProxy.ref.toTyped, secondaryDataServices = withServices, outputConfig = NotifierConfig( simulationResultInfo = false, @@ -246,11 +248,13 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ - weatherService.expectMsg(RegisterForWeatherMessage(51.4843281, 7.4116482)) + weatherService.expectMsg( + RegisterForWeatherMessage(wecAgent.ref, 51.4843281, 7.4116482) + ) /* ... as well as corresponding state and state data */ wecAgent.stateName shouldBe HandleInformation @@ -294,7 +298,9 @@ class WecAgentModelCalculationSpec requestValueStore shouldBe ValueStore[ComplexPower](resolution) /* Additional information */ - awaitRegistrationResponsesFrom shouldBe Iterable(weatherService.ref) + awaitRegistrationResponsesFrom shouldBe Iterable( + weatherService.ref.toTyped + ) foreseenNextDataTicks shouldBe Map.empty case _ => fail( @@ -305,7 +311,7 @@ class WecAgentModelCalculationSpec /* Reply, that registration was successful */ weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(4711L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(4711L)), ) /* Expect a completion message */ @@ -322,7 +328,7 @@ class WecAgentModelCalculationSpec ] => /* Only check the awaited next data ticks, as the rest has yet been checked */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(4711L) + weatherService.ref.toTyped -> Some(4711L) ) case _ => fail( @@ -346,14 +352,16 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* Expect a registration message */ - weatherService.expectMsg(RegisterForWeatherMessage(51.4843281, 7.4116482)) + weatherService.expectMsg( + RegisterForWeatherMessage(wecAgent.ref, 51.4843281, 7.4116482) + ) weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -414,14 +422,14 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -441,7 +449,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 900L, - weatherService.ref, + weatherService.ref.toTyped, weatherData, Some(1800L), ), @@ -462,12 +470,12 @@ class WecAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(1800L) + weatherService.ref.toTyped -> Some(1800L) ) /* The yet sent data is also registered */ expectedSenders shouldBe Map( - weatherService.ref -> Some(weatherData) + weatherService.ref.toTyped -> Some(weatherData) ) /* It is not yet triggered */ @@ -536,14 +544,14 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -568,11 +576,11 @@ class WecAgentModelCalculationSpec ) => /* The next data tick is already registered */ baseStateData.foreseenDataTicks shouldBe Map( - weatherService.ref -> Some(900L) + weatherService.ref.toTyped -> Some(900L) ) /* The yet sent data is also registered */ - expectedSenders shouldBe Map(weatherService.ref -> None) + expectedSenders shouldBe Map(weatherService.ref.toTyped -> None) /* It is yet triggered */ isYetTriggered shouldBe true @@ -594,7 +602,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 900L, - weatherService.ref, + weatherService.ref.toTyped, weatherData, Some(1800L), ), @@ -656,14 +664,14 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -690,7 +698,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 900L, - weatherService.ref, + weatherService.ref.toTyped, weatherData, Some(1800L), ), @@ -727,14 +735,14 @@ class WecAgentModelCalculationSpec primaryServiceProxy.expectMsgType[PrimaryServiceRegistrationMessage] primaryServiceProxy.send( wecAgent, - RegistrationFailedMessage(primaryServiceProxy.ref), + RegistrationFailedMessage(primaryServiceProxy.ref.toTyped), ) /* I'm not interested in the content of the RegistrationMessage */ weatherService.expectMsgType[RegisterForWeatherMessage] weatherService.send( wecAgent, - RegistrationSuccessfulMessage(weatherService.ref, Some(900L)), + RegistrationSuccessfulMessage(weatherService.ref.toTyped, Some(900L)), ) /* I'm not interested in the content of the Completion */ @@ -747,7 +755,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 900L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(50d), WattsPerSquareMeter(100d), @@ -765,7 +773,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 1800L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(50d), WattsPerSquareMeter(100d), @@ -783,7 +791,7 @@ class WecAgentModelCalculationSpec wecAgent, ProvideWeatherMessage( 2700L, - weatherService.ref, + weatherService.ref.toTyped, WeatherData( WattsPerSquareMeter(50d), WattsPerSquareMeter(100d), diff --git a/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala b/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala index 0a4dab2d51..887b4b9eea 100644 --- a/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala +++ b/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala @@ -21,7 +21,7 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.ScheduleServiceActivation import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.test.common.{TestKitWithShutdown, TestSpawnerClassic} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK diff --git a/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala b/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala index 8e6cf9e07d..76dc7f1e61 100644 --- a/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala +++ b/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala @@ -6,33 +6,39 @@ package edu.ie3.simona.service.ev -import com.typesafe.config.ConfigFactory import edu.ie3.simona.api.data.ev.ExtEvData import edu.ie3.simona.api.data.ev.model.EvModel import edu.ie3.simona.api.data.ev.ontology._ import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage import edu.ie3.simona.exceptions.ServiceException import edu.ie3.simona.model.participant.evcs.EvModelWrapper -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } import edu.ie3.simona.ontology.messages.services.EvMessage._ -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + ServiceMessageUniversal, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, + WrappedExternalMessage, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock -import edu.ie3.simona.service.SimonaService import edu.ie3.simona.service.ev.ExtEvDataService.InitExtEvData -import edu.ie3.simona.test.common.{ - EvTestData, - TestKitWithShutdown, - TestSpawnerClassic, -} +import edu.ie3.simona.test.common.{EvTestData, TestSpawnerTyped} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.quantities.PowerSystemUnits -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.testkit.{TestActorRef, TestProbe} +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + ScalaTestWithActorTestKit, + TestProbe, +} +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps +import org.apache.pekko.testkit.TestKit.awaitCond import org.scalatest.wordspec.AnyWordSpecLike import tech.units.indriya.quantity.Quantities @@ -40,21 +46,19 @@ import java.util.UUID import scala.concurrent.duration.DurationInt import scala.jdk.CollectionConverters._ import scala.jdk.OptionConverters._ +import scala.language.implicitConversions class ExtEvDataServiceSpec - extends TestKitWithShutdown( - ActorSystem( - "ExtEvDataServiceSpec", - ConfigFactory - .parseString(""" - |pekko.loggers = ["org.apache.pekko.testkit.TestEventListener"] - |pekko.loglevel = "INFO" - |""".stripMargin), - ) - ) + extends ScalaTestWithActorTestKit with AnyWordSpecLike with EvTestData - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): WrappedActivation = + WrappedActivation(msg) + + implicit def wrap(msg: EvDataMessageFromExt): WrappedExternalMessage = + WrappedExternalMessage(msg) private val evcs1UUID = UUID.fromString("06a14909-366e-4e94-a593-1016e1455b30") @@ -63,93 +67,95 @@ class ExtEvDataServiceSpec "An uninitialized ev movement service" must { "send correct completion message after initialisation" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsg( - ScheduleActivation(evService.toTyped, INIT_SIM_TICK, Some(key)) - ) + evService ! Create(InitExtEvData(extEvData), key) + + val activationMsg = scheduler.expectMessageType[ScheduleActivation] + activationMsg.tick shouldBe INIT_SIM_TICK + activationMsg.unlockKey shouldBe Some(key) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) } "stash registration request and handle it correctly once initialized" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) - val evcs1 = TestProbe("evcs1") + val evcs1 = TestProbe[Any]("evcs1") // this one should be stashed - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() scheduler.expectNoMessage() val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsg( - ScheduleActivation(evService.toTyped, INIT_SIM_TICK, Some(key)) - ) + evService ! Create(InitExtEvData(extEvData), key) + + val activationMsg = scheduler.expectMessageType[ScheduleActivation] + activationMsg.tick shouldBe INIT_SIM_TICK + activationMsg.unlockKey shouldBe Some(key) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) } } "An idle ev movements service" must { "handle duplicate registrations correctly" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - val evcs1 = TestProbe("evcs1") - val evcs2 = TestProbe("evcs2") + val evcs1 = TestProbe[ServiceMessageUniversal]("evcs1") + val evcs2 = TestProbe[ServiceMessageUniversal]("evcs2") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() - evcs2.send(evService, RegisterForEvDataMessage(evcs2UUID)) + evService ! RegisterForEvDataMessage(evcs2.ref.toClassic, evcs2UUID) evcs2.expectNoMessage() // register first one again - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() extEvData.sendExtMsg( @@ -158,74 +164,78 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) - evcs2.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) + evcs2.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) } "fail when activated without having received ExtEvMessage" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsg( - ScheduleActivation(evService.toTyped, INIT_SIM_TICK, Some(key)) - ) + evService ! Create(InitExtEvData(extEvData), key) + + val activationMsg = scheduler.expectMessageType[ScheduleActivation] + activationMsg.tick shouldBe INIT_SIM_TICK + activationMsg.unlockKey shouldBe Some(key) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) // we trigger ev service and expect an exception - assertThrows[ServiceException] { - evService.receive( - Activation(0), - scheduler.ref, - ) + assertThrows[Exception] { + evService ! Activation(0) } scheduler.expectNoMessage() } "handle free lots requests correctly and forward them to the correct evcs" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - val evcs1 = TestProbe("evcs1") - val evcs2 = TestProbe("evcs2") + val evcs1 = TestProbe[Any]("evcs1") + val evcs2 = TestProbe[Any]("evcs2") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() - evcs2.send(evService, RegisterForEvDataMessage(evcs2UUID)) + evService ! RegisterForEvDataMessage(evcs2.ref.toClassic, evcs2UUID) evcs2.expectNoMessage() extEvData.sendExtMsg( @@ -234,12 +244,18 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) - evcs2.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) + evcs2.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) extEvData.sendExtMsg( new RequestEvcsFreeLots() @@ -247,51 +263,40 @@ class ExtEvDataServiceSpec // ev service should receive request at this moment // scheduler should receive schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - evcs1.expectMsg( + evcs1.expectMessage( EvFreeLotsRequest(tick) ) - evcs2.expectMsg( + evcs2.expectMessage( EvFreeLotsRequest(tick) ) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) extEvData.receiveTriggerQueue shouldBe empty // return free lots to ev service - evcs1.send( - evService, - FreeLotsResponse( - evcs1UUID, - 2, - ), - ) + evService ! FreeLotsResponse(evcs1UUID, 2) // nothing should happen yet, waiting for second departed ev extEvData.receiveTriggerQueue shouldBe empty - evcs2.send( - evService, - FreeLotsResponse( - evcs2UUID, - 0, - ), - ) + evService ! FreeLotsResponse(evcs2UUID, 0) // ev service should recognize that all evcs that are expected are returned, // thus should send ProvideEvcsFreeLots awaitCond( !extEvData.receiveTriggerQueue.isEmpty, max = 3.seconds, - message = "No message received", ) extEvData.receiveTriggerQueue.size() shouldBe 1 // only evcs 1 should be included, the other one is full @@ -301,32 +306,32 @@ class ExtEvDataServiceSpec } "handle price requests correctly by returning dummy values" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - val evcs1 = TestProbe("evcs1") - val evcs2 = TestProbe("evcs2") + val evcs1 = TestProbe[Any]("evcs1") + val evcs2 = TestProbe[Any]("evcs2") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() - evcs2.send(evService, RegisterForEvDataMessage(evcs2UUID)) + evService ! RegisterForEvDataMessage(evcs2.ref.toClassic, evcs2UUID) evcs2.expectNoMessage() extEvData.sendExtMsg( @@ -335,23 +340,31 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) - evcs2.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) + evcs2.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) extEvData.sendExtMsg(new RequestCurrentPrices()) // ev service should receive request at this moment // scheduler should receive schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) evcs1.expectNoMessage() evcs2.expectNoMessage() @@ -360,8 +373,7 @@ class ExtEvDataServiceSpec // thus should send ProvideEvcsFreeLots awaitCond( !extEvData.receiveTriggerQueue.isEmpty, - max = 3.seconds, - message = "No message received", + max = 10.seconds, ) extEvData.receiveTriggerQueue.size() shouldBe 1 // only evcs 1 should be included, the other one is full @@ -372,79 +384,81 @@ class ExtEvDataServiceSpec ).asJava ) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) } "return free lots requests right away if there are no evcs registered" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) extEvData.sendExtMsg(new RequestEvcsFreeLots()) // ev service should receive movements msg at this moment // scheduler receives schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) // ev service should send ProvideEvcsFreeLots right away awaitCond( !extEvData.receiveTriggerQueue.isEmpty, - max = 3.seconds, - message = "No message received", + max = 10.seconds, ) extEvData.receiveTriggerQueue.size() shouldBe 1 extEvData.receiveTriggerQueue.take() shouldBe new ProvideEvcsFreeLots() } "handle ev departure requests correctly and return departed evs" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - val evcs1 = TestProbe("evcs1") - val evcs2 = TestProbe("evcs1") + val evcs1 = TestProbe[Any]("evcs1") + val evcs2 = TestProbe[Any]("evcs1") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() - evcs2.send(evService, RegisterForEvDataMessage(evcs2UUID)) + evService ! RegisterForEvDataMessage(evcs2.ref.toClassic, evcs2UUID) evcs2.expectNoMessage() extEvData.sendExtMsg( @@ -453,12 +467,18 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) - evcs2.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) + evcs2.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) val departures = Map( evcs1UUID -> List(evA.getUuid).asJava, @@ -471,30 +491,32 @@ class ExtEvDataServiceSpec // ev service should receive departure msg at this moment // scheduler should receive schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - evcs1.expectMsg( + evcs1.expectMessage( DepartingEvsRequest(tick, scala.collection.immutable.Seq(evA.getUuid)) ) - evcs2.expectMsg( + evcs2.expectMessage( DepartingEvsRequest(tick, scala.collection.immutable.Seq(evB.getUuid)) ) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) // return evs to ev service val updatedEvA = evA.copyWith( Quantities.getQuantity(6.0, PowerSystemUnits.KILOWATTHOUR) ) - evcs1.send( - evService, - DepartingEvsResponse(evcs1UUID, Seq(EvModelWrapper(updatedEvA))), + evService ! DepartingEvsResponse( + evcs1UUID, + Seq(EvModelWrapper(updatedEvA)), ) // nothing should happen yet, waiting for second departed ev @@ -504,9 +526,9 @@ class ExtEvDataServiceSpec Quantities.getQuantity(4.0, PowerSystemUnits.KILOWATTHOUR) ) - evcs2.send( - evService, - DepartingEvsResponse(evcs2UUID, Seq(EvModelWrapper(updatedEvB))), + evService ! DepartingEvsResponse( + evcs2UUID, + Seq(EvModelWrapper(updatedEvB)), ) // ev service should recognize that all evs that are expected are returned, @@ -514,7 +536,6 @@ class ExtEvDataServiceSpec awaitCond( !extEvData.receiveTriggerQueue.isEmpty, max = 3.seconds, - message = "No message received", ) extEvData.receiveTriggerQueue.size() shouldBe 1 extEvData.receiveTriggerQueue.take() shouldBe new ProvideDepartingEvs( @@ -523,24 +544,24 @@ class ExtEvDataServiceSpec } "return ev departure requests right away if request list is empty" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) extEvData.sendExtMsg( new RequestDepartingEvs(Map.empty[UUID, java.util.List[UUID]].asJava) @@ -548,20 +569,21 @@ class ExtEvDataServiceSpec // ev service should receive departure msg at this moment // scheduler should receive schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) // ev service should send ProvideDepartingEvs right away awaitCond( !extEvData.receiveTriggerQueue.isEmpty, max = 3.seconds, - message = "No message received", ) extEvData.receiveTriggerQueue.size() shouldBe 1 extEvData.receiveTriggerQueue.take() shouldBe new ProvideDepartingEvs( @@ -570,32 +592,32 @@ class ExtEvDataServiceSpec } "handle ev arrivals correctly and forward them to the correct evcs" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsgType[Completion] + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] - val evcs1 = TestProbe("evcs1") - val evcs2 = TestProbe("evcs2") + val evcs1 = TestProbe[EvMessage]("evcs1") + val evcs2 = TestProbe[EvMessage]("evcs2") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() - evcs2.send(evService, RegisterForEvDataMessage(evcs2UUID)) + evService ! RegisterForEvDataMessage(evcs2.ref.toClassic, evcs2UUID) evcs2.expectNoMessage() extEvData.sendExtMsg( @@ -604,12 +626,18 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) - evcs2.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) + evcs2.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) val arrivals = Map( evcs1UUID -> List[EvModel](evA).asJava, @@ -622,54 +650,56 @@ class ExtEvDataServiceSpec // ev service should receive movements msg at this moment // scheduler receive schedule msg - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - val evsMessage1 = evcs1.expectMsgType[ProvideEvDataMessage] + val evsMessage1 = evcs1.expectMessageType[ProvideEvDataMessage] evsMessage1.tick shouldBe tick evsMessage1.data shouldBe ArrivingEvs( Seq(EvModelWrapper(evA)) ) - val evsMessage2 = evcs2.expectMsgType[ProvideEvDataMessage] + val evsMessage2 = evcs2.expectMessageType[ProvideEvDataMessage] evsMessage2.tick shouldBe tick evsMessage2.data shouldBe ArrivingEvs( Seq(EvModelWrapper(evB)) ) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) // no response expected extEvData.receiveTriggerQueue shouldBe empty } "skip a movements provision from an evcs that is not registered" in { - val scheduler = TestProbe("scheduler") - val extSimAdapter = TestProbe("extSimAdapter") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val extSimAdapter = TestProbe[ScheduleDataServiceMessage]("extSimAdapter") - val evService = TestActorRef(new ExtEvDataService(scheduler.ref)) - val extEvData = new ExtEvData(evService, extSimAdapter.ref) + val evService = testKit.spawn(ExtEvDataService(scheduler.ref)) + val adapter = testKit.spawn(ExtEvDataService.adapter(evService)) + val extEvData = + new ExtEvData(adapter.toClassic, extSimAdapter.ref.toClassic) val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - evService, - SimonaService.Create(InitExtEvData(extEvData), key), - ) - scheduler.expectMsgType[ScheduleActivation] + evService ! Create(InitExtEvData(extEvData), key) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsgType[Completion] + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] - val evcs1 = TestProbe("evcs1") + val evcs1 = TestProbe[Any]("evcs1") - evcs1.send(evService, RegisterForEvDataMessage(evcs1UUID)) + evService ! RegisterForEvDataMessage(evcs1.ref.toClassic, evcs1UUID) evcs1.expectNoMessage() extEvData.sendExtMsg( @@ -678,11 +708,15 @@ class ExtEvDataServiceSpec Some(long2Long(0L)).toJava, ) ) - extSimAdapter.expectMsg(new ScheduleDataServiceMessage(evService)) - scheduler.send(evService, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(evService.toTyped)) + extSimAdapter.expectMessage( + new ScheduleDataServiceMessage(adapter.toClassic) + ) + evService ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor)) - evcs1.expectMsg(RegistrationSuccessfulMessage(evService.ref, Some(0L))) + evcs1.expectMessage( + RegistrationSuccessfulMessage(evService.ref, Some(0L)) + ) val arrivals = Map( evcs1UUID -> List[EvModel](evA).asJava, @@ -695,20 +729,20 @@ class ExtEvDataServiceSpec // ev service should receive movements msg at this moment // scheduler should receive schedule msg - extSimAdapter.expectMsgType[ScheduleDataServiceMessage] + extSimAdapter.expectMessageType[ScheduleDataServiceMessage] val tick = 0L // we trigger ev service - scheduler.send(evService, Activation(tick)) + evService ! Activation(tick) - val evsMessage1 = evcs1.expectMsgType[ProvideEvDataMessage] + val evsMessage1 = evcs1.expectMessageType[ProvideEvDataMessage] evsMessage1.tick shouldBe tick evsMessage1.data shouldBe ArrivingEvs( Seq(EvModelWrapper(evA)) ) - scheduler.expectMsg(Completion(evService.toTyped)) + scheduler.expectMessage(Completion(activationMsg.actor)) // no response expected extEvData.receiveTriggerQueue shouldBe empty diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala index be522fbc9c..0ff5f9353a 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala @@ -6,17 +6,11 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{ActorRef, ActorSystem, PoisonPill} -import org.apache.pekko.testkit.{TestActorRef, TestProbe} -import org.apache.pekko.util.Timeout -import com.typesafe.config.ConfigFactory import edu.ie3.datamodel.io.csv.CsvIndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.naming.FileNamingStrategy -import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation import edu.ie3.datamodel.io.source.TimeSeriesMappingSource import edu.ie3.datamodel.io.source.csv.CsvTimeSeriesMappingSource -import edu.ie3.datamodel.models.value.{SValue, Value} +import edu.ie3.datamodel.models.value.SValue import edu.ie3.simona.config.SimonaConfig.PrimaryDataCsvParams import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.{ CouchbaseParams, @@ -29,55 +23,68 @@ import edu.ie3.simona.exceptions.{ InitializationException, InvalidConfigParameterException, } -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationFailedMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ PrimaryServiceRegistrationMessage, WorkerRegistrationMessage, } -import edu.ie3.simona.service.SimonaService +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationFailedMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} +import edu.ie3.simona.service.ServiceStateData.ServiceConstantStateData import edu.ie3.simona.service.primary.PrimaryServiceProxy.{ InitPrimaryServiceProxyStateData, PrimaryServiceStateData, SourceRef, } -import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ - CsvInitPrimaryServiceStateData, - InitPrimaryServiceStateData, -} +import edu.ie3.simona.service.primary.PrimaryServiceWorker.CsvInitPrimaryServiceStateData import edu.ie3.simona.test.common.input.TimeSeriesTestData -import edu.ie3.simona.test.common.{AgentSpec, TestSpawnerClassic} +import edu.ie3.simona.test.common.{AgentTypedSpec, TestSpawnerTyped} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil +import org.apache.pekko.actor.testkit.typed.scaladsl.TestProbe +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.ActorContext +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps +import org.mockito.Mockito.when +import org.scalatest.Inside.inside import org.scalatest.PartialFunctionValues import org.scalatest.prop.TableDrivenPropertyChecks +import org.scalatestplus.mockito.MockitoSugar.mock +import org.slf4j.{Logger, LoggerFactory} import java.nio.file.{Path, Paths} import java.time.ZonedDateTime -import java.util.concurrent.TimeUnit -import java.util.{Objects, UUID} -import scala.concurrent.ExecutionContext.Implicits.global -import scala.util.{Failure, Success, Try} +import java.util.UUID +import scala.language.implicitConversions +import scala.util.{Failure, Success} class PrimaryServiceProxySpec - extends AgentSpec( - ActorSystem( - "PrimaryServiceProxySpec", - ConfigFactory - .parseString(""" - |pekko.loggers = ["org.apache.pekko.testkit.TestEventListener"] - |pekko.loglevel="OFF" - """.stripMargin), - ) - ) + extends AgentTypedSpec with TableDrivenPropertyChecks with PartialFunctionValues with TimeSeriesTestData - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): WrappedActivation = + WrappedActivation(msg) + + implicit val constantData: ServiceConstantStateData = + mock[ServiceConstantStateData] + implicit val log: Logger = LoggerFactory.getLogger("PrimaryServiceProxySpec") + implicit val ctx: ActorContext[_] = { + val m = mock[ActorContext[_]] + when(m.log).thenReturn(log) + m + } + // this works both on Windows and Unix systems val baseDirectoryPath: Path = Paths .get( @@ -127,7 +134,7 @@ class PrimaryServiceProxySpec mappingSource, ) - private val scheduler: TestProbe = TestProbe("scheduler") + private val scheduler = TestProbe[SchedulerMessage]("scheduler") "Testing a primary service config" should { "lead to complaining about too much source definitions" in { @@ -240,15 +247,11 @@ class PrimaryServiceProxySpec validPrimaryConfig, simulationStart, ) - val proxyRef: TestActorRef[PrimaryServiceProxy] = TestActorRef( - new PrimaryServiceProxy(scheduler.ref, initStateData, simulationStart) + val proxy: ActorRef[PrimaryDataMessage] = testKit.spawn( + PrimaryServiceProxy(scheduler.ref, initStateData) ) - val proxy: PrimaryServiceProxy = proxyRef.underlyingActor "Building state data from given config" should { - val prepareStateData = - PrivateMethod[Try[PrimaryServiceStateData]](Symbol("prepareStateData")) - "fail, in case no config is given" in { val maliciousConfig = PrimaryConfig( None, @@ -257,7 +260,7 @@ class PrimaryServiceProxySpec None, ) - proxy invokePrivate prepareStateData( + PrimaryServiceProxy.prepareStateData( maliciousConfig, simulationStart, ) match { @@ -277,7 +280,7 @@ class PrimaryServiceProxySpec None, ) - proxy invokePrivate prepareStateData( + PrimaryServiceProxy.prepareStateData( maliciousConfig, simulationStart, ) match { @@ -290,7 +293,7 @@ class PrimaryServiceProxySpec } "result in correct data" in { - proxy invokePrivate prepareStateData( + PrimaryServiceProxy.prepareStateData( validPrimaryConfig, simulationStart, ) match { @@ -342,53 +345,33 @@ class PrimaryServiceProxySpec "Sending initialization information to an uninitialized actor" should { "lead to a completion message without trigger requests" in { + proxy ! Activation(INIT_SIM_TICK) - scheduler.send(proxyRef, Activation(INIT_SIM_TICK)) + scheduler.expectMessageType[ScheduleActivation] - scheduler.expectMsg(Completion(proxyRef.toTyped)) + val completionMsg = scheduler.expectMessageType[Completion] + completionMsg.newTick shouldBe None } } "Spinning off a worker" should { - val initializeWorker = - PrivateMethod[Try[ActorRef]](Symbol("initializeWorker")) - - "successfully instantiate an actor within the actor system" in { - val classToWorkerRef = PrivateMethod[ActorRef](Symbol("classToWorkerRef")) - - val testClass = - classOf[ - SValue - ] // The class has to be child of edu.ie3.datamodel.models.value.Value - - val workerRef = proxy invokePrivate classToWorkerRef( - testClass, - workerId, - ) - Objects.nonNull(workerRef) shouldBe true - - /* Kill the worker, as we do not need it */ - workerRef ! PoisonPill - } - "successfully build initialization data for the worker" in { - val toInitData = PrivateMethod[Try[InitPrimaryServiceStateData]]( - Symbol("toInitData") - ) val metaInformation = new CsvIndividualTimeSeriesMetaInformation( metaPq, Paths.get("its_pq_" + uuidPq), ) - proxy invokePrivate toInitData( + PrimaryServiceProxy.toInitData( metaInformation, simulationStart, validPrimaryConfig, + classOf[SValue], ) match { case Success( CsvInitPrimaryServiceStateData( actualTimeSeriesUuid, actualSimulationStart, + actualValueClass, actualCsvSep, directoryPath, filePath, @@ -398,6 +381,7 @@ class PrimaryServiceProxySpec ) => actualTimeSeriesUuid shouldBe uuidPq actualSimulationStart shouldBe simulationStart + actualValueClass shouldBe classOf[SValue] actualCsvSep shouldBe csvSep directoryPath shouldBe baseDirectoryPath filePath shouldBe metaInformation.getFullFilePath @@ -422,7 +406,7 @@ class PrimaryServiceProxySpec None, None, ) - proxy invokePrivate initializeWorker( + PrimaryServiceProxy.initializeWorker( metaPq, simulationStart, maliciousPrimaryConfig, @@ -432,17 +416,6 @@ class PrimaryServiceProxySpec exception.getClass shouldBe classOf[InitializationException] exception.getMessage shouldBe "Unable to build init data for worker. Kill the uninitialized worker. Goodbye my friend!" exception.getCause.getMessage shouldBe s"Cannot build initialization data for a worker due to unsupported source config '$maliciousPrimaryConfig'." - - /* Check, if the worker has been killed, yet. */ - implicit val timeout: Timeout = Timeout(2, TimeUnit.SECONDS) - system.actorSelection("/user/" + workerId).resolveOne().onComplete { - case Failure(exception) => - logger - .debug("Worker actor couldn't be found. Reason: ", exception) - succeed - case Success(_) => - fail("Worker actor shouldn't be existing, but exists.") - } case Success(_) => fail( "Instantiating a worker with malicious primary config should fail." @@ -453,108 +426,91 @@ class PrimaryServiceProxySpec "succeed on fine input data" in { /* We "fake" the creation of the worker to infiltrate a test probe. This empowers us to check, if a matching init * message is sent to the worker */ - val worker = TestProbe("workerTestProbe") - val fakeProxyRef = - TestActorRef( - new PrimaryServiceProxy( - scheduler.ref, - initStateData, - simulationStart, - ) { - override protected def classToWorkerRef[V <: Value]( - valueClass: Class[V], - timeSeriesUuid: String, - ): ActorRef = worker.ref - - // needs to be overwritten as to make it available to the private method tester - @SuppressWarnings(Array("NoOpOverride")) - override protected def initializeWorker( - metaInformation: IndividualTimeSeriesMetaInformation, - simulationStart: ZonedDateTime, - primaryConfig: PrimaryConfig, - ): Try[ActorRef] = - super.initializeWorker( - metaInformation, - simulationStart, - primaryConfig, - ) - } - ) - val fakeProxy: PrimaryServiceProxy = fakeProxyRef.underlyingActor + val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") + val metaInformation = new CsvIndividualTimeSeriesMetaInformation( metaPq, Paths.get("its_pq_" + uuidPq), ) - scheduler.expectNoMessage() - - fakeProxy invokePrivate initializeWorker( + val sourceRef = SourceRef( metaInformation, - simulationStart, - validPrimaryConfig, - ) match { - case Success(workerRef) => - /* Check, if expected init message has been sent */ - workerRef shouldBe worker.ref - - inside(worker.expectMsgType[SimonaService.Create[_]]) { - case SimonaService.Create( - CsvInitPrimaryServiceStateData( - actualTimeSeriesUuid, - actualSimulationStart, - actualCsvSep, - directoryPath, - filePath, - fileNamingStrategy, - timePattern, - ), - _, - ) => - actualTimeSeriesUuid shouldBe uuidPq - actualSimulationStart shouldBe simulationStart - actualCsvSep shouldBe csvSep - directoryPath shouldBe baseDirectoryPath - filePath shouldBe metaInformation.getFullFilePath - classOf[FileNamingStrategy].isAssignableFrom( - fileNamingStrategy.getClass - ) shouldBe true - timePattern shouldBe TimeUtil.withDefaults.getDateTimeFormatter.toString - } + Some(worker.ref), + ) - // receiving schedule activation, don't know why but ok... - scheduler.expectMsgType[ScheduleActivation] + val modifiedInitStateData = initStateData.copy( + timeSeriesToSourceRef = Map(uuidPq -> sourceRef) + ) - /* Kill the worker aka. test probe */ - workerRef ! PoisonPill - succeed - case Failure(exception) => - fail( - "Spinning off a worker with correct input data should be successful, but failed with:", - exception, - ) + val fakeProxyRef = testKit.spawn( + PrimaryServiceProxy( + scheduler.ref, + modifiedInitStateData, + ) + ) + + scheduler.expectMessageType[ScheduleActivation] + + fakeProxyRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] + + fakeProxyRef ! Activation(0) + + inside(worker.expectMessageType[PrimaryDataMessage]) { + case Create( + CsvInitPrimaryServiceStateData( + actualTimeSeriesUuid, + actualSimulationStart, + actualValueClass, + actualCsvSep, + directoryPath, + filePath, + fileNamingStrategy, + timePattern, + ), + _, + ) => + actualTimeSeriesUuid shouldBe uuidPq + actualSimulationStart shouldBe simulationStart + actualValueClass shouldBe classOf[SValue] + actualCsvSep shouldBe csvSep + directoryPath shouldBe baseDirectoryPath + filePath shouldBe metaInformation.getFullFilePath + classOf[FileNamingStrategy].isAssignableFrom( + fileNamingStrategy.getClass + ) shouldBe true + timePattern shouldBe TimeUtil.withDefaults.getDateTimeFormatter.toString } + + // receiving schedule activation, don't know why but ok... + scheduler.expectMessageType[ScheduleActivation] + + testKit.stop(worker.ref) } } + private val dummyWorker = TestProbe[PrimaryDataMessage]("dummyWorker") + private val requestingAgent = TestProbe[Any]("agent") + "Updating state data" should { val updateStateData = PrivateMethod[PrimaryServiceStateData](Symbol("updateStateData")) "not work, if time series hasn't been covered before" in { val exception = intercept[IllegalArgumentException] { - proxy invokePrivate updateStateData( + PrimaryServiceProxy invokePrivate updateStateData( proxyStateData, UUID.fromString("394fd072-832c-4c36-869b-c574ee37afe1"), - self, + dummyWorker.ref, ) } exception.getMessage shouldBe "Cannot update entry for time series '394fd072-832c-4c36-869b-c574ee37afe1', as it hasn't been part of it before." } "work otherwise" in { - proxy invokePrivate updateStateData( + PrimaryServiceProxy invokePrivate updateStateData( proxyStateData, uuidPq, - self, + dummyWorker.ref, ) match { case PrimaryServiceStateData( modelToTimeSeries, @@ -566,7 +522,7 @@ class PrimaryServiceProxySpec modelToTimeSeries shouldBe proxyStateData.modelToTimeSeries timeSeriesToSourceRef shouldBe Map( uuidP -> SourceRef(metaP, None), - uuidPq -> SourceRef(metaPq, Some(self)), + uuidPq -> SourceRef(metaPq, Some(dummyWorker.ref)), ) simulationStart shouldBe proxyStateData.simulationStart primaryConfig shouldBe proxyStateData.primaryConfig @@ -576,35 +532,35 @@ class PrimaryServiceProxySpec } "Handling of a covered model" should { - val handleCoveredModel = PrivateMethod(Symbol("handleCoveredModel")) - "fail, if no information can be obtained from state data" in { val maliciousStateData = proxyStateData.copy(timeSeriesToSourceRef = Map.empty[UUID, SourceRef]) - proxy invokePrivate handleCoveredModel( + PrimaryServiceProxy.handleCoveredModel( modelUuid, uuidPq, maliciousStateData, - self, + dummyWorker.ref.toClassic, ) - expectMsg(RegistrationFailedMessage(proxyRef)) + dummyWorker.expectMessage(RegistrationFailedMessage(null)) } "forward the registration request, if worker is already known" in { val adaptedStateData = proxyStateData.copy( timeSeriesToSourceRef = Map( - uuidPq -> SourceRef(metaPq, Some(self)) + uuidPq -> SourceRef(metaPq, Some(dummyWorker.ref)) ) ) - proxy invokePrivate handleCoveredModel( + PrimaryServiceProxy.handleCoveredModel( modelUuid, uuidPq, adaptedStateData, - self, + requestingAgent.ref.toClassic, + ) + dummyWorker.expectMessage( + WorkerRegistrationMessage(requestingAgent.ref.toClassic) ) - expectMsg(WorkerRegistrationMessage(self)) } "fail, if worker cannot be spun off" in { @@ -617,97 +573,73 @@ class PrimaryServiceProxySpec ) ) - proxy invokePrivate handleCoveredModel( + PrimaryServiceProxy.handleCoveredModel( modelUuid, uuidPq, maliciousStateData, - self, + requestingAgent.ref.toClassic, ) - expectMsg(RegistrationFailedMessage(proxyRef)) + requestingAgent.expectMessage(RegistrationFailedMessage(null)) } "spin off a worker, if needed and forward the registration request" in { /* We once again fake the class, so that we can infiltrate a probe */ - val worker = TestProbe("workerTestProbe") - val fakeProxyRef = - TestActorRef( - new PrimaryServiceProxy( - scheduler.ref, - initStateData, - simulationStart, - ) { - override protected def initializeWorker( - metaInformation: IndividualTimeSeriesMetaInformation, - simulationStart: ZonedDateTime, - primaryConfig: PrimaryConfig, - ): Try[ActorRef] = Success(worker.ref) - - // needs to be overwritten as to make it available to the private method tester - @SuppressWarnings(Array("NoOpOverride")) - override protected def handleCoveredModel( - modelUuid: UUID, - timeSeriesUuid: UUID, - stateData: PrimaryServiceStateData, - requestingActor: ActorRef, - ): Unit = - super.handleCoveredModel( - modelUuid, - timeSeriesUuid, - stateData, - requestingActor, - ) - } - ) - val fakeProxy = fakeProxyRef.underlyingActor + val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") - fakeProxy invokePrivate handleCoveredModel( + PrimaryServiceProxy.handleCoveredModel( modelUuid, uuidPq, proxyStateData, - self, + requestingAgent.ref.toClassic, + ) + worker.expectMessage( + WorkerRegistrationMessage(requestingAgent.ref.toClassic) ) - worker.expectMsg(WorkerRegistrationMessage(self)) } } "Trying to register with a proxy" should { "fail, if there is no information for the requested model" in { val request = PrimaryServiceRegistrationMessage( - UUID.fromString("2850a2d6-4b70-43c9-b5cc-cd823a72d860") + requestingAgent.ref.toClassic, + UUID.fromString("2850a2d6-4b70-43c9-b5cc-cd823a72d860"), ) - proxyRef ! request - expectMsg(RegistrationFailedMessage(proxyRef)) + proxy ! request + requestingAgent.expectMessage(RegistrationFailedMessage(proxy)) } "succeed, if model is handled" in { /* We once again fake the class, so that we can infiltrate a probe */ - val worker = TestProbe("workerTestProbe") + val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") + + val modifiedInitStateData = initStateData.copy( + timeSeriesToSourceRef = + Map(modelUuid -> SourceRef(metaP, Some(worker.ref))) + ) + val fakeProxyRef = - TestActorRef( - new PrimaryServiceProxy( + testKit.spawn( + PrimaryServiceProxy( scheduler.ref, - initStateData, - simulationStart, - ) { - override protected def initializeWorker( - metaInformation: IndividualTimeSeriesMetaInformation, - simulationStart: ZonedDateTime, - primaryConfig: PrimaryConfig, - ): Try[ActorRef] = Success(worker.ref) - } + modifiedInitStateData, + ) ) + scheduler.expectMessageType[ScheduleActivation] + /* Initialize the fake proxy */ - scheduler.send( - fakeProxyRef, - Activation(INIT_SIM_TICK), - ) - scheduler.expectMsg(Completion(fakeProxyRef.toTyped)) + fakeProxyRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] /* Try to register with fake proxy */ - fakeProxyRef ! PrimaryServiceRegistrationMessage(modelUuid) - worker.expectMsg(WorkerRegistrationMessage(self)) + fakeProxyRef ! PrimaryServiceRegistrationMessage( + requestingAgent.ref.toClassic, + modelUuid, + ) + worker.expectMessage( + WorkerRegistrationMessage(requestingAgent.ref.toClassic) + ) } } } diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala index fee341c869..4a9b6f58a4 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala @@ -6,50 +6,49 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.actor.typed.scaladsl.adapter.{ - ClassicActorRefOps, - TypedActorRefOps, -} -import org.apache.pekko.testkit.{TestActorRef, TestProbe} import com.dimafeng.testcontainers.{ForAllTestContainer, PostgreSQLContainer} -import com.typesafe.config.ConfigFactory import edu.ie3.simona.config.SimonaConfig import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.SqlParams -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.WrappedActivation +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + ServiceMessageUniversal, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.service.primary.PrimaryServiceProxy.InitPrimaryServiceProxyStateData -import edu.ie3.simona.test.common.{AgentSpec, TestSpawnerClassic} +import edu.ie3.simona.test.common.{AgentTypedSpec, TestSpawnerTyped} import edu.ie3.simona.test.helper.TestContainerHelper import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + BehaviorTestKit, + TestProbe, +} +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import org.scalatest.BeforeAndAfterAll import org.testcontainers.utility.DockerImageName import java.util.UUID +import scala.language.implicitConversions class PrimaryServiceProxySqlIT - extends AgentSpec( - ActorSystem( - "PrimaryServiceWorkerSqlIT", - ConfigFactory - .parseString(""" - |pekko.loglevel="OFF" - """.stripMargin), - ) - ) + extends AgentTypedSpec with ForAllTestContainer with BeforeAndAfterAll with TestContainerHelper - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): ServiceMessageUniversal = + WrappedActivation(msg) override val container: PostgreSQLContainer = PostgreSQLContainer( DockerImageName.parse("postgres:14.2") @@ -80,7 +79,7 @@ class PrimaryServiceProxySqlIT container.close() } - private val scheduler = TestProbe("Scheduler") + private val scheduler = TestProbe[SchedulerMessage]("Scheduler") // function definition because postgres parameters are only available after initialization private def sqlParams: SqlParams = SqlParams( @@ -91,7 +90,7 @@ class PrimaryServiceProxySqlIT timePattern = "yyyy-MM-dd'T'HH:mm:ssX", ) - private def createProxy(): TestActorRef[PrimaryServiceProxy] = { + private def createProxy(): BehaviorTestKit[PrimaryDataMessage] = { val initData = InitPrimaryServiceProxyStateData( SimonaConfig.Simona.Input.Primary( None, @@ -102,11 +101,10 @@ class PrimaryServiceProxySqlIT simulationStart, ) - TestActorRef( - PrimaryServiceProxy.props( + BehaviorTestKit( + PrimaryServiceProxy( scheduler.ref, initData, - simulationStart, ) ) } @@ -114,64 +112,58 @@ class PrimaryServiceProxySqlIT "A primary service proxy with SQL source" should { "initialize when given proper SQL input configs" in { - val proxyRef = createProxy() + val proxyRef = createProxy().ref - scheduler.send(proxyRef, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(proxyRef.toTyped)) + proxyRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] } "handle participant request correctly if participant has primary data" in { - val systemParticipantProbe = TestProbe("SystemParticipant") + val systemParticipantProbe = TestProbe[Any]("SystemParticipant") - val proxyRef = createProxy() + val proxyRef = createProxy().ref - scheduler.send(proxyRef, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(proxyRef.toTyped)) + proxyRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] - systemParticipantProbe.send( - proxyRef, - PrimaryServiceRegistrationMessage( - UUID.fromString("b86e95b0-e579-4a80-a534-37c7a470a409") - ), + proxyRef ! PrimaryServiceRegistrationMessage( + systemParticipantProbe.ref.toClassic, + UUID.fromString("b86e95b0-e579-4a80-a534-37c7a470a409"), ) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - val initActivation = scheduler.expectMsgType[ScheduleActivation] + val initActivation = scheduler.expectMessageType[ScheduleActivation] initActivation.tick shouldBe INIT_SIM_TICK initActivation.unlockKey should not be empty // extract ref to the worker that the proxy created val workerRef = initActivation.actor - scheduler.send( - workerRef.toClassic, - Activation(INIT_SIM_TICK), - ) + workerRef ! Activation(INIT_SIM_TICK) - scheduler.expectMsg(Completion(workerRef, Some(0))) + scheduler.expectMessage(Completion(workerRef, Some(0))) - systemParticipantProbe.expectMsg( - RegistrationSuccessfulMessage(workerRef.toClassic, Some(0L)) + systemParticipantProbe.expectMessage( + RegistrationSuccessfulMessage(workerRef, Some(0L)) ) } "handle participant request correctly if participant does not have primary data" in { - val systemParticipantProbe = TestProbe("SystemParticipant") + val systemParticipantProbe = TestProbe[Any]("SystemParticipant") - val proxyRef = createProxy() + val proxyRef = createProxy().ref - scheduler.send(proxyRef, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(proxyRef.toTyped)) + proxyRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessageType[Completion] - systemParticipantProbe.send( - proxyRef, - PrimaryServiceRegistrationMessage( - UUID.fromString("db958617-e49d-44d3-b546-5f7b62776afd") - ), + proxyRef ! PrimaryServiceRegistrationMessage( + systemParticipantProbe.ref.toClassic, + UUID.fromString("db958617-e49d-44d3-b546-5f7b62776afd"), ) scheduler.expectNoMessage() - systemParticipantProbe.expectMsg(RegistrationFailedMessage(proxyRef)) + systemParticipantProbe.expectMessage(RegistrationFailedMessage(proxyRef)) } } } 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 c08f189b79..a00d7c64ee 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSpec.scala @@ -6,59 +6,77 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.testkit.{TestActorRef, TestProbe} -import com.typesafe.config.ConfigFactory +import com.typesafe.scalalogging.LazyLogging import edu.ie3.datamodel.io.factory.timeseries.TimeBasedSimpleValueFactory import edu.ie3.datamodel.io.naming.FileNamingStrategy import edu.ie3.datamodel.io.source.csv.CsvTimeSeriesSource import edu.ie3.datamodel.models.StandardUnits -import edu.ie3.datamodel.models.value.{HeatDemandValue, PValue} +import edu.ie3.datamodel.models.value.{HeatDemandValue, PValue, SValue} import edu.ie3.simona.agent.participant.data.Data.PrimaryData.ActivePower -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.WorkerRegistrationMessage +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ + ProvidePrimaryDataMessage, + WorkerRegistrationMessage, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, +} import edu.ie3.simona.ontology.messages.services.WeatherMessage.RegisterForWeatherMessage +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + ServiceMessageUniversal, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock -import edu.ie3.simona.service.SimonaService import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ CsvInitPrimaryServiceStateData, InitPrimaryServiceStateData, PrimaryServiceInitializedStateData, - ProvidePrimaryDataMessage, } import edu.ie3.simona.service.primary.PrimaryServiceWorkerSpec.WrongInitPrimaryServiceStateData -import edu.ie3.simona.test.common.{AgentSpec, TestSpawnerClassic} +import edu.ie3.simona.test.common.TestSpawnerTyped import edu.ie3.simona.test.common.input.TimeSeriesTestData +import edu.ie3.simona.test.matchers.SquantsMatchers import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + ScalaTestWithActorTestKit, + TestProbe, +} +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps +import org.scalatest.Inside.inside +import org.scalatest.PrivateMethodTester +import org.scalatest.wordspec.AnyWordSpecLike +import org.slf4j.{Logger, LoggerFactory} import squants.energy.{Kilowatts, Watts} import tech.units.indriya.quantity.Quantities import java.nio.file.{Path, Paths} import java.time.ZonedDateTime import java.util.UUID +import scala.language.implicitConversions import scala.util.{Failure, Success} class PrimaryServiceWorkerSpec - extends AgentSpec( - ActorSystem( - "PrimaryServiceWorkerSpec", - ConfigFactory - .parseString(""" - |pekko.loglevel="OFF" - """.stripMargin), - ) - ) + extends ScalaTestWithActorTestKit + with AnyWordSpecLike + with SquantsMatchers + with PrivateMethodTester + with LazyLogging with TimeSeriesTestData - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): ServiceMessageUniversal = + WrappedActivation(msg) + // this works both on Windows and Unix systems val baseDirectoryPath: Path = Paths .get( @@ -69,8 +87,9 @@ class PrimaryServiceWorkerSpec .toURI ) - val validInitData: CsvInitPrimaryServiceStateData = + val validInitData: CsvInitPrimaryServiceStateData[PValue] = CsvInitPrimaryServiceStateData( + valueClass = classOf[PValue], timeSeriesUuid = uuidP, csvSep = ";", directoryPath = baseDirectoryPath, @@ -84,16 +103,14 @@ class PrimaryServiceWorkerSpec private implicit val powerTolerance: squants.Power = Watts(0.1) "A primary service actor" should { - val scheduler = TestProbe("scheduler") + val scheduler = TestProbe[SchedulerMessage]("scheduler") + val systemParticipant = TestProbe[Any]("dummySystemParticipant") - val serviceRef = - TestActorRef( - new PrimaryServiceWorker[PValue]( - scheduler.ref, - classOf[PValue], - ) - ) - val service = serviceRef.underlyingActor + val service = new PrimaryServiceWorker() + implicit val serviceRef: ActorRef[PrimaryDataMessage] = + testKit.spawn(PrimaryServiceWorker(scheduler.ref)) + implicit val log: Logger = + LoggerFactory.getLogger(classOf[PrimaryServiceWorkerSpec]) "refuse instantiation on wrong init data" in { val maliciousInitData = WrongInitPrimaryServiceStateData() @@ -135,7 +152,8 @@ class PrimaryServiceWorkerSpec // time series exists, but is malformed val tsUuid = UUID.fromString("3fbfaa97-cff4-46d4-95ba-a95665e87c27") - val maliciousInitData = CsvInitPrimaryServiceStateData( + val maliciousInitData = CsvInitPrimaryServiceStateData[SValue]( + valueClass = classOf[SValue], timeSeriesUuid = tsUuid, simulationStart = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"), @@ -183,41 +201,42 @@ class PrimaryServiceWorkerSpec } "init the service actor" in { - val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled + val key = ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled - scheduler.send( - serviceRef, - SimonaService.Create(validInitData, key), - ) - scheduler.expectMsg( - ScheduleActivation(serviceRef.toTyped, INIT_SIM_TICK, Some(key)) - ) + serviceRef ! Create(validInitData, key) - scheduler.send(serviceRef, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(serviceRef.toTyped, Some(0))) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] + activationMsg.tick shouldBe INIT_SIM_TICK + activationMsg.unlockKey shouldBe Some(key) + + serviceRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor, Some(0))) } "refuse registration for wrong registration request" in { - serviceRef ! RegisterForWeatherMessage(51.4843281, 7.4116482) - expectNoMessage() + serviceRef ! RegisterForWeatherMessage( + systemParticipant.ref.toClassic, + 51.4843281, + 7.4116482, + ) + systemParticipant.expectNoMessage() } - val systemParticipant: TestProbe = TestProbe("dummySystemParticipant") "correctly register a forwarded request" in { - serviceRef ! WorkerRegistrationMessage(systemParticipant.ref) + serviceRef ! WorkerRegistrationMessage(systemParticipant.ref.toClassic) /* Wait for request approval */ - systemParticipant.expectMsg( + systemParticipant.expectMessage( RegistrationSuccessfulMessage(serviceRef, Some(0L)) ) /* We cannot directly check, if the requesting actor is among the subscribers, therefore we ask the actor to * provide data to all subscribed actors and check, if the subscribed probe gets one */ - scheduler.send(serviceRef, Activation(0)) - scheduler.expectMsgType[Completion] - systemParticipant.expectMsgAllClassOf(classOf[ProvidePrimaryDataMessage]) + serviceRef ! Activation(0) + scheduler.expectMessageType[Completion] + systemParticipant.expectMessageType[ProvidePrimaryDataMessage] } /* At this point, the test (self) is registered with the service */ @@ -235,21 +254,15 @@ class PrimaryServiceWorkerSpec classOf[PValue], new TimeBasedSimpleValueFactory[PValue](classOf[PValue]), ), - Vector(self), + Vector(systemParticipant.ref.toClassic), ) "correctly distribute proper primary data" in { - val announcePrimaryData = PrivateMethod[ - ( - PrimaryServiceInitializedStateData[PValue], - Option[Long], - ) - ](Symbol("announcePrimaryData")) val tick = 0L val primaryData = ActivePower(Kilowatts(50.0)) val serviceStateData = validStateData.copy() - service invokePrivate announcePrimaryData( + service.announcePrimaryData( tick, primaryData, serviceStateData, @@ -271,7 +284,7 @@ class PrimaryServiceWorkerSpec maybeNextTick shouldBe Some(900L) } /* Check, if correct message is sent */ - expectMsgClass(classOf[ProvidePrimaryDataMessage]) match { + systemParticipant.expectMessageType[ProvidePrimaryDataMessage] match { case ProvidePrimaryDataMessage( actualTick, actualServiceRef, @@ -285,13 +298,6 @@ class PrimaryServiceWorkerSpec } } - val processDataAndAnnounce = PrivateMethod[ - ( - PrimaryServiceInitializedStateData[PValue], - Option[Long], - ) - ](Symbol("processDataAndAnnounce")) - "not sent anything, if conversion to primary data failed" in { val tick = 0L val maliciousValue = new HeatDemandValue( @@ -301,7 +307,7 @@ class PrimaryServiceWorkerSpec activationTicks = SortedDistinctSeq(Seq(900L)) ) - service invokePrivate processDataAndAnnounce( + service.processDataAndAnnounce( tick, maliciousValue, stateData, @@ -319,7 +325,7 @@ class PrimaryServiceWorkerSpec nextActivationTick shouldBe Some(900L) maybeNextTick shouldBe Some(900L) } - expectNoMessage() + systemParticipant.expectNoMessage() } "announce information, if conversion succeeds" in { @@ -330,7 +336,7 @@ class PrimaryServiceWorkerSpec activationTicks = SortedDistinctSeq(Seq(900L)) ) - service invokePrivate processDataAndAnnounce( + service.processDataAndAnnounce( tick, value, serviceStateData, @@ -350,7 +356,7 @@ class PrimaryServiceWorkerSpec /* Rest has already been tested */ } - expectMsg( + systemParticipant.expectMessage( ProvidePrimaryDataMessage( tick, serviceRef, @@ -362,18 +368,21 @@ class PrimaryServiceWorkerSpec "should not announce anything, if time step is not covered in source" in { - scheduler.send(serviceRef, Activation(200)) + serviceRef ! Activation(200) - scheduler.expectMsg(Completion(serviceRef.toTyped, Some(1800))) - expectNoMessage() + val completionMsg = scheduler.expectMessageType[Completion] + completionMsg.newTick shouldBe Some(1800) + + systemParticipant.expectNoMessage() } "should announce something, if the time step is covered in source" in { - scheduler.send(serviceRef, Activation(900)) - scheduler.expectMsg(Completion(serviceRef.toTyped)) + serviceRef ! Activation(900) + val completionMsg = scheduler.expectMessageType[Completion] + completionMsg.newTick shouldBe None inside( - systemParticipant.expectMsgClass(classOf[ProvidePrimaryDataMessage]) + systemParticipant.expectMessageType[ProvidePrimaryDataMessage] ) { case ProvidePrimaryDataMessage( tick, @@ -398,13 +407,15 @@ object PrimaryServiceWorkerSpec { final case class WrongInitPrimaryServiceStateData( override val simulationStart: ZonedDateTime, override val timeSeriesUuid: UUID, - ) extends InitPrimaryServiceStateData + override val valueClass: Class[PValue], + ) extends InitPrimaryServiceStateData[PValue] object WrongInitPrimaryServiceStateData { def apply(): WrongInitPrimaryServiceStateData = new WrongInitPrimaryServiceStateData( ZonedDateTime.now(), UUID.randomUUID(), + classOf[PValue], ) } } diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSqlIT.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSqlIT.scala index 9a50b4fce9..0c70a5cf3d 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSqlIT.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceWorkerSqlIT.scala @@ -6,11 +6,7 @@ package edu.ie3.simona.service.primary -import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.testkit.{TestActorRef, TestProbe} import com.dimafeng.testcontainers.{ForAllTestContainer, PostgreSQLContainer} -import com.typesafe.config.ConfigFactory import edu.ie3.datamodel.io.naming.DatabaseNamingStrategy import edu.ie3.datamodel.models.value.{HeatAndSValue, PValue} import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ @@ -18,48 +14,50 @@ import edu.ie3.simona.agent.participant.data.Data.PrimaryData.{ ComplexPowerAndHeat, } import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.SqlParams -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.RegistrationSuccessfulMessage -import edu.ie3.simona.ontology.messages.services.ServiceMessage.WorkerRegistrationMessage -import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey -import edu.ie3.simona.service.SimonaService -import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ +import edu.ie3.simona.ontology.messages.services.PrimaryDataMessage.{ ProvidePrimaryDataMessage, - SqlInitPrimaryServiceStateData, + WorkerRegistrationMessage, } +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, +} +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} +import edu.ie3.simona.scheduler.ScheduleLock.{LockMsg, ScheduleKey} +import edu.ie3.simona.service.primary.PrimaryServiceWorker.SqlInitPrimaryServiceStateData import edu.ie3.simona.test.common.input.TimeSeriesTestData -import edu.ie3.simona.test.common.{AgentSpec, TestSpawnerClassic} +import edu.ie3.simona.test.common.{AgentTypedSpec, TestSpawnerTyped} import edu.ie3.simona.test.helper.TestContainerHelper import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil import edu.ie3.util.scala.quantities.Kilovars +import org.apache.pekko.actor.testkit.typed.scaladsl.TestProbe +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import org.scalatest.BeforeAndAfterAll import org.scalatest.prop.TableDrivenPropertyChecks import org.testcontainers.utility.DockerImageName import squants.energy.Kilowatts import java.util.UUID +import scala.language.implicitConversions class PrimaryServiceWorkerSqlIT - extends AgentSpec( - ActorSystem( - "PrimaryServiceWorkerSqlIT", - ConfigFactory - .parseString(""" - |pekko.loglevel="OFF" - """.stripMargin), - ) - ) + extends AgentTypedSpec with ForAllTestContainer with BeforeAndAfterAll with TableDrivenPropertyChecks with TimeSeriesTestData with TestContainerHelper - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): ServiceMessageUniversal = + WrappedActivation(msg) override val container: PostgreSQLContainer = PostgreSQLContainer( DockerImageName.parse("postgres:14.2") @@ -89,22 +87,19 @@ class PrimaryServiceWorkerSqlIT "A primary service actor with SQL source" should { "initialize and send out data when activated" in { - val scheduler = TestProbe("Scheduler") - val lock = TestProbe("lock") + val scheduler = TestProbe[SchedulerMessage]("Scheduler") + val lock = TestProbe[LockMsg]("lock") val cases = Table( ( - "service", + "valueClass", "uuid", "firstTick", "firstData", "maybeNextTick", ), ( - PrimaryServiceWorker.props( - scheduler.ref, - classOf[HeatAndSValue], - ), + classOf[HeatAndSValue], uuidPqh, 0L, ComplexPowerAndHeat( @@ -115,10 +110,7 @@ class PrimaryServiceWorkerSqlIT Some(900L), ), ( - PrimaryServiceWorker.props( - scheduler.ref, - classOf[PValue], - ), + classOf[PValue], uuidP, 0L, ActivePower( @@ -130,17 +122,18 @@ class PrimaryServiceWorkerSqlIT forAll(cases) { ( - service, + valueClass, uuid, firstTick, firstData, maybeNextTick, ) => - val serviceRef = TestActorRef(service) + val serviceRef = testKit.spawn(PrimaryServiceWorker(scheduler.ref)) val initData = SqlInitPrimaryServiceStateData( uuid, simulationStart, + valueClass, SqlParams( jdbcUrl = container.jdbcUrl, userName = container.username, @@ -151,32 +144,33 @@ class PrimaryServiceWorkerSqlIT new DatabaseNamingStrategy(), ) - val key1 = ScheduleKey(lock.ref.toTyped, UUID.randomUUID()) - scheduler.send( - serviceRef, - SimonaService.Create(initData, key1), - ) - scheduler.expectMsg( - ScheduleActivation(serviceRef.toTyped, INIT_SIM_TICK, Some(key1)) + val key1 = ScheduleKey(lock.ref, UUID.randomUUID()) + serviceRef ! Create(initData, key1) + + val scheduleActivationMsg = + scheduler.expectMessageType[ScheduleActivation] + scheduleActivationMsg.tick shouldBe INIT_SIM_TICK + scheduleActivationMsg.unlockKey shouldBe Some(key1) + + serviceRef ! Activation(INIT_SIM_TICK) + scheduler.expectMessage( + Completion(scheduleActivationMsg.actor, Some(firstTick)) ) - scheduler.send(serviceRef, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(serviceRef.toTyped, Some(firstTick))) + val participant = TestProbe[Any]() - val participant = TestProbe() + serviceRef ! WorkerRegistrationMessage(participant.ref.toClassic) - participant.send( - serviceRef, - WorkerRegistrationMessage(participant.ref), - ) - participant.expectMsg( + participant.expectMessage( RegistrationSuccessfulMessage(serviceRef, Some(firstTick)) ) - scheduler.send(serviceRef, Activation(firstTick)) - scheduler.expectMsg(Completion(serviceRef.toTyped, maybeNextTick)) + serviceRef ! Activation(firstTick) + scheduler.expectMessage( + Completion(scheduleActivationMsg.actor, maybeNextTick) + ) - val dataMsg = participant.expectMsgType[ProvidePrimaryDataMessage] + val dataMsg = participant.expectMessageType[ProvidePrimaryDataMessage] dataMsg.tick shouldBe firstTick dataMsg.data shouldBe firstData dataMsg.nextDataTick shouldBe maybeNextTick diff --git a/src/test/scala/edu/ie3/simona/service/weather/WeatherServiceSpec.scala b/src/test/scala/edu/ie3/simona/service/weather/WeatherServiceSpec.scala index cff17ec153..7bce795a75 100644 --- a/src/test/scala/edu/ie3/simona/service/weather/WeatherServiceSpec.scala +++ b/src/test/scala/edu/ie3/simona/service/weather/WeatherServiceSpec.scala @@ -9,58 +9,53 @@ package edu.ie3.simona.service.weather import com.typesafe.config.ConfigFactory import com.typesafe.scalalogging.LazyLogging import edu.ie3.simona.config.SimonaConfig -import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.{ RegistrationFailedMessage, RegistrationSuccessfulMessage, } +import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ + Create, + WrappedActivation, +} import edu.ie3.simona.ontology.messages.services.WeatherMessage._ +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock -import edu.ie3.simona.service.SimonaService import edu.ie3.simona.service.weather.WeatherService.InitWeatherServiceStateData import edu.ie3.simona.service.weather.WeatherSource.AgentCoordinates -import edu.ie3.simona.test.common.{ - ConfigTestData, - TestKitWithShutdown, - TestSpawnerClassic, -} +import edu.ie3.simona.test.common.{ConfigTestData, TestSpawnerTyped} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil import edu.ie3.util.scala.quantities.WattsPerSquareMeter -import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.testkit.{ - EventFilter, - ImplicitSender, - TestActorRef, +import org.apache.pekko.actor.testkit.typed.CapturedLogEvent +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + BehaviorTestKit, + ScalaTestWithActorTestKit, TestProbe, } +import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps import org.scalatest.PrivateMethodTester import org.scalatest.wordspec.AnyWordSpecLike +import org.slf4j.event.Level import squants.motion.MetersPerSecond import squants.thermal.Celsius +import scala.language.implicitConversions + class WeatherServiceSpec - extends TestKitWithShutdown( - ActorSystem( - "WeatherServiceSpec", - ConfigFactory - .parseString(""" - |pekko.loggers = ["org.apache.pekko.testkit.TestEventListener"] - |pekko.loglevel = "INFO" - """.stripMargin), - ) - ) - with ImplicitSender + extends ScalaTestWithActorTestKit with AnyWordSpecLike with PrivateMethodTester with LazyLogging with ConfigTestData - with TestSpawnerClassic { + with TestSpawnerTyped { + + implicit def wrap(msg: Activation): ServiceMessageUniversal = + WrappedActivation(msg) // setup config for scheduler private val config = ConfigFactory @@ -91,95 +86,85 @@ class WeatherServiceSpec private val validCoordinate: AgentCoordinates = AgentCoordinates(52.02083574, 7.40110716) - private val scheduler = TestProbe("scheduler") + private val scheduler = TestProbe[SchedulerMessage]("scheduler") + + private val agent = TestProbe[Any]("agent") // build the weather service - private val weatherActor: TestActorRef[WeatherService] = TestActorRef( - new WeatherService( - scheduler.ref, - TimeUtil.withDefaults.toZonedDateTime( - simonaConfig.simona.time.startDateTime - ), - TimeUtil.withDefaults.toZonedDateTime( - simonaConfig.simona.time.endDateTime - ), - 4, - ) + private val weatherActor = testKit.spawn( + WeatherService(scheduler.ref) ) "A weather service" must { "receive correct completion message after initialisation" in { val key = - ScheduleLock.singleKey(TSpawner, scheduler.ref.toTyped, INIT_SIM_TICK) - scheduler.expectMsgType[ScheduleActivation] // lock activation scheduled - - scheduler.send( - weatherActor, - SimonaService.Create( - InitWeatherServiceStateData( - simonaConfig.simona.input.weather.datasource + ScheduleLock.singleKey(TSpawner, scheduler.ref, INIT_SIM_TICK) + scheduler + .expectMessageType[ScheduleActivation] // lock activation scheduled + + weatherActor ! Create( + InitWeatherServiceStateData( + simonaConfig.simona.input.weather.datasource, + TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.startDateTime + ), + TimeUtil.withDefaults.toZonedDateTime( + simonaConfig.simona.time.endDateTime ), - key, ), + key, ) - scheduler.expectMsg( - ScheduleActivation(weatherActor.toTyped, INIT_SIM_TICK, Some(key)) - ) - scheduler.send(weatherActor, Activation(INIT_SIM_TICK)) - scheduler.expectMsg(Completion(weatherActor.toTyped, Some(0))) + val activationMsg = scheduler.expectMessageType[ScheduleActivation] + activationMsg.tick shouldBe INIT_SIM_TICK + activationMsg.unlockKey shouldBe Some(key) + + weatherActor ! Activation(INIT_SIM_TICK) + scheduler.expectMessage(Completion(activationMsg.actor, Some(0))) } "announce failed weather registration on invalid coordinate" in { - EventFilter - .error( - pattern = - "\\[.*] Unable to obtain necessary information to register for coordinate AgentCoordinates\\(180\\.5,90\\.5\\)\\.", - occurrences = 1, - ) - .intercept { - weatherActor ! RegisterForWeatherMessage( - invalidCoordinate.latitude, - invalidCoordinate.longitude, - ) - } - - expectMsg(RegistrationFailedMessage(weatherActor)) + weatherActor ! RegisterForWeatherMessage( + agent.ref.toClassic, + invalidCoordinate.latitude, + invalidCoordinate.longitude, + ) + + agent.expectMessage(RegistrationFailedMessage(weatherActor)) } "announce, that a valid coordinate is registered" in { /* The successful registration stems from the test above */ weatherActor ! RegisterForWeatherMessage( + agent.ref.toClassic, validCoordinate.latitude, validCoordinate.longitude, ) - expectMsg(RegistrationSuccessfulMessage(weatherActor.ref, Some(0L))) + agent.expectMessage( + RegistrationSuccessfulMessage(weatherActor, Some(0L)) + ) } "recognize, that a valid coordinate yet is registered" in { /* The successful registration stems from the test above */ - EventFilter - .warning( - pattern = "Sending actor Actor\\[.*] is already registered", - occurrences = 1, - ) - .intercept { - weatherActor ! RegisterForWeatherMessage( - validCoordinate.latitude, - validCoordinate.longitude, - ) - } - expectNoMessage() + weatherActor ! RegisterForWeatherMessage( + agent.ref.toClassic, + validCoordinate.latitude, + validCoordinate.longitude, + ) + + agent.expectNoMessage() } "send out correct weather information upon activity start trigger and request the triggering for the next tick" in { /* Send out an activity start trigger as the scheduler */ - scheduler.send(weatherActor, Activation(0)) + weatherActor ! Activation(0) - scheduler.expectMsg(Completion(weatherActor.toTyped, Some(3600))) + val activationMsg = scheduler.expectMessageType[Completion] + activationMsg.newTick shouldBe Some(3600) - expectMsg( + agent.expectMessage( ProvideWeatherMessage( 0, weatherActor, @@ -197,11 +182,14 @@ class WeatherServiceSpec "sends out correct weather information when triggered again and does not as for triggering, if the end is reached" in { /* Send out an activity start trigger as the scheduler */ - scheduler.send(weatherActor, Activation(3600)) + weatherActor ! Activation(3600) + + val activationMsg = scheduler.expectMessageType[Completion] + activationMsg.newTick shouldBe None - scheduler.expectMsg(Completion(weatherActor.toTyped)) + (Completion(activationMsg.actor)) - expectMsg( + agent.expectMessage( ProvideWeatherMessage( 3600, weatherActor, diff --git a/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala b/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala index 9d1140be17..090e0bb7e6 100644 --- a/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala +++ b/src/test/scala/edu/ie3/simona/sim/SimonaSimSpec.scala @@ -18,6 +18,10 @@ import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} import edu.ie3.simona.main.RunSimona.SimonaEnded import edu.ie3.simona.ontology.messages.SchedulerMessage import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.scheduler.TimeAdvancer import edu.ie3.simona.scheduler.core.Core.CoreFactory import edu.ie3.simona.scheduler.core.RegularSchedulerCore @@ -32,7 +36,6 @@ import org.apache.pekko.actor.testkit.typed.scaladsl.{ import org.apache.pekko.actor.typed.scaladsl.adapter._ import org.apache.pekko.actor.typed.scaladsl.{ActorContext, Behaviors} import org.apache.pekko.actor.typed.{ActorRef, Behavior} -import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.nio.file.Path import java.util.UUID @@ -420,14 +423,14 @@ object SimonaSimSpec { override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = - context.spawn(empty, uniqueName("primaryService")).toClassic + ): ActorRef[PrimaryDataMessage] = + context.spawn(empty, uniqueName("primaryService")) override def weatherService( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = - context.spawn(empty, uniqueName("weatherService")).toClassic + ): ActorRef[WeatherMessage] = + context.spawn(empty, uniqueName("weatherService")) override def timeAdvancer( context: ActorContext[_], diff --git a/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala b/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala index 0428ed765b..8cd5e4459b 100644 --- a/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala +++ b/src/test/scala/edu/ie3/simona/sim/setup/SimonaSetupSpec.scala @@ -16,6 +16,10 @@ import edu.ie3.simona.agent.grid.GridAgent import edu.ie3.simona.event.listener.{ResultEventListener, RuntimeEventListener} import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} import edu.ie3.simona.ontology.messages.SchedulerMessage +import edu.ie3.simona.ontology.messages.services.{ + PrimaryDataMessage, + WeatherMessage, +} import edu.ie3.simona.scheduler.TimeAdvancer import edu.ie3.simona.scheduler.core.Core.CoreFactory import edu.ie3.simona.scheduler.core.RegularSchedulerCore @@ -24,7 +28,6 @@ import edu.ie3.simona.test.common.UnitSpec import edu.ie3.simona.test.common.model.grid.SubGridGateMokka import org.apache.pekko.actor.typed.ActorRef import org.apache.pekko.actor.typed.scaladsl.ActorContext -import org.apache.pekko.actor.{ActorRef => ClassicRef} import java.nio.file.Path import java.util.UUID @@ -50,12 +53,16 @@ class SimonaSetupSpec extends UnitSpec with SimonaSetup with SubGridGateMokka { override def primaryServiceProxy( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = throw new NotImplementedException("This is a dummy setup") + ): ActorRef[PrimaryDataMessage] = throw new NotImplementedException( + "This is a dummy setup" + ) override def weatherService( context: ActorContext[_], scheduler: ActorRef[SchedulerMessage], - ): ClassicRef = throw new NotImplementedException("This is a dummy setup") + ): ActorRef[WeatherMessage] = throw new NotImplementedException( + "This is a dummy setup" + ) override def extSimulations( context: ActorContext[_], diff --git a/src/test/scala/edu/ie3/simona/test/common/AgentSpec.scala b/src/test/scala/edu/ie3/simona/test/common/AgentSpec.scala index 8c39b41096..eea4a24889 100644 --- a/src/test/scala/edu/ie3/simona/test/common/AgentSpec.scala +++ b/src/test/scala/edu/ie3/simona/test/common/AgentSpec.scala @@ -7,7 +7,7 @@ package edu.ie3.simona.test.common import org.apache.pekko.actor.{ActorRef, ActorSystem} -import org.apache.pekko.testkit.ImplicitSender +import org.apache.pekko.testkit.{ImplicitSender, TestProbe} import com.typesafe.scalalogging.LazyLogging import org.scalatest.PrivateMethodTester import org.scalatest.matchers.should @@ -26,5 +26,7 @@ class AgentSpec(actorSystem: ActorSystem) with PrivateMethodTester with LazyLogging { + val noSender: ActorRef = TestProbe("any").ref + val systemListener: Iterable[ActorRef] = Iterable.empty } diff --git a/src/test/scala/edu/ie3/simona/test/common/AgentTypedSpec.scala b/src/test/scala/edu/ie3/simona/test/common/AgentTypedSpec.scala new file mode 100644 index 0000000000..2f104947e1 --- /dev/null +++ b/src/test/scala/edu/ie3/simona/test/common/AgentTypedSpec.scala @@ -0,0 +1,26 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.test.common + +import com.typesafe.scalalogging.LazyLogging +import org.apache.pekko.actor.ActorRef +import org.apache.pekko.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit +import org.scalatest.PrivateMethodTester +import org.scalatest.matchers.should +import org.scalatest.wordspec.AnyWordSpecLike + +/** Class to help building tests for agents + */ +class AgentTypedSpec + extends ScalaTestWithActorTestKit + with AnyWordSpecLike + with should.Matchers + with PrivateMethodTester + with LazyLogging { + + val systemListener: Iterable[ActorRef] = Iterable.empty +} From dc97350b9d831859f3f70ad27cf50208fab2baf9 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Fri, 20 Dec 2024 13:26:40 +0100 Subject: [PATCH 2/2] Fixing some failing tests. --- .../ie3/simona/service/ExtDataSupport.scala | 6 +- .../ie3/simona/service/SimonaService.scala | 2 +- .../service/primary/PrimaryServiceProxy.scala | 8 +- .../service/ev/ExtEvDataServiceSpec.scala | 17 ++- .../primary/PrimaryServiceProxySpec.scala | 121 ++++++++++-------- .../primary/PrimaryServiceProxySqlIT.scala | 31 +++-- 6 files changed, 104 insertions(+), 81 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala index 77faa4bfa1..2526cb3454 100644 --- a/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala +++ b/src/main/scala/edu/ie3/simona/service/ExtDataSupport.scala @@ -31,18 +31,18 @@ trait ExtDataSupport[ case (_, WrappedExternalMessage(extMsg)) => val updatedStateData = handleDataMessage(extMsg)(stateData) - buffer.unstashAll(idleInternal(updatedStateData, constantData, buffer)) + buffer.unstashAll(idle(updatedStateData, constantData, buffer)) case (_, extResponseMsg: EvResponseMessage) => val updatedStateData = handleDataResponseMessage(extResponseMsg)(stateData) - buffer.unstashAll(idleInternal(updatedStateData, constantData, buffer)) + buffer.unstashAll(idle(updatedStateData, constantData, buffer)) case (ctx, unsupported) => ctx.log.warn(s"Received unsupported message: $unsupported!") buffer.stash(unsupported) - Behaviors.unhandled + buffer.unstashAll(idleInternal) } /** Handle a message from outside the simulation diff --git a/src/main/scala/edu/ie3/simona/service/SimonaService.scala b/src/main/scala/edu/ie3/simona/service/SimonaService.scala index b4c36de856..240fc85cbe 100644 --- a/src/main/scala/edu/ie3/simona/service/SimonaService.scala +++ b/src/main/scala/edu/ie3/simona/service/SimonaService.scala @@ -146,7 +146,7 @@ abstract class SimonaService[ case (ctx, registrationMsg: ServiceRegistrationMessage) => /* Someone asks to register for information from the service */ handleRegistrationRequest(registrationMsg)(stateData, ctx) match { - case Success(stateData) => idleInternal(stateData, constantData, buffer) + case Success(stateData) => idle(stateData, constantData, buffer) case Failure(exception) => ctx.log.error( "Error during registration." + diff --git a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala index 8a1d46be09..a4fa133455 100644 --- a/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala +++ b/src/main/scala/edu/ie3/simona/service/primary/PrimaryServiceProxy.scala @@ -97,8 +97,6 @@ object PrimaryServiceProxy { final case class InitPrimaryServiceProxyStateData( primaryConfig: PrimaryConfig, simulationStart: ZonedDateTime, - private[primary] val timeSeriesToSourceRef: Map[UUID, SourceRef] = - Map.empty, ) extends InitializeServiceStateData /** Holding the state of an initialized proxy. @@ -371,7 +369,7 @@ object PrimaryServiceProxy { * @return * Message handling routine */ - private def onMessage(stateData: PrimaryServiceStateData)(implicit + private[service] def onMessage(stateData: PrimaryServiceStateData)(implicit constantData: ServiceConstantStateData ): Behavior[PrimaryDataMessage] = Behaviors.receive { case (ctx, PrimaryServiceRegistrationMessage(actorRef, modelUuid)) => @@ -419,7 +417,7 @@ object PrimaryServiceProxy { requestingActor: ClassicRef, )(implicit constantData: ServiceConstantStateData, - ctx: ActorContext[_], + ctx: ActorContext[PrimaryDataMessage], ): Unit = { val timeSeriesToSourceRef = stateData.timeSeriesToSourceRef timeSeriesToSourceRef.get(timeSeriesUuid) match { @@ -514,7 +512,7 @@ object PrimaryServiceProxy { * @return * The [[ActorRef]] to the spun off actor */ - protected[service] def classToWorkerRef( + private[service] def classToWorkerRef( timeSeriesUuid: String )(implicit constantData: ServiceConstantStateData, diff --git a/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala b/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala index 76dc7f1e61..952ce7c714 100644 --- a/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala +++ b/src/test/scala/edu/ie3/simona/service/ev/ExtEvDataServiceSpec.scala @@ -10,23 +10,23 @@ import edu.ie3.simona.api.data.ev.ExtEvData import edu.ie3.simona.api.data.ev.model.EvModel import edu.ie3.simona.api.data.ev.ontology._ import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage -import edu.ie3.simona.exceptions.ServiceException +import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException import edu.ie3.simona.model.participant.evcs.EvModelWrapper import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } import edu.ie3.simona.ontology.messages.services.EvMessage._ -import edu.ie3.simona.ontology.messages.services.{ - EvMessage, - ServiceMessageUniversal, -} import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.RegistrationResponseMessage.RegistrationSuccessfulMessage import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ Create, WrappedActivation, WrappedExternalMessage, } +import edu.ie3.simona.ontology.messages.services.{ + EvMessage, + ServiceMessageUniversal, +} import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.service.ev.ExtEvDataService.InitExtEvData @@ -167,6 +167,8 @@ class ExtEvDataServiceSpec extSimAdapter.expectMessage( new ScheduleDataServiceMessage(adapter.toClassic) ) + scheduler.expectNoMessage() + evService ! Activation(INIT_SIM_TICK) scheduler.expectMessage(Completion(activationMsg.actor)) @@ -202,7 +204,7 @@ class ExtEvDataServiceSpec scheduler.expectMessage(Completion(activationMsg.actor)) // we trigger ev service and expect an exception - assertThrows[Exception] { + assertThrows[InvalidRegistrationRequestException] { evService ! Activation(0) } @@ -247,6 +249,9 @@ class ExtEvDataServiceSpec extSimAdapter.expectMessage( new ScheduleDataServiceMessage(adapter.toClassic) ) + + scheduler.expectNoMessage() + evService ! Activation(INIT_SIM_TICK) scheduler.expectMessage(Completion(activationMsg.actor)) diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala index 0ff5f9353a..6a8c4a63ec 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySpec.scala @@ -38,6 +38,7 @@ import edu.ie3.simona.ontology.messages.services.ServiceMessageUniversal.{ WrappedActivation, } import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} +import edu.ie3.simona.scheduler.ScheduleLock.LockMsg import edu.ie3.simona.service.ServiceStateData.ServiceConstantStateData import edu.ie3.simona.service.primary.PrimaryServiceProxy.{ InitPrimaryServiceProxyStateData, @@ -49,10 +50,14 @@ import edu.ie3.simona.test.common.input.TimeSeriesTestData import edu.ie3.simona.test.common.{AgentTypedSpec, TestSpawnerTyped} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.TimeUtil -import org.apache.pekko.actor.testkit.typed.scaladsl.TestProbe -import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + BehaviorTestKit, + TestProbe, +} import org.apache.pekko.actor.typed.scaladsl.ActorContext import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps +import org.apache.pekko.actor.typed.{ActorRef, Behavior, Props} +import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.when import org.scalatest.Inside.inside import org.scalatest.PartialFunctionValues @@ -72,19 +77,6 @@ class PrimaryServiceProxySpec with PartialFunctionValues with TimeSeriesTestData with TestSpawnerTyped { - - implicit def wrap(msg: Activation): WrappedActivation = - WrappedActivation(msg) - - implicit val constantData: ServiceConstantStateData = - mock[ServiceConstantStateData] - implicit val log: Logger = LoggerFactory.getLogger("PrimaryServiceProxySpec") - implicit val ctx: ActorContext[_] = { - val m = mock[ActorContext[_]] - when(m.log).thenReturn(log) - m - } - // this works both on Windows and Unix systems val baseDirectoryPath: Path = Paths .get( @@ -134,8 +126,24 @@ class PrimaryServiceProxySpec mappingSource, ) + implicit def wrap(msg: Activation): WrappedActivation = + WrappedActivation(msg) + private val scheduler = TestProbe[SchedulerMessage]("scheduler") + implicit val constantData: ServiceConstantStateData = { + val m = mock[ServiceConstantStateData] + when(m.scheduler).thenReturn(scheduler.ref) + m + } + + implicit val log: Logger = LoggerFactory.getLogger("PrimaryServiceProxySpec") + implicit val ctx: ActorContext[PrimaryDataMessage] = { + val m = mock[ActorContext[PrimaryDataMessage]] + when(m.log).thenReturn(log) + m + } + "Testing a primary service config" should { "lead to complaining about too much source definitions" in { val maliciousConfig = PrimaryConfig( @@ -427,36 +435,35 @@ class PrimaryServiceProxySpec /* We "fake" the creation of the worker to infiltrate a test probe. This empowers us to check, if a matching init * message is sent to the worker */ val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") + val lockProbe = TestProbe[LockMsg]("lockProbe") + val activationAdapter = TestProbe[Activation]("activationAdapter") val metaInformation = new CsvIndividualTimeSeriesMetaInformation( metaPq, Paths.get("its_pq_" + uuidPq), ) - val sourceRef = SourceRef( - metaInformation, - Some(worker.ref), - ) - - val modifiedInitStateData = initStateData.copy( - timeSeriesToSourceRef = Map(uuidPq -> sourceRef) - ) - - val fakeProxyRef = testKit.spawn( - PrimaryServiceProxy( - scheduler.ref, - modifiedInitStateData, - ) - ) + val context: ActorContext[_] = { + val m = mock[ActorContext[_]] + when(m.log).thenReturn(log) - scheduler.expectMessageType[ScheduleActivation] + when(m.spawn(any[Behavior[PrimaryDataMessage]], any[String], any())) + .thenReturn(worker.ref) + when(m.spawnAnonymous(any[Behavior[LockMsg]], any())) + .thenReturn(lockProbe.ref) + when(m.spawnAnonymous(any[Behavior[Activation]], any())) + .thenReturn(activationAdapter.ref) - fakeProxyRef ! Activation(INIT_SIM_TICK) - scheduler.expectMessageType[Completion] + m + } - fakeProxyRef ! Activation(0) + PrimaryServiceProxy.initializeWorker( + metaInformation, + simulationStart, + initStateData.primaryConfig, + )(constantData, context) - inside(worker.expectMessageType[PrimaryDataMessage]) { + inside(worker.expectMessageType[Create[_]]) { case Create( CsvInitPrimaryServiceStateData( actualTimeSeriesUuid, @@ -484,8 +491,6 @@ class PrimaryServiceProxySpec // receiving schedule activation, don't know why but ok... scheduler.expectMessageType[ScheduleActivation] - - testKit.stop(worker.ref) } } @@ -586,12 +591,19 @@ class PrimaryServiceProxySpec /* We once again fake the class, so that we can infiltrate a probe */ val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") + val adaptedStateData = proxyStateData.copy( + timeSeriesToSourceRef = Map( + uuidPq -> SourceRef(metaPq, Some(worker.ref)) + ) + ) + PrimaryServiceProxy.handleCoveredModel( modelUuid, uuidPq, - proxyStateData, + adaptedStateData, requestingAgent.ref.toClassic, ) + worker.expectMessage( WorkerRegistrationMessage(requestingAgent.ref.toClassic) ) @@ -613,30 +625,27 @@ class PrimaryServiceProxySpec /* We once again fake the class, so that we can infiltrate a probe */ val worker = TestProbe[PrimaryDataMessage]("workerTestProbe") - val modifiedInitStateData = initStateData.copy( - timeSeriesToSourceRef = - Map(modelUuid -> SourceRef(metaP, Some(worker.ref))) + val adaptedStateData = proxyStateData.copy( + modelToTimeSeries = Map(modelUuid -> uuidPq), + timeSeriesToSourceRef = Map( + uuidPq -> SourceRef(metaPq, Some(worker.ref)) + ), ) - val fakeProxyRef = - testKit.spawn( - PrimaryServiceProxy( - scheduler.ref, - modifiedInitStateData, - ) + val fakeProxy = BehaviorTestKit( + PrimaryServiceProxy.onMessage( + adaptedStateData ) - - scheduler.expectMessageType[ScheduleActivation] - - /* Initialize the fake proxy */ - fakeProxyRef ! Activation(INIT_SIM_TICK) - scheduler.expectMessageType[Completion] + ) /* Try to register with fake proxy */ - fakeProxyRef ! PrimaryServiceRegistrationMessage( - requestingAgent.ref.toClassic, - modelUuid, + fakeProxy.run( + PrimaryServiceRegistrationMessage( + requestingAgent.ref.toClassic, + modelUuid, + ) ) + worker.expectMessage( WorkerRegistrationMessage(requestingAgent.ref.toClassic) ) diff --git a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala index 4a9b6f58a4..77581881f7 100644 --- a/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala +++ b/src/test/scala/edu/ie3/simona/service/primary/PrimaryServiceProxySqlIT.scala @@ -33,7 +33,11 @@ import org.apache.pekko.actor.testkit.typed.scaladsl.{ BehaviorTestKit, TestProbe, } -import org.apache.pekko.actor.typed.scaladsl.adapter.TypedActorRefOps +import org.apache.pekko.actor.typed.ActorRef +import org.apache.pekko.actor.typed.scaladsl.adapter.{ + ClassicActorRefOps, + TypedActorRefOps, +} import org.scalatest.BeforeAndAfterAll import org.testcontainers.utility.DockerImageName @@ -90,7 +94,7 @@ class PrimaryServiceProxySqlIT timePattern = "yyyy-MM-dd'T'HH:mm:ssX", ) - private def createProxy(): BehaviorTestKit[PrimaryDataMessage] = { + private def createProxy(): ActorRef[PrimaryDataMessage] = { val initData = InitPrimaryServiceProxyStateData( SimonaConfig.Simona.Input.Primary( None, @@ -101,7 +105,7 @@ class PrimaryServiceProxySqlIT simulationStart, ) - BehaviorTestKit( + testKit.spawn( PrimaryServiceProxy( scheduler.ref, initData, @@ -112,16 +116,21 @@ class PrimaryServiceProxySqlIT "A primary service proxy with SQL source" should { "initialize when given proper SQL input configs" in { - val proxyRef = createProxy().ref + val proxyRef = createProxy() + + scheduler.expectMessageType[ScheduleActivation] proxyRef ! Activation(INIT_SIM_TICK) scheduler.expectMessageType[Completion] } "handle participant request correctly if participant has primary data" in { - val systemParticipantProbe = TestProbe[Any]("SystemParticipant") + val systemParticipantProbe = + TestProbe[ServiceMessageUniversal]("SystemParticipant") - val proxyRef = createProxy().ref + val proxyRef = createProxy() + + scheduler.expectMessageType[ScheduleActivation] proxyRef ! Activation(INIT_SIM_TICK) scheduler.expectMessageType[Completion] @@ -143,15 +152,17 @@ class PrimaryServiceProxySqlIT scheduler.expectMessage(Completion(workerRef, Some(0))) - systemParticipantProbe.expectMessage( - RegistrationSuccessfulMessage(workerRef, Some(0L)) - ) + val msg = + systemParticipantProbe.expectMessageType[RegistrationSuccessfulMessage] + msg.nextDataTick shouldBe Some(0L) } "handle participant request correctly if participant does not have primary data" in { val systemParticipantProbe = TestProbe[Any]("SystemParticipant") - val proxyRef = createProxy().ref + val proxyRef = createProxy() + + scheduler.expectMessageType[ScheduleActivation] proxyRef ! Activation(INIT_SIM_TICK) scheduler.expectMessageType[Completion]