Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public class ClientService {

public List<ClientConnectionVO> listConnections(String clusterId, String type) {
log.info("Listing client connections, clusterId={}, type={}", clusterId, type);
return clientProvider.findConnections(clusterId, type);
return clientProvider.findConnections(normalizeFilter(clusterId), normalizeFilter(type));
}

private String normalizeFilter(String value) {
return value == null || value.isBlank() ? null : value.trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ public class ProducerConnectionService {

public List<ProducerConnectionVO> listConnections(String topic, String producerGroup) {
log.info("Listing producer connections, topic={}, producerGroup={}", topic, producerGroup);
String normalizedTopic = normalizeFilter(topic);
String normalizedProducerGroup = normalizeFilter(producerGroup);
return clientService.listConnections(null, ClientType.Producer.name()).stream()
.filter(connection -> matchesFilter(connection, topic, producerGroup))
.filter(connection -> matchesFilter(connection, normalizedTopic, normalizedProducerGroup))
.map(this::toProducerConnection)
.toList();
}
Expand All @@ -60,4 +62,8 @@ private ProducerConnectionVO toProducerConnection(ClientConnectionVO connection)
private boolean hasText(String value) {
return value != null && !value.trim().isEmpty();
}

private String normalizeFilter(String value) {
return hasText(value) ? value.trim() : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ public class InstanceService {

public List<InstanceVO> listInstances(InstanceType type, String search) {
log.debug("Listing instances, type={}, search={}", type, search);
String normalizedSearch = search == null || search.isBlank() ? null : search.trim();

if (type != null && search != null && !search.isBlank()) {
return instanceRepository.findByTypeAndSearch(type, search);
if (type != null && normalizedSearch != null) {
return instanceRepository.findByTypeAndSearch(type, normalizedSearch);
} else if (type != null) {
return instanceRepository.findByType(type);
} else if (search != null && !search.isBlank()) {
return instanceRepository.search(search);
} else if (normalizedSearch != null) {
return instanceRepository.search(normalizedSearch);
}
return instanceRepository.findAll();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ public class ConsumerDiagnosticsService {
private final ConsumerDiagnosticsProvider diagnosticsProvider;

public ConsumerStackTraceVO getConsumerStack(String groupName, String clientId) {
if (!StringUtils.hasText(groupName)) {
throw new BusinessException(HttpStatus.BAD_REQUEST.value(), "groupName is required");
}
if (!StringUtils.hasText(clientId)) {
throw new BusinessException(HttpStatus.BAD_REQUEST.value(), "clientId is required");
String normalizedGroupName = normalizeRequired(groupName, "groupName");
String normalizedClientId = normalizeRequired(clientId, "clientId");
return diagnosticsProvider.getConsumerStack(normalizedGroupName, normalizedClientId);
}

private String normalizeRequired(String value, String fieldName) {
if (!StringUtils.hasText(value)) {
throw new BusinessException(HttpStatus.BAD_REQUEST.value(), fieldName + " is required");
}
return diagnosticsProvider.getConsumerStack(groupName, clientId);
return value.trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public class MetadataService {


public List<TopicVO> listTopics(String clusterId, String type, String search) {
return metadataProvider.listTopics(clusterId, type, search);
return metadataProvider.listTopics(
normalizeFilter(clusterId),
normalizeFilter(type),
normalizeFilter(search));
}


Expand Down Expand Up @@ -75,7 +78,7 @@ public SendMessageVO sendMessage(SendMessageDTO request) {


public List<ConsumerGroupVO> listConsumerGroups(String clusterId, String search) {
return metadataProvider.listConsumerGroups(clusterId, search);
return metadataProvider.listConsumerGroups(normalizeFilter(clusterId), normalizeFilter(search));
}


Expand Down Expand Up @@ -114,4 +117,8 @@ public void resetOffset(String name, long timestamp, String topic) {
public List<NamespaceVO> listNamespaces() {
throw new UnsupportedOperationException("Not implemented");
}

private String normalizeFilter(String value) {
return value == null || value.isBlank() ? null : value.trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ public class InMemoryAuditRepository implements AuditRepository {
public List<AuditRecordVO> findAll(String search, String operationType,
LocalDateTime startDate, LocalDateTime endDate,
String result) {
String normalizedSearch = normalize(search);
return records.values().stream()
.filter(r -> search == null || search.isEmpty()
|| r.getDetail().toLowerCase().contains(search.toLowerCase())
|| r.getOperator().toLowerCase().contains(search.toLowerCase())
|| r.getTarget().toLowerCase().contains(search.toLowerCase()))
.filter(r -> normalizedSearch == null
|| containsIgnoreCase(r.getDetail(), normalizedSearch)
|| containsIgnoreCase(r.getOperator(), normalizedSearch)
|| containsIgnoreCase(r.getTarget(), normalizedSearch))
.filter(r -> operationType == null || operationType.isEmpty()
|| operationType.equals(r.getOperationType()))
.filter(r -> startDate == null || r.getTimestamp() != null && !r.getTimestamp().isBefore(startDate))
Expand All @@ -54,6 +55,17 @@ public List<AuditRecordVO> findAll(String search, String operationType,
.collect(Collectors.toList());
}

private String normalize(String value) {
if (value == null || value.isBlank()) {
return null;
}
return value.toLowerCase();
}

private boolean containsIgnoreCase(String value, String normalizedSearch) {
return value != null && value.toLowerCase().contains(normalizedSearch);
}

@Override
public int deleteBefore(LocalDateTime cutoff) {
List<String> toRemove = records.values().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.studio.cluster.client;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class ClientServiceTest {

@Mock
private ClientProvider clientProvider;

@InjectMocks
private ClientService clientService;

@Test
void listConnectionsShouldTrimFiltersBeforeQueryingProvider() {
ClientConnectionVO connection = ClientConnectionVO.builder()
.clientId("client-1")
.clusterName("production-cluster")
.build();
when(clientProvider.findConnections("production-cluster", "Producer")).thenReturn(List.of(connection));

List<ClientConnectionVO> result = clientService.listConnections(" production-cluster ", " Producer ");

assertThat(result).containsExactly(connection);
verify(clientProvider).findConnections("production-cluster", "Producer");
}

@Test
void listConnectionsShouldTreatBlankFiltersAsUnspecified() {
when(clientProvider.findConnections(null, null)).thenReturn(List.of());

List<ClientConnectionVO> result = clientService.listConnections(" ", "\t");

assertThat(result).isEmpty();
verify(clientProvider).findConnections(null, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ void listConnectionsShouldFallbackToProducerGroupWhenTopicIsMissing() {
assertThat(result.get(0).getClientId()).isEqualTo("producer-1");
}

@Test
void listConnectionsShouldTrimFilterValues() {
ClientConnectionVO producer = ClientConnectionVO.builder()
.clientId("producer-1")
.type(ClientType.Producer)
.groupOrTopic("order-topic")
.producerGroup("pg-order")
.address("10.0.0.1:38888")
.language(ClientLanguage.Java)
.version("5.1.0")
.build();
when(clientService.listConnections(null, ClientType.Producer.name())).thenReturn(List.of(producer));

List<ProducerConnectionVO> result = producerConnectionService.listConnections(" order-topic ", " pg-order ");

assertThat(result).hasSize(1);
assertThat(result.get(0).getClientId()).isEqualTo("producer-1");
}

@Test
void listConnectionsShouldRequireProducerGroupWhenBothFiltersAreProvided() {
ClientConnectionVO producer = ClientConnectionVO.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ void listInstancesShouldSearchByKeyword() {
verify(instanceRepository).search("prod");
}

@Test
void listInstancesShouldTrimSearchKeyword() {
List<InstanceVO> instances = List.of(
InstanceVO.builder().name("production").build()
);
when(instanceRepository.search("prod")).thenReturn(instances);

List<InstanceVO> result = instanceService.listInstances(null, " prod ");

assertThat(result).hasSize(1);
verify(instanceRepository).search("prod");
}

@Test
void listInstancesShouldFilterByTypeAndSearch() {
List<InstanceVO> instances = List.of(
Expand All @@ -96,6 +109,19 @@ void listInstancesShouldFilterByTypeAndSearch() {
verify(instanceRepository).findByTypeAndSearch(InstanceType.PROXY, "prod");
}

@Test
void listInstancesShouldTrimSearchKeywordWhenFilteringByType() {
List<InstanceVO> instances = List.of(
InstanceVO.builder().name("production-proxy").type(InstanceType.PROXY).build()
);
when(instanceRepository.findByTypeAndSearch(InstanceType.PROXY, "prod")).thenReturn(instances);

List<InstanceVO> result = instanceService.listInstances(InstanceType.PROXY, " prod ");

assertThat(result).hasSize(1);
verify(instanceRepository).findByTypeAndSearch(InstanceType.PROXY, "prod");
}

@Test
void listInstancesShouldIgnoreBlankSearch() {
List<InstanceVO> instances = List.of(InstanceVO.builder().name("inst").build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ void getConsumerStackShouldDelegateToProvider() {
verify(diagnosticsProvider).getConsumerStack("cg-orders", "client-1");
}

@Test
void getConsumerStackShouldTrimInputsBeforeDelegatingToProvider() {
ConsumerStackTraceVO stackTrace = ConsumerStackTraceVO.builder()
.groupName("cg-orders")
.clientId("client-1")
.capturedAt(LocalDateTime.now())
.threadCount(0)
.threads(List.of())
.build();
when(diagnosticsProvider.getConsumerStack("cg-orders", "client-1")).thenReturn(stackTrace);

ConsumerStackTraceVO result = diagnosticsService.getConsumerStack(" cg-orders ", " client-1 ");

assertThat(result.getGroupName()).isEqualTo("cg-orders");
assertThat(result.getClientId()).isEqualTo("client-1");
verify(diagnosticsProvider).getConsumerStack("cg-orders", "client-1");
}

@Test
void getConsumerStackShouldRejectBlankGroupName() {
assertThatThrownBy(() -> diagnosticsService.getConsumerStack(" ", "client-1"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ void listTopicsShouldReturnEmptyWhenNone() {
assertThat(result).isEmpty();
}

@Test
void listTopicsShouldNormalizeFiltersBeforeQueryingProvider() {
TopicVO topic = new TopicVO();
topic.setName("order-topic");
when(metadataProvider.listTopics("cluster-1", "FIFO", "order")).thenReturn(List.of(topic));

List<TopicVO> result = metadataService.listTopics(" cluster-1 ", " FIFO ", " order ");

assertThat(result).containsExactly(topic);
verify(metadataProvider).listTopics("cluster-1", "FIFO", "order");
}

@Test
void listTopicsShouldTreatBlankFiltersAsUnspecified() {
when(metadataProvider.listTopics(null, null, null)).thenReturn(List.of());

List<TopicVO> result = metadataService.listTopics(" ", "\t", "");

assertThat(result).isEmpty();
verify(metadataProvider).listTopics(null, null, null);
}

@Test
void createTopicShouldDelegateToAdminClient() {
TopicVO input = new TopicVO();
Expand Down Expand Up @@ -141,4 +163,16 @@ void listConsumerGroupsShouldPassSearchFilter() {
assertThat(result).isEmpty();
verify(metadataProvider).listConsumerGroups(null, "order");
}

@Test
void listConsumerGroupsShouldNormalizeFiltersBeforeQueryingProvider() {
ConsumerGroupVO group = new ConsumerGroupVO();
group.setName("cg-order");
when(metadataProvider.listConsumerGroups("cluster-1", "order")).thenReturn(List.of(group));

List<ConsumerGroupVO> result = metadataService.listConsumerGroups(" cluster-1 ", " order ");

assertThat(result).containsExactly(group);
verify(metadataProvider).listConsumerGroups("cluster-1", "order");
}
}
Loading
Loading