diff --git a/CHANGES.md b/CHANGES.md index 2bf6a929d1b..f858f53548b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -54,6 +54,7 @@ Apollo 1.9.0 * [feature: add email for select user on apollo portal](https://github.com/ctripcorp/apollo/pull/3797) * [feature: modify item comment valid size](https://github.com/ctripcorp/apollo/pull/3803) * [speed up the stale issue mark and close phase](https://github.com/ctripcorp/apollo/pull/3808) +* [Reduce bootstrap time in the situation with large properties](https://github.com/ctripcorp/apollo/pull/3816) ------------------ All issues and pull requests are [here](https://github.com/ctripcorp/apollo/milestone/6?closed=1) diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/Config.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/Config.java index ef87f2dd5b2..5acd830cc56 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/Config.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/Config.java @@ -18,7 +18,6 @@ import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.google.common.base.Function; - import java.util.Date; import java.util.Locale; import java.util.Set; @@ -27,8 +26,12 @@ * @author Jason Song(song_s@ctrip.com) */ public interface Config { + + String[] EMPTY_NAMES = new String[0]; + /** - * Return the property value with the given key, or {@code defaultValue} if the key doesn't exist. + * Return the property value with the given key, or {@code defaultValue} if the key doesn't + * exist. * * @param key the property name * @param defaultValue the default value when key is not found or any error occurred @@ -224,11 +227,11 @@ void addChangeListener(ConfigChangeListener listener, Set interestedKeys boolean removeChangeListener(ConfigChangeListener listener); /** - * Return a set of the property names + * Return the names of all properties * - * @return the property names + * @return the property names (never null) */ - Set getPropertyNames(); + String[] getPropertyNames(); /** * Return the user-defined property value with the given key, or {@code defaultValue} if the key doesn't exist. diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java index ba3fe6cffaf..3bda0b7bfac 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java @@ -16,29 +16,25 @@ */ package com.ctrip.framework.apollo.internals; +import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; +import com.ctrip.framework.apollo.enums.PropertyChangeType; +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.tracer.Tracer; +import com.ctrip.framework.apollo.util.ExceptionUtil; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.RateLimiter; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; -import java.util.Set; import java.util.concurrent.atomic.AtomicReference; - import org.slf4j.Logger; -import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; -import com.ctrip.framework.apollo.enums.PropertyChangeType; -import com.ctrip.framework.apollo.model.ConfigChange; -import com.ctrip.framework.apollo.tracer.Tracer; -import com.ctrip.framework.apollo.util.ExceptionUtil; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.RateLimiter; - /** * @author Jason Song(song_s@ctrip.com) @@ -49,6 +45,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis private final String m_namespace; private final Properties m_resourceProperties; private final AtomicReference m_configProperties; + private String[] m_propertyNames; private final ConfigRepository m_configRepository; private final RateLimiter m_warnLogRateLimiter; @@ -65,6 +62,7 @@ public DefaultConfig(String namespace, ConfigRepository configRepository) { m_resourceProperties = loadFromResource(m_namespace); m_configRepository = configRepository; m_configProperties = new AtomicReference<>(); + m_propertyNames = EMPTY_NAMES; m_warnLogRateLimiter = RateLimiter.create(0.017); // 1 warning log output per minute initialize(); } @@ -117,13 +115,8 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { - Properties properties = m_configProperties.get(); - if (properties == null) { - return Collections.emptySet(); - } - - return stringPropertyNames(properties); + public String[] getPropertyNames() { + return m_propertyNames; } @Override @@ -131,17 +124,17 @@ public ConfigSourceType getSourceType() { return m_sourceType; } - private Set stringPropertyNames(Properties properties) { + private String[] stringPropertyNames(Properties properties) { //jdk9以下版本Properties#enumerateStringProperties方法存在性能问题,keys() + get(k) 重复迭代, jdk9之后改为entrySet遍历. - Map h = new LinkedHashMap<>(); + List names = new ArrayList<>(properties.size()); for (Map.Entry e : properties.entrySet()) { Object k = e.getKey(); Object v = e.getValue(); if (k instanceof String && v instanceof String) { - h.put((String) k, (String) v); + names.add((String) k); } } - return h.keySet(); + return names.toArray(EMPTY_NAMES); } @Override @@ -170,6 +163,11 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { m_configProperties.set(newConfigProperties); m_sourceType = sourceType; + if (newConfigProperties == null) { + m_propertyNames = EMPTY_NAMES; + } else { + m_propertyNames = stringPropertyNames(newConfigProperties); + } } private Map updateAndCalcConfigChanges(Properties newConfigProperties, diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java index f9b29ccd095..ecf250f0fa3 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java @@ -17,20 +17,16 @@ package com.ctrip.framework.apollo.internals; import com.ctrip.framework.apollo.enums.ConfigSourceType; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.tracer.Tracer; import com.ctrip.framework.apollo.util.ExceptionUtil; import com.google.common.base.Function; import com.google.common.collect.Maps; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Jason Song(song_s@ctrip.com) @@ -40,6 +36,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList private final String m_namespace; private final ConfigRepository m_configRepository; private volatile Properties m_configProperties; + private String[] m_propertyNames; private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE; /** @@ -51,6 +48,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList public SimpleConfig(String namespace, ConfigRepository configRepository) { m_namespace = namespace; m_configRepository = configRepository; + m_propertyNames = EMPTY_NAMES; this.initialize(); } @@ -78,12 +76,8 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { - if (m_configProperties == null) { - return Collections.emptySet(); - } - - return m_configProperties.stringPropertyNames(); + public String[] getPropertyNames() { + return m_propertyNames; } @Override @@ -119,5 +113,10 @@ public String apply(ConfigChange input) { private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { m_configProperties = newConfigProperties; m_sourceType = sourceType; + if (newConfigProperties == null) { + m_propertyNames = EMPTY_NAMES; + } else { + m_propertyNames = newConfigProperties.stringPropertyNames().toArray(EMPTY_NAMES); + } } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java index 32ee605cadb..7d097b9705a 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java @@ -21,6 +21,7 @@ import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.utils.DeferredLogger; +import com.ctrip.framework.apollo.spring.config.CompositeConfigPropertySource; import com.ctrip.framework.apollo.spring.config.ConfigPropertySourceFactory; import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants; import com.ctrip.framework.apollo.spring.util.SpringInjector; @@ -34,7 +35,6 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; -import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; /** @@ -113,21 +113,26 @@ public void initialize(ConfigurableApplicationContext context) { */ protected void initialize(ConfigurableEnvironment environment) { - if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) { + if (environment.getPropertySources() + .contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) { //already initialized, replay the logs that were printed before the logging system was initialized DeferredLogger.replayTo(); return; } - String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION); + String namespaces = environment + .getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, + ConfigConsts.NAMESPACE_APPLICATION); logger.debug("Apollo bootstrap namespaces: {}", namespaces); List namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces); - CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME); + CompositeConfigPropertySource composite = new CompositeConfigPropertySource( + PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME); for (String namespace : namespaceList) { Config config = ConfigService.getConfig(namespace); - composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config)); + composite.addPropertySource( + configPropertySourceFactory.getConfigPropertySource(namespace, config)); } environment.getPropertySources().addFirst(composite); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySource.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySource.java new file mode 100644 index 00000000000..02ce4fa88be --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySource.java @@ -0,0 +1,57 @@ +package com.ctrip.framework.apollo.spring.config; + +import com.ctrip.framework.apollo.ConfigChangeListener; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.PropertySource; + +/** + * @author Shawyeok (shawyeok@outlook.com) + */ +public class CompositeConfigPropertySource extends CompositePropertySource { + + private String[] names; + + public CompositeConfigPropertySource(String name) { + super(name); + } + + @Override + public String[] getPropertyNames() { + String[] propertyNames = this.names; + if (propertyNames == null) { + this.names = propertyNames = super.getPropertyNames(); + } + return propertyNames; + } + + @Override + public void addPropertySource(PropertySource propertySource) { + super.addPropertySource(propertySource); + if (propertySource instanceof ConfigPropertySource) { + ((ConfigPropertySource) propertySource).addChangeListener(new ClearNameCacheListener(this)); + } + } + + @Override + public void addFirstPropertySource(PropertySource propertySource) { + super.addFirstPropertySource(propertySource); + if (propertySource instanceof ConfigPropertySource) { + ((ConfigPropertySource) propertySource).addChangeListener(new ClearNameCacheListener(this)); + } + } + + static class ClearNameCacheListener implements ConfigChangeListener { + + private final CompositeConfigPropertySource source; + + public ClearNameCacheListener(CompositeConfigPropertySource source) { + this.source = source; + } + + @Override + public void onChange(ConfigChangeEvent changeEvent) { + source.names = null; + } + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySource.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySource.java index 298ce798d74..550c3c5fb51 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySource.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySource.java @@ -16,32 +16,29 @@ */ package com.ctrip.framework.apollo.spring.config; +import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigChangeListener; -import java.util.Set; - import org.springframework.core.env.EnumerablePropertySource; -import com.ctrip.framework.apollo.Config; - /** * Property source wrapper for Config * * @author Jason Song(song_s@ctrip.com) */ public class ConfigPropertySource extends EnumerablePropertySource { - private static final String[] EMPTY_ARRAY = new String[0]; ConfigPropertySource(String name, Config source) { super(name, source); } + @Override + public boolean containsProperty(String name) { + return this.source.getProperty(name, null) != null; + } + @Override public String[] getPropertyNames() { - Set propertyNames = this.source.getPropertyNames(); - if (propertyNames.isEmpty()) { - return EMPTY_ARRAY; - } - return propertyNames.toArray(new String[propertyNames.size()]); + return this.source.getPropertyNames(); } @Override diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java index 7649f69e693..634e331dfd1 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.spring.config; +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener; import com.ctrip.framework.apollo.spring.util.SpringInjector; @@ -23,11 +25,9 @@ import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; - -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigService; - import com.google.common.collect.Sets; +import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Set; import org.springframework.beans.BeansException; @@ -37,12 +37,8 @@ import org.springframework.context.EnvironmentAware; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; -import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; - -import java.util.Collection; -import java.util.Iterator; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; @@ -76,11 +72,13 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) } private void initializePropertySources() { - if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME)) { + if (environment.getPropertySources() + .contains(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME)) { //already initialized return; } - CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME); + CompositeConfigPropertySource composite = new CompositeConfigPropertySource( + PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME); //sort by order asc ImmutableSortedSet orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet()); diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/ConfigServiceTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/ConfigServiceTest.java index 4d340db107b..05528aa46d1 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/ConfigServiceTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/ConfigServiceTest.java @@ -18,19 +18,16 @@ import static org.junit.Assert.assertEquals; -import com.ctrip.framework.apollo.enums.ConfigSourceType; -import java.util.Set; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import com.ctrip.framework.apollo.build.MockInjector; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; +import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.internals.AbstractConfig; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.util.ConfigUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * @author Jason Song(song_s@ctrip.com) @@ -118,8 +115,8 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { - return null; + public String[] getPropertyNames() { + return EMPTY_NAMES; } @Override diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/integration/ConfigIntegrationTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/integration/ConfigIntegrationTest.java index b20c93010f5..21504c45b9d 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/integration/ConfigIntegrationTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/integration/ConfigIntegrationTest.java @@ -21,19 +21,36 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import com.ctrip.framework.apollo.BaseIntegrationTest; +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigChangeListener; +import com.ctrip.framework.apollo.ConfigService; +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.ConfigConsts; +import com.ctrip.framework.apollo.core.dto.ApolloConfig; +import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification; +import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; +import com.ctrip.framework.apollo.internals.RemoteConfigLongPollService; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.util.OrderedProperties; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.SettableFuture; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; -import java.util.*; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; @@ -42,23 +59,6 @@ import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; -import com.ctrip.framework.apollo.BaseIntegrationTest; -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigChangeListener; -import com.ctrip.framework.apollo.ConfigService; -import com.ctrip.framework.apollo.build.ApolloInjector; -import com.ctrip.framework.apollo.core.ConfigConsts; -import com.ctrip.framework.apollo.core.dto.ApolloConfig; -import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification; -import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; -import com.ctrip.framework.apollo.internals.RemoteConfigLongPollService; -import com.ctrip.framework.apollo.model.ConfigChangeEvent; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.util.concurrent.SettableFuture; - /** * @author Jason Song(song_s@ctrip.com) */ @@ -143,10 +143,9 @@ public void testOrderGetConfigWithNoLocalFileButWithRemoteConfig() throws Except Config config = ConfigService.getAppConfig(); - Set propertyNames = config.getPropertyNames(); - Iterator it = propertyNames.iterator(); - assertEquals(someKey1, it.next()); - assertEquals(someKey2, it.next()); + String[] propertyNames = config.getPropertyNames(); + assertEquals(someKey1, propertyNames[0]); + assertEquals(someKey2, propertyNames[1]); } @@ -200,11 +199,10 @@ public void testOrderGetConfigWithLocalFileAndWithRemoteConfig() throws Exceptio assertEquals(anotherValue, config.getProperty(someKey, null)); - Set propertyNames = config.getPropertyNames(); - Iterator it = propertyNames.iterator(); - assertEquals(someKey, it.next()); - assertEquals(someKey1, it.next()); - assertEquals(someKey2, it.next()); + String[] propertyNames = config.getPropertyNames(); + assertEquals(someKey, propertyNames[0]); + assertEquals(someKey1, propertyNames[1]); + assertEquals(someKey2, propertyNames[2]); assertEquals(anotherValue1, config.getProperty(someKey1, "")); } @@ -261,10 +259,9 @@ public void testOrderGetConfigWithLocalFileAndRemoteConfigError() throws Excepti assertEquals(someValue1, config.getProperty(someKey1, null)); assertEquals(someValue2, config.getProperty(someKey2, null)); - Set propertyNames = config.getPropertyNames(); - Iterator it = propertyNames.iterator(); - assertEquals(someKey1, it.next()); - assertEquals(someKey2, it.next()); + String[] propertyNames = config.getPropertyNames(); + assertEquals(someKey1, propertyNames[0]); + assertEquals(someKey2, propertyNames[1]); } @Test diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/AbstractConfigTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/AbstractConfigTest.java index 37335b770ac..dc2193d306e 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/AbstractConfigTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/AbstractConfigTest.java @@ -30,7 +30,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -176,7 +175,7 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { + public String[] getPropertyNames() { throw new UnsupportedOperationException(); } diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigManagerTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigManagerTest.java index 6bbaf1a2c98..30db192fbeb 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigManagerTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigManagerTest.java @@ -21,21 +21,18 @@ import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; -import com.ctrip.framework.apollo.enums.ConfigSourceType; -import java.util.Properties; -import java.util.Set; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigFile; import com.ctrip.framework.apollo.build.MockInjector; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; +import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; import com.ctrip.framework.apollo.util.ConfigUtil; +import java.util.Properties; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * @author Jason Song(song_s@ctrip.com) @@ -122,8 +119,8 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { - return null; + public String[] getPropertyNames() { + return EMPTY_NAMES; } @Override diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigTest.java index 281b91059b5..ceaa033700d 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/DefaultConfigTest.java @@ -26,42 +26,38 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigChangeListener; +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; import com.ctrip.framework.apollo.enums.ConfigSourceType; +import com.ctrip.framework.apollo.enums.PropertyChangeType; +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.OrderedProperties; import com.ctrip.framework.apollo.util.factory.PropertiesFactory; +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.io.Files; +import com.google.common.util.concurrent.SettableFuture; import java.io.File; import java.util.Calendar; import java.util.Date; +import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Set; -import java.util.Collections; -import java.util.List; import java.util.concurrent.TimeUnit; - -import com.google.common.base.Function; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; import org.awaitility.core.ThrowingRunnable; import org.junit.After; import org.junit.Before; import org.junit.Test; - -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigChangeListener; -import com.ctrip.framework.apollo.build.MockInjector; -import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; -import com.ctrip.framework.apollo.enums.PropertyChangeType; -import com.ctrip.framework.apollo.model.ConfigChange; -import com.ctrip.framework.apollo.model.ConfigChangeEvent; -import com.ctrip.framework.apollo.util.ConfigUtil; -import com.google.common.base.Charsets; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.Files; -import com.google.common.util.concurrent.SettableFuture; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -837,10 +833,10 @@ public void testGetPropertyNames() { DefaultConfig defaultConfig = new DefaultConfig(someNamespace, configRepository); - Set propertyNames = defaultConfig.getPropertyNames(); + String[] propertyNames = defaultConfig.getPropertyNames(); - assertEquals(10, propertyNames.size()); - assertEquals(someProperties.stringPropertyNames(), propertyNames); + assertEquals(10, propertyNames.length); + assertArrayEquals(someProperties.stringPropertyNames().toArray(new String[0]), propertyNames); } @Test @@ -864,10 +860,10 @@ public Properties answer(InvocationOnMock invocation) { DefaultConfig defaultConfig = new DefaultConfig(someNamespace, configRepository); - Set propertyNames = defaultConfig.getPropertyNames(); + String[] propertyNames = defaultConfig.getPropertyNames(); - assertEquals(10, propertyNames.size()); - assertEquals(someProperties.stringPropertyNames(), propertyNames); + assertEquals(10, propertyNames.length); + assertArrayEquals(someProperties.stringPropertyNames().toArray(new String[0]), propertyNames); } @Test @@ -875,10 +871,10 @@ public void testGetPropertyNamesWithNullProp() { when(configRepository.getConfig()).thenReturn(null); DefaultConfig defaultConfig = - new DefaultConfig(someNamespace, configRepository); + new DefaultConfig(someNamespace, configRepository); - Set propertyNames = defaultConfig.getPropertyNames(); - assertEquals(Collections.emptySet(), propertyNames); + String[] propertyNames = defaultConfig.getPropertyNames(); + assertEquals(0, propertyNames.length); } @Test diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/InterestedConfigChangeEventTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/InterestedConfigChangeEventTest.java index 932d10d2ae3..5474e2aeb11 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/InterestedConfigChangeEventTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/InterestedConfigChangeEventTest.java @@ -16,12 +16,15 @@ */ package com.ctrip.framework.apollo.internals; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.PropertyChangeType; -import com.ctrip.framework.apollo.internals.AbstractConfig; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.google.common.collect.Sets; @@ -29,7 +32,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -37,8 +39,6 @@ import org.junit.Test; import org.mockito.Matchers; -import static org.mockito.Mockito.*; - /** * @author wxq */ @@ -92,7 +92,7 @@ public String getProperty(String key, String defaultValue) { } @Override - public Set getPropertyNames() { + public String[] getPropertyNames() { throw new UnsupportedOperationException(); } diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java index e2237b79c47..8328b775038 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java @@ -16,12 +16,18 @@ */ package com.ctrip.framework.apollo.spring; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; import com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer; import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants; -import com.google.common.collect.Sets; +import java.util.List; +import org.assertj.core.util.Arrays; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -40,13 +46,6 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.List; - -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * @author Jason Song(song_s@ctrip.com) */ @@ -84,9 +83,11 @@ public static void beforeClass() throws Exception { mockedConfig = mock(Config.class); - when(mockedConfig.getPropertyNames()).thenReturn(Sets.newHashSet(TEST_BEAN_CONDITIONAL_ON_KEY, someProperty)); + when(mockedConfig.getPropertyNames()) + .thenReturn(Arrays.array(TEST_BEAN_CONDITIONAL_ON_KEY, someProperty)); - when(mockedConfig.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())).thenReturn(Boolean.TRUE.toString()); + when(mockedConfig.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())) + .thenReturn(Boolean.TRUE.toString()); when(mockedConfig.getProperty(eq(someProperty), anyString())).thenReturn(someValue); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, mockedConfig); @@ -130,8 +131,11 @@ public static void beforeClass() throws Exception { Config config = mock(Config.class); Config anotherConfig = mock(Config.class); - when(config.getPropertyNames()).thenReturn(Sets.newHashSet(TEST_BEAN_CONDITIONAL_ON_KEY)); - when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())).thenReturn(Boolean.TRUE.toString()); + when(config.getPropertyNames()).thenReturn(Arrays.array(TEST_BEAN_CONDITIONAL_ON_KEY)); + when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())) + .thenReturn(Boolean.TRUE.toString()); + + when(anotherConfig.getPropertyNames()).thenReturn(new String[0]); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, anotherConfig); mockConfig(FX_APOLLO_NAMESPACE, config); @@ -171,6 +175,7 @@ public static void beforeClass() throws Exception { prepareYamlConfigFile("application.yml", readYamlContentAsConfigFileProperties("case6.yml")); Config anotherConfig = mock(Config.class); + when(anotherConfig.getPropertyNames()).thenReturn(new String[0]); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, anotherConfig); mockConfig(FX_APOLLO_NAMESPACE, anotherConfig); @@ -208,8 +213,9 @@ public static void beforeClass() throws Exception { Config config = mock(Config.class); - when(config.getPropertyNames()).thenReturn(Sets.newHashSet(TEST_BEAN_CONDITIONAL_ON_KEY)); - when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())).thenReturn(Boolean.FALSE.toString()); + when(config.getPropertyNames()).thenReturn(Arrays.array(TEST_BEAN_CONDITIONAL_ON_KEY)); + when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())) + .thenReturn(Boolean.FALSE.toString()); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, config); } @@ -276,6 +282,7 @@ public static void beforeClass() throws Exception { System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "true"); Config config = mock(Config.class); + when(config.getPropertyNames()).thenReturn(new String[0]); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, config); } @@ -343,8 +350,9 @@ public static void beforeClass() throws Exception { Config config = mock(Config.class); - when(config.getPropertyNames()).thenReturn(Sets.newHashSet(TEST_BEAN_CONDITIONAL_ON_KEY)); - when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())).thenReturn(Boolean.FALSE.toString()); + when(config.getPropertyNames()).thenReturn(Arrays.array(TEST_BEAN_CONDITIONAL_ON_KEY)); + when(config.getProperty(eq(TEST_BEAN_CONDITIONAL_ON_KEY), anyString())) + .thenReturn(Boolean.FALSE.toString()); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, config); } @@ -406,6 +414,7 @@ public static void beforeClass() { System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, "true"); Config config = mock(Config.class); + when(config.getPropertyNames()).thenReturn(new String[0]); mockConfig(ConfigConsts.NAMESPACE_APPLICATION, config); } diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/JavaConfigAnnotationTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/JavaConfigAnnotationTest.java index c125afcc538..ece18e6e3be 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/JavaConfigAnnotationTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/JavaConfigAnnotationTest.java @@ -16,6 +16,22 @@ */ package com.ctrip.framework.apollo.spring; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anySetOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.ConfigFileChangeListener; @@ -32,8 +48,10 @@ import com.google.common.util.concurrent.SettableFuture; import java.io.IOException; import java.util.Collections; +import java.util.List; import java.util.Properties; import java.util.Queue; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; @@ -48,25 +66,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anySetOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - /** * @author Jason Song(song_s@ctrip.com) */ @@ -229,7 +228,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable { TestApolloConfigChangeListenerBean1 bean = getBean(TestApolloConfigChangeListenerBean1.class, AppConfig3.class); //PropertySourcesProcessor add listeners to listen config changed of all namespace - assertEquals(4, applicationListeners.size()); + assertEquals(5, applicationListeners.size()); assertEquals(1, fxApolloListeners.size()); for (ConfigChangeListener listener : applicationListeners) { @@ -302,7 +301,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable { TestApolloChildConfigChangeListener bean = getBean(TestApolloChildConfigChangeListener.class, AppConfig7.class); //PropertySourcesProcessor add listeners to listen config changed of all namespace - assertEquals(5, applicationListeners.size()); + assertEquals(6, applicationListeners.size()); assertEquals(1, fxApolloListeners.size()); for (ConfigChangeListener listener : applicationListeners) { @@ -460,8 +459,9 @@ public void testApolloConfigChangeListenerResolveExpressionSimple() { // no using verify(ignoreConfig, never()).addChangeListener(any(ConfigChangeListener.class)); - // one invocation for spring value auto update and another for the @ApolloConfigChangeListener annotation - verify(applicationConfig, times(2)).addChangeListener(any(ConfigChangeListener.class)); + // one invocation for spring value auto update and one for the @ApolloConfigChangeListener annotation + // and another for CompositeConfigPropertySource$ClearNameCacheListener + verify(applicationConfig, times(3)).addChangeListener(any(ConfigChangeListener.class)); } /** diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/XMLConfigAnnotationTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/XMLConfigAnnotationTest.java index 1afc1b80a72..5a574cba811 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/XMLConfigAnnotationTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/XMLConfigAnnotationTest.java @@ -16,7 +16,6 @@ */ package com.ctrip.framework.apollo.spring; -import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anySetOf; @@ -25,10 +24,16 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigChangeListener; +import com.ctrip.framework.apollo.core.ConfigConsts; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.Collections; import java.util.List; - import java.util.Set; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -37,14 +42,6 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigChangeListener; -import com.ctrip.framework.apollo.core.ConfigConsts; -import com.ctrip.framework.apollo.model.ConfigChangeEvent; -import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; -import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; -import com.google.common.collect.Lists; - /** * @author Jason Song(song_s@ctrip.com) */ @@ -111,7 +108,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable { TestApolloConfigChangeListenerBean1.class); //PropertySourcesProcessor add listeners to listen config changed of all namespace - assertEquals(4, applicationListeners.size()); + assertEquals(5, applicationListeners.size()); assertEquals(1, fxApolloListeners.size()); for (ConfigChangeListener listener : applicationListeners) { diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySourceTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySourceTest.java new file mode 100644 index 00000000000..db6d9a41afa --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySourceTest.java @@ -0,0 +1,106 @@ +package com.ctrip.framework.apollo.spring.config; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.ctrip.framework.apollo.ConfigChangeListener; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.config.CompositeConfigPropertySource.ClearNameCacheListener; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import org.assertj.core.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; +import org.springframework.core.env.PropertySource; + +/** + * @author Shawyeok (shawyeok@outlook.com) + */ +@RunWith(MockitoJUnitRunner.class) +public class CompositeConfigPropertySourceTest { + + private CompositeConfigPropertySource compositeSource; + + @Mock + private ConfigPropertySource configPropertySource; + + private List listeners; + + @Before + public void setUp() throws Exception { + compositeSource = new CompositeConfigPropertySource("testCompositeSource"); + listeners = new LinkedList<>(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ConfigChangeListener listener = invocation.getArgumentAt(0, ConfigChangeListener.class); + listeners.add(listener); + return Void.class; + } + }).when(configPropertySource).addChangeListener(any(ConfigChangeListener.class)); + compositeSource.addPropertySource(configPropertySource); + } + + @Test + public void testGetPropertyNames() { + String[] propertyNames = Arrays.array("propertyName"); + String[] anotherPropertyNames = Arrays.array("propertyName", "anotherPropertyName"); + + when(configPropertySource.getPropertyNames()).thenReturn(propertyNames, anotherPropertyNames); + + String[] returnedPropertyNames = compositeSource.getPropertyNames(); + assertArrayEquals(propertyNames, returnedPropertyNames); + assertSame(returnedPropertyNames, compositeSource.getPropertyNames()); + + listeners.get(0).onChange(new ConfigChangeEvent(null, null)); + + returnedPropertyNames = compositeSource.getPropertyNames(); + assertArrayEquals(anotherPropertyNames, returnedPropertyNames); + assertSame(returnedPropertyNames, compositeSource.getPropertyNames()); + } + + @Test + public void testAddPropertySource() { + verify(configPropertySource, times(1)).addChangeListener(any(ClearNameCacheListener.class)); + assertEquals(1, listeners.size()); + assertTrue(compositeSource.getPropertySources().contains(configPropertySource)); + } + + @Test + public void testAddFirstPropertySource() { + ConfigPropertySource anotherSource = mock(ConfigPropertySource.class); + final List anotherListenerList = new LinkedList<>(); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + ConfigChangeListener listener = invocation.getArgumentAt(0, ConfigChangeListener.class); + anotherListenerList.add(listener); + return Void.class; + } + }).when(anotherSource).addChangeListener(any(ConfigChangeListener.class)); + compositeSource.addFirstPropertySource(anotherSource); + + Collection> propertySources = compositeSource.getPropertySources(); + Iterator> it = propertySources.iterator(); + + assertEquals(2, propertySources.size()); + assertEquals(1, anotherListenerList.size()); + assertSame(anotherSource, it.next()); + assertSame(configPropertySource, it.next()); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySourceTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySourceTest.java index 5df4f7eedac..a0179998b5b 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySourceTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/config/ConfigPropertySourceTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; @@ -29,9 +30,8 @@ import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigChangeListener; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.List; -import java.util.Set; +import org.assertj.core.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,7 +58,7 @@ public void setUp() throws Exception { public void testGetPropertyNames() throws Exception { String somePropertyName = "somePropertyName"; String anotherPropertyName = "anotherPropertyName"; - Set somePropertyNames = Sets.newHashSet(somePropertyName, anotherPropertyName); + String[] somePropertyNames = Arrays.array(somePropertyName, anotherPropertyName); when(someConfig.getPropertyNames()).thenReturn(somePropertyNames); @@ -66,12 +66,12 @@ public void testGetPropertyNames() throws Exception { verify(someConfig, times(1)).getPropertyNames(); - assertArrayEquals(somePropertyNames.toArray(), result); + assertArrayEquals(somePropertyNames, result); } @Test public void testGetEmptyPropertyNames() throws Exception { - when(someConfig.getPropertyNames()).thenReturn(Sets.newHashSet()); + when(someConfig.getPropertyNames()).thenReturn(new String[0]); assertEquals(0, configPropertySource.getPropertyNames().length); } @@ -111,4 +111,16 @@ public Object answer(InvocationOnMock invocation) throws Throwable { assertEquals(2, listeners.size()); assertTrue(listeners.containsAll(Lists.newArrayList(someListener, anotherListener))); } + + @Test + public void testContainsProperty() { + String somePropertyName = "somePropertyName"; + String anotherPropertyName = "anotherPropertyName"; + String someValue = "someValue"; + + when(someConfig.getProperty(somePropertyName, null)).thenReturn(someValue); + + assertTrue(configPropertySource.containsProperty(somePropertyName)); + assertFalse(configPropertySource.containsProperty(anotherPropertyName)); + } }