fix(monitoring): corriger calcul CPU — getProcessCpuLoad au lieu de loadAverage/processors
Le calcul précédent `getSystemLoadAverage() / getAvailableProcessors() * 100` utilisait : - getSystemLoadAverage() : charge 1min du NODE Linux hôte entier (12 CPU sur prod VPS) - getAvailableProcessors() : limite conteneur K8s (1 CPU pour le pod UnionFlow) Résultat : load 1.5 sur le node → cpuUsage = (1.5 / 1) * 100 = 150% capé à 100%. Déclenchement constant d'alertes "CPU 100%" (19 faux positifs / 24h sur prod le 20-21/04/2026) dès que le node fait autre chose que dormir. Correctif : utilise com.sun.management.OperatingSystemMXBean.getProcessCpuLoad() qui retourne la charge CPU du process JVM courant (0.0-1.0), conscient du conteneur. Branche -1 préservée (API non dispo sur certaines JVM). Tests mis à jour : AlertMonitoringServiceMockStaticCoverageTest injecte désormais un com.sun.management.OperatingSystemMXBean et mocke getProcessCpuLoad() (compatible mock-maker-inline déjà configuré). AlertMonitoringServiceTest conserve sa logique OS-agnostique via des thresholds extrêmes (-1 toujours / 100 jamais).
This commit is contained in:
@@ -82,12 +82,15 @@ public class AlertMonitoringService {
|
||||
*/
|
||||
private void checkCpuThreshold(AlertConfiguration config) {
|
||||
try {
|
||||
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
double loadAvg = osBean.getSystemLoadAverage();
|
||||
int processors = osBean.getAvailableProcessors();
|
||||
|
||||
// Calculer l'utilisation CPU en pourcentage
|
||||
double cpuUsage = loadAvg < 0 ? 0.0 : Math.min(100.0, (loadAvg / processors) * 100.0);
|
||||
// getProcessCpuLoad() renvoie la charge CPU de CE process JVM (0.0-1.0),
|
||||
// ce qui est correct en conteneur K8s/Docker.
|
||||
// getSystemLoadAverage() renvoie la charge du NODE entier (hôte Linux),
|
||||
// divisée par availableProcessors() limité par le conteneur (ex: 1),
|
||||
// ce qui produit des faux positifs dès que le node est actif.
|
||||
com.sun.management.OperatingSystemMXBean osBean =
|
||||
(com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
double processCpuLoad = osBean.getProcessCpuLoad();
|
||||
double cpuUsage = processCpuLoad < 0 ? 0.0 : Math.min(100.0, processCpuLoad * 100.0);
|
||||
lastCpuUsage = cpuUsage;
|
||||
|
||||
int threshold = config.getCpuThresholdPercent();
|
||||
|
||||
@@ -18,7 +18,6 @@ import dev.lions.unionflow.server.repository.SystemLogRepository;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
@@ -35,11 +34,12 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
* Tests unitaires purs (sans Quarkus) pour {@link AlertMonitoringService}.
|
||||
*
|
||||
* <p>Utilise {@code mockStatic(ManagementFactory.class)} pour injecter des beans MXBean
|
||||
* contrôlés et couvrir les branches inaccessibles sur certains systèmes (notamment Windows
|
||||
* où {@code getSystemLoadAverage()} retourne toujours -1).
|
||||
* contrôlés et couvrir les branches du calcul CPU basé sur
|
||||
* {@code com.sun.management.OperatingSystemMXBean.getProcessCpuLoad()} (0.0-1.0, -1 si indispo).
|
||||
*
|
||||
* <p>Note : utilise {@code mock-maker-inline} (configuré via
|
||||
* {@code src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker}).
|
||||
* {@code src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker}) —
|
||||
* nécessaire pour mocker {@code com.sun.management.OperatingSystemMXBean} (type JDK interne).
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@DisplayName("AlertMonitoringService — branches via mockStatic ManagementFactory")
|
||||
@@ -69,31 +69,31 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// L85 : branche ternaire loadAvg >= 0 → Math.min(100.0, (loadAvg / processors) * 100.0)
|
||||
// checkCpuThreshold : branche processCpuLoad >= 0
|
||||
// cpuUsage = Math.min(100.0, processCpuLoad * 100.0)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Couvre la branche {@code loadAvg >= 0} à la ligne 85 :
|
||||
* {@code Math.min(100.0, (loadAvg / processors) * 100.0)}.
|
||||
* Couvre la branche {@code processCpuLoad >= 0} :
|
||||
* {@code cpuUsage = Math.min(100.0, processCpuLoad * 100.0)}.
|
||||
*
|
||||
* <p>On injecte un {@code OperatingSystemMXBean} mock qui retourne
|
||||
* {@code getSystemLoadAverage() = 0.5} (valeur positive ≥ 0) et
|
||||
* {@code getAvailableProcessors() = 4}.
|
||||
* → {@code cpuUsage = Math.min(100.0, (0.5/4)*100.0) = Math.min(100.0, 12.5) = 12.5}.
|
||||
* <p>On injecte un {@code com.sun.management.OperatingSystemMXBean} mock qui retourne
|
||||
* {@code getProcessCpuLoad() = 0.125} (valeur positive ≥ 0).
|
||||
* → {@code cpuUsage = Math.min(100.0, 0.125 * 100.0) = 12.5}.
|
||||
*
|
||||
* <p>Avec {@code threshold = 0}, {@code 12.5 > 0} → branche cpuUsage > threshold → true
|
||||
* → {@code lastCpuHighTime} est mis à null initialement → il est settté à now().
|
||||
* → {@code lastCpuHighTime} est mis à null initialement → il est setté à now().
|
||||
* Aucune alerte n'est créée (première itération).
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkCpuThreshold : loadAvg >= 0 → Math.min branch (L85) via OperatingSystemMXBean mock")
|
||||
void checkCpuThreshold_loadAvgPositive_coversL85MathMinBranch() {
|
||||
@DisplayName("checkCpuThreshold : processCpuLoad >= 0 → Math.min branch via OperatingSystemMXBean mock")
|
||||
void checkCpuThreshold_processCpuLoadPositive_coversMathMinBranch() {
|
||||
AlertConfiguration config = buildConfig(true, 0, 60, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
OperatingSystemMXBean osMock = mock(OperatingSystemMXBean.class);
|
||||
when(osMock.getSystemLoadAverage()).thenReturn(0.5); // >= 0 → branche Math.min à L85
|
||||
when(osMock.getAvailableProcessors()).thenReturn(4);
|
||||
com.sun.management.OperatingSystemMXBean osMock =
|
||||
mock(com.sun.management.OperatingSystemMXBean.class);
|
||||
when(osMock.getProcessCpuLoad()).thenReturn(0.125); // >= 0 → branche Math.min
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean).thenReturn(osMock);
|
||||
@@ -108,28 +108,28 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Couvre la branche {@code loadAvg >= 0} à L85 avec une valeur élevée déclenchant une alerte.
|
||||
* Couvre la branche {@code processCpuLoad >= 0} avec une valeur élevée déclenchant une alerte.
|
||||
*
|
||||
* <p>On simule un CPU à 200% (loadAvg=8, processors=4 → cpuUsage=200, cappé à 100%).
|
||||
* <p>On simule un CPU à 200% brut (getProcessCpuLoad=2.0 — cas théorique) cappé à 100% via Math.min.
|
||||
* Après deux appels avec {@code durationMinutes=0}, l'alerte est créée.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkCpuThreshold : loadAvg élevé → cpuUsage 100% → alerte créée en 2 appels (L85 Math.min branch)")
|
||||
void checkCpuThreshold_loadAvgHighPositive_triggersAlert_coversL85() {
|
||||
@DisplayName("checkCpuThreshold : processCpuLoad élevé → cpuUsage cappé à 100% → alerte créée en 2 appels")
|
||||
void checkCpuThreshold_processCpuLoadHighPositive_triggersAlert() {
|
||||
// Premier appel : reset lastCpuHighTime via threshold élevé
|
||||
AlertConfiguration resetConfig = buildConfig(true, 100, 0, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(resetConfig);
|
||||
|
||||
OperatingSystemMXBean osMock = mock(OperatingSystemMXBean.class);
|
||||
when(osMock.getSystemLoadAverage()).thenReturn(2.0); // >= 0 → Math.min branch
|
||||
when(osMock.getAvailableProcessors()).thenReturn(4);
|
||||
com.sun.management.OperatingSystemMXBean osMock =
|
||||
mock(com.sun.management.OperatingSystemMXBean.class);
|
||||
when(osMock.getProcessCpuLoad()).thenReturn(0.5); // >= 0 → Math.min branch (50%)
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean).thenReturn(osMock);
|
||||
service.monitorSystemMetrics(); // cpuUsage=50%, threshold=100 → below → lastCpuHighTime=null
|
||||
}
|
||||
|
||||
// Deuxième et troisième appels avec threshold=-1 (0.0 > -1 always), durationMinutes=0
|
||||
// Deuxième et troisième appels avec threshold=-1 (50.0 > -1 always), durationMinutes=0
|
||||
AlertConfiguration triggerConfig = buildConfig(true, -1, 0, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(triggerConfig);
|
||||
when(systemAlertRepository.findByTimestampBetween(any(LocalDateTime.class), any(LocalDateTime.class)))
|
||||
@@ -149,28 +149,28 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// L113-114 : catch(Exception e) dans checkCpuThreshold
|
||||
// catch(Exception e) dans checkCpuThreshold
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Couvre les lignes 113-114 ({@code catch(Exception e)} et {@code log.error(...)}) dans
|
||||
* Couvre le bloc {@code catch(Exception e)} et {@code log.error(...)} dans
|
||||
* {@code checkCpuThreshold()}.
|
||||
*
|
||||
* <p>On force {@code ManagementFactory.getOperatingSystemMXBean()} à lancer une
|
||||
* {@code RuntimeException}. Cette exception est capturée par le catch à L113,
|
||||
* loggée à L114, et la méthode retourne silencieusement.
|
||||
* {@code RuntimeException}. Cette exception est capturée par le catch,
|
||||
* loggée, et la méthode retourne silencieusement.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkCpuThreshold : ManagementFactory.getOperatingSystemMXBean() throw → catch L113-114 couvert")
|
||||
void checkCpuThreshold_managementFactoryThrows_coversCatchL113to114() {
|
||||
@DisplayName("checkCpuThreshold : ManagementFactory.getOperatingSystemMXBean() throw → catch couvert")
|
||||
void checkCpuThreshold_managementFactoryThrows_coversCatch() {
|
||||
AlertConfiguration config = buildConfig(true, 80, 5, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean)
|
||||
.thenThrow(new RuntimeException("Simulated JMX failure — covers catch L113-114"));
|
||||
.thenThrow(new RuntimeException("Simulated JMX failure — covers catch"));
|
||||
|
||||
// L113-114 : l'exception est catchée → monitorSystemMetrics ne propage pas
|
||||
// L'exception est catchée → monitorSystemMetrics ne propage pas
|
||||
assertThatCode(() -> service.monitorSystemMetrics())
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
@@ -180,19 +180,19 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Couvre L113-114 via une exception lancée pendant le calcul (NullPointerException
|
||||
* depuis le mock MemoryMXBean non configuré pour OperatingSystemMXBean).
|
||||
* Couvre le catch via une exception lancée pendant le calcul (RuntimeException
|
||||
* depuis l'appel à {@code getProcessCpuLoad()}).
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkCpuThreshold : OperatingSystemMXBean.getAvailableProcessors() throw → catch L113-114")
|
||||
void checkCpuThreshold_availableProcessorsThrows_coversCatchL113to114() {
|
||||
@DisplayName("checkCpuThreshold : OperatingSystemMXBean.getProcessCpuLoad() throw → catch couvert")
|
||||
void checkCpuThreshold_processCpuLoadThrows_coversCatch() {
|
||||
AlertConfiguration config = buildConfig(true, 80, 5, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
OperatingSystemMXBean osMock = mock(OperatingSystemMXBean.class);
|
||||
when(osMock.getSystemLoadAverage()).thenReturn(0.5);
|
||||
when(osMock.getAvailableProcessors())
|
||||
.thenThrow(new RuntimeException("Simulated getAvailableProcessors failure"));
|
||||
com.sun.management.OperatingSystemMXBean osMock =
|
||||
mock(com.sun.management.OperatingSystemMXBean.class);
|
||||
when(osMock.getProcessCpuLoad())
|
||||
.thenThrow(new RuntimeException("Simulated getProcessCpuLoad failure"));
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean).thenReturn(osMock);
|
||||
@@ -205,11 +205,11 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// L127 : branche ternaire maxMemory <= 0 → 0.0
|
||||
// checkMemoryThreshold : branche ternaire maxMemory <= 0 → 0.0
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Couvre la branche {@code maxMemory <= 0} à la ligne 127 :
|
||||
* Couvre la branche {@code maxMemory <= 0} :
|
||||
* {@code double memoryUsage = maxMemory > 0 ? ... : 0.0}.
|
||||
*
|
||||
* <p>On injecte un {@code MemoryMXBean} mock dont {@code getHeapMemoryUsage().getMax()}
|
||||
@@ -219,14 +219,14 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
* <p>Avec threshold=0 : {@code 0.0 > 0} est false → pas d'alerte.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkMemoryThreshold : maxMemory = -1 (non défini) → memoryUsage = 0.0 → branche false L127")
|
||||
void checkMemoryThreshold_maxMemoryMinusOne_coversL127FalseBranch() {
|
||||
@DisplayName("checkMemoryThreshold : maxMemory = -1 (non défini) → memoryUsage = 0.0 → branche false")
|
||||
void checkMemoryThreshold_maxMemoryMinusOne_coversFalseBranch() {
|
||||
AlertConfiguration config = buildConfig(false, 80, 5, true, 0, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
MemoryMXBean memMock = mock(MemoryMXBean.class);
|
||||
MemoryUsage heapUsageMock = mock(MemoryUsage.class);
|
||||
when(heapUsageMock.getMax()).thenReturn(-1L); // maxMemory = -1 → branche false à L127
|
||||
when(heapUsageMock.getMax()).thenReturn(-1L); // maxMemory = -1 → branche false
|
||||
when(heapUsageMock.getUsed()).thenReturn(100L);
|
||||
when(memMock.getHeapMemoryUsage()).thenReturn(heapUsageMock);
|
||||
|
||||
@@ -242,19 +242,19 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Couvre L127 branche false avec maxMemory = 0.
|
||||
* Couvre la branche false du ternaire avec maxMemory = 0.
|
||||
*
|
||||
* <p>La condition {@code maxMemory > 0} est false pour maxMemory = 0 aussi.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkMemoryThreshold : maxMemory = 0 → memoryUsage = 0.0 → branche false L127")
|
||||
void checkMemoryThreshold_maxMemoryZero_coversL127FalseBranch() {
|
||||
@DisplayName("checkMemoryThreshold : maxMemory = 0 → memoryUsage = 0.0 → branche false")
|
||||
void checkMemoryThreshold_maxMemoryZero_coversFalseBranch() {
|
||||
AlertConfiguration config = buildConfig(false, 80, 5, true, 0, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
MemoryMXBean memMock = mock(MemoryMXBean.class);
|
||||
MemoryUsage heapUsageMock = mock(MemoryUsage.class);
|
||||
when(heapUsageMock.getMax()).thenReturn(0L); // maxMemory = 0 → branche false à L127
|
||||
when(heapUsageMock.getMax()).thenReturn(0L); // maxMemory = 0 → branche false
|
||||
when(heapUsageMock.getUsed()).thenReturn(50L);
|
||||
when(memMock.getHeapMemoryUsage()).thenReturn(heapUsageMock);
|
||||
|
||||
@@ -270,11 +270,11 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Couvre L127 branche true (maxMemory > 0) + alerte mémoire créée.
|
||||
* Couvre la branche true (maxMemory > 0) + alerte mémoire créée.
|
||||
* Vérifie que le mock MemoryMXBean avec une valeur positive couvre la branche vraie.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkMemoryThreshold : maxMemory > 0 + usage > threshold → alerte créée (L127 branche true)")
|
||||
@DisplayName("checkMemoryThreshold : maxMemory > 0 + usage > threshold → alerte créée (branche true)")
|
||||
void checkMemoryThreshold_maxMemoryPositive_usageAboveThreshold_createsAlert() {
|
||||
AlertConfiguration config = buildConfig(false, 80, 5, true, 0, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
@@ -299,25 +299,27 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// L85 : combinaison de loadAvg >= 0 avec threshold dépassé (couvre Math.min)
|
||||
// checkCpuThreshold : branche processCpuLoad < 0 (API non disponible)
|
||||
// cpuUsage = 0.0 (ternaire : processCpuLoad < 0 ? 0.0 : ...)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Couvre explicitement la branche {@code loadAvg < 0} (L85, branche true du ternaire)
|
||||
* pour compléter la couverture des deux branches du ternaire à L85.
|
||||
* Couvre explicitement la branche {@code processCpuLoad < 0} du ternaire
|
||||
* pour compléter la couverture des deux branches du ternaire.
|
||||
*
|
||||
* <p>On injecte {@code getSystemLoadAverage() = -1.0} (loadAvg < 0 → cpuUsage = 0.0).
|
||||
* Cela simule le comportement Windows où loadAvg = -1.
|
||||
* <p>On injecte {@code getProcessCpuLoad() = -1.0} → cpuUsage = 0.0.
|
||||
* Cela simule le cas où l'API n'est pas disponible (le contrat JDK dit que
|
||||
* {@code getProcessCpuLoad()} peut retourner -1 si la valeur n'est pas disponible).
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("checkCpuThreshold : loadAvg = -1 (Windows) → cpuUsage = 0.0 → branche true L85 ternaire")
|
||||
void checkCpuThreshold_loadAvgNegative_coversL85TrueBranch() {
|
||||
@DisplayName("checkCpuThreshold : processCpuLoad = -1 (indispo) → cpuUsage = 0.0 → branche true ternaire")
|
||||
void checkCpuThreshold_processCpuLoadNegative_coversTrueBranch() {
|
||||
AlertConfiguration config = buildConfig(true, 100, 5, false, 100, false);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(config);
|
||||
|
||||
OperatingSystemMXBean osMock = mock(OperatingSystemMXBean.class);
|
||||
when(osMock.getSystemLoadAverage()).thenReturn(-1.0); // < 0 → cpuUsage = 0.0
|
||||
when(osMock.getAvailableProcessors()).thenReturn(4);
|
||||
com.sun.management.OperatingSystemMXBean osMock =
|
||||
mock(com.sun.management.OperatingSystemMXBean.class);
|
||||
when(osMock.getProcessCpuLoad()).thenReturn(-1.0); // < 0 → cpuUsage = 0.0
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean).thenReturn(osMock);
|
||||
@@ -331,7 +333,7 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// L229 : lambda anyMatch dans hasRecentCpuAlert
|
||||
// hasRecentCpuAlert : lambda anyMatch
|
||||
// Couverture supplémentaire des branches de la lambda
|
||||
// =========================================================================
|
||||
|
||||
@@ -340,11 +342,11 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
* {@code source = "CPU"} et {@code acknowledged = false} → {@code anyMatch} retourne true
|
||||
* → {@code hasRecentCpuAlert()} = true → aucune nouvelle alerte créée.
|
||||
*
|
||||
* <p>La lambda à L229 : {@code "CPU".equals(alert.getSource()) && !alert.getAcknowledged()}
|
||||
* <p>Lambda : {@code "CPU".equals(alert.getSource()) && !alert.getAcknowledged()}
|
||||
* — branche : source="CPU" true ET acknowledged=false → true → anyMatch=true.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("hasRecentCpuAlert lambda L229 : source=CPU + acknowledged=false → anyMatch true → pas d'alerte")
|
||||
@DisplayName("hasRecentCpuAlert lambda : source=CPU + acknowledged=false → anyMatch true → pas d'alerte")
|
||||
void hasRecentCpuAlert_lambda_sourceCpu_acknowledgedFalse_anyMatchTrue_noNewAlert() throws Exception {
|
||||
// Préparer : reset lastCpuHighTime à null d'abord
|
||||
injectField(service, "lastCpuHighTime", null);
|
||||
@@ -362,9 +364,9 @@ class AlertMonitoringServiceMockStaticCoverageTest {
|
||||
when(systemAlertRepository.findByTimestampBetween(any(LocalDateTime.class), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of(existingCpuAlert));
|
||||
|
||||
OperatingSystemMXBean osMock = mock(OperatingSystemMXBean.class);
|
||||
when(osMock.getSystemLoadAverage()).thenReturn(2.0); // loadAvg >= 0 → Math.min branch L85
|
||||
when(osMock.getAvailableProcessors()).thenReturn(4); // cpuUsage = 50% > -1
|
||||
com.sun.management.OperatingSystemMXBean osMock =
|
||||
mock(com.sun.management.OperatingSystemMXBean.class);
|
||||
when(osMock.getProcessCpuLoad()).thenReturn(0.5); // >= 0 → Math.min branch → cpuUsage=50%
|
||||
|
||||
try (MockedStatic<ManagementFactory> mf = mockStatic(ManagementFactory.class)) {
|
||||
mf.when(ManagementFactory::getOperatingSystemMXBean).thenReturn(osMock);
|
||||
|
||||
@@ -215,14 +215,14 @@ class AlertMonitoringServiceTest {
|
||||
@Test
|
||||
@DisplayName("monitorSystemMetrics - CPU enabled, duration elapsed, no recent CPU alert => alert is created")
|
||||
void monitorSystemMetrics_cpuEnabled_durationElapsed_noRecentAlert_createsCpuAlert() {
|
||||
// Reset state: threshold=100 forces CPU (0.0 on Windows) to be below threshold → lastCpuHighTime = null
|
||||
// Reset state: threshold=100 forces CPU (always <= 100% via Math.min cap) to be below threshold → lastCpuHighTime = null
|
||||
AlertConfiguration resetConfig = buildDisabledConfig();
|
||||
resetConfig.setCpuHighAlertEnabled(true);
|
||||
resetConfig.setCpuThresholdPercent(100);
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(resetConfig);
|
||||
alertMonitoringService.monitorSystemMetrics();
|
||||
|
||||
// threshold=-1: any CPU (even 0.0 on Windows where loadAvg=-1) satisfies 0.0 > -1
|
||||
// threshold=-1: any CPU (even 0.0 when getProcessCpuLoad() returns -1 or 0 on idle JVM) satisfies 0.0 > -1
|
||||
AlertConfiguration config = buildDisabledConfig();
|
||||
config.setCpuHighAlertEnabled(true);
|
||||
config.setCpuThresholdPercent(-1); // guaranteed: 0.0 > -1 is always true
|
||||
@@ -488,7 +488,7 @@ class AlertMonitoringServiceTest {
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(resetConfig);
|
||||
alertMonitoringService.monitorSystemMetrics();
|
||||
|
||||
// threshold=-1: 0.0 > -1 is always true (even on Windows with cpuUsage=0.0)
|
||||
// threshold=-1: 0.0 > -1 is always true (getProcessCpuLoad() returns 0.0..1.0 or -1; cpuUsage clamped to [0, 100])
|
||||
AlertConfiguration config = buildDisabledConfig();
|
||||
config.setCpuHighAlertEnabled(true);
|
||||
config.setCpuThresholdPercent(-1);
|
||||
@@ -556,7 +556,7 @@ class AlertMonitoringServiceTest {
|
||||
when(alertConfigurationRepository.getConfiguration()).thenReturn(resetConfig);
|
||||
alertMonitoringService.monitorSystemMetrics();
|
||||
|
||||
// threshold=-1: 0.0 > -1 is always true (even on Windows with cpuUsage=0.0)
|
||||
// threshold=-1: 0.0 > -1 is always true (getProcessCpuLoad() returns 0.0..1.0 or -1; cpuUsage clamped to [0, 100])
|
||||
AlertConfiguration config = buildDisabledConfig();
|
||||
config.setCpuHighAlertEnabled(true);
|
||||
config.setCpuThresholdPercent(-1);
|
||||
|
||||
Reference in New Issue
Block a user