diff --git a/config/nacos/cn/iam-service.yml b/config/nacos/cn/iam-service.yml index f735164e7..52b571129 100644 --- a/config/nacos/cn/iam-service.yml +++ b/config/nacos/cn/iam-service.yml @@ -7,10 +7,10 @@ spring: baiyue: security-event: event-bridge-url: ${SECURITY_EVENT_BRIDGE_URL:http://event-bridge-overseas:9312} - customer-dimension-initialization: - fixed-delay-ms: ${CUSTOMER_DIMENSION_INITIALIZATION_FIXED_DELAY_MS:5000} - max-attempts: ${CUSTOMER_DIMENSION_INITIALIZATION_MAX_ATTEMPTS:12} + security-event: + event-bridge-url: ${SECURITY_EVENT_BRIDGE_URL:http://event-bridge-overseas:9312} notification: scheduler-enabled: ${NOTIFICATION_SCHEDULER_ENABLED:false} dispatch-timeout-seconds: ${NOTIFICATION_DISPATCH_TIMEOUT_SECONDS:300} mq-consumer-enabled: ${NOTIFICATION_MQ_CONSUMER_ENABLED:false} + diff --git a/iam/src/main/resources/application.yml b/iam/src/main/resources/application.yml index 5faf2522f..c01cc552b 100644 --- a/iam/src/main/resources/application.yml +++ b/iam/src/main/resources/application.yml @@ -25,9 +25,8 @@ spring: baiyue: security-event: event-bridge-url: ${SECURITY_EVENT_BRIDGE_URL:http://event-bridge-overseas:9312} - customer-dimension-initialization: - fixed-delay-ms: ${CUSTOMER_DIMENSION_INITIALIZATION_FIXED_DELAY_MS:5000} - max-attempts: ${CUSTOMER_DIMENSION_INITIALIZATION_MAX_ATTEMPTS:12} + security-event: + event-bridge-url: ${SECURITY_EVENT_BRIDGE_URL:http://event-bridge-overseas:9312} notification: scheduler-enabled: ${NOTIFICATION_SCHEDULER_ENABLED:false} dispatch-timeout-seconds: ${NOTIFICATION_DISPATCH_TIMEOUT_SECONDS:300} @@ -50,3 +49,4 @@ logging: max-history: "${LOGGING_ROLLING_MAX_HISTORY:7}" total-size-cap: "${LOGGING_ROLLING_TOTAL_SIZE_CAP:5GB}" clean-history-on-start: "${LOGGING_ROLLING_CLEAN_HISTORY_ON_START:false}" + diff --git a/iam/src/test/java/com/baiyue/iam/service/MerchantOnboardingServiceTest.java b/iam/src/test/java/com/baiyue/iam/service/MerchantOnboardingServiceTest.java index 2b48686ef..c0d166639 100644 --- a/iam/src/test/java/com/baiyue/iam/service/MerchantOnboardingServiceTest.java +++ b/iam/src/test/java/com/baiyue/iam/service/MerchantOnboardingServiceTest.java @@ -42,6 +42,7 @@ class MerchantOnboardingServiceTest { @MockBean private CustomerDimensionRuleInitializationService dimensionRuleInitialization; @MockBean private OverseasStorageFeeInitializationService overseasStorageFeeInitialization; @MockBean private SecurityEventOutboxService securityEvents; + @MockBean private SecurityEventOutboxService securityEvents; @Resource private MerchantOnboardingService service; @Test void clientRegistrationCreatesOwnerAndAssignsGlobalMerchantOwnerRole() { @@ -55,8 +56,8 @@ class MerchantOnboardingServiceTest { when(roles.selectOne(any())).thenReturn(ownerRole); var result = service.register(new MerchantRegistrationRequest( - 9001L, "注册人", "测试ä¼�业", "张三", "13800138000", - "owner@example.com", "CN", "深圳市å®�安区")); + 9001L, "×¢²áÈË", "²âÊÔÆóÒµ", "ÕÅÈý", "13800138000", + "owner@example.com", "CN", "ÉîÛÚÊб¦°²Çø")); ArgumentCaptor tenant = ArgumentCaptor.forClass(IamTenant.class); ArgumentCaptor user = ArgumentCaptor.forClass(IamUser.class); @@ -67,19 +68,21 @@ class MerchantOnboardingServiceTest { verify(memberships).insert(membership.capture()); verify(membershipRoles).insert(roleGrant.capture()); verify(dimensionRuleInitialization).initialize(result.tenantId(), 9001L); - verify(overseasStorageFeeInitialization).initialize(result.tenantId(), 9001L, "测试ä¼�业"); + verify(overseasStorageFeeInitialization).initialize(result.tenantId(), 9001L, "²âÊÔÆóÒµ"); + verify(securityEvents).tenantStatus(result.tenantId(), "PROFILE_REQUIRED"); + verify(securityEvents).userStatus(9001L, result.tenantId(), "MERCHANT", "ACTIVE"); + verify(securityEvents).permissionChanged(9001L, result.tenantId(), "MERCHANT", + "INITIAL_AUTHORIZATION"); verify(securityEvents).tenantStatus(result.tenantId(), "PROFILE_REQUIRED"); verify(securityEvents).userStatus(9001L, result.tenantId(), "MERCHANT", "ACTIVE"); verify(securityEvents).permissionChanged(9001L, result.tenantId(), "MERCHANT", "INITIAL_AUTHORIZATION"); assertEquals("PROFILE_REQUIRED", result.tenantStatus()); - assertEquals("PENDING", result.dimensionInitializationStatus()); - assertEquals("PENDING", tenant.getValue().getDimensionInitializationStatus()); assertEquals(result.tenantId(), tenant.getValue().getId()); - assertEquals("测试ä¼�业", tenant.getValue().getLegalName()); - assertEquals("张三", tenant.getValue().getLegalRepresentative()); - assertEquals("注册人", tenant.getValue().getContactName()); + assertEquals("²âÊÔÆóÒµ", tenant.getValue().getLegalName()); + assertEquals("ÕÅÈý", tenant.getValue().getLegalRepresentative()); + assertEquals("×¢²áÈË", tenant.getValue().getContactName()); assertEquals(9001L, user.getValue().getAuthUserId()); assertEquals("ACTIVE", user.getValue().getStatus()); assertEquals(result.tenantId(), membership.getValue().getTenantId()); @@ -124,7 +127,7 @@ class MerchantOnboardingServiceTest { } @Test - void clientRegistrationFailsWhenDurableInitializationIntentCannotBePersisted() { + void clientRegistrationFailsWhenFourDefaultBoxDimensionsCannotBeInitialized() { IamRole ownerRole = new IamRole(); ownerRole.setId(4000100L); ownerRole.setTenantId(0L); @@ -133,14 +136,14 @@ class MerchantOnboardingServiceTest { ownerRole.setStatus("ACTIVE"); when(roles.selectOne(any())).thenReturn(ownerRole); org.mockito.Mockito.doThrow(new com.baiyue.common.core.exception.BizException( - com.baiyue.common.core.api.ResultCode.SERVICE_UNAVAILABLE, "åˆ�始化失败")) + com.baiyue.common.core.api.ResultCode.SERVICE_UNAVAILABLE, "³õʼ»¯Ê§°Ü")) .when(dimensionRuleInitialization).initialize( org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyLong()); var failure = assertThrows(com.baiyue.common.core.exception.BizException.class, () -> service.register(new MerchantRegistrationRequest( - 9001L, "注册人", "测试ä¼�业", "张三", "13800138000", - "owner@example.com", "CN", "深圳市å®�安区"))); + 9001L, "×¢²áÈË", "²âÊÔÆóÒµ", "ÕÅÈý", "13800138000", + "owner@example.com", "CN", "ÉîÛÚÊб¦°²Çø"))); assertEquals(com.baiyue.common.core.api.ResultCode.SERVICE_UNAVAILABLE, failure.getResultCode()); } @@ -190,7 +193,7 @@ class MerchantOnboardingServiceTest { when(qualifications.selectCount(any())).thenReturn(0L); when(reviews.selectCount(any())).thenReturn(0L); org.mockito.Mockito.doThrow(new com.baiyue.common.core.exception.BizException( - com.baiyue.common.core.api.ResultCode.SERVICE_UNAVAILABLE, "è¡¥å�¿å¤±è´¥")) + com.baiyue.common.core.api.ResultCode.SERVICE_UNAVAILABLE, "²¹³¥Ê§°Ü")) .when(dimensionRuleInitialization).compensateRegistration(10001L); assertThrows(com.baiyue.common.core.exception.BizException.class, @@ -201,3 +204,4 @@ class MerchantOnboardingServiceTest { verify(tenants, never()).deleteById((java.io.Serializable) any()); } } + diff --git a/iam/src/test/java/com/baiyue/iam/service/TenantServiceTest.java b/iam/src/test/java/com/baiyue/iam/service/TenantServiceTest.java index eb7bb54dc..a7886a304 100644 --- a/iam/src/test/java/com/baiyue/iam/service/TenantServiceTest.java +++ b/iam/src/test/java/com/baiyue/iam/service/TenantServiceTest.java @@ -151,22 +151,22 @@ class TenantServiceTest { var updated = service.updateMerchant(10001L, new UpdateTenantRequest("New name", "New legal", "Bob", "Alice", "13800138000", "alice@example.com", - "专业版", "alice_wechat", "Sales Zhang", 45, "LIMITED_COMPANY", LocalDate.of(2020, 1, 2), - new BigDecimal("5000000.00"), "CNY", "深圳市å�—山区示例路 1 å�·", "一期é‡�点客户")); + "רҵ°æ", "alice_wechat", "Sales Zhang", 45, "LIMITED_COMPANY", LocalDate.of(2020, 1, 2), + new BigDecimal("5000000.00"), "CNY", "ÉîÛÚÊÐÄÏÉ½ÇøÊ¾Àý· 1 ºÅ", "Ò»ÆÚÖØµã¿Í»§")); var disabled = service.changeMerchantStatus(10001L, new ChangeTenantStatusRequest("DISABLED")); assertEquals("New name", updated.tenantName()); assertEquals("Bob", updated.legalRepresentative()); assertEquals("alice_wechat", updated.contactWechat()); - assertEquals("专业版", updated.servicePackage()); + assertEquals("רҵ°æ", updated.servicePackage()); assertEquals("Sales Zhang", updated.salesOwnerName()); assertEquals(45, updated.paymentTermDays()); assertEquals("LIMITED_COMPANY", updated.enterpriseType()); assertEquals(LocalDate.of(2020, 1, 2), updated.establishedDate()); assertEquals(new BigDecimal("5000000.00"), updated.registeredCapital()); assertEquals("CNY", updated.registeredCapitalCurrency()); - assertEquals("深圳市å�—山区示例路 1 å�·", updated.registeredAddress()); - assertEquals("一期é‡�点客户", updated.internalRemark()); + assertEquals("ÉîÛÚÊÐÄÏÉ½ÇøÊ¾Àý· 1 ºÅ", updated.registeredAddress()); + assertEquals("Ò»ÆÚÖØµã¿Í»§", updated.internalRemark()); assertEquals("DISABLED", disabled.status()); verify(repository, org.mockito.Mockito.times(2)).saveTenant(tenant); } @@ -178,7 +178,7 @@ class TenantServiceTest { BizException exception = assertThrows(BizException.class, () -> service.updateMerchant(10001L, new UpdateTenantRequest("New name", "New legal", "Bob", "Alice", "13900139000", null, - "基础版", null, null, 30, null, null, null, "CNY", null, null))); + "»ù´¡°æ", null, null, 30, null, null, null, "CNY", null, null))); assertEquals(ResultCode.CONFLICT, exception.getResultCode()); assertEquals("13800138000", tenant.getContactPhone()); @@ -273,7 +273,7 @@ class TenantServiceTest { BizException platformFailure = assertThrows(BizException.class, () -> service.updateMerchant(10001L, new UpdateTenantRequest("New name", "New legal", "Bob", "Alice", "13800138000", null, - "基础版", null, null, 30, null, null, null, "CNY", null, null))); + "»ù´¡°æ", null, null, 30, null, null, null, "CNY", null, null))); BizException merchantFailure = assertThrows(BizException.class, () -> service.update(10001L, new UpdateProfileRequest("New name", "New legal", "Bob", "Alice", "13800138000", "alice@example.com"))); @@ -308,32 +308,32 @@ class TenantServiceTest { var created = service.register(new RegisterRequest( "Example Merchant", "Example Merchant Ltd", "Bob", "Alice", "13800138000", - "alice@example.com", "基础版", "alice_wechat", "Sales Zhang", 30, "LIMITED_COMPANY", - LocalDate.of(2020, 1, 2), new BigDecimal("5000000.00"), "CNY", "深圳市å�—山区", "è�‰ç¨¿å®¢æˆ·"), + "alice@example.com", "»ù´¡°æ", "alice_wechat", "Sales Zhang", 30, "LIMITED_COMPANY", + LocalDate.of(2020, 1, 2), new BigDecimal("5000000.00"), "CNY", "ÉîÛÚÊÐÄÏÉ½Çø", "²Ý¸å¿Í»§"), 9001L); assertEquals("PROFILE_REQUIRED", created.tenant().status()); - assertEquals("PENDING", created.tenant().dimensionInitializationStatus()); assertEquals("Bob", created.tenant().legalRepresentative()); - assertEquals("基础版", created.tenant().servicePackage()); + assertEquals("»ù´¡°æ", created.tenant().servicePackage()); assertEquals("13800138000", created.administratorUsername()); assertEquals("Password1234", created.temporaryPassword()); verify(repository).insertTenant(argThat(tenant -> Long.valueOf(9001L).equals(tenant.getCreatedBy()) && Long.valueOf(9001L).equals(tenant.getUpdatedBy()))); verify(dimensionRuleInitialization).initialize(created.tenant().id(), 9001L); verify(securityEvents).tenantStatus(created.tenant().id(), "PROFILE_REQUIRED"); + verify(securityEvents).tenantStatus(created.tenant().id(), "PROFILE_REQUIRED"); verify(provisioning).provisionPlatformCreatedTenant(any(), eq(9001L)); verify(repository, never()).insertReview(any()); } @Test - void platformRegistrationFailsWhenDurableInitializationIntentCannotBePersisted() { - doThrow(new BizException(ResultCode.SERVICE_UNAVAILABLE, "åˆ�始化失败")) + void platformRegistrationFailsWhenFourDefaultBoxDimensionsCannotBeInitialized() { + doThrow(new BizException(ResultCode.SERVICE_UNAVAILABLE, "³õʼ»¯Ê§°Ü")) .when(dimensionRuleInitialization).initialize(any(Long.class), any(Long.class)); BizException failure = assertThrows(BizException.class, () -> service.register(new RegisterRequest( "Example Merchant", "Example Merchant Ltd", "Bob", "Alice", "13800138000", - "alice@example.com", "基础版", null, null, 30, null, + "alice@example.com", "»ù´¡°æ", null, null, 30, null, null, null, "CNY", null, null), 9001L)); assertEquals(ResultCode.SERVICE_UNAVAILABLE, failure.getResultCode()); @@ -347,7 +347,7 @@ class TenantServiceTest { var created = service.register(new RegisterRequest( "Example Merchant", "Example Merchant Ltd", "Bob", "Alice", "13800138000", - "alice@example.com", "基础版", null, null, 30, null, + "alice@example.com", "»ù´¡°æ", null, null, 30, null, null, null, "CNY", null, null), 9001L); assertEquals(null, created.tenant().unifiedSocialCreditCode()); @@ -420,7 +420,7 @@ class TenantServiceTest { TenantAdministratorProvisioningService.ProvisioningResult.created( 81L, "merchant_10001", "Password1234")).when(provisioning).initialize(any()); - var result = service.review(71L, 9001L, true, "资料完整"); + var result = service.review(71L, 9001L, true, "×ÊÁÏÍêÕû"); assertEquals(10001L, result.tenantId()); assertEquals(true, result.administratorCreated()); @@ -431,6 +431,7 @@ class TenantServiceTest { verify(repository).saveReview(review); verify(repository).saveTenant(tenant); verify(securityEvents).tenantStatus(10001L, "ACTIVE"); + verify(securityEvents).tenantStatus(10001L, "ACTIVE"); } @Test @@ -446,7 +447,7 @@ class TenantServiceTest { doReturn(TenantAdministratorProvisioningService.ProvisioningResult.existing()) .when(provisioning).initialize(any()); - var result = service.review(71L, 9001L, true, "资料完整"); + var result = service.review(71L, 9001L, true, "×ÊÁÏÍêÕû"); assertEquals(false, result.administratorCreated()); assertEquals(null, result.administratorUsername()); @@ -470,7 +471,7 @@ class TenantServiceTest { doReturn(administrator).when(provisioning).initialize(any()); doThrow(new RuntimeException("review write failed")).when(repository).saveReview(review); - assertThrows(RuntimeException.class, () -> service.review(71L, 9001L, true, "资料完整")); + assertThrows(RuntimeException.class, () -> service.review(71L, 9001L, true, "×ÊÁÏÍêÕû")); verify(provisioning).compensate(any(), eq(administrator)); verify(repository, never()).saveTenant(tenant); @@ -492,26 +493,12 @@ class TenantServiceTest { assertEquals(true, withQualification.eligible()); } - @Test - void activeCustomerCannotOrderUntilDefaultDimensionsAreReady() { - IamTenant tenant = merchant(10001L, "ACTIVE"); - tenant.setDimensionInitializationStatus("FAILED"); - when(repository.findTenant(10001L)).thenReturn(tenant); - - var result = service.orderEligibility(10001L); - - assertEquals(false, result.eligible()); - assertEquals("Customer default dimensions are not ready", result.reason()); - verify(profileRepository, never()).findQualifications(10001L); - } - private IamTenant merchant(long id, String status) { IamTenant tenant = new IamTenant(); tenant.setId(id); tenant.setTenantCode("TEN" + id); tenant.setTenantType("MERCHANT"); tenant.setStatus(status); - tenant.setDimensionInitializationStatus("READY"); tenant.setTenantName("Example Merchant"); tenant.setLegalName("Example Merchant Ltd"); tenant.setUnifiedSocialCreditCode("91330100EXAMPLE001"); @@ -544,3 +531,4 @@ class TenantServiceTest { return review; } } + diff --git a/scripts/synchronous-dependency-contract.test.mjs b/scripts/synchronous-dependency-contract.test.mjs index fa082a7fd..a9b69530f 100644 --- a/scripts/synchronous-dependency-contract.test.mjs +++ b/scripts/synchronous-dependency-contract.test.mjs @@ -130,19 +130,6 @@ test('every reviewed synchronous client has a complete and exclusive executable } }) -test('IAM customer dimension Feign is reachable only from the background relay', async () => { - const references = [] - for (const file of await javaFiles(path.join(root, 'iam', 'src', 'main', 'java'))) { - const source = await readFile(file, 'utf8') - if (source.includes('CustomerDimensionRuleClient')) { - references.push(path.relative(root, file).replaceAll('\\', '/')) - } - } - assert.deepEqual(references.sort(), [ - 'iam/src/main/java/com/baiyue/iam/client/CustomerDimensionRuleClient.java', - 'iam/src/main/java/com/baiyue/iam/service/CustomerDimensionInitializationRelay.java' - ]) -}) test('all four Lastleg RestClient gateways use explicit bounded transports', async () => { const clients = new Map([