Commit 5fe54966 authored by Jason Song's avatar Jason Song

use linked hash map to keep server side config order and do some refactoring to apollo-client

parent 82790e5f
...@@ -31,14 +31,7 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -31,14 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -153,7 +146,7 @@ public class ReleaseService { ...@@ -153,7 +146,7 @@ public class ReleaseService {
Map<String, String> operateNamespaceItems = getNamespaceItems(namespace); Map<String, String> operateNamespaceItems = getNamespaceItems(namespace);
Map<String, Object> operationContext = Maps.newHashMap(); Map<String, Object> operationContext = Maps.newLinkedHashMap();
operationContext.put(ReleaseOperationContext.SOURCE_BRANCH, branchName); operationContext.put(ReleaseOperationContext.SOURCE_BRANCH, branchName);
operationContext.put(ReleaseOperationContext.BASE_RELEASE_ID, branchReleaseId); operationContext.put(ReleaseOperationContext.BASE_RELEASE_ID, branchReleaseId);
operationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish); operationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish);
...@@ -188,7 +181,7 @@ public class ReleaseService { ...@@ -188,7 +181,7 @@ public class ReleaseService {
} }
//master release //master release
Map<String, Object> operationContext = Maps.newHashMap(); Map<String, Object> operationContext = Maps.newLinkedHashMap();
operationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish); operationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish);
Release release = masterRelease(namespace, releaseName, releaseComment, operateNamespaceItems, Release release = masterRelease(namespace, releaseName, releaseComment, operateNamespaceItems,
...@@ -211,7 +204,7 @@ public class ReleaseService { ...@@ -211,7 +204,7 @@ public class ReleaseService {
Release parentLatestRelease = findLatestActiveRelease(parentNamespace); Release parentLatestRelease = findLatestActiveRelease(parentNamespace);
Map<String, String> parentConfigurations = parentLatestRelease != null ? Map<String, String> parentConfigurations = parentLatestRelease != null ?
gson.fromJson(parentLatestRelease.getConfigurations(), gson.fromJson(parentLatestRelease.getConfigurations(),
GsonType.CONFIG) : new HashMap<>(); GsonType.CONFIG) : new LinkedHashMap<>();
long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId(); long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId();
Map<String, String> configsToPublish = mergeConfiguration(parentConfigurations, childNamespaceItems); Map<String, String> configsToPublish = mergeConfiguration(parentConfigurations, childNamespaceItems);
...@@ -342,7 +335,7 @@ public class ReleaseService { ...@@ -342,7 +335,7 @@ public class ReleaseService {
childNamespace.getNamespaceName()); childNamespace.getNamespaceName());
long previousReleaseId = previousRelease == null ? 0 : previousRelease.getId(); long previousReleaseId = previousRelease == null ? 0 : previousRelease.getId();
Map<String, Object> releaseOperationContext = Maps.newHashMap(); Map<String, Object> releaseOperationContext = Maps.newLinkedHashMap();
releaseOperationContext.put(ReleaseOperationContext.BASE_RELEASE_ID, baseReleaseId); releaseOperationContext.put(ReleaseOperationContext.BASE_RELEASE_ID, baseReleaseId);
releaseOperationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish); releaseOperationContext.put(ReleaseOperationContext.IS_EMERGENCY_PUBLISH, isEmergencyPublish);
releaseOperationContext.put(ReleaseOperationContext.BRANCH_RELEASE_KEYS, branchReleaseKeys); releaseOperationContext.put(ReleaseOperationContext.BRANCH_RELEASE_KEYS, branchReleaseKeys);
...@@ -372,7 +365,7 @@ public class ReleaseService { ...@@ -372,7 +365,7 @@ public class ReleaseService {
private Map<String, String> mergeConfiguration(Map<String, String> baseConfigurations, private Map<String, String> mergeConfiguration(Map<String, String> baseConfigurations,
Map<String, String> coverConfigurations) { Map<String, String> coverConfigurations) {
Map<String, String> result = new HashMap<>(); Map<String, String> result = new LinkedHashMap<>();
//copy base configuration //copy base configuration
for (Map.Entry<String, String> entry : baseConfigurations.entrySet()) { for (Map.Entry<String, String> entry : baseConfigurations.entrySet()) {
result.put(entry.getKey(), entry.getValue()); result.put(entry.getKey(), entry.getValue());
...@@ -388,8 +381,8 @@ public class ReleaseService { ...@@ -388,8 +381,8 @@ public class ReleaseService {
private Map<String, String> getNamespaceItems(Namespace namespace) { private Map<String, String> getNamespaceItems(Namespace namespace) {
List<Item> items = itemService.findItemsWithoutOrdered(namespace.getId()); List<Item> items = itemService.findItemsWithOrdered(namespace.getId());
Map<String, String> configurations = new HashMap<>(); Map<String, String> configurations = new LinkedHashMap<>();
for (Item item : items) { for (Item item : items) {
if (StringUtils.isEmpty(item.getKey())) { if (StringUtils.isEmpty(item.getKey())) {
continue; continue;
...@@ -520,7 +513,7 @@ public class ReleaseService { ...@@ -520,7 +513,7 @@ public class ReleaseService {
Map<String, String> masterReleaseConfigs, Map<String, String> branchReleaseConfigs, Map<String, String> masterReleaseConfigs, Map<String, String> branchReleaseConfigs,
Collection<String> branchReleaseKeys) { Collection<String> branchReleaseKeys) {
Map<String, String> modifiedConfigs = new HashMap<>(); Map<String, String> modifiedConfigs = new LinkedHashMap<>();
if (CollectionUtils.isEmpty(branchReleaseConfigs)) { if (CollectionUtils.isEmpty(branchReleaseConfigs)) {
return modifiedConfigs; return modifiedConfigs;
......
...@@ -88,7 +88,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -88,7 +88,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
// step 4: check properties file from classpath // step 4: check properties file from classpath
if (value == null && m_resourceProperties != null) { if (value == null && m_resourceProperties != null) {
value = (String) m_resourceProperties.getProperty(key); value = m_resourceProperties.getProperty(key);
} }
if (value == null && m_configProperties.get() == null && m_warnLogRateLimiter.tryAcquire()) { if (value == null && m_configProperties.get() == null && m_warnLogRateLimiter.tryAcquire()) {
......
...@@ -107,7 +107,9 @@ public class OrderedProperties extends Properties { ...@@ -107,7 +107,9 @@ public class OrderedProperties extends Properties {
@Override @Override
public synchronized Object remove(Object key) { public synchronized Object remove(Object key) {
this.propertyNames.remove(key); if (key instanceof String) {
this.propertyNames.remove(key);
}
return super.remove(key); return super.remove(key);
} }
......
...@@ -3,10 +3,7 @@ package com.ctrip.framework.apollo.util.factory; ...@@ -3,10 +3,7 @@ package com.ctrip.framework.apollo.util.factory;
import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.build.ApolloInjector;
import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.ConfigUtil;
import com.ctrip.framework.apollo.util.OrderedProperties; import com.ctrip.framework.apollo.util.OrderedProperties;
import com.google.common.base.Strings;
import java.util.Properties; import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Default PropertiesFactory implementation. * Default PropertiesFactory implementation.
...@@ -15,8 +12,6 @@ import org.slf4j.LoggerFactory; ...@@ -15,8 +12,6 @@ import org.slf4j.LoggerFactory;
*/ */
public class DefaultPropertiesFactory implements PropertiesFactory { public class DefaultPropertiesFactory implements PropertiesFactory {
private static final Logger logger = LoggerFactory.getLogger(DefaultPropertiesFactory.class);
private ConfigUtil m_configUtil; private ConfigUtil m_configUtil;
public DefaultPropertiesFactory() { public DefaultPropertiesFactory() {
......
...@@ -12,7 +12,7 @@ public interface PropertiesFactory { ...@@ -12,7 +12,7 @@ public interface PropertiesFactory {
/** /**
* Configuration to keep properties order as same as line order in .yml/.yaml/.properties file. * Configuration to keep properties order as same as line order in .yml/.yaml/.properties file.
*/ */
public static final String APOLLO_PROPERTY_ORDER_ENABLE = "apollo.property.order.enable"; String APOLLO_PROPERTY_ORDER_ENABLE = "apollo.property.order.enable";
/** /**
* <pre> * <pre>
......
...@@ -44,6 +44,7 @@ public abstract class BaseIntegrationTest { ...@@ -44,6 +44,7 @@ public abstract class BaseIntegrationTest {
protected static String someDataCenter; protected static String someDataCenter;
protected static int refreshInterval; protected static int refreshInterval;
protected static TimeUnit refreshTimeUnit; protected static TimeUnit refreshTimeUnit;
protected static boolean propertiesOrderEnabled;
private Server server; private Server server;
protected Gson gson = new Gson(); protected Gson gson = new Gson();
...@@ -64,6 +65,7 @@ public abstract class BaseIntegrationTest { ...@@ -64,6 +65,7 @@ public abstract class BaseIntegrationTest {
someDataCenter = "someDC"; someDataCenter = "someDC";
refreshInterval = 5; refreshInterval = 5;
refreshTimeUnit = TimeUnit.MINUTES; refreshTimeUnit = TimeUnit.MINUTES;
propertiesOrderEnabled = false;
//as ConfigService is singleton, so we must manually clear its container //as ConfigService is singleton, so we must manually clear its container
ConfigService.reset(); ConfigService.reset();
...@@ -140,6 +142,10 @@ public abstract class BaseIntegrationTest { ...@@ -140,6 +142,10 @@ public abstract class BaseIntegrationTest {
BaseIntegrationTest.refreshTimeUnit = refreshTimeUnit; BaseIntegrationTest.refreshTimeUnit = refreshTimeUnit;
} }
protected void setPropertiesOrderEnabled(boolean propertiesOrderEnabled) {
BaseIntegrationTest.propertiesOrderEnabled = propertiesOrderEnabled;
}
public static class MockConfigUtil extends ConfigUtil { public static class MockConfigUtil extends ConfigUtil {
@Override @Override
...@@ -204,7 +210,7 @@ public abstract class BaseIntegrationTest { ...@@ -204,7 +210,7 @@ public abstract class BaseIntegrationTest {
@Override @Override
public boolean isPropertiesOrderEnabled() { public boolean isPropertiesOrderEnabled() {
return true; return propertiesOrderEnabled;
} }
} }
......
...@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals; ...@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import com.ctrip.framework.apollo.util.OrderedProperties;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
...@@ -17,7 +18,6 @@ import javax.servlet.ServletException; ...@@ -17,7 +18,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
...@@ -53,7 +53,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -53,7 +53,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
private String defaultNamespace; private String defaultNamespace;
private String someOtherNamespace; private String someOtherNamespace;
private RemoteConfigLongPollService remoteConfigLongPollService; private RemoteConfigLongPollService remoteConfigLongPollService;
private PropertiesFactory propertiesFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -68,9 +67,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -68,9 +67,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
} }
configDir.mkdirs(); configDir.mkdirs();
remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class); remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class);
System.setProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE, "true");
propertiesFactory = ApolloInjector.getInstance(PropertiesFactory.class);
} }
@Override @Override
...@@ -78,7 +74,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -78,7 +74,6 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
public void tearDown() throws Exception { public void tearDown() throws Exception {
ReflectionTestUtils.invokeMethod(remoteConfigLongPollService, "stopLongPollingRefresh"); ReflectionTestUtils.invokeMethod(remoteConfigLongPollService, "stopLongPollingRefresh");
recursiveDelete(configDir); recursiveDelete(configDir);
System.clearProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE);
super.tearDown(); super.tearDown();
} }
...@@ -117,6 +112,8 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -117,6 +112,8 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
@Test @Test
public void testOrderGetConfigWithNoLocalFileButWithRemoteConfig() throws Exception { public void testOrderGetConfigWithNoLocalFileButWithRemoteConfig() throws Exception {
setPropertiesOrderEnabled(true);
String someKey1 = "someKey1"; String someKey1 = "someKey1";
String someValue1 = "someValue1"; String someValue1 = "someValue1";
String someKey2 = "someKey2"; String someKey2 = "someKey2";
...@@ -167,7 +164,9 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -167,7 +164,9 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
String someKey2 = "someKey2"; String someKey2 = "someKey2";
String someValue2 = "someValue2"; String someValue2 = "someValue2";
Properties properties = propertiesFactory.getPropertiesInstance(); setPropertiesOrderEnabled(true);
Properties properties = new OrderedProperties();
properties.put(someKey, someValue); properties.put(someKey, someValue);
properties.put(someKey1, someValue1); properties.put(someKey1, someValue1);
properties.put(someKey2, someValue2); properties.put(someKey2, someValue2);
...@@ -230,7 +229,10 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -230,7 +229,10 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
String someValue1 = "someValue1"; String someValue1 = "someValue1";
String someKey2 = "someKey2"; String someKey2 = "someKey2";
String someValue2 = "someValue2"; String someValue2 = "someValue2";
Properties properties = propertiesFactory.getPropertiesInstance();
setPropertiesOrderEnabled(true);
Properties properties = new OrderedProperties();
properties.put(someKey1, someValue1); properties.put(someKey1, someValue1);
properties.put(someKey2, someValue2); properties.put(someKey2, someValue2);
createLocalCachePropertyFile(properties); createLocalCachePropertyFile(properties);
......
...@@ -10,7 +10,7 @@ import static org.mockito.Mockito.verify; ...@@ -10,7 +10,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory; import com.ctrip.framework.apollo.util.OrderedProperties;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
...@@ -44,6 +44,8 @@ import com.google.common.base.Joiner; ...@@ -44,6 +44,8 @@ import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -54,12 +56,21 @@ public class DefaultConfigTest { ...@@ -54,12 +56,21 @@ public class DefaultConfigTest {
private ConfigRepository configRepository; private ConfigRepository configRepository;
private Properties someProperties; private Properties someProperties;
private ConfigSourceType someSourceType; private ConfigSourceType someSourceType;
private PropertiesFactory propertiesFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockInjector.reset(); MockInjector.reset();
MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil()); MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil());
MockInjector.setInstance(PropertiesFactory.class, new DefaultPropertiesFactory());
propertiesFactory = mock(PropertiesFactory.class);
when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
someResourceDir = new File(ClassLoaderUtil.getClassPath() + "/META-INF/config"); someResourceDir = new File(ClassLoaderUtil.getClassPath() + "/META-INF/config");
someResourceDir.mkdirs(); someResourceDir.mkdirs();
...@@ -726,15 +737,15 @@ public class DefaultConfigTest { ...@@ -726,15 +737,15 @@ public class DefaultConfigTest {
@Test @Test
public void testRemoveChangeListener() throws Exception { public void testRemoveChangeListener() throws Exception {
String someNamespace = "someNamespace"; String someNamespace = "someNamespace";
final ConfigChangeEvent someConfigChangEvent = mock(ConfigChangeEvent.class); final ConfigChangeEvent someConfigChangeEvent = mock(ConfigChangeEvent.class);
ConfigChangeEvent anotherConfigChangEvent = mock(ConfigChangeEvent.class); ConfigChangeEvent anotherConfigChangeEvent = mock(ConfigChangeEvent.class);
final SettableFuture<ConfigChangeEvent> someListenerFuture1 = SettableFuture.create(); final SettableFuture<ConfigChangeEvent> someListenerFuture1 = SettableFuture.create();
final SettableFuture<ConfigChangeEvent> someListenerFuture2 = SettableFuture.create(); final SettableFuture<ConfigChangeEvent> someListenerFuture2 = SettableFuture.create();
ConfigChangeListener someListener = new ConfigChangeListener() { ConfigChangeListener someListener = new ConfigChangeListener() {
@Override @Override
public void onChange(ConfigChangeEvent changeEvent) { public void onChange(ConfigChangeEvent changeEvent) {
if (someConfigChangEvent == changeEvent) { if (someConfigChangeEvent == changeEvent) {
someListenerFuture1.set(changeEvent); someListenerFuture1.set(changeEvent);
} else { } else {
someListenerFuture2.set(changeEvent); someListenerFuture2.set(changeEvent);
...@@ -747,7 +758,7 @@ public class DefaultConfigTest { ...@@ -747,7 +758,7 @@ public class DefaultConfigTest {
ConfigChangeListener anotherListener = new ConfigChangeListener() { ConfigChangeListener anotherListener = new ConfigChangeListener() {
@Override @Override
public void onChange(ConfigChangeEvent changeEvent) { public void onChange(ConfigChangeEvent changeEvent) {
if (someConfigChangEvent == changeEvent) { if (someConfigChangeEvent == changeEvent) {
anotherListenerFuture1.set(changeEvent); anotherListenerFuture1.set(changeEvent);
} else { } else {
anotherListenerFuture2.set(changeEvent); anotherListenerFuture2.set(changeEvent);
...@@ -762,17 +773,17 @@ public class DefaultConfigTest { ...@@ -762,17 +773,17 @@ public class DefaultConfigTest {
config.addChangeListener(someListener); config.addChangeListener(someListener);
config.addChangeListener(anotherListener); config.addChangeListener(anotherListener);
config.fireConfigChange(someConfigChangEvent); config.fireConfigChange(someConfigChangeEvent);
assertEquals(someConfigChangEvent, someListenerFuture1.get(500, TimeUnit.MILLISECONDS)); assertEquals(someConfigChangeEvent, someListenerFuture1.get(500, TimeUnit.MILLISECONDS));
assertEquals(someConfigChangEvent, anotherListenerFuture1.get(500, TimeUnit.MILLISECONDS)); assertEquals(someConfigChangeEvent, anotherListenerFuture1.get(500, TimeUnit.MILLISECONDS));
assertFalse(config.removeChangeListener(yetAnotherListener)); assertFalse(config.removeChangeListener(yetAnotherListener));
assertTrue(config.removeChangeListener(someListener)); assertTrue(config.removeChangeListener(someListener));
config.fireConfigChange(anotherConfigChangEvent); config.fireConfigChange(anotherConfigChangeEvent);
assertEquals(anotherConfigChangEvent, anotherListenerFuture2.get(500, TimeUnit.MILLISECONDS)); assertEquals(anotherConfigChangeEvent, anotherListenerFuture2.get(500, TimeUnit.MILLISECONDS));
TimeUnit.MILLISECONDS.sleep(100); TimeUnit.MILLISECONDS.sleep(100);
...@@ -792,8 +803,34 @@ public class DefaultConfigTest { ...@@ -792,8 +803,34 @@ public class DefaultConfigTest {
when(configRepository.getConfig()).thenReturn(someProperties); when(configRepository.getConfig()).thenReturn(someProperties);
DefaultConfig defaultConfig = DefaultConfig defaultConfig = new DefaultConfig(someNamespace, configRepository);
new DefaultConfig(someNamespace, configRepository);
Set<String> propertyNames = defaultConfig.getPropertyNames();
assertEquals(10, propertyNames.size());
assertEquals(someProperties.stringPropertyNames(), propertyNames);
}
@Test
public void testGetPropertyNamesWithOrderedProperties() {
String someKeyPrefix = "someKey";
String someValuePrefix = "someValue";
when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new OrderedProperties();
}
});
//set up config repo
someProperties = new OrderedProperties();
for (int i = 0; i < 10; i++) {
someProperties.setProperty(someKeyPrefix + i, someValuePrefix + i);
}
when(configRepository.getConfig()).thenReturn(someProperties);
DefaultConfig defaultConfig = new DefaultConfig(someNamespace, configRepository);
Set<String> propertyNames = defaultConfig.getPropertyNames(); Set<String> propertyNames = defaultConfig.getPropertyNames();
......
package com.ctrip.framework.apollo.internals; package com.ctrip.framework.apollo.internals;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.isIn;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
...@@ -14,15 +10,12 @@ import static org.mockito.Mockito.verify; ...@@ -14,15 +10,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import org.hamcrest.Matcher;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -34,12 +27,13 @@ import com.ctrip.framework.apollo.util.ConfigUtil; ...@@ -34,12 +27,13 @@ import com.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.io.Files; import com.google.common.io.Files;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/** /**
* Created by Jason on 4/9/16. * Created by Jason on 4/9/16.
*/ */
public class LocalFileConfigRepositoryTest { public class LocalFileConfigRepositoryTest {
private File someBaseDir; private File someBaseDir;
private String someNamespace; private String someNamespace;
private ConfigRepository upstreamRepo; private ConfigRepository upstreamRepo;
...@@ -49,7 +43,6 @@ public class LocalFileConfigRepositoryTest { ...@@ -49,7 +43,6 @@ public class LocalFileConfigRepositoryTest {
private String defaultKey; private String defaultKey;
private String defaultValue; private String defaultValue;
private ConfigSourceType someSourceType; private ConfigSourceType someSourceType;
private MockConfigUtil configUtil;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
...@@ -67,10 +60,15 @@ public class LocalFileConfigRepositoryTest { ...@@ -67,10 +60,15 @@ public class LocalFileConfigRepositoryTest {
when(upstreamRepo.getSourceType()).thenReturn(someSourceType); when(upstreamRepo.getSourceType()).thenReturn(someSourceType);
MockInjector.reset(); MockInjector.reset();
configUtil = new MockConfigUtil(); MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil());
MockInjector.setInstance(ConfigUtil.class, configUtil); PropertiesFactory propertiesFactory = mock(PropertiesFactory.class);
MockInjector.setInstance(PropertiesFactory.class, new DefaultPropertiesFactory()); when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
} }
@After @After
...@@ -123,8 +121,7 @@ public class LocalFileConfigRepositoryTest { ...@@ -123,8 +121,7 @@ public class LocalFileConfigRepositoryTest {
Files.write(defaultKey + "=" + someValue, file, Charsets.UTF_8); Files.write(defaultKey + "=" + someValue, file, Charsets.UTF_8);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someNamespace, LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someNamespace, upstreamRepo);
upstreamRepo);
localRepo.setLocalCacheDir(someBaseDir, true); localRepo.setLocalCacheDir(someBaseDir, true);
Properties properties = localRepo.getConfig(); Properties properties = localRepo.getConfig();
...@@ -141,20 +138,9 @@ public class LocalFileConfigRepositoryTest { ...@@ -141,20 +138,9 @@ public class LocalFileConfigRepositoryTest {
Properties result = localFileConfigRepository.getConfig(); Properties result = localFileConfigRepository.getConfig();
if (!isJDK11() || (isJDK11() && configUtil.isPropertiesOrderEnabled())) { assertThat(
assertThat( "LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache", result.entrySet(), equalTo(someProperties.entrySet()));
result.entrySet(), equalTo(someProperties.entrySet()));
} else {
//In JDK11 Properties return EntrySet without customize equals implementation, so equalTo will check
//whether they are same object. This is why two statements are used to check items in entryset.
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
result.entrySet(), everyItem(isIn(someProperties.entrySet())));
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
someProperties.entrySet(), everyItem(isIn(result.entrySet())));
}
assertEquals(someSourceType, localFileConfigRepository.getSourceType()); assertEquals(someSourceType, localFileConfigRepository.getSourceType());
} }
...@@ -173,20 +159,9 @@ public class LocalFileConfigRepositoryTest { ...@@ -173,20 +159,9 @@ public class LocalFileConfigRepositoryTest {
Properties anotherProperties = anotherLocalRepoWithNoFallback.getConfig(); Properties anotherProperties = anotherLocalRepoWithNoFallback.getConfig();
if (!isJDK11() || (isJDK11() && configUtil.isPropertiesOrderEnabled())) { assertThat(
assertThat( "LocalFileConfigRepository should persist local cache files and return that afterwards",
"LocalFileConfigRepository should persist local cache files and return that afterwards", someProperties.entrySet(), equalTo(anotherProperties.entrySet()));
someProperties.entrySet(), equalTo(anotherProperties.entrySet()));
} else {
//In JDK11 Properties return EntrySet without customize equals implementation, so equalTo will check
//whether they are same object. This is why two statements are used to check items in entryset.
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
someProperties.entrySet(), everyItem(isIn(anotherProperties.entrySet())));
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
anotherProperties.entrySet(), everyItem(isIn(someProperties.entrySet())));
}
assertEquals(someSourceType, localRepo.getSourceType()); assertEquals(someSourceType, localRepo.getSourceType());
} }
...@@ -221,7 +196,6 @@ public class LocalFileConfigRepositoryTest { ...@@ -221,7 +196,6 @@ public class LocalFileConfigRepositoryTest {
} }
public static class MockConfigUtil extends ConfigUtil { public static class MockConfigUtil extends ConfigUtil {
@Override @Override
public String getAppId() { public String getAppId() {
return someAppId; return someAppId;
...@@ -231,10 +205,6 @@ public class LocalFileConfigRepositoryTest { ...@@ -231,10 +205,6 @@ public class LocalFileConfigRepositoryTest {
public String getCluster() { public String getCluster() {
return someCluster; return someCluster;
} }
public String getJavaVersion() {
return System.getProperty("java.version");
}
} }
private File createLocalCachePropertyFile(Properties properties) throws IOException { private File createLocalCachePropertyFile(Properties properties) throws IOException {
...@@ -250,8 +220,4 @@ public class LocalFileConfigRepositoryTest { ...@@ -250,8 +220,4 @@ public class LocalFileConfigRepositoryTest {
} }
return file; return file;
} }
private boolean isJDK11() {
return configUtil.getJavaVersion().startsWith("11.");
}
} }
...@@ -10,8 +10,6 @@ import com.ctrip.framework.apollo.ConfigFileChangeListener; ...@@ -10,8 +10,6 @@ import com.ctrip.framework.apollo.ConfigFileChangeListener;
import com.ctrip.framework.apollo.build.MockInjector; import com.ctrip.framework.apollo.build.MockInjector;
import com.ctrip.framework.apollo.enums.PropertyChangeType; import com.ctrip.framework.apollo.enums.PropertyChangeType;
import com.ctrip.framework.apollo.model.ConfigFileChangeEvent; import com.ctrip.framework.apollo.model.ConfigFileChangeEvent;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import java.util.Properties; import java.util.Properties;
...@@ -21,9 +19,11 @@ import org.junit.Before; ...@@ -21,9 +19,11 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import org.mockito.stubbing.Answer;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -34,13 +34,20 @@ public class PropertiesConfigFileTest { ...@@ -34,13 +34,20 @@ public class PropertiesConfigFileTest {
private String someNamespace; private String someNamespace;
@Mock @Mock
private ConfigRepository configRepository; private ConfigRepository configRepository;
@Mock
private PropertiesFactory propertiesFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
someNamespace = "someName"; someNamespace = "someName";
MockInjector.reset(); MockInjector.reset();
MockInjector.setInstance(ConfigUtil.class, new ConfigUtil()); when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
MockInjector.setInstance(PropertiesFactory.class, new DefaultPropertiesFactory()); @Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
} }
@Test @Test
......
...@@ -23,7 +23,7 @@ import com.ctrip.framework.apollo.core.signature.Signature; ...@@ -23,7 +23,7 @@ import com.ctrip.framework.apollo.core.signature.Signature;
import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.ctrip.framework.apollo.exceptions.ApolloConfigException; import com.ctrip.framework.apollo.exceptions.ApolloConfigException;
import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.ConfigUtil;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory; import com.ctrip.framework.apollo.util.OrderedProperties;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import com.ctrip.framework.apollo.util.http.HttpRequest; import com.ctrip.framework.apollo.util.http.HttpRequest;
import com.ctrip.framework.apollo.util.http.HttpResponse; import com.ctrip.framework.apollo.util.http.HttpResponse;
...@@ -40,7 +40,6 @@ import java.util.Map; ...@@ -40,7 +40,6 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -49,7 +48,6 @@ import org.mockito.Mock; ...@@ -49,7 +48,6 @@ import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
/** /**
* Created by Jason on 4/9/16. * Created by Jason on 4/9/16.
...@@ -68,6 +66,8 @@ public class RemoteConfigRepositoryTest { ...@@ -68,6 +66,8 @@ public class RemoteConfigRepositoryTest {
@Mock @Mock
private static HttpResponse<List<ApolloConfigNotification>> pollResponse; private static HttpResponse<List<ApolloConfigNotification>> pollResponse;
private RemoteConfigLongPollService remoteConfigLongPollService; private RemoteConfigLongPollService remoteConfigLongPollService;
@Mock
private PropertiesFactory propertiesFactory;
private static String someAppId; private static String someAppId;
private static String someCluster; private static String someCluster;
...@@ -98,21 +98,40 @@ public class RemoteConfigRepositoryTest { ...@@ -98,21 +98,40 @@ public class RemoteConfigRepositoryTest {
MockInjector.setInstance(RemoteConfigLongPollService.class, remoteConfigLongPollService); MockInjector.setInstance(RemoteConfigLongPollService.class, remoteConfigLongPollService);
System.setProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE, "true"); when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
PropertiesFactory propertiesFactory = new DefaultPropertiesFactory(); @Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory); MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
someAppId = "someAppId"; someAppId = "someAppId";
someCluster = "someCluster"; someCluster = "someCluster";
} }
@After @Test
public void tearDown() throws Exception { public void testLoadConfig() throws Exception {
System.clearProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE); String someKey = "someKey";
String someValue = "someValue";
Map<String, String> configurations = Maps.newHashMap();
configurations.put(someKey, someValue);
ApolloConfig someApolloConfig = assembleApolloConfig(configurations);
when(someResponse.getStatusCode()).thenReturn(200);
when(someResponse.getBody()).thenReturn(someApolloConfig);
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(someNamespace);
Properties config = remoteConfigRepository.getConfig();
assertEquals(configurations, config);
assertEquals(ConfigSourceType.REMOTE, remoteConfigRepository.getSourceType());
remoteConfigLongPollService.stopLongPollingRefresh();
} }
@Test @Test
public void testLoadConfig() throws Exception { public void testLoadConfigWithOrderedProperties() throws Exception {
String someKey = "someKey"; String someKey = "someKey";
String someValue = "someValue"; String someValue = "someValue";
Map<String, String> configurations = Maps.newLinkedHashMap(); Map<String, String> configurations = Maps.newLinkedHashMap();
...@@ -122,21 +141,25 @@ public class RemoteConfigRepositoryTest { ...@@ -122,21 +141,25 @@ public class RemoteConfigRepositoryTest {
when(someResponse.getStatusCode()).thenReturn(200); when(someResponse.getStatusCode()).thenReturn(200);
when(someResponse.getBody()).thenReturn(someApolloConfig); when(someResponse.getBody()).thenReturn(someApolloConfig);
when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new OrderedProperties();
}
});
RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(someNamespace); RemoteConfigRepository remoteConfigRepository = new RemoteConfigRepository(someNamespace);
Properties config = remoteConfigRepository.getConfig(); Properties config = remoteConfigRepository.getConfig();
// assertEquals(configurations, config); assertTrue(config instanceof OrderedProperties);
assertTrue(configurations.equals(config)); assertEquals(configurations, config);
assertEquals(ConfigSourceType.REMOTE, remoteConfigRepository.getSourceType()); assertEquals(ConfigSourceType.REMOTE, remoteConfigRepository.getSourceType());
remoteConfigLongPollService.stopLongPollingRefresh(); remoteConfigLongPollService.stopLongPollingRefresh();
if (configUtil.isPropertiesOrderEnabled()) { String[] actualArrays = config.keySet().toArray(new String[]{});
String[] actualArrays = config.keySet().toArray(new String[]{}); String[] expectedArrays = {"someKey", "someKey2"};
String[] expectedArrays = {"someKey", "someKey2"}; assertArrayEquals(expectedArrays, actualArrays);
assertArrayEquals(expectedArrays, actualArrays);
}
} }
@Test @Test
......
...@@ -6,16 +6,15 @@ import static org.mockito.Mockito.when; ...@@ -6,16 +6,15 @@ import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.build.MockInjector; import com.ctrip.framework.apollo.build.MockInjector;
import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.Config;
...@@ -25,6 +24,7 @@ import com.ctrip.framework.apollo.model.ConfigChange; ...@@ -25,6 +24,7 @@ import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import org.mockito.stubbing.Answer;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -35,22 +35,23 @@ public class SimpleConfigTest { ...@@ -35,22 +35,23 @@ public class SimpleConfigTest {
private String someNamespace; private String someNamespace;
@Mock @Mock
private ConfigRepository configRepository; private ConfigRepository configRepository;
@Mock
private PropertiesFactory propertiesFactory;
private ConfigSourceType someSourceType; private ConfigSourceType someSourceType;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
someNamespace = "someName"; someNamespace = "someName";
System.setProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE, "true"); when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
PropertiesFactory propertiesFactory = new DefaultPropertiesFactory(); @Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory); MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
} }
@After
public void tearDown() throws Exception {
System.clearProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE);
}
@Test @Test
public void testGetProperty() throws Exception { public void testGetProperty() throws Exception {
Properties someProperties = new Properties(); Properties someProperties = new Properties();
......
...@@ -10,7 +10,6 @@ import com.ctrip.framework.apollo.ConfigFileChangeListener; ...@@ -10,7 +10,6 @@ import com.ctrip.framework.apollo.ConfigFileChangeListener;
import com.ctrip.framework.apollo.build.MockInjector; import com.ctrip.framework.apollo.build.MockInjector;
import com.ctrip.framework.apollo.enums.PropertyChangeType; import com.ctrip.framework.apollo.enums.PropertyChangeType;
import com.ctrip.framework.apollo.model.ConfigFileChangeEvent; import com.ctrip.framework.apollo.model.ConfigFileChangeEvent;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import java.util.Properties; import java.util.Properties;
...@@ -21,10 +20,12 @@ import org.junit.Before; ...@@ -21,10 +20,12 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import org.mockito.stubbing.Answer;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
...@@ -35,13 +36,19 @@ public class XmlConfigFileTest { ...@@ -35,13 +36,19 @@ public class XmlConfigFileTest {
private String someNamespace; private String someNamespace;
@Mock @Mock
private ConfigRepository configRepository; private ConfigRepository configRepository;
@Mock
private PropertiesFactory propertiesFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
someNamespace = "someName"; someNamespace = "someName";
System.setProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE, "true"); when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
PropertiesFactory propertiesFactory = new DefaultPropertiesFactory(); @Override
public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory); MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
} }
......
...@@ -7,17 +7,17 @@ import com.ctrip.framework.apollo.build.MockInjector; ...@@ -7,17 +7,17 @@ import com.ctrip.framework.apollo.build.MockInjector;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.ConfigSourceType;
import com.ctrip.framework.apollo.exceptions.ApolloConfigException; import com.ctrip.framework.apollo.exceptions.ApolloConfigException;
import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.OrderedProperties;
import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
import com.ctrip.framework.apollo.util.yaml.YamlParser; import com.ctrip.framework.apollo.util.yaml.YamlParser;
import java.util.Properties; import java.util.Properties;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class YamlConfigFileTest { public class YamlConfigFileTest {
...@@ -27,6 +27,8 @@ public class YamlConfigFileTest { ...@@ -27,6 +27,8 @@ public class YamlConfigFileTest {
private ConfigRepository configRepository; private ConfigRepository configRepository;
@Mock @Mock
private YamlParser yamlParser; private YamlParser yamlParser;
@Mock
private PropertiesFactory propertiesFactory;
private ConfigSourceType someSourceType; private ConfigSourceType someSourceType;
...@@ -34,17 +36,16 @@ public class YamlConfigFileTest { ...@@ -34,17 +36,16 @@ public class YamlConfigFileTest {
public void setUp() throws Exception { public void setUp() throws Exception {
someNamespace = "someName"; someNamespace = "someName";
System.setProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE, "true");
MockInjector.reset(); MockInjector.reset();
MockInjector.setInstance(YamlParser.class, yamlParser); MockInjector.setInstance(YamlParser.class, yamlParser);
MockInjector.setInstance(ConfigUtil.class, new ConfigUtil());
MockInjector.setInstance(PropertiesFactory.class, new DefaultPropertiesFactory());
}
@After when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
public void tearDown() throws Exception { @Override
System.clearProperty(PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE); public Properties answer(InvocationOnMock invocation) {
return new Properties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
} }
@Test @Test
...@@ -70,6 +71,12 @@ public class YamlConfigFileTest { ...@@ -70,6 +71,12 @@ public class YamlConfigFileTest {
@Test @Test
public void testWhenHasContentWithOrder() throws Exception { public void testWhenHasContentWithOrder() throws Exception {
when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new OrderedProperties();
}
});
Properties someProperties = new Properties(); Properties someProperties = new Properties();
String key = ConfigConsts.CONFIG_FILE_CONTENT_KEY; String key = ConfigConsts.CONFIG_FILE_CONTENT_KEY;
String someContent = "someKey: 'someValue'\nsomeKey2: 'someValue2'"; String someContent = "someKey: 'someValue'\nsomeKey2: 'someValue2'";
......
...@@ -10,7 +10,6 @@ import org.junit.Test; ...@@ -10,7 +10,6 @@ import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/** /**
* @author Jason Song(song_s@ctrip.com) * @author Jason Song(song_s@ctrip.com)
......
...@@ -6,13 +6,11 @@ import java.util.Collection; ...@@ -6,13 +6,11 @@ import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Properties; import java.util.Properties;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class OrderedPropertiesTest { public class OrderedPropertiesTest {
private OrderedProperties orderedProperties; private OrderedProperties orderedProperties;
private Properties legacyProperties;
@Before @Before
public void setUp() { public void setUp() {
...@@ -23,7 +21,7 @@ public class OrderedPropertiesTest { ...@@ -23,7 +21,7 @@ public class OrderedPropertiesTest {
@Test @Test
public void testOrderedPropertiesInvokedAsLegacyProperties() { public void testOrderedPropertiesInvokedAsLegacyProperties() {
legacyProperties = orderedProperties; Properties legacyProperties = orderedProperties;
assertEquals(orderedProperties.size(), legacyProperties.size()); assertEquals(orderedProperties.size(), legacyProperties.size());
legacyProperties.put("key3", "value3"); legacyProperties.put("key3", "value3");
...@@ -85,10 +83,9 @@ public class OrderedPropertiesTest { ...@@ -85,10 +83,9 @@ public class OrderedPropertiesTest {
@Test @Test
public void testPropertyNames() { public void testPropertyNames() {
Enumeration<String> propertyNames = (Enumeration<String>) orderedProperties.propertyNames(); Enumeration<?> propertyNames = orderedProperties.propertyNames();
assertTrue(propertyNames.nextElement().equals("key1")); assertEquals("key1", propertyNames.nextElement());
assertTrue(propertyNames.nextElement().equals("key2")); assertEquals("key2", propertyNames.nextElement());
} }
......
package com.ctrip.framework.apollo.util.yaml; package com.ctrip.framework.apollo.util.yaml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.build.MockInjector;
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.io.Files;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import org.junit.Test; import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ByteArrayResource;
import org.yaml.snakeyaml.parser.ParserException; import org.yaml.snakeyaml.parser.ParserException;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
public class YamlParserTest { public class YamlParserTest {
private YamlParser parser = new YamlParser(); private YamlParser parser = new YamlParser();
...@@ -37,14 +44,50 @@ public class YamlParserTest { ...@@ -37,14 +44,50 @@ public class YamlParserTest {
testInvalid("case8.yaml"); testInvalid("case8.yaml");
} }
private void test(String caseName) throws Exception { @Test
File file = new File("src/test/resources/yaml/" + caseName); public void testOrderProperties() throws IOException {
String yamlContent = loadYaml("orderedcase.yaml");
String yamlContent = Files.toString(file, Charsets.UTF_8); Properties nonOrderedProperties = parser.yamlToProperties(yamlContent);
MockInjector.reset();
PropertiesFactory propertiesFactory = mock(PropertiesFactory.class);;
when(propertiesFactory.getPropertiesInstance()).thenAnswer(new Answer<Properties>() {
@Override
public Properties answer(InvocationOnMock invocation) {
return new OrderedProperties();
}
});
MockInjector.setInstance(PropertiesFactory.class, propertiesFactory);
parser = new YamlParser();
Properties orderedProperties = parser.yamlToProperties(yamlContent);
assertTrue(orderedProperties instanceof OrderedProperties);
checkPropertiesEquals(nonOrderedProperties, orderedProperties);
String[] propertyNames = orderedProperties.stringPropertyNames().toArray(new String[0]);
assertEquals("k2", propertyNames[0]);
assertEquals("k4", propertyNames[1]);
assertEquals("k1", propertyNames[2]);
}
private void test(String caseName) throws Exception {
String yamlContent = loadYaml(caseName);
check(yamlContent); check(yamlContent);
} }
private String loadYaml(String caseName) throws IOException {
File file = new File("src/test/resources/yaml/" + caseName);
return Files.toString(file, Charsets.UTF_8);
}
private void testInvalid(String caseName) throws Exception { private void testInvalid(String caseName) throws Exception {
File file = new File("src/test/resources/yaml/" + caseName); File file = new File("src/test/resources/yaml/" + caseName);
......
k2: "someValue"
k4: "anotherValue"
k1: "yetAnotherValue"
\ No newline at end of file
...@@ -177,7 +177,7 @@ public class ConfigController { ...@@ -177,7 +177,7 @@ public class ConfigController {
* Release in lower index override those in higher index * Release in lower index override those in higher index
*/ */
Map<String, String> mergeReleaseConfigurations(List<Release> releases) { Map<String, String> mergeReleaseConfigurations(List<Release> releases) {
Map<String, String> result = Maps.newHashMap(); Map<String, String> result = Maps.newLinkedHashMap();
for (Release release : Lists.reverse(releases)) { for (Release release : Lists.reverse(releases)) {
result.putAll(gson.fromJson(release.getConfigurations(), configurationTypeReference)); result.putAll(gson.fromJson(release.getConfigurations(), configurationTypeReference));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment