diff --git a/server/src/main/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSource.java b/server/src/main/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSource.java index 701bab1a..de208331 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSource.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSource.java @@ -108,10 +108,22 @@ private void validateQuery(MetricQueryDTO query) { if (query == null) { throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query is required"); } + if (!StringUtils.hasText(query.getMetric())) { + throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query is required"); + } + if (query.getStart() <= 0) { + throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query start must be positive"); + } + if (query.getEnd() <= 0) { + throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query end must be positive"); + } if (query.getEnd() < query.getStart()) { throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query end must not be earlier than start"); } + if (!StringUtils.hasText(query.getStep())) { + throw new PrometheusException(HttpStatus.BAD_REQUEST.value(), "Metric query step is required"); + } } private URI queryRangeUri() { diff --git a/server/src/test/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSourceTest.java b/server/src/test/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSourceTest.java index 3d2fbb26..905d6887 100644 --- a/server/src/test/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSourceTest.java +++ b/server/src/test/java/com/rocketmq/studio/cluster/metrics/PrometheusMetricsSourceTest.java @@ -244,6 +244,70 @@ void queryShouldRejectEndEarlierThanStart() { .hasMessage("Metric query end must not be earlier than start"); } + @Test + void queryShouldRejectBlankMetric() { + MetricQueryDTO invalidQuery = MetricQueryDTO.builder() + .metric(" ") + .start(1L) + .end(2L) + .step("30s") + .build(); + + assertThatThrownBy(() -> source(Duration.ofSeconds(2)).query(invalidQuery)) + .isInstanceOf(PrometheusException.class) + .satisfies(exception -> assertThat(((PrometheusException) exception).getStatusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value())) + .hasMessage("Metric query is required"); + } + + @Test + void queryShouldRejectNonPositiveStart() { + MetricQueryDTO invalidQuery = MetricQueryDTO.builder() + .metric("up") + .start(0L) + .end(2L) + .step("30s") + .build(); + + assertThatThrownBy(() -> source(Duration.ofSeconds(2)).query(invalidQuery)) + .isInstanceOf(PrometheusException.class) + .satisfies(exception -> assertThat(((PrometheusException) exception).getStatusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value())) + .hasMessage("Metric query start must be positive"); + } + + @Test + void queryShouldRejectNonPositiveEnd() { + MetricQueryDTO invalidQuery = MetricQueryDTO.builder() + .metric("up") + .start(1L) + .end(0L) + .step("30s") + .build(); + + assertThatThrownBy(() -> source(Duration.ofSeconds(2)).query(invalidQuery)) + .isInstanceOf(PrometheusException.class) + .satisfies(exception -> assertThat(((PrometheusException) exception).getStatusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value())) + .hasMessage("Metric query end must be positive"); + } + + @Test + void queryShouldRejectBlankStep() { + MetricQueryDTO invalidQuery = MetricQueryDTO.builder() + .metric("up") + .start(1L) + .end(2L) + .step(" ") + .build(); + + assertThatThrownBy(() -> source(Duration.ofSeconds(2)).query(invalidQuery)) + .isInstanceOf(PrometheusException.class) + .satisfies(exception -> assertThat(((PrometheusException) exception).getStatusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value())) + .hasMessage("Metric query step is required"); + } + @Test void queryShouldFailLoudWhenPrometheusIsNotConfigured() { PrometheusProperties properties = new PrometheusProperties();