优化
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
package com.baiyue.overseassecurity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OverseasSecurityContractTest {
|
||||
@Test void sqlFreezesReliableInboxProjectionAndRedisRecoveryBoundary() throws Exception {
|
||||
String sql = read("overseas-security-service/src/main/resources/db/overseas-security.sql");
|
||||
String service = read("overseas-security-service/src/main/java/com/baiyue/overseassecurity/service/SecurityProjectionService.java");
|
||||
String validation = read("overseas-security-service/src/main/java/com/baiyue/overseassecurity/service/OverseasSecurityValidationService.java");
|
||||
String mirror = read("overseas-security-service/src/main/java/com/baiyue/overseassecurity/service/SecurityProjectionRedisMirror.java");
|
||||
assertThat(sql).contains("PRIMARY KEY (event_id)", "payload_hash CHAR(64)",
|
||||
"PRIMARY KEY (aggregate_type, aggregate_id)", "aggregate_version BIGINT", "permission_version BIGINT");
|
||||
assertThat(service).contains("ProjectionMonotonicity.decide", "Decision.APPLY");
|
||||
assertThat(mirror).contains("TransactionPhase.AFTER_COMMIT", "Redis 镜像写入失败");
|
||||
assertThat(validation).contains("SELECT MAX(permission_version)", "USER_DISABLED",
|
||||
"TENANT_DISABLED", "PERMISSION_VERSION_STALE");
|
||||
}
|
||||
|
||||
@Test void eventBridgeRoutesIamTypesWithoutInspectingTheirPayload() throws Exception {
|
||||
String dispatcher = read("event-bridge-service/src/main/java/com/baiyue/eventbridge/service/OverseasEventDispatcher.java");
|
||||
String client = read("event-bridge-service/src/main/java/com/baiyue/eventbridge/service/HttpSecurityProjectionEventClient.java");
|
||||
String lastleg = read("lastleg-service/src/main/java/com/baiyue/lastleg/controller/LastlegOrderController.java");
|
||||
assertThat(dispatcher).contains("IAM_USER_STATUS_CHANGED", "IAM_TENANT_STATUS_CHANGED",
|
||||
"IAM_PERMISSION_VERSION_CHANGED", "securityProjectionEventClient.deliver(event)");
|
||||
assertThat(dispatcher).doesNotContain("IamSecurityEventsV1", "permissionVersion()", "status()");
|
||||
assertThat(client).contains("path(\"data\").path(\"eventId\")", "row.getEventId().equals")
|
||||
.doesNotContain("IamSecurityEventsV1");
|
||||
assertThat(lastleg).contains("Lastleg 不消费该事件类型")
|
||||
.doesNotContain("? shippingNodeConsumer.consume(event) : consumer.consume(event)");
|
||||
}
|
||||
|
||||
@Test void internalOpenApiNeverAcceptsRawTokensOrCredentials() throws Exception {
|
||||
String openapi = read("overseas-security-service/src/main/resources/openapi/internal-overseas-security-v1.yaml");
|
||||
assertThat(openapi).contains("/internal/overseas-security/v1/events:",
|
||||
"/internal/overseas-security/v1/validate:", "X-Internal-Service-Token",
|
||||
"userId, tenantId, tokenVersion and permissionVersion");
|
||||
assertThat(openapi).doesNotContain("accessToken", "refreshToken", "password:", "Authorization");
|
||||
}
|
||||
|
||||
private static String read(String relative) throws Exception {
|
||||
Path path = Path.of(relative);
|
||||
if (!Files.exists(path)) path = Path.of("..").resolve(relative);
|
||||
return Files.readString(path, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baiyue.overseassecurity.service;
|
||||
|
||||
import com.baiyue.overseassecurity.dto.OverseasSecurityDtos.FailureReason;
|
||||
import com.baiyue.overseassecurity.dto.OverseasSecurityDtos.ValidationRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class OverseasSecurityValidationServiceTest {
|
||||
private final JdbcTemplate jdbc = mock(JdbcTemplate.class);
|
||||
private final OverseasSecurityValidationService service = new OverseasSecurityValidationService(jdbc);
|
||||
|
||||
@Test void disabledUserAndTenantFailClosed() {
|
||||
when(jdbc.query(anyString(), any(RowMapper.class), any(Object[].class)))
|
||||
.thenReturn(List.of("DISABLED"));
|
||||
assertThat(service.validate(new ValidationRequest(42L, 0L, 3L, 8L)).failureReason())
|
||||
.isEqualTo(FailureReason.USER_DISABLED);
|
||||
}
|
||||
|
||||
@Test void stalePermissionVersionFailsAndCurrentVersionPasses() {
|
||||
when(jdbc.query(anyString(), any(RowMapper.class), any(Object[].class)))
|
||||
.thenReturn(List.of(), List.of());
|
||||
when(jdbc.queryForObject(anyString(), any(Class.class), any(Object[].class))).thenReturn(9L, 9L);
|
||||
assertThat(service.validate(new ValidationRequest(42L, 0L, 3L, 8L)).failureReason())
|
||||
.isEqualTo(FailureReason.PERMISSION_VERSION_STALE);
|
||||
assertThat(service.validate(new ValidationRequest(42L, 0L, 3L, 9L)).valid()).isTrue();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.baiyue.overseassecurity.service;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class ProjectionMonotonicityTest {
|
||||
@Test void appliesFirstAndNewerVersions() {
|
||||
assertThat(ProjectionMonotonicity.decide(null, null, 1, "hash-1"))
|
||||
.isEqualTo(ProjectionMonotonicity.Decision.APPLY);
|
||||
assertThat(ProjectionMonotonicity.decide(1L, "hash-1", 2, "hash-2"))
|
||||
.isEqualTo(ProjectionMonotonicity.Decision.APPLY);
|
||||
}
|
||||
|
||||
@Test void ignoresOlderAndSameHashVersions() {
|
||||
assertThat(ProjectionMonotonicity.decide(3L, "hash-3", 2, "hash-2"))
|
||||
.isEqualTo(ProjectionMonotonicity.Decision.STALE);
|
||||
assertThat(ProjectionMonotonicity.decide(3L, "hash-3", 3, "hash-3"))
|
||||
.isEqualTo(ProjectionMonotonicity.Decision.DUPLICATE_VERSION);
|
||||
}
|
||||
|
||||
@Test void rejectsSameVersionWithDifferentHash() {
|
||||
assertThatThrownBy(() -> ProjectionMonotonicity.decide(3L, "hash-a", 3, "hash-b"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("payloadHash 冲突");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user