This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 76a0204b18 fix(admin): carry namespaceid on appauth delete events
(#7962)
76a0204b18 is described below
commit 76a0204b1825054b81841efdba09231a646c1e88
Author: Duansg <[email protected]>
AuthorDate: Thu Oct 22 20:18:50 2026 -0700
fix(admin): carry namespaceid on appauth delete events (#7962)
---
.../admin/service/impl/AppAuthServiceImpl.java | 11 +-
.../shenyu/admin/service/AppAuthServiceTest.java | 116 ++++++++++++++++++++-
2 files changed, 119 insertions(+), 8 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
index 21ea38efb1..ab3e584748 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
@@ -46,6 +46,7 @@ import org.apache.shenyu.admin.service.AppAuthService;
import org.apache.shenyu.admin.transfer.AppAuthTransfer;
import org.apache.shenyu.admin.utils.ShenyuResultMessage;
import org.apache.shenyu.common.constant.AdminConstants;
+import org.apache.shenyu.common.constant.Constants;
import org.apache.shenyu.common.dto.AppAuthData;
import org.apache.shenyu.common.dto.AuthParamData;
import org.apache.shenyu.common.dto.AuthPathData;
@@ -464,16 +465,18 @@ public class AppAuthServiceImpl implements AppAuthService
{
authParamMapper.deleteByAuthIds(ids);
authPathMapper.deleteByAuthIds(ids);
- List<AppAuthData> appAuthData = appAuthList.stream().map(appAuthDO ->
AppAuthData.builder()
+ Map<String, List<AppAuthData>> namespaceDataList =
appAuthList.stream().map(appAuthDO -> AppAuthData.builder()
+
.namespaceId(StringUtils.defaultString(appAuthDO.getNamespaceId(),
Constants.SYS_DEFAULT_NAMESPACE_ID))
.appKey(appAuthDO.getAppKey())
.appSecret(appAuthDO.getAppSecret())
.open(appAuthDO.getOpen())
.enabled(appAuthDO.getEnabled())
.paramDataList(null)
.pathDataList(null)
- .build()).collect(Collectors.toCollection(() -> new
ArrayList<>(appAuthList.size())));
- // publish delete event of AppAuthData
- eventPublisher.publishEvent(new
DataChangedEvent(ConfigGroupEnum.APP_AUTH, DataEventTypeEnum.DELETE,
appAuthData));
+
.build()).collect(Collectors.groupingBy(AppAuthData::getNamespaceId));
+ // publish a separate delete event for each namespace
+ namespaceDataList.forEach((namespaceId, dataList) ->
eventPublisher.publishEvent(
+ new DataChangedEvent(ConfigGroupEnum.APP_AUTH,
DataEventTypeEnum.DELETE, dataList, namespaceId)));
return affectCount;
}
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/AppAuthServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/AppAuthServiceTest.java
index 1888e3ec90..d14a888c1f 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/AppAuthServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/AppAuthServiceTest.java
@@ -44,27 +44,34 @@ import org.apache.shenyu.admin.utils.ShenyuResultMessage;
import org.apache.shenyu.common.constant.AdminConstants;
import org.apache.shenyu.common.dto.AppAuthData;
import org.apache.shenyu.common.enums.ConfigGroupEnum;
+import org.apache.shenyu.common.enums.DataEventTypeEnum;
import org.apache.shenyu.common.exception.CommonErrorCode;
import org.apache.shenyu.common.utils.SignUtils;
import org.apache.shenyu.common.utils.UUIDUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.test.util.ReflectionTestUtils;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
@@ -192,10 +199,103 @@ public final class AppAuthServiceTest {
assertThat(this.appAuthService.createOrUpdate(updateAppAuthDTO),
greaterThan(0));
}
+ @ParameterizedTest
+ @ValueSource(strings = {"ns-A", SYS_DEFAULT_NAMESPACE_ID})
+ public void testDeletePreservesNamespace(final String namespaceId) {
+ appAuthDO.setNamespaceId(namespaceId);
+ List<String> ids = Collections.singletonList(appAuthDO.getId());
+
given(appAuthMapper.selectByIds(ids)).willReturn(Collections.singletonList(appAuthDO));
+ given(appAuthMapper.deleteByIds(ids)).willReturn(1);
+
+ assertEquals(1, appAuthService.delete(ids));
+
+ verify(authParamMapper).deleteByAuthIds(ids);
+ verify(authPathMapper).deleteByAuthIds(ids);
+ ArgumentCaptor<DataChangedEvent> eventCaptor =
ArgumentCaptor.forClass(DataChangedEvent.class);
+ verify(eventPublisher).publishEvent(eventCaptor.capture());
+ assertDeleteEvent(eventCaptor.getValue(), namespaceId,
appAuthDO.getAppKey());
+ }
+
+ @Test
+ public void testDeletePublishesOneEventPerNamespace() {
+ AppAuthDO first = buildAppAuthDO("auth-A1", "ns-A");
+ AppAuthDO second = buildAppAuthDO("auth-B", "ns-B");
+ AppAuthDO third = buildAppAuthDO("auth-A2", "ns-A");
+ AppAuthDO defaultAuth = buildAppAuthDO("auth-default",
SYS_DEFAULT_NAMESPACE_ID);
+ List<AppAuthDO> authList = List.of(first, second, third, defaultAuth);
+ List<String> ids =
authList.stream().map(AppAuthDO::getId).collect(Collectors.toList());
+ given(appAuthMapper.selectByIds(ids)).willReturn(authList);
+ given(appAuthMapper.deleteByIds(ids)).willReturn(authList.size());
+
+ assertEquals(authList.size(), appAuthService.delete(ids));
+
+ verify(authParamMapper).deleteByAuthIds(ids);
+ verify(authPathMapper).deleteByAuthIds(ids);
+ ArgumentCaptor<DataChangedEvent> eventCaptor =
ArgumentCaptor.forClass(DataChangedEvent.class);
+ verify(eventPublisher, times(3)).publishEvent(eventCaptor.capture());
+ Map<String, DataChangedEvent> events =
eventCaptor.getAllValues().stream()
+ .collect(Collectors.toMap(DataChangedEvent::getNamespaceId,
event -> event));
+ assertEquals(Set.of("ns-A", "ns-B", SYS_DEFAULT_NAMESPACE_ID),
events.keySet());
+ assertDeleteEvent(events.get("ns-A"), "ns-A", first.getAppKey(),
third.getAppKey());
+ assertDeleteEvent(events.get("ns-B"), "ns-B", second.getAppKey());
+ assertDeleteEvent(events.get(SYS_DEFAULT_NAMESPACE_ID),
SYS_DEFAULT_NAMESPACE_ID, defaultAuth.getAppKey());
+ }
+
+ @Test
+ public void testDeleteFallsBackToDefaultNamespaceWhenMissing() {
+ AppAuthDO legacyAuth = buildAppAuthDO("auth-legacy", null);
+ AppAuthDO defaultAuth = buildAppAuthDO("auth-default",
SYS_DEFAULT_NAMESPACE_ID);
+ List<AppAuthDO> authList = List.of(legacyAuth, defaultAuth);
+ List<String> ids =
authList.stream().map(AppAuthDO::getId).collect(Collectors.toList());
+ given(appAuthMapper.selectByIds(ids)).willReturn(authList);
+ given(appAuthMapper.deleteByIds(ids)).willReturn(authList.size());
+
+ assertEquals(authList.size(), appAuthService.delete(ids));
+
+ ArgumentCaptor<DataChangedEvent> eventCaptor =
ArgumentCaptor.forClass(DataChangedEvent.class);
+ verify(eventPublisher).publishEvent(eventCaptor.capture());
+ assertDeleteEvent(eventCaptor.getValue(), SYS_DEFAULT_NAMESPACE_ID,
legacyAuth.getAppKey(), defaultAuth.getAppKey());
+ }
+
+ @ParameterizedTest
+ @NullAndEmptySource
+ public void testDeleteWithoutIdsDoesNotPublish(final List<String> ids) {
+ assertEquals(0, appAuthService.delete(ids));
+
+ verifyNoInteractions(appAuthMapper, authParamMapper, authPathMapper,
eventPublisher);
+ }
+
@Test
- public void testDelete() {
- int count =
appAuthService.delete(Collections.singletonList(appAuthDO.getId()));
- assertThat(count, greaterThanOrEqualTo(0));
+ public void testDeleteMissingRecordsDoesNotPublish() {
+ List<String> ids = Collections.singletonList(appAuthDO.getId());
+
given(appAuthMapper.selectByIds(ids)).willReturn(Collections.emptyList());
+
+ assertEquals(0, appAuthService.delete(ids));
+
+ verify(appAuthMapper, never()).deleteByIds(any());
+ verifyNoInteractions(authParamMapper, authPathMapper, eventPublisher);
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1})
+ public void testDeleteWithoutAffectedRowsDoesNotPublish(final int
affectCount) {
+ List<String> ids = Collections.singletonList(appAuthDO.getId());
+
given(appAuthMapper.selectByIds(ids)).willReturn(Collections.singletonList(appAuthDO));
+ given(appAuthMapper.deleteByIds(ids)).willReturn(affectCount);
+
+ assertEquals(affectCount, appAuthService.delete(ids));
+
+ verifyNoInteractions(authParamMapper, authPathMapper, eventPublisher);
+ }
+
+ private void assertDeleteEvent(final DataChangedEvent event, final String
namespaceId, final String... appKeys) {
+ assertEquals(ConfigGroupEnum.APP_AUTH, event.getGroupKey());
+ assertEquals(DataEventTypeEnum.DELETE,
ReflectionTestUtils.invokeMethod(event, "getEventType"));
+ assertEquals(namespaceId, event.getNamespaceId());
+ assertEquals(appKeys.length, event.getSource().size());
+ List<AppAuthData> authData =
event.getSource().stream().map(AppAuthData.class::cast).collect(Collectors.toList());
+ authData.forEach(data -> assertEquals(namespaceId,
data.getNamespaceId()));
+ assertEquals(Set.of(appKeys),
authData.stream().map(AppAuthData::getAppKey).collect(Collectors.toSet()));
}
@Test
@@ -461,6 +561,14 @@ public final class AppAuthServiceTest {
return appAuthDO;
}
+ private AppAuthDO buildAppAuthDO(final String id, final String
namespaceId) {
+ AppAuthDO auth = buildAppAuthDO();
+ auth.setId(id);
+ auth.setAppKey(id + "-key");
+ auth.setNamespaceId(namespaceId);
+ return auth;
+ }
+
private AuthParamDTO buildAuthParamDTO() {
AuthParamDTO authParamDTO = new AuthParamDTO();
authParamDTO.setAppName("testAppName");