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();
+ }
+
+ }
+}