Skip to content

Commit 4ad623c

Browse files
committed
[ITB-2095] Conformance statement creation may still be unexpectedly skipped
1 parent e48b36e commit 4ad623c

1 file changed

Lines changed: 134 additions & 74 deletions

File tree

gitb-ui/app/managers/SystemManager.scala

Lines changed: 134 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ package managers
1717

1818
import actors.events.{ConformanceStatementCreatedEvent, SystemUpdatedEvent}
1919
import exceptions.{AutomationApiException, ErrorCodes}
20-
import managers.SystemManager.{ExistingResult, logger}
20+
import managers.SystemManager._
2121
import managers.triggers.TriggerHelper
2222
import models.Enums.{TestResultStatus, UserRole}
2323
import 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

Comments
 (0)