mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
refactor: update to Springboot4 and Hibernate 7 (#4057)
Co-authored-by: lynx009 <2030509072@qq.com>
This commit is contained in:
+2
-1
@@ -39,6 +39,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -71,7 +72,7 @@ public abstract class AbstractCollectE2eTest {
|
||||
public void setUp() throws Exception {
|
||||
// Initialize mocks
|
||||
MockitoAnnotations.openMocks(this);
|
||||
when(defineDao.findAll()).thenReturn(new ArrayList<>());
|
||||
lenient().when(defineDao.findAll()).thenReturn(new ArrayList<>());
|
||||
when(timeout.task()).thenReturn(timerJob);
|
||||
when(timerJob.getJob()).thenReturn(job);
|
||||
metricsCollect = new MetricsCollect(mock(Metrics.class), timeout, mock(CollectDataDispatch.class), null, List.of());
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<okhttp.version>4.12.0</okhttp.version>
|
||||
<jackson.version>2.15.2</jackson.version>
|
||||
<maven.resources.plugin.version>3.3.1</maven.resources.plugin.version>
|
||||
<maven.dependency.plugin.version>3.6.1</maven.dependency.plugin.version>
|
||||
|
||||
@@ -84,6 +82,11 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JUnit 5 -->
|
||||
<dependency>
|
||||
|
||||
+30
-18
@@ -28,10 +28,11 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
@@ -44,6 +45,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -59,6 +61,10 @@ import static org.mockito.Mockito.doAnswer;
|
||||
* E2E tests for periodic log alert processing.
|
||||
*/
|
||||
@SpringBootTest(classes = org.apache.hertzbeat.startup.HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestPropertySource(properties = {
|
||||
"warehouse.store.duckdb.enabled=false",
|
||||
"warehouse.store.greptime.enabled=true"
|
||||
})
|
||||
@Slf4j
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public class LogPeriodicAlertE2eTest {
|
||||
@@ -81,7 +87,7 @@ public class LogPeriodicAlertE2eTest {
|
||||
AlertDefine errorCountAlertByGroup;
|
||||
AlertDefine errorCountAlertByIndividual;
|
||||
|
||||
@SpyBean
|
||||
@MockitoSpyBean
|
||||
private AlarmCommonReduce alarmCommonReduce;
|
||||
|
||||
static GenericContainer<?> vector;
|
||||
@@ -101,9 +107,7 @@ public class LogPeriodicAlertE2eTest {
|
||||
|
||||
@DynamicPropertySource
|
||||
static void greptimeProps(DynamicPropertyRegistry r) {
|
||||
// Configure GreptimeDB storage
|
||||
r.add("warehouse.store.duckdb.enabled", () -> "false");
|
||||
r.add("warehouse.store.greptime.enabled", () -> "true");
|
||||
// Configure GreptimeDB storage endpoints (dynamic ports)
|
||||
r.add("warehouse.store.greptime.http-endpoint", () -> "http://localhost:" + greptimedb.getMappedPort(GREPTIME_HTTP_PORT));
|
||||
r.add("warehouse.store.greptime.grpc-endpoints", () -> "localhost:" + greptimedb.getMappedPort(GREPTIME_GRPC_PORT));
|
||||
r.add("warehouse.store.greptime.username", () -> "");
|
||||
@@ -111,10 +115,15 @@ public class LogPeriodicAlertE2eTest {
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
void setUpAll() {
|
||||
void setUpAll() throws InterruptedException {
|
||||
// Setup test alert definitions
|
||||
setupTestAlertDefines();
|
||||
Testcontainers.exposeHostPorts(port);
|
||||
|
||||
// Wait for HertzBeat to be fully ready before starting Vector
|
||||
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
|
||||
Thread.sleep(5000); // Give HertzBeat time to fully initialize
|
||||
|
||||
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
|
||||
.withExposedPorts(VECTOR_PORT)
|
||||
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
|
||||
@@ -171,19 +180,22 @@ public class LogPeriodicAlertE2eTest {
|
||||
|
||||
await().atMost(Duration.ofSeconds(60))
|
||||
.pollInterval(Duration.ofSeconds(3))
|
||||
.untilAsserted(() -> assertFalse(capturedGroupAlerts.isEmpty(),
|
||||
"Should have generated periodic error count group alert"));
|
||||
.untilAsserted(() -> {
|
||||
Optional<SingleAlert> matchedAlert = capturedGroupAlerts.stream()
|
||||
.flatMap(List::stream)
|
||||
.filter(alert -> alert.getLabels() != null)
|
||||
.filter(alert -> String.valueOf(errorCountAlertByGroup.getId())
|
||||
.equals(alert.getLabels().get(CommonConstants.LABEL_DEFINE_ID)))
|
||||
.findFirst();
|
||||
|
||||
List<SingleAlert> groupAlerts = capturedGroupAlerts.get(0);
|
||||
|
||||
assertNotNull(groupAlerts, "Group alerts should not be null");
|
||||
assertFalse(groupAlerts.isEmpty(), "Group alerts should not be empty");
|
||||
|
||||
SingleAlert anyAlert = groupAlerts.get(0);
|
||||
assertEquals(CommonConstants.ALERT_STATUS_FIRING, anyAlert.getStatus(), "Alert should be in firing status");
|
||||
assertNotNull(anyAlert.getLabels(), "Alert should have labels");
|
||||
assertEquals(CommonConstants.ALERT_SEVERITY_CRITICAL, anyAlert.getLabels().get(CommonConstants.LABEL_ALERT_SEVERITY), "Alert should have critical severity");
|
||||
assertTrue(anyAlert.getTriggerTimes() >= 1, "Alert should indicate aggregated trigger times");
|
||||
assertTrue(matchedAlert.isPresent(), "Should have captured group alert from target alert define");
|
||||
SingleAlert anyAlert = matchedAlert.get();
|
||||
assertEquals(CommonConstants.ALERT_STATUS_FIRING, anyAlert.getStatus(), "Alert should be in firing status");
|
||||
assertEquals(CommonConstants.ALERT_SEVERITY_CRITICAL,
|
||||
anyAlert.getLabels().get(CommonConstants.LABEL_ALERT_SEVERITY),
|
||||
"Alert should have critical severity");
|
||||
assertTrue(anyAlert.getTriggerTimes() >= 1, "Alert should indicate aggregated trigger times");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-7
@@ -27,8 +27,8 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
@@ -64,7 +64,8 @@ public class LogRealTimeAlertE2eTest {
|
||||
private static final int VECTOR_PORT = 8686;
|
||||
private static final String VECTOR_CONFIG_PATH = "/etc/vector/vector.yml";
|
||||
private static final String ENV_HERTZBEAT_PORT = "HERTZBEAT_PORT";
|
||||
private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(120);
|
||||
private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(180);
|
||||
private static final Duration TEST_WAIT_TIMEOUT = Duration.ofSeconds(120);
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@@ -72,18 +73,23 @@ public class LogRealTimeAlertE2eTest {
|
||||
private final List<SingleAlert> capturedAlerts = new ArrayList<>();
|
||||
private final ArrayList<List<SingleAlert>> capturedGroupAlerts = new ArrayList<>();
|
||||
|
||||
@SpyBean
|
||||
@MockitoSpyBean
|
||||
private AlarmCommonReduce alarmCommonReduce;
|
||||
|
||||
static GenericContainer<?> vector;
|
||||
|
||||
@BeforeAll
|
||||
void setUpAll() {
|
||||
void setUpAll() throws InterruptedException {
|
||||
// Setup test alert definitions
|
||||
setupTestAlertDefines();
|
||||
|
||||
|
||||
// Expose host ports for testcontainers
|
||||
Testcontainers.exposeHostPorts(port);
|
||||
|
||||
// Wait for HertzBeat to be fully ready before starting Vector
|
||||
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
|
||||
Thread.sleep(5000); // Give HertzBeat time to fully initialize
|
||||
|
||||
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
|
||||
.withExposedPorts(VECTOR_PORT)
|
||||
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
|
||||
@@ -107,8 +113,8 @@ public class LogRealTimeAlertE2eTest {
|
||||
capturedAlerts.clear();
|
||||
|
||||
// Wait for real alert to be generated through AlarmCommonReduce
|
||||
await().atMost(Duration.ofSeconds(60))
|
||||
.pollInterval(Duration.ofSeconds(2))
|
||||
await().atMost(TEST_WAIT_TIMEOUT)
|
||||
.pollInterval(Duration.ofSeconds(3))
|
||||
.untilAsserted(() -> assertFalse(capturedAlerts.isEmpty(),
|
||||
"Should have generated at least one alert for error logs"));
|
||||
|
||||
|
||||
+6
-1
@@ -64,8 +64,13 @@ public class LogIngestionE2eTest {
|
||||
static GenericContainer<?> vector;
|
||||
|
||||
@BeforeAll
|
||||
void setUpAll() {
|
||||
void setUpAll() throws InterruptedException {
|
||||
Testcontainers.exposeHostPorts(port);
|
||||
|
||||
// Wait for HertzBeat to be fully ready before starting Vector
|
||||
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
|
||||
Thread.sleep(5000); // Give HertzBeat time to fully initialize
|
||||
|
||||
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
|
||||
.withExposedPorts(VECTOR_PORT)
|
||||
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
|
||||
|
||||
+34
-13
@@ -29,6 +29,10 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
@@ -37,8 +41,6 @@ import org.testcontainers.utility.DockerImageName;
|
||||
import org.testcontainers.utility.MountableFile;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
@@ -48,6 +50,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
* E2E tests for GreptimeDB log storage.
|
||||
*/
|
||||
@SpringBootTest(classes = org.apache.hertzbeat.startup.HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestPropertySource(properties = {
|
||||
"warehouse.store.duckdb.enabled=false",
|
||||
"warehouse.store.greptime.enabled=true"
|
||||
})
|
||||
@Slf4j
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public class GreptimeLogStorageE2eTest {
|
||||
@@ -86,8 +92,6 @@ public class GreptimeLogStorageE2eTest {
|
||||
|
||||
@DynamicPropertySource
|
||||
static void greptimeProps(DynamicPropertyRegistry r) {
|
||||
r.add("warehouse.store.duckdb.enabled", () -> "false");
|
||||
r.add("warehouse.store.greptime.enabled", () -> "true");
|
||||
r.add("warehouse.store.greptime.http-endpoint", () -> "http://localhost:" + greptimedb.getMappedPort(GREPTIME_HTTP_PORT));
|
||||
r.add("warehouse.store.greptime.grpc-endpoints", () -> "localhost:" + greptimedb.getMappedPort(GREPTIME_GRPC_PORT));
|
||||
r.add("warehouse.store.greptime.username", () -> "");
|
||||
@@ -96,10 +100,14 @@ public class GreptimeLogStorageE2eTest {
|
||||
|
||||
|
||||
@BeforeAll
|
||||
void setUpAll() {
|
||||
void setUpAll() throws InterruptedException {
|
||||
// Expose host ports for testcontainers
|
||||
Testcontainers.exposeHostPorts(port);
|
||||
|
||||
// Wait for HertzBeat to be fully ready before starting Vector
|
||||
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
|
||||
Thread.sleep(5000); // Give HertzBeat time to fully initialize
|
||||
|
||||
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
|
||||
.withExposedPorts(VECTOR_PORT)
|
||||
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
|
||||
@@ -114,9 +122,10 @@ public class GreptimeLogStorageE2eTest {
|
||||
|
||||
@Test
|
||||
void testLogStorageToGreptimeDb() {
|
||||
log.info("GreptimeDbDataStorage serverAvailable: {}", greptimeDbDataStorage.isServerAvailable());
|
||||
|
||||
List<LogEntry> capturedLogs = new ArrayList<>();
|
||||
|
||||
|
||||
// Wait for Vector to generate and send logs to HertzBeat
|
||||
await().atMost(Duration.ofSeconds(30))
|
||||
.pollInterval(Duration.ofSeconds(3))
|
||||
@@ -131,7 +140,7 @@ public class GreptimeLogStorageE2eTest {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Test interrupted", e);
|
||||
}
|
||||
|
||||
|
||||
// Assert that we have captured at least some logs
|
||||
assertFalse(capturedLogs.isEmpty(), "Should have captured at least one log entry");
|
||||
});
|
||||
@@ -142,13 +151,25 @@ public class GreptimeLogStorageE2eTest {
|
||||
assertNotNull(firstLog, "First log should not be null");
|
||||
assertNotNull(firstLog.getBody(), "Log body should not be null");
|
||||
assertNotNull(firstLog.getSeverityText(), "Severity text should not be null");
|
||||
|
||||
|
||||
// Directly write logs to GreptimeDB to test storage functionality
|
||||
log.info("Directly writing {} captured logs to GreptimeDB", capturedLogs.size());
|
||||
greptimeDbDataStorage.saveLogDataBatch(capturedLogs);
|
||||
|
||||
// Give some time for the write to complete
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
// Additional wait to ensure logs are persisted to GreptimeDB
|
||||
await().atMost(Duration.ofSeconds(30))
|
||||
.pollInterval(Duration.ofSeconds(2))
|
||||
.untilAsserted(() -> {
|
||||
// Query GreptimeDB directly to verify data persistence
|
||||
List<LogEntry> storedLogs = queryStoredLogs();
|
||||
log.info("Queried {} logs from GreptimeDB", storedLogs.size());
|
||||
assertFalse(storedLogs.isEmpty(), "Should have logs stored in GreptimeDB");
|
||||
});
|
||||
}
|
||||
@@ -157,10 +178,10 @@ public class GreptimeLogStorageE2eTest {
|
||||
* Helper method to query stored logs directly from GreptimeDB
|
||||
*/
|
||||
private List<LogEntry> queryStoredLogs() {
|
||||
long endTime = System.currentTimeMillis();
|
||||
long startTime = endTime - Duration.ofMinutes(5).toMillis(); // Look back 5 minutes
|
||||
|
||||
return greptimeDbDataStorage.queryLogsByMultipleConditions(
|
||||
startTime, endTime, null, null, null, null, null);
|
||||
// Query without time condition to verify data exists
|
||||
List<LogEntry> result = greptimeDbDataStorage.queryLogsByMultipleConditions(
|
||||
null, null, null, null, null, null, null);
|
||||
log.info("queryLogsByMultipleConditions returned {} entries", result.size());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ sinks:
|
||||
type: console
|
||||
encoding:
|
||||
codec: json
|
||||
|
||||
# Send to HertzBeat
|
||||
|
||||
# Send to HertzBeat with increased timeout and retry
|
||||
emit_syslog:
|
||||
inputs: [ "remap_syslog" ]
|
||||
type: opentelemetry
|
||||
@@ -114,4 +114,13 @@ sinks:
|
||||
strategy: basic
|
||||
user: admin
|
||||
password: hertzbeat
|
||||
|
||||
# Increase timeout and retry settings for stability in CI environments
|
||||
request:
|
||||
timeout_secs: 60
|
||||
retry_attempts: 10
|
||||
retry_initial_backoff_secs: 2
|
||||
retry_max_duration_secs: 120
|
||||
# Batch settings for better throughput
|
||||
batch:
|
||||
max_bytes: 524288
|
||||
timeout_secs: 5
|
||||
|
||||
Reference in New Issue
Block a user