diff --git a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/MaximumKPICalculationStrategy.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/MaximumKPICalculationStrategy.kt index 7fe7cf05fe36b650c642db280b7ede72763a5930..93e3ab0368e2ae7134c8b9178f7d9b80ed73379b 100644 --- a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/MaximumKPICalculationStrategy.kt +++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/MaximumKPICalculationStrategy.kt @@ -3,13 +3,32 @@ package de.fraunhofer.iem.kpiCalculator.core.strategy import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.KpiCalculationResult object MaximumKPICalculationStrategy { - fun calculateKPI(childScores: List<Pair<KpiCalculationResult, Double>>): KpiCalculationResult { + fun calculateKPI( + childScores: List<Pair<KpiCalculationResult, Double>>, + considerIncomplete: Boolean = true + ): KpiCalculationResult { if (childScores.isEmpty()) { return KpiCalculationResult.Empty } - val successScores = childScores.filterIsInstance<KpiCalculationResult.Success>() + val incompleteResults = if (considerIncomplete) { + childScores.mapNotNull { + val res = it.first + if (res is KpiCalculationResult.Incomplete) { + KpiCalculationResult.Success(res.score) + } else { + null + } + } + } else { + emptyList() + } + + val successScores = listOf( + childScores.map { it.first }.filterIsInstance<KpiCalculationResult.Success>(), + incompleteResults + ).flatten() val max = if (successScores.isEmpty()) diff --git a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RatioKPICalculationStrategy.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RatioKPICalculationStrategy.kt index 16aa012838b292083b110a2c390b732984f62f86..b08c3b1b108a338c43d70073d4cfa27a04a0cd4d 100644 --- a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RatioKPICalculationStrategy.kt +++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RatioKPICalculationStrategy.kt @@ -27,7 +27,7 @@ object RatioKPICalculationStrategy { try { if (firstValue >= secondValue) { return KpiCalculationResult.Success( - score = (secondValue.toDouble() / firstValue.toDouble()).toInt() * 100 + score = ((secondValue.toDouble() / firstValue.toDouble()) * 100).toInt() ) } return KpiCalculationResult.Success( diff --git a/kpi-calculator/core/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculatorTest.kt b/kpi-calculator/core/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculatorTest.kt index dadb1a1724b57958da83ea20a1a8185c9d70a629..dfffba34ccd4e5491dc73d43dc9743027852a397 100644 --- a/kpi-calculator/core/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculatorTest.kt +++ b/kpi-calculator/core/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculatorTest.kt @@ -1,14 +1,17 @@ package de.fraunhofer.iem.kpiCalculator.core import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId +import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiStrategyId import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto -import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.DefaultHierarchy +import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.* import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.fail class KpiCalculatorTest { @Test - fun calculateKpis() { + fun calculateDefaultHierarchyKpis() { val rawValueKpiDtos = listOf( RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 8), RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 9), @@ -24,4 +27,92 @@ class KpiCalculatorTest { val res = KpiCalculator.calculateKpis(DefaultHierarchy.get(), rawValueKpiDtos) println(res) } + + @Test + fun calculateMaxKpis() { + val rawValueKpiDtos = listOf( + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 82), + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 90), + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 65), + ) + + val root = KpiNode( + kpiId = KpiId.ROOT, strategyType = KpiStrategyId.AGGREGATION_STRATEGY, children = listOf( + KpiEdge( + target = + KpiNode( + kpiId = KpiId.MAXIMAL_VULNERABILITY, + strategyType = KpiStrategyId.MAXIMUM_STRATEGY, + children = listOf( + KpiEdge( + target = KpiNode( + kpiId = KpiId.VULNERABILITY_SCORE, + strategyType = KpiStrategyId.RAW_VALUE_STRATEGY, + children = emptyList() + ), weight = 1.0 + ) + ) + ), weight = 1.0 + ) + ) + ) + val hierarchy = KpiHierarchy.create(root) + + val res = KpiCalculator.calculateKpis(hierarchy, rawValueKpiDtos) + val result = res.kpiResult + + if (result is KpiCalculationResult.Success) { + assertEquals(90, result.score) + } else { + fail() + } + } + + @Test + fun calculateMaxKpisIncomplete() { + val rawValueKpiDtos = listOf( + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 82), + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 90), + RawValueKpiDto(kind = KpiId.VULNERABILITY_SCORE, score = 65), + ) + + val root = KpiNode( + kpiId = KpiId.ROOT, strategyType = KpiStrategyId.AGGREGATION_STRATEGY, children = listOf( + KpiEdge( + target = + KpiNode( + kpiId = KpiId.SECURITY, + strategyType = KpiStrategyId.MAXIMUM_STRATEGY, + children = listOf( + KpiEdge( + target = KpiNode( + kpiId = KpiId.VULNERABILITY_SCORE, + strategyType = KpiStrategyId.RAW_VALUE_STRATEGY, + children = emptyList() + ), weight = 0.5 + ), + KpiEdge( + target = KpiNode( + kpiId = KpiId.SAST_USAGE, + strategyType = KpiStrategyId.RAW_VALUE_STRATEGY, + children = emptyList() + ), + weight = 0.5 + ) + ) + ), weight = 1.0 + ) + ) + ) + val hierarchy = KpiHierarchy.create(root) + + val res = KpiCalculator.calculateKpis(hierarchy, rawValueKpiDtos) + val result = res.kpiResult + + if (result is KpiCalculationResult.Incomplete) { + assertEquals(90, result.score) + } else { + fail() + } + } }