@@ -17,7 +17,7 @@ package managers
1717
1818import actors .events .{ConformanceStatementCreatedEvent , SystemUpdatedEvent }
1919import exceptions .{AutomationApiException , ErrorCodes }
20- import managers .SystemManager .{ ExistingResult , logger }
20+ import managers .SystemManager ._
2121import managers .triggers .TriggerHelper
2222import models .Enums .{TestResultStatus , UserRole }
2323import models ._
@@ -38,6 +38,9 @@ object SystemManager {
3838
3939 private val logger : Logger = LoggerFactory .getLogger(classOf [SystemManager ])
4040 private case class ExistingResult (sessionId : String , result : String , outputMessage : Option [String ], endTime : Option [Timestamp ])
41+ private case class ActorInfo (specId : Long , actorId : Long )
42+ private case class TestCaseInfo (testCaseId : Long , testSuiteId : Long )
43+ private case class StatementPropertyInfo (parameterId : Long , endpointId : Long , defaultValue : String , actorId : Long )
4144
4245}
4346
@@ -570,6 +573,7 @@ class SystemManager @Inject() (repositoryUtils: RepositoryUtils,
570573 def defineConformanceStatements (systemId : Long , actorIds : Seq [Long ]): Future [Unit ] = {
571574 DB .run(
572575 (for {
576+ // ---- ALL READS FIRST ----
573577 communityId <- getCommunityIdOfSystemInternal(systemId)
574578 domainId <- {
575579 if (communityId == Constants .DefaultCommunityId ) {
@@ -579,45 +583,130 @@ class SystemManager @Inject() (repositoryUtils: RepositoryUtils,
579583 PersistenceSchema .communities.filter(_.id === communityId).map(_.domain).result.head
580584 }
581585 }
582- actorIdsToProcess <- PersistenceSchema .systemImplementsActors
586+ existingStatementActorIds <- PersistenceSchema .systemImplementsActors
583587 .filter(_.systemId === systemId)
584588 .map(_.actorId)
585589 .result
586- .map { existingStatementActorIds =>
587- actorIds.toSet.removedAll(existingStatementActorIds)
588- }
590+ actorIdsToProcess = actorIds.toSet.removedAll(existingStatementActorIds)
589591 actorsToProcess <- {
590592 if (actorIdsToProcess.isEmpty) {
591- DBIO .successful(Seq .empty[( Long , Long ) ])
593+ DBIO .successful(Seq .empty[ActorInfo ])
592594 } else {
593595 PersistenceSchema .specificationHasActors
594596 .join(PersistenceSchema .actors).on(_.actorId === _.id)
595- .filterOpt(domainId)((q, id) => q._2.domain === id) // Ensure these are valid actors within the domain.
597+ .filterOpt(domainId)((q, id) => q._2.domain === id)
596598 .filter(_._1.actorId inSet actorIdsToProcess)
597599 .map(_._1)
598600 .result
601+ .map(_.map(x => ActorInfo (x._1, x._2)))
599602 }
600603 }
604+ conformanceInfoPerActor <- DBIO .sequence(
605+ actorsToProcess.map { actor =>
606+ PersistenceSchema .testCaseHasActors
607+ .join(PersistenceSchema .testSuiteHasTestCases).on(_.testcase === _.testcase)
608+ .filter(_._1.actor === actor.actorId)
609+ .filter(_._1.sut === true )
610+ .map(r => (r._1.testcase, r._2.testsuite))
611+ .result
612+ .map(info => (actor, info.map(x => TestCaseInfo (x._1, x._2))))
613+ }
614+ )
615+ allTestCaseIds = conformanceInfoPerActor.flatMap(_._2.map(_.testCaseId)).toSet
616+ existingResults <- {
617+ if (allTestCaseIds.isEmpty) {
618+ DBIO .successful(Seq .empty)
619+ } else {
620+ PersistenceSchema .testResults
621+ .filter(_.sutId === systemId)
622+ .filter(_.testCaseId inSet allTestCaseIds)
623+ .sortBy(_.endTime.desc)
624+ .result
625+ }
626+ }
627+ allActorIds = actorsToProcess.map(_.actorId).toSet
628+ propertiesWithDefaults <- {
629+ if (allActorIds.isEmpty) {
630+ DBIO .successful(Seq .empty)
631+ } else {
632+ PersistenceSchema .parameters
633+ .join(PersistenceSchema .endpoints).on(_.endpoint === _.id)
634+ .filter(_._2.actor inSet allActorIds)
635+ .filter(_._1.defaultValue.isDefined)
636+ .map(x => (x._1.id, x._1.endpoint, x._1.defaultValue.get, x._2.actor))
637+ .result
638+ .map(_.map(x => StatementPropertyInfo (x._1, x._2, x._3, x._4)))
639+ }
640+ }
641+ propertiesWithDefaultsThatAreSet <- {
642+ if (propertiesWithDefaults.isEmpty) {
643+ DBIO .successful(Seq .empty)
644+ } else {
645+ PersistenceSchema .configs
646+ .filter(_.system === systemId)
647+ .filter(_.parameter inSet propertiesWithDefaults.map(_.parameterId))
648+ .map(_.parameter)
649+ .result
650+ }
651+ }
652+ // ---- ALL WRITES AFTER ----
601653 _ <- {
602654 if (actorsToProcess.isEmpty) {
603655 logger.info(" Skipping creation of conformance statement(s). No actors were found from IDs [{}] that were not already associated to system [{}]." , actorIds.mkString(" ," ), systemId)
604656 DBIO .successful(())
605657 } else {
606- val actions = new ListBuffer [DBIO [_]]
607- actorsToProcess.foreach { actor =>
608- actions += defineConformanceStatement(systemId, actor._1, actor._2, setDefaultParameterValues = true )
658+ val existingResultsMap = createExistingResultMap(existingResults)
659+ val alreadySetPropertyIds = propertiesWithDefaultsThatAreSet.toSet
660+ val actions = new ListBuffer [DBIO [_]]()
661+ conformanceInfoPerActor.foreach { case (actorInfo, conformanceInfo) =>
662+ actions += (PersistenceSchema .systemImplementsActors += (systemId, actorInfo.specId, actorInfo.actorId))
663+ conformanceInfo.foreach { testCaseInfo =>
664+ actions += createEmptyConformanceResult(existingResultsMap, testCaseInfo.testCaseId, testCaseInfo.testSuiteId, systemId, actorInfo.specId, actorInfo.actorId)
665+ }
666+ propertiesWithDefaults
667+ .filter(_.actorId == actorInfo.actorId)
668+ .foreach { defaultPropertyInfo =>
669+ if (! alreadySetPropertyIds.contains(defaultPropertyInfo.parameterId)) {
670+ actions += (PersistenceSchema .configs += Configs (systemId, defaultPropertyInfo.parameterId, defaultPropertyInfo.endpointId, defaultPropertyInfo.defaultValue, None ))
671+ }
672+ }
609673 }
610674 toDBIO(actions)
611675 }
612676 }
613- } yield (communityId, actorsToProcess.map(_._2 ))).transactionally
677+ } yield (communityId, actorsToProcess.map(_.actorId ))).transactionally
614678 ).map { result =>
615679 result._2.foreach { actorId =>
616680 triggerHelper.publishTriggerEvent(new ConformanceStatementCreatedEvent (result._1, systemId, actorId))
617681 }
618682 }
619683 }
620684
685+ private def createExistingResultMap (existingResults : Seq [TestResult ]): Map [Long , ExistingResult ] = {
686+ val existingResultsMap = new mutable.HashMap [Long , ExistingResult ]
687+ existingResults.foreach { existingResult =>
688+ if (! existingResultsMap.contains(existingResult.testCaseId.get)) {
689+ existingResultsMap += (existingResult.testCaseId.get -> ExistingResult (existingResult.sessionId, existingResult.result, existingResult.outputMessage, existingResult.endTime))
690+ }
691+ }
692+ existingResultsMap.toMap
693+ }
694+
695+ private def createEmptyConformanceResult (existingResultsMap : Map [Long , ExistingResult ], testCaseId : Long , testSuiteId : Long , systemId : Long , specId : Long , actorId : Long ) = {
696+ var result = TestResultStatus .UNDEFINED
697+ var outputMessage : Option [String ] = None
698+ var sessionId : Option [String ] = None
699+ var updateTime : Option [Timestamp ] = None
700+ if (existingResultsMap.contains(testCaseId)) {
701+ val existingData = existingResultsMap(testCaseId)
702+ sessionId = Some (existingData.sessionId)
703+ result = TestResultStatus .withName(existingData.result)
704+ outputMessage = existingData.outputMessage
705+ updateTime = existingData.endTime
706+ }
707+ PersistenceSchema .conformanceResults += ConformanceResult (0L , systemId, specId, actorId, testSuiteId, testCaseId, result.toString, outputMessage, sessionId, updateTime)
708+ }
709+
621710 def defineConformanceStatementViaApi (organisationKey : String , systemKey : String , actorKey : String ): Future [Unit ] = {
622711 DB .run((
623712 for {
@@ -677,92 +766,63 @@ class SystemManager @Inject() (repositoryUtils: RepositoryUtils,
677766 .filter(_._1.sut === true )
678767 .map(r => (r._1.testcase, r._2.testsuite))
679768 .result
769+ .map(_.map(x => TestCaseInfo (x._1, x._2)))
680770 existingResultsMap <- {
681771 if (conformanceInfo.isEmpty) {
682772 DBIO .successful(Map .empty[Long , ExistingResult ])
683773 } else {
684774 PersistenceSchema .testResults
685775 .filter(_.sutId === system)
686- .filter(_.testCaseId inSet conformanceInfo.map(_._1)) // In expected set of test case IDs
776+ .filter(_.testCaseId inSet conformanceInfo.map(_.testCaseId))
687777 .sortBy(_.endTime.desc)
688778 .result
689- .map { existingResults =>
690- val existingResultsMap = new mutable.HashMap [Long , ExistingResult ]
691- existingResults.foreach { existingResult =>
692- if (! existingResultsMap.contains(existingResult.testCaseId.get)) {
693- existingResultsMap += (existingResult.testCaseId.get -> ExistingResult (existingResult.sessionId, existingResult.result, existingResult.outputMessage, existingResult.endTime))
694- }
695- }
696- existingResultsMap.toMap
697- }
779+ .map(createExistingResultMap)
698780 }
699781 }
700782 _ <- {
701783 val actions = new ListBuffer [DBIO [_]]()
702- conformanceInfo.foreach { conformanceInfoEntry =>
703- val testCase = conformanceInfoEntry._1
704- val testSuite = conformanceInfoEntry._2
705- var result = TestResultStatus .UNDEFINED
706- var outputMessage : Option [String ] = None
707- var sessionId : Option [String ] = None
708- var updateTime : Option [Timestamp ] = None
709- if (existingResultsMap.contains(testCase)) {
710- val existingData = existingResultsMap(testCase)
711- sessionId = Some (existingData.sessionId)
712- result = TestResultStatus .withName(existingData.result)
713- outputMessage = existingData.outputMessage
714- updateTime = existingData.endTime
715- }
716- actions += (PersistenceSchema .conformanceResults += ConformanceResult (0L , system, spec, actor, testSuite, testCase, result.toString, outputMessage, sessionId, updateTime))
784+ conformanceInfo.foreach { testCaseInfo =>
785+ actions += createEmptyConformanceResult(existingResultsMap, testCaseInfo.testCaseId, testCaseInfo.testSuiteId, system, spec, actor)
717786 }
718787 toDBIO(actions)
719788 }
720- // Set properties with default values.
721789 _ <- {
722790 if (setDefaultParameterValues) {
723- setDefaultParameterValuesForSystem(actor, system)
791+ for {
792+ propertiesWithDefaults <- PersistenceSchema .parameters
793+ .join(PersistenceSchema .endpoints).on(_.endpoint === _.id)
794+ .filter(_._2.actor === actor)
795+ .filter(_._1.defaultValue.isDefined)
796+ .map(x => (x._1.id, x._1.endpoint, x._1.defaultValue.get))
797+ .result
798+ propertiesWithDefaultsThatAreSet <- {
799+ if (propertiesWithDefaults.isEmpty) {
800+ DBIO .successful(Seq .empty)
801+ } else {
802+ PersistenceSchema .configs
803+ .filter(_.system === system)
804+ .filter(_.parameter inSet propertiesWithDefaults.map(_._1))
805+ .map(_.parameter)
806+ .result
807+ }
808+ }
809+ _ <- {
810+ val actions = new ListBuffer [DBIO [_]]()
811+ propertiesWithDefaults.foreach { defaultPropertyInfo =>
812+ if (! propertiesWithDefaultsThatAreSet.contains(defaultPropertyInfo._1)) {
813+ actions += (PersistenceSchema .configs += Configs (system, defaultPropertyInfo._1, defaultPropertyInfo._2, defaultPropertyInfo._3, None ))
814+ }
815+ }
816+ toDBIO(actions)
817+ }
818+ } yield ()
724819 } else {
725820 DBIO .successful(())
726821 }
727822 }
728823 } yield ()
729824 }
730825
731- private def setDefaultParameterValuesForSystem (actor : Long , system : Long ): DBIO [Unit ] = {
732- for {
733- // 1. Determine the properties that have default values.
734- propertiesWithDefaults <- PersistenceSchema .parameters
735- .join(PersistenceSchema .endpoints).on(_.endpoint === _.id)
736- .filter(_._2.actor === actor)
737- .filter(_._1.defaultValue.isDefined)
738- .map(x => (x._1.id, x._1.endpoint, x._1.defaultValue.get))
739- .result
740- // 2. See which of these properties have values.
741- propertiesWithDefaultsThatAreSet <-
742- if (propertiesWithDefaults.isEmpty) {
743- DBIO .successful(List .empty)
744- } else {
745- PersistenceSchema .configs
746- .filter(_.system === system)
747- .filter(_.parameter inSet propertiesWithDefaults.map(x => x._1))
748- .map(x => x.parameter)
749- .result
750- }
751- // 3. Apply the default values for any properties that are not set.
752- _ <- {
753- val actions = new ListBuffer [DBIO [_]]()
754- if (propertiesWithDefaults.nonEmpty) {
755- propertiesWithDefaults.foreach { defaultPropertyInfo =>
756- if (! propertiesWithDefaultsThatAreSet.contains(defaultPropertyInfo._1)) {
757- actions += (PersistenceSchema .configs += Configs (system, defaultPropertyInfo._1, defaultPropertyInfo._2, defaultPropertyInfo._3, None ))
758- }
759- }
760- }
761- toDBIO(actions)
762- }
763- } yield ()
764- }
765-
766826 private def getConformanceStatementReferencesInternal (systemId : Long ): DBIO [List [ConformanceResult ]] = {
767827 PersistenceSchema .conformanceResults.filter(_.sut === systemId).result.map(_.toList)
768828 }
@@ -966,7 +1026,7 @@ class SystemManager @Inject() (repositoryUtils: RepositoryUtils,
9661026 DB .run(getCommunityIdOfSystemInternal(systemId))
9671027 }
9681028
969- def getCommunityIdOfSystemInternal (systemId : Long ): DBIO [Long ] = {
1029+ private def getCommunityIdOfSystemInternal (systemId : Long ): DBIO [Long ] = {
9701030 PersistenceSchema .systems
9711031 .join(PersistenceSchema .organizations).on(_.owner === _.id)
9721032 .filter(_._1.id === systemId)
0 commit comments