diff --git a/microsphere-i18n-spring-boot/pom.xml b/microsphere-i18n-spring-boot/pom.xml index c6237aa..0bec721 100644 --- a/microsphere-i18n-spring-boot/pom.xml +++ b/microsphere-i18n-spring-boot/pom.xml @@ -75,6 +75,24 @@ test + + org.junit.jupiter + junit-jupiter + test + + + + org.assertj + assertj-core + test + + + + com.jayway.jsonpath + json-path-assert + test + + org.springframework spring-test diff --git a/microsphere-i18n-spring-boot/src/main/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpoint.java b/microsphere-i18n-spring-boot/src/main/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpoint.java index 2c8ef0f..24766b5 100644 --- a/microsphere-i18n-spring-boot/src/main/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpoint.java +++ b/microsphere-i18n-spring-boot/src/main/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpoint.java @@ -24,7 +24,6 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -86,7 +85,10 @@ public Map> invoke() { if (subServiceMessageSource instanceof AbstractResourceServiceMessageSource) { AbstractResourceServiceMessageSource resourceServiceMessageSource = (AbstractResourceServiceMessageSource) subServiceMessageSource; Map> localizedResourceMessages = resourceServiceMessageSource.getLocalizedResourceMessages(); - allLocalizedResourceMessages.putAll(localizedResourceMessages); +// allLocalizedResourceMessages.putAll(localizedResourceMessages); + localizedResourceMessages.forEach( + (k, v) -> allLocalizedResourceMessages.merge(k, v, (oldValue, value) -> value.isEmpty() ? oldValue : value) + ); } } } diff --git a/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpointTest.java b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpointTest.java new file mode 100644 index 0000000..6128c44 --- /dev/null +++ b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/I18nEndpointTest.java @@ -0,0 +1,51 @@ +package io.microsphere.i18n.spring.boot.actuate; + +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.DocumentContext; +import io.microsphere.i18n.spring.annotation.EnableI18n; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; + +import java.util.Map; + +import static com.jayway.jsonpath.JsonPath.using; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +class I18nEndpointTest { + ApplicationContextRunner applicationContextRunner; + + @BeforeEach + void setup() { + applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EndpointConfiguration.class)); + } + + @Test + void shouldReturnCommonI18nMessages() { + applicationContextRunner.run(context -> { + Map> invoke = context.getBean(I18nEndpoint.class).invoke(); + DocumentContext parse = using(Configuration.defaultConfiguration()).parse(invoke); + assertThat(parse, hasJsonPath("$.['common.i18n_messages_en.properties']")); + assertThat(parse, hasJsonPath("$.['common.i18n_messages_zh.properties']")); + assertThat(parse, hasJsonPath("$.['common.i18n_messages_zh_CN.properties']")); + assertThat(parse, hasJsonPath("$.['META-INF/i18n/common/i18n_messages_en.properties']")); + assertThat(parse, hasJsonPath("$.['META-INF/i18n/common/i18n_messages_en.properties'].['common.a']", equalTo("a"))); + assertThat(parse, hasJsonPath("$.['META-INF/i18n/common/i18n_messages_zh.properties']")); + assertThat(parse, hasJsonPath("$.['META-INF/i18n/common/i18n_messages_zh_CN.properties']")); + assertThat(parse, hasJsonPath("$.['META-INF/i18n/common/i18n_messages_zh_CN.properties'].['common.a']", equalTo("啊"))); + }); + } + + @EnableI18n + static class EndpointConfiguration { + @Bean + I18nEndpoint i18nEndpoint() { + return new I18nEndpoint(); + } + } +} diff --git a/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/autoconfigure/I18nEndpointAutoConfigurationTest.java b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/autoconfigure/I18nEndpointAutoConfigurationTest.java new file mode 100644 index 0000000..55e803a --- /dev/null +++ b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/actuate/autoconfigure/I18nEndpointAutoConfigurationTest.java @@ -0,0 +1,45 @@ +package io.microsphere.i18n.spring.boot.actuate.autoconfigure; + +import io.microsphere.i18n.spring.boot.actuate.I18nEndpoint; +import io.microsphere.i18n.spring.boot.autoconfigure.I18nAutoConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + + +class I18nEndpointAutoConfigurationTest { + + ApplicationContextRunner applicationContextRunner; + + @BeforeEach + void setup() { + applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + I18nAutoConfiguration.class, + I18nEndpointAutoConfiguration.class + )); + } + + @Test + void shouldHaveEndpointBean() { + applicationContextRunner.withPropertyValues("management.endpoints.web.exposure.include=i18n") + .run(context -> assertThat(context).hasSingleBean(I18nEndpoint.class)); + } + + + @Test + void shouldNotHaveEndpointBean() { + applicationContextRunner + .run(context -> assertThat(context).doesNotHaveBean(I18nEndpoint.class)); + } + + @Test + void shouldNotHaveEndpointBeanWhenEnablePropertyIsFalse() { + applicationContextRunner.withPropertyValues("management.endpoint.i18n.enabled=false") + .withPropertyValues("management.endpoints.web.exposure.include=*") + .run(context -> assertThat(context).doesNotHaveBean(I18nEndpoint.class)); + } +} diff --git a/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/autoconfigure/I18nAutoConfigurationTests.java b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/autoconfigure/I18nAutoConfigurationTests.java new file mode 100644 index 0000000..c3dcfbb --- /dev/null +++ b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/autoconfigure/I18nAutoConfigurationTests.java @@ -0,0 +1,47 @@ +package io.microsphere.i18n.spring.boot.autoconfigure; + +import io.microsphere.i18n.spring.DelegatingServiceMessageSource; +import io.microsphere.i18n.spring.beans.factory.ServiceMessageSourceFactoryBean; +import io.microsphere.i18n.spring.beans.factory.config.I18nBeanPostProcessor; +import io.microsphere.i18n.spring.beans.factory.support.ServiceMessageSourceBeanLifecyclePostProcessor; +import io.microsphere.i18n.spring.context.I18nApplicationListener; +import io.microsphere.i18n.spring.context.MessageSourceAdapter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +class I18nAutoConfigurationTests { + + ApplicationContextRunner applicationContextRunner; + + @BeforeEach + void setup() { + applicationContextRunner = new ApplicationContextRunner(); + } + + @Test + void shouldContainServiceMessageSourceFactoryBean() { + applicationContextRunner.withPropertyValues("spring.application.name=I18nAutoConfigurationTests") + .withConfiguration(AutoConfigurations.of(I18nAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class)) + .run(context -> { + assertThat(context) + .hasBean("applicationServiceMessageSource") + .getBean("applicationServiceMessageSource") + .hasFieldOrPropertyWithValue("source", "I18nAutoConfigurationTests"); + + + assertThat(context).getBeans(ServiceMessageSourceFactoryBean.class).hasSizeGreaterThanOrEqualTo(1); + + assertThat(context).getBean("serviceMessageSource").isInstanceOf(DelegatingServiceMessageSource.class); + assertThat(context).getBean("messageSource").isInstanceOf(MessageSourceAdapter.class); + + assertThat(context).hasSingleBean(I18nApplicationListener.class) + .hasSingleBean(I18nBeanPostProcessor.class) + .hasSingleBean(ServiceMessageSourceBeanLifecyclePostProcessor.class); + }); + } +} diff --git a/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/condition/ConditionalOnI18nEnabledTests.java b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/condition/ConditionalOnI18nEnabledTests.java new file mode 100644 index 0000000..0804578 --- /dev/null +++ b/microsphere-i18n-spring-boot/src/test/java/io/microsphere/i18n/spring/boot/condition/ConditionalOnI18nEnabledTests.java @@ -0,0 +1,61 @@ +package io.microsphere.i18n.spring.boot.condition; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + + +class ConditionalOnI18nEnabledTests { + + ApplicationContextRunner applicationContextRunner; + + @BeforeEach + void setup() { + applicationContextRunner = new ApplicationContextRunner(); + } + + @Test + void shouldEnableI18nByDefault() { + applicationContextRunner.withUserConfiguration(Config.class) + .run(context -> assertThat(context).hasBean("a")); + } + + @Test + void shouldEnableI18nWhenPropertyIsTrue() { + applicationContextRunner.withUserConfiguration(Config.class) + .withPropertyValues("microsphere.i18n.enabled=true") + .run(context -> assertThat(context).hasBean("a")); + } + + @Test + void shouldDisableI18nWhenPropertyIsFalse() { + applicationContextRunner.withUserConfiguration(Config.class) + .withPropertyValues("microsphere.i18n.enabled=false") + .run(context -> assertThat(context).doesNotHaveBean("a")); + } + + @Test + void shouldDisableI18nWhenMissingClass() { + applicationContextRunner.withUserConfiguration(Config.class) + .withPropertyValues("microsphere.i18n.enabled=true") + .withClassLoader(new FilteredClassLoader( + "io.microsphere.i18n.ServiceMessageSource", + "io.microsphere.i18n.spring.annotation.EnableI18n")) + .run(context -> assertThat(context).doesNotHaveBean("a")); + } + + @Configuration + static class Config { + + @Bean + @ConditionalOnI18nEnabled + public String a() { + return "a"; + } + } +} diff --git a/microsphere-i18n-spring-cloud/pom.xml b/microsphere-i18n-spring-cloud/pom.xml index cc5989d..5f4c343 100644 --- a/microsphere-i18n-spring-cloud/pom.xml +++ b/microsphere-i18n-spring-cloud/pom.xml @@ -81,6 +81,24 @@ test + + org.junit.jupiter + junit-jupiter + test + + + + org.assertj + assertj-core + test + + + + com.jayway.jsonpath + json-path-assert + test + + org.springframework spring-test diff --git a/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/autoconfigure/I18nCloudAutoConfigurationTest.java b/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/autoconfigure/I18nCloudAutoConfigurationTest.java new file mode 100644 index 0000000..f2cb553 --- /dev/null +++ b/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/autoconfigure/I18nCloudAutoConfigurationTest.java @@ -0,0 +1,33 @@ +package io.microsphere.i18n.spring.cloud.autoconfigure; + +import io.microsphere.i18n.spring.boot.autoconfigure.I18nAutoConfiguration; +import io.microsphere.i18n.spring.cloud.event.ReloadableResourceServiceMessageSourceListener; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + + +class I18nCloudAutoConfigurationTest { + ApplicationContextRunner applicationContextRunner ; + + @BeforeEach + void setup() { + applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(I18nAutoConfiguration.class, I18nCloudAutoConfiguration.class)); + } + + @Test + void shouldContainReloadableResourceServiceMessageSourceListenerBean() { + applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ReloadableResourceServiceMessageSourceListener.class)); + } + + @Test + void shouldNotContainReloadableResourceServiceMessageSourceListenerBeanWhenMissingEnvironmentChangeEvent() { + applicationContextRunner.withClassLoader(new FilteredClassLoader("org.springframework.cloud.context.environment.EnvironmentChangeEvent")) + .run(context -> assertThat(context).doesNotHaveBean(ReloadableResourceServiceMessageSourceListener.class)); + } +} diff --git a/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/integration/MessageSourceIntegrationTest.java b/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/integration/MessageSourceIntegrationTest.java new file mode 100644 index 0000000..00eb3f8 --- /dev/null +++ b/microsphere-i18n-spring-cloud/src/test/java/io/microsphere/i18n/spring/cloud/integration/MessageSourceIntegrationTest.java @@ -0,0 +1,64 @@ +package io.microsphere.i18n.spring.cloud.integration; + +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.DocumentContext; +import io.microsphere.i18n.ServiceMessageSource; +import io.microsphere.i18n.spring.boot.actuate.I18nEndpoint; +import io.microsphere.i18n.spring.boot.actuate.autoconfigure.I18nEndpointAutoConfiguration; +import io.microsphere.i18n.spring.boot.autoconfigure.I18nAutoConfiguration; +import io.microsphere.i18n.spring.cloud.event.ReloadableResourceServiceMessageSourceListener; +import org.assertj.core.util.Maps; +import org.assertj.core.util.Sets; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +import java.util.Locale; + +import static com.jayway.jsonpath.JsonPath.using; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.equalTo; + +@SpringBootTest(classes = MessageSourceIntegrationTest.Config.class) +class MessageSourceIntegrationTest { + + @Test + void shouldGetMessageWhenChangeMessageSourceProperty(ApplicationContext applicationContext) { + String key = "common.i18n_messages_en.properties"; + ServiceMessageSource serviceMessageSource = applicationContext.getBean("commonServiceMessageSource", ServiceMessageSource.class); + + assertThat(serviceMessageSource.getMessage("common.a", Locale.ENGLISH)) + .isEqualTo("a"); + ConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment(); + environment.getPropertySources().addLast(new MapPropertySource("test", Maps.newHashMap(key, "common.a=a.2024"))); + + applicationContext.publishEvent(new EnvironmentChangeEvent(Sets.set(key))); + + + assertThat(serviceMessageSource.getMessage("common.a", Locale.ENGLISH)) + .isEqualTo("a.2024"); + + DocumentContext parse = using(Configuration.defaultConfiguration()).parse(applicationContext.getBean(I18nEndpoint.class).invoke()); + MatcherAssert.assertThat(parse, hasJsonPath("$.['common.i18n_messages_en.properties'].['common.a']", equalTo("a.2024"))); + } + + @ImportAutoConfiguration(classes = { + I18nAutoConfiguration.class, + I18nEndpointAutoConfiguration.class + }) + static class Config { + + @Bean + ReloadableResourceServiceMessageSourceListener reloadableResourceServiceMessageSourceListener() { + return new ReloadableResourceServiceMessageSourceListener(); + } + + } +}