package com.xuqm.tenant.service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.xuqm.tenant.config.PrivateDeploymentProperties; import com.xuqm.tenant.dto.CreateAppRequest; import com.xuqm.tenant.entity.AppEntity; import com.xuqm.tenant.repository.AppRepository; import com.xuqm.tenant.repository.FeatureServiceRepository; import com.xuqm.tenant.repository.TenantRepository; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class AppServiceConfigIssuanceTest { @Test void newlyIssuedClientConfigDoesNotContainServerCredential() throws Exception { AppRepository appRepository = mock(AppRepository.class); OperationLogService operationLogService = mock(OperationLogService.class); FeatureServiceRepository featureServiceRepository = mock(FeatureServiceRepository.class); PrivateDeploymentProperties deploymentProperties = new PrivateDeploymentProperties(); TenantRepository tenantRepository = mock(TenantRepository.class); ConfigFileSigningService signingService = mock(ConfigFileSigningService.class); ArgumentCaptor canonicalPayload = ArgumentCaptor.forClass(String.class); when(appRepository.save(any(AppEntity.class))).thenAnswer(invocation -> invocation.getArgument(0)); when(signingService.sign(canonicalPayload.capture())).thenReturn("signed-config"); AppService service = new AppService( appRepository, operationLogService, featureServiceRepository, deploymentProperties, tenantRepository, signingService); ReflectionTestUtils.setField(service, "sdkPlatformPublicBaseUrl", "https://sdk.example.com/"); AppEntity created = service.create("tenant-1", new CreateAppRequest( "com.example.android", "com.example.ios", "com.example.harmony", "Example", null, null)); JsonNode payload = new ObjectMapper().readTree(canonicalPayload.getValue()); assertThat(created.getConfigFileContent()).isEqualTo("signed-config"); assertThat(payload.path("appKey").asText()).isEqualTo(created.getAppKey()); assertThat(payload.path("serverUrl").asText()).isEqualTo("https://sdk.example.com/"); assertThat(payload.has("signingKey")).isFalse(); assertThat(payload.has("appSecret")).isFalse(); } @Test void resettingServerAppSecretDoesNotInvalidateIndependentClientConfig() { AppRepository appRepository = mock(AppRepository.class); OperationLogService operationLogService = mock(OperationLogService.class); FeatureServiceRepository featureServiceRepository = mock(FeatureServiceRepository.class); ConfigFileSigningService signingService = mock(ConfigFileSigningService.class); AppEntity app = new AppEntity(); app.setId("app-1"); app.setTenantId("tenant-1"); app.setAppKey("ak_test"); app.setAppSecret("old-secret"); app.setName("Example"); app.setPackageName("com.example"); app.setConfigFileContent("unchanged-signed-config"); app.setConfigFileId("config-1"); app.setConfigFileRevision(7); when(appRepository.findByAppKey("ak_test")).thenReturn(java.util.Optional.of(app)); when(appRepository.save(any(AppEntity.class))).thenAnswer(invocation -> invocation.getArgument(0)); AppService service = new AppService( appRepository, operationLogService, featureServiceRepository, new PrivateDeploymentProperties(), mock(TenantRepository.class), signingService); String newSecret = service.resetSecret("ak_test", "tenant-1"); assertThat(newSecret).isNotBlank().isNotEqualTo("old-secret"); assertThat(app.getConfigFileContent()).isEqualTo("unchanged-signed-config"); assertThat(app.getConfigFileRevision()).isEqualTo(7); verify(signingService, never()).sign(any()); } }