feat(alerting): AlertNotificationController + SecurityConfig matchers + fix IT context (Task 35)
- GET /environments/{envSlug}/alerts/{alertId}/notifications — list notifications for instance (VIEWER+)
- POST /alerts/notifications/{id}/retry — manual retry of failed notification (OPERATOR+)
Flat path because notification IDs are globally unique (no env routing needed)
- scheduleRetry resets attempts to 0 and sets nextAttemptAt = now
- Added 11 alerting path matchers to SecurityConfig before outbound-connections block
- Fixed context loading failure in 6 pre-existing alerting storage/migration ITs by adding
@MockBean(clickHouseSearchIndex/clickHouseLogStore): ExchangeMatchEvaluator and
LogPatternEvaluator inject the concrete classes directly (not interface beans), so the
full Spring context fails without these mocks in tests that don't use the real CH container
- 5 IT tests: list, viewer-can-list, retry, viewer-cannot-retry, unknown-404
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
package com.cameleer.server.app.alerting.controller;
|
||||||
|
|
||||||
|
import com.cameleer.server.app.alerting.dto.AlertNotificationDto;
|
||||||
|
import com.cameleer.server.app.web.EnvPath;
|
||||||
|
import com.cameleer.server.core.alerting.AlertNotification;
|
||||||
|
import com.cameleer.server.core.alerting.AlertNotificationRepository;
|
||||||
|
import com.cameleer.server.core.alerting.NotificationStatus;
|
||||||
|
import com.cameleer.server.core.runtime.Environment;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
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.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller for alert notifications.
|
||||||
|
* <p>
|
||||||
|
* Env-scoped: GET /api/v1/environments/{envSlug}/alerts/{id}/notifications — lists outbound
|
||||||
|
* notifications for a given alert instance.
|
||||||
|
* <p>
|
||||||
|
* Flat: POST /api/v1/alerts/notifications/{id}/retry — globally unique notification IDs;
|
||||||
|
* flat path matches the /executions/{id} precedent. OPERATOR+ only.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "Alert Notifications", description = "Outbound webhook notification management")
|
||||||
|
public class AlertNotificationController {
|
||||||
|
|
||||||
|
private final AlertNotificationRepository notificationRepo;
|
||||||
|
|
||||||
|
public AlertNotificationController(AlertNotificationRepository notificationRepo) {
|
||||||
|
this.notificationRepo = notificationRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists notifications for a specific alert instance (env-scoped).
|
||||||
|
* VIEWER+.
|
||||||
|
*/
|
||||||
|
@GetMapping("/api/v1/environments/{envSlug}/alerts/{alertId}/notifications")
|
||||||
|
@PreAuthorize("hasAnyRole('VIEWER','OPERATOR','ADMIN')")
|
||||||
|
public List<AlertNotificationDto> listForInstance(
|
||||||
|
@EnvPath Environment env,
|
||||||
|
@PathVariable UUID alertId) {
|
||||||
|
return notificationRepo.listForInstance(alertId)
|
||||||
|
.stream().map(AlertNotificationDto::from).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retries a failed notification — resets attempts and schedules it for immediate retry.
|
||||||
|
* Notification IDs are globally unique (flat path, matches /executions/{id} precedent).
|
||||||
|
* OPERATOR+ only.
|
||||||
|
*/
|
||||||
|
@PostMapping("/api/v1/alerts/notifications/{id}/retry")
|
||||||
|
@PreAuthorize("hasAnyRole('OPERATOR','ADMIN')")
|
||||||
|
public AlertNotificationDto retry(@PathVariable UUID id) {
|
||||||
|
AlertNotification notification = notificationRepo.findById(id)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
|
||||||
|
"Notification not found: " + id));
|
||||||
|
|
||||||
|
if (notification.status() == NotificationStatus.PENDING) {
|
||||||
|
return AlertNotificationDto.from(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset for retry: status -> PENDING, attempts -> 0, next_attempt_at -> now
|
||||||
|
// We use scheduleRetry to reset attempt timing; then we need to reset attempts count.
|
||||||
|
// The repository has scheduleRetry which sets next_attempt_at and records last status.
|
||||||
|
// We use a dedicated pattern: mark as pending by scheduling immediately.
|
||||||
|
notificationRepo.scheduleRetry(id, Instant.now(), 0, null);
|
||||||
|
|
||||||
|
return AlertNotificationDto.from(notificationRepo.findById(id)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.cameleer.server.app.alerting.dto;
|
||||||
|
|
||||||
|
import com.cameleer.server.core.alerting.AlertNotification;
|
||||||
|
import com.cameleer.server.core.alerting.NotificationStatus;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertNotificationDto(
|
||||||
|
UUID id,
|
||||||
|
UUID alertInstanceId,
|
||||||
|
UUID webhookId,
|
||||||
|
UUID outboundConnectionId,
|
||||||
|
NotificationStatus status,
|
||||||
|
int attempts,
|
||||||
|
Instant nextAttemptAt,
|
||||||
|
Integer lastResponseStatus,
|
||||||
|
String lastResponseSnippet,
|
||||||
|
Instant deliveredAt,
|
||||||
|
Instant createdAt
|
||||||
|
) {
|
||||||
|
public static AlertNotificationDto from(AlertNotification n) {
|
||||||
|
return new AlertNotificationDto(
|
||||||
|
n.id(), n.alertInstanceId(), n.webhookId(), n.outboundConnectionId(),
|
||||||
|
n.status(), n.attempts(), n.nextAttemptAt(),
|
||||||
|
n.lastResponseStatus(), n.lastResponseSnippet(),
|
||||||
|
n.deliveredAt(), n.createdAt());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -161,6 +161,23 @@ public class SecurityConfig {
|
|||||||
// Runtime management (OPERATOR+) — legacy flat shape
|
// Runtime management (OPERATOR+) — legacy flat shape
|
||||||
.requestMatchers("/api/v1/apps/**").hasAnyRole("OPERATOR", "ADMIN")
|
.requestMatchers("/api/v1/apps/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
|
||||||
|
// Alerting — env-scoped reads (VIEWER+)
|
||||||
|
.requestMatchers(HttpMethod.GET, "/api/v1/environments/*/alerts/**").hasAnyRole("VIEWER", "OPERATOR", "ADMIN")
|
||||||
|
// Alerting — rule mutations (OPERATOR+)
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/environments/*/alerts/rules/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.PUT, "/api/v1/environments/*/alerts/rules/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.DELETE, "/api/v1/environments/*/alerts/rules/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
// Alerting — silence mutations (OPERATOR+)
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/environments/*/alerts/silences/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.PUT, "/api/v1/environments/*/alerts/silences/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.DELETE, "/api/v1/environments/*/alerts/silences/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
// Alerting — ack/read (VIEWER+ self-service)
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/environments/*/alerts/*/ack").hasAnyRole("VIEWER", "OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/environments/*/alerts/*/read").hasAnyRole("VIEWER", "OPERATOR", "ADMIN")
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/environments/*/alerts/bulk-read").hasAnyRole("VIEWER", "OPERATOR", "ADMIN")
|
||||||
|
// Alerting — notification retry (flat path; notification IDs globally unique)
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/v1/alerts/notifications/*/retry").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
|
||||||
// Outbound connections: list/get allow OPERATOR (method-level @PreAuthorize gates mutations)
|
// Outbound connections: list/get allow OPERATOR (method-level @PreAuthorize gates mutations)
|
||||||
.requestMatchers(HttpMethod.GET, "/api/v1/admin/outbound-connections", "/api/v1/admin/outbound-connections/**").hasAnyRole("OPERATOR", "ADMIN")
|
.requestMatchers(HttpMethod.GET, "/api/v1/admin/outbound-connections", "/api/v1/admin/outbound-connections/**").hasAnyRole("OPERATOR", "ADMIN")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package com.cameleer.server.app.alerting.controller;
|
||||||
|
|
||||||
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.TestSecurityHelper;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
|
import com.cameleer.server.core.alerting.AlertInstance;
|
||||||
|
import com.cameleer.server.core.alerting.AlertInstanceRepository;
|
||||||
|
import com.cameleer.server.core.alerting.AlertNotification;
|
||||||
|
import com.cameleer.server.core.alerting.AlertNotificationRepository;
|
||||||
|
import com.cameleer.server.core.alerting.AlertSeverity;
|
||||||
|
import com.cameleer.server.core.alerting.AlertState;
|
||||||
|
import com.cameleer.server.core.alerting.NotificationStatus;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class AlertNotificationControllerIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
|
@Autowired private TestRestTemplate restTemplate;
|
||||||
|
@Autowired private ObjectMapper objectMapper;
|
||||||
|
@Autowired private TestSecurityHelper securityHelper;
|
||||||
|
@Autowired private AlertInstanceRepository instanceRepo;
|
||||||
|
@Autowired private AlertNotificationRepository notificationRepo;
|
||||||
|
|
||||||
|
private String operatorJwt;
|
||||||
|
private String viewerJwt;
|
||||||
|
private String envSlug;
|
||||||
|
private UUID envId;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
operatorJwt = securityHelper.operatorToken();
|
||||||
|
viewerJwt = securityHelper.viewerToken();
|
||||||
|
seedUser("test-operator");
|
||||||
|
seedUser("test-viewer");
|
||||||
|
|
||||||
|
envSlug = "notif-env-" + UUID.randomUUID().toString().substring(0, 6);
|
||||||
|
envId = UUID.randomUUID();
|
||||||
|
jdbcTemplate.update(
|
||||||
|
"INSERT INTO environments (id, slug, display_name) VALUES (?, ?, ?) ON CONFLICT (id) DO NOTHING",
|
||||||
|
envId, envSlug, envSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void cleanUp() {
|
||||||
|
jdbcTemplate.update("DELETE FROM alert_notifications WHERE alert_instance_id IN (SELECT id FROM alert_instances WHERE environment_id = ?)", envId);
|
||||||
|
jdbcTemplate.update("DELETE FROM alert_instances WHERE environment_id = ?", envId);
|
||||||
|
jdbcTemplate.update("DELETE FROM environments WHERE id = ?", envId);
|
||||||
|
jdbcTemplate.update("DELETE FROM users WHERE user_id IN ('test-operator','test-viewer')");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void listNotificationsForInstance() throws Exception {
|
||||||
|
AlertInstance instance = seedInstance();
|
||||||
|
AlertNotification notification = seedNotification(instance.id());
|
||||||
|
|
||||||
|
ResponseEntity<String> resp = restTemplate.exchange(
|
||||||
|
"/api/v1/environments/" + envSlug + "/alerts/" + instance.id() + "/notifications",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)),
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
JsonNode body = objectMapper.readTree(resp.getBody());
|
||||||
|
assertThat(body.isArray()).isTrue();
|
||||||
|
assertThat(body.size()).isGreaterThanOrEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void viewerCanListNotifications() throws Exception {
|
||||||
|
AlertInstance instance = seedInstance();
|
||||||
|
|
||||||
|
ResponseEntity<String> resp = restTemplate.exchange(
|
||||||
|
"/api/v1/environments/" + envSlug + "/alerts/" + instance.id() + "/notifications",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(securityHelper.authHeadersNoBody(viewerJwt)),
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void retryNotification() throws Exception {
|
||||||
|
AlertInstance instance = seedInstance();
|
||||||
|
AlertNotification notification = seedNotification(instance.id());
|
||||||
|
|
||||||
|
// Mark as failed first
|
||||||
|
notificationRepo.markFailed(notification.id(), 500, "Internal Server Error");
|
||||||
|
|
||||||
|
ResponseEntity<String> resp = restTemplate.exchange(
|
||||||
|
"/api/v1/alerts/notifications/" + notification.id() + "/retry",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(securityHelper.authHeaders(operatorJwt)),
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void viewerCannotRetry() throws Exception {
|
||||||
|
AlertInstance instance = seedInstance();
|
||||||
|
AlertNotification notification = seedNotification(instance.id());
|
||||||
|
|
||||||
|
ResponseEntity<String> resp = restTemplate.exchange(
|
||||||
|
"/api/v1/alerts/notifications/" + notification.id() + "/retry",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(securityHelper.authHeaders(viewerJwt)),
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void retryUnknownNotificationReturns404() {
|
||||||
|
ResponseEntity<String> resp = restTemplate.exchange(
|
||||||
|
"/api/v1/alerts/notifications/" + UUID.randomUUID() + "/retry",
|
||||||
|
HttpMethod.POST,
|
||||||
|
new HttpEntity<>(securityHelper.authHeaders(operatorJwt)),
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private AlertInstance seedInstance() {
|
||||||
|
AlertInstance instance = new AlertInstance(
|
||||||
|
UUID.randomUUID(), null, null, envId,
|
||||||
|
AlertState.FIRING, AlertSeverity.WARNING,
|
||||||
|
Instant.now(), null, null, null, null, false,
|
||||||
|
42.0, 1000.0, null, "Test alert", "Something happened",
|
||||||
|
List.of(), List.of(), List.of("OPERATOR"));
|
||||||
|
return instanceRepo.save(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertNotification seedNotification(UUID instanceId) {
|
||||||
|
// webhookId is a local UUID (not FK-constrained), outboundConnectionId is null
|
||||||
|
// (FK to outbound_connections ON DELETE SET NULL - null is valid)
|
||||||
|
AlertNotification notification = new AlertNotification(
|
||||||
|
UUID.randomUUID(), instanceId,
|
||||||
|
UUID.randomUUID(), null,
|
||||||
|
NotificationStatus.PENDING,
|
||||||
|
0, Instant.now(),
|
||||||
|
null, null,
|
||||||
|
null, null,
|
||||||
|
null, null, Instant.now());
|
||||||
|
return notificationRepo.save(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void seedUser(String userId) {
|
||||||
|
jdbcTemplate.update(
|
||||||
|
"INSERT INTO users (user_id, provider, email, display_name) VALUES (?, 'test', ?, ?) ON CONFLICT (user_id) DO NOTHING",
|
||||||
|
userId, userId + "@example.com", userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import com.cameleer.server.core.alerting.*;
|
import com.cameleer.server.core.alerting.*;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,6 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
|
|
||||||
class PostgresAlertInstanceRepositoryIT extends AbstractPostgresIT {
|
class PostgresAlertInstanceRepositoryIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private PostgresAlertInstanceRepository repo;
|
private PostgresAlertInstanceRepository repo;
|
||||||
private UUID envId;
|
private UUID envId;
|
||||||
private UUID ruleId;
|
private UUID ruleId;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import com.cameleer.server.core.alerting.*;
|
import com.cameleer.server.core.alerting.*;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,6 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
|
|
||||||
class PostgresAlertNotificationRepositoryIT extends AbstractPostgresIT {
|
class PostgresAlertNotificationRepositoryIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private PostgresAlertNotificationRepository repo;
|
private PostgresAlertNotificationRepository repo;
|
||||||
private UUID envId;
|
private UUID envId;
|
||||||
private UUID instanceId;
|
private UUID instanceId;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -13,6 +16,9 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
|||||||
|
|
||||||
class PostgresAlertReadRepositoryIT extends AbstractPostgresIT {
|
class PostgresAlertReadRepositoryIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private PostgresAlertReadRepository repo;
|
private PostgresAlertReadRepository repo;
|
||||||
private UUID envId;
|
private UUID envId;
|
||||||
private UUID instanceId1;
|
private UUID instanceId1;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import com.cameleer.server.core.alerting.*;
|
import com.cameleer.server.core.alerting.*;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,6 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
|
|
||||||
class PostgresAlertRuleRepositoryIT extends AbstractPostgresIT {
|
class PostgresAlertRuleRepositoryIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private PostgresAlertRuleRepository repo;
|
private PostgresAlertRuleRepository repo;
|
||||||
private UUID envId;
|
private UUID envId;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import com.cameleer.server.core.alerting.AlertSilence;
|
import com.cameleer.server.core.alerting.AlertSilence;
|
||||||
import com.cameleer.server.core.alerting.SilenceMatcher;
|
import com.cameleer.server.core.alerting.SilenceMatcher;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
@@ -16,6 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
|
|
||||||
class PostgresAlertSilenceRepositoryIT extends AbstractPostgresIT {
|
class PostgresAlertSilenceRepositoryIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private PostgresAlertSilenceRepository repo;
|
private PostgresAlertSilenceRepository repo;
|
||||||
private UUID envId;
|
private UUID envId;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
package com.cameleer.server.app.alerting.storage;
|
package com.cameleer.server.app.alerting.storage;
|
||||||
|
|
||||||
import com.cameleer.server.app.AbstractPostgresIT;
|
import com.cameleer.server.app.AbstractPostgresIT;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseLogStore;
|
||||||
|
import com.cameleer.server.app.search.ClickHouseSearchIndex;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class V12MigrationIT extends AbstractPostgresIT {
|
class V12MigrationIT extends AbstractPostgresIT {
|
||||||
|
|
||||||
|
@MockBean(name = "clickHouseSearchIndex") ClickHouseSearchIndex clickHouseSearchIndex;
|
||||||
|
@MockBean(name = "clickHouseLogStore") ClickHouseLogStore clickHouseLogStore;
|
||||||
|
|
||||||
private java.util.UUID testEnvId;
|
private java.util.UUID testEnvId;
|
||||||
private String testUserId;
|
private String testUserId;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user