Skip to content

Commit

Permalink
[backend/frontend] display latest simulations results on scenario ove…
Browse files Browse the repository at this point in the history
…rview
  • Loading branch information
isselparra committed Dec 4, 2024
1 parent 756dd1e commit 82cbbe4
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 259 deletions.
Original file line number Diff line number Diff line change
@@ -1,46 +1,33 @@
package io.openbas.rest.scenario;

import static io.openbas.database.model.User.ROLE_USER;
import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI;
import static org.springframework.util.StringUtils.hasText;

import io.openbas.database.repository.ScenarioRepository;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.scenario.response.ScenarioStatistic;
import io.openbas.rest.scenario.service.ScenarioStatisticService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.transaction.Transactional;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Secured(ROLE_USER)
@RequiredArgsConstructor
public class ScenarioStatisticApi extends RestBehavior {

private final ScenarioRepository scenarioRepository;
private final ScenarioStatisticService scenarioStatisticService;

@GetMapping(SCENARIO_URI + "/statistics")
@GetMapping(SCENARIO_URI + "/{scenarioId}/statistics")
@PreAuthorize("isScenarioObserver(#scenarioId)")
@Transactional(rollbackOn = Exception.class)
@Operation(summary = "Retrieve scenario statistics")
public ScenarioStatistic scenarioStatistic() {
ScenarioStatistic statistic = new ScenarioStatistic();
statistic.setScenariosGlobalCount(this.scenarioRepository.count());
statistic.setScenariosCategoriesCount(findTopCategories());
return statistic;
}

private Map<String, Long> findTopCategories() {
List<Object[]> results = this.scenarioRepository.findTopCategories(3);
Map<String, Long> categoryCount = new LinkedHashMap<>();
for (Object[] result : results) {
String category = (String) result[0];
if (hasText(category)) {
Long count = (Long) result[1];
categoryCount.put(category, count);
}
}
return categoryCount;
public ScenarioStatistic getScenarioStatistics(@PathVariable @NotBlank final String scenarioId) {
return scenarioStatisticService.getStatistics(scenarioId);

Check warning on line 31 in openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java#L31

Added line #L31 was not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.openbas.rest.scenario.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;

public record GlobalScoreBySimulationEndDate(

Check warning on line 7 in openbas-api/src/main/java/io/openbas/rest/scenario/response/GlobalScoreBySimulationEndDate.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/response/GlobalScoreBySimulationEndDate.java#L7

Added line #L7 was not covered by tests
@JsonProperty("simulation_end_date") @NotNull Instant simulationEndDate,
@JsonProperty("global_score_success_percentage") @NotNull
double globalScoreSuccessPercentage) {}
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package io.openbas.rest.scenario.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
import lombok.Data;
import jakarta.validation.constraints.NotNull;

@Data
public class ScenarioStatistic {

@JsonProperty("scenarios_global_count")
private long scenariosGlobalCount;

@JsonProperty("scenarios_attack_scenario_count")
private Map<String, Long> scenariosCategoriesCount;
}
public record ScenarioStatistic(

Check warning on line 6 in openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java#L6

Added line #L6 was not covered by tests
@JsonProperty("simulations_results_latest") @NotNull
SimulationsResultsLatest simulationsResultsLatest) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.openbas.rest.scenario.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.expectation.ExpectationType;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;

public record SimulationsResultsLatest(

Check warning on line 9 in openbas-api/src/main/java/io/openbas/rest/scenario/response/SimulationsResultsLatest.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/response/SimulationsResultsLatest.java#L9

Added line #L9 was not covered by tests
@JsonProperty("global_scores_by_expectation_type") @NotNull
Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> globalScoresByExpectationType) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package io.openbas.rest.scenario.service;

import io.openbas.database.raw.RawFinishedExerciseWithInjects;
import io.openbas.database.repository.ExerciseRepository;
import io.openbas.expectation.ExpectationType;
import io.openbas.rest.scenario.response.GlobalScoreBySimulationEndDate;
import io.openbas.rest.scenario.response.ScenarioStatistic;
import io.openbas.rest.scenario.response.SimulationsResultsLatest;
import io.openbas.utils.AtomicTestingUtils.ExpectationResultsByType;
import io.openbas.utils.AtomicTestingUtils.ResultDistribution;
import io.openbas.utils.ResultUtils;
import java.util.*;
import java.util.function.BinaryOperator;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ScenarioStatisticService {

private final ExerciseRepository exerciseRepository;

private final ResultUtils resultUtils;

public ScenarioStatistic getStatistics(String scenarioId) {
return getLatestSimulationsStatistics(scenarioId);

Check warning on line 26 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L26

Added line #L26 was not covered by tests
}

private ScenarioStatistic getLatestSimulationsStatistics(String scenarioId) {
List<RawFinishedExerciseWithInjects> rawFinishedExercises =
exerciseRepository.rawLatestFinishedExercisesWithInjectsByScenarioId(scenarioId);

Check warning on line 31 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L30-L31

Added lines #L30 - L31 were not covered by tests

Map<ExpectationType, List<GlobalScoreBySimulationEndDate>>
initialGlobalScoresByExpectationType = new HashMap<>();
initialGlobalScoresByExpectationType.put(ExpectationType.PREVENTION, new ArrayList<>());
initialGlobalScoresByExpectationType.put(ExpectationType.DETECTION, new ArrayList<>());
initialGlobalScoresByExpectationType.put(ExpectationType.HUMAN_RESPONSE, new ArrayList<>());

Check warning on line 37 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L34-L37

Added lines #L34 - L37 were not covered by tests

Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> globalScoresByExpectationType =
rawFinishedExercises.stream()
.reduce(

Check warning on line 41 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L39-L41

Added lines #L39 - L41 were not covered by tests
initialGlobalScoresByExpectationType,
(scoresByType, rawFinishedExercise) ->
addGlobalScores(

Check warning on line 44 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L44

Added line #L44 was not covered by tests
scoresByType,
rawFinishedExercise,
resultUtils.getResultsByTypes(rawFinishedExercise.getInject_ids())),
getMapBinaryOperator());

Check warning on line 48 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L47-L48

Added lines #L47 - L48 were not covered by tests

return new ScenarioStatistic(new SimulationsResultsLatest(globalScoresByExpectationType));

Check warning on line 50 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L50

Added line #L50 was not covered by tests
}

private static Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> addGlobalScores(
Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> globalScoresByExpectationType,
RawFinishedExerciseWithInjects rawFinishedExercise,
List<ExpectationResultsByType> expectationResultsByType) {

updateGlobalScores(

Check warning on line 58 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L58

Added line #L58 was not covered by tests
globalScoresByExpectationType,
rawFinishedExercise,
expectationResultsByType,
ExpectationType.PREVENTION);

updateGlobalScores(

Check warning on line 64 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L64

Added line #L64 was not covered by tests
globalScoresByExpectationType,
rawFinishedExercise,
expectationResultsByType,
ExpectationType.DETECTION);

updateGlobalScores(

Check warning on line 70 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L70

Added line #L70 was not covered by tests
globalScoresByExpectationType,
rawFinishedExercise,
expectationResultsByType,
ExpectationType.HUMAN_RESPONSE);

return globalScoresByExpectationType;

Check warning on line 76 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L76

Added line #L76 was not covered by tests
}

private static void updateGlobalScores(
Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> globalScoresByExpectationType,
RawFinishedExerciseWithInjects rawFinishedExercise,
List<ExpectationResultsByType> expectationResultsByType,
ExpectationType expectationType) {
List<GlobalScoreBySimulationEndDate> globalScores =
getGlobalScoresBySimulationEndDates(

Check warning on line 85 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L84-L85

Added lines #L84 - L85 were not covered by tests
rawFinishedExercise, expectationResultsByType, expectationType);
updateGlobalScoresByExpectationType(

Check warning on line 87 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L87

Added line #L87 was not covered by tests
globalScoresByExpectationType, globalScores, expectationType);
}

Check warning on line 89 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L89

Added line #L89 was not covered by tests

private static void updateGlobalScoresByExpectationType(
Map<ExpectationType, List<GlobalScoreBySimulationEndDate>> globalScoresByType,
List<GlobalScoreBySimulationEndDate> globalScores,
ExpectationType expectationType) {
List<GlobalScoreBySimulationEndDate> previousGlobalScores =
globalScoresByType.getOrDefault(expectationType, new ArrayList<>());
previousGlobalScores.addAll(globalScores);
globalScoresByType.put(expectationType, previousGlobalScores);
}

Check warning on line 99 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L95-L99

Added lines #L95 - L99 were not covered by tests

private static List<GlobalScoreBySimulationEndDate> getGlobalScoresBySimulationEndDates(
RawFinishedExerciseWithInjects rawFinishedExercise,
List<ExpectationResultsByType> expectationResultsByType,
ExpectationType expectationType) {

return expectationResultsByType.stream()

Check warning on line 106 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L106

Added line #L106 was not covered by tests
.filter(expectationResultByType -> expectationResultByType.type() == expectationType)
.map(

Check warning on line 108 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L108

Added line #L108 was not covered by tests
expectationResultByType ->
new GlobalScoreBySimulationEndDate(
rawFinishedExercise.getExercise_end_date(),
getPercentageOfInjectsOnSuccess(expectationResultByType)))
.toList();

Check warning on line 113 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L110-L113

Added lines #L110 - L113 were not covered by tests
}

private static float getPercentageOfInjectsOnSuccess(
ExpectationResultsByType expectationResultByType) {
if (expectationResultByType.distribution().isEmpty()) {
return 0;

Check warning on line 119 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L119

Added line #L119 was not covered by tests
}
var totalNumberOfInjects =
expectationResultByType.distribution().stream()
.map(ResultDistribution::value)
.reduce(0, Integer::sum);
var numberOfInjectsOnSuccess = expectationResultByType.distribution().getFirst().value();
return (float) numberOfInjectsOnSuccess / totalNumberOfInjects;

Check warning on line 126 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L121-L126

Added lines #L121 - L126 were not covered by tests
}

private static BinaryOperator<Map<ExpectationType, List<GlobalScoreBySimulationEndDate>>>
getMapBinaryOperator() {
return (m1, m2) -> {
m1.putAll(m2);
return m1;

Check warning on line 133 in openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/service/ScenarioStatisticService.java#L131-L133

Added lines #L131 - L133 were not covered by tests
};
}
}
4 changes: 2 additions & 2 deletions openbas-front/src/actions/scenarios/scenario-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ export const updateScenarioRecurrence = (

// -- STATISTIC --

export const fetchScenarioStatistic = () => {
const uri = `${SCENARIO_URI}/statistics`;
export const fetchScenarioStatistic = (scenarioId: Scenario['scenario_id']) => {
const uri = `${SCENARIO_URI}/${scenarioId}/statistics`;
return simpleCall(uri);
};

Expand Down
Loading

0 comments on commit 82cbbe4

Please sign in to comment.