package com.ctrip.framework.apollo.internals;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq;
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 java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import com.ctrip.framework.apollo.build.MockInjector;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.io.Files;
/**
* Created by Jason on 4/9/16.
*/
public class LocalFileConfigRepositoryTest {
private File someBaseDir;
private String someNamespace;
private ConfigRepository upstreamRepo;
private Properties someProperties;
private static String someAppId = "someApp";
private static String someCluster = "someCluster";
private String defaultKey;
private String defaultValue;
@Before
public void setUp() throws Exception {
someBaseDir = new File("src/test/resources/config-cache");
someBaseDir.mkdir();
someNamespace = "someName";
someProperties = new Properties();
defaultKey = "defaultKey";
defaultValue = "defaultValue";
someProperties.setProperty(defaultKey, defaultValue);
upstreamRepo = mock(ConfigRepository.class);
when(upstreamRepo.getConfig()).thenReturn(someProperties);
MockInjector.reset();
MockInjector.setInstance(ConfigUtil.class, new MockConfigUtil());
}
@After
public void tearDown() throws Exception {
recursiveDelete(someBaseDir);
}
//helper method to clean created files
private void recursiveDelete(File file) {
if (!file.exists()) {
return;
}
if (file.isDirectory()) {
for (File f : file.listFiles()) {
recursiveDelete(f);
}
}
file.delete();
}
private String assembleLocalCacheFileName() {
return String.format("%s.properties", Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR)
.join(someAppId, someCluster, someNamespace));
}
@Test
public void testLoadConfigWithLocalFile() throws Exception {
String someKey = "someKey";
String someValue = "someValue\nxxx\nyyy";
Properties someProperties = new Properties();
someProperties.setProperty(someKey, someValue);
createLocalCachePropertyFile(someProperties);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someNamespace);
localRepo.setLocalCacheDir(someBaseDir, true);
Properties properties = localRepo.getConfig();
assertEquals(someValue, properties.getProperty(someKey));
}
@Test
public void testLoadConfigWithLocalFileAndFallbackRepo() throws Exception {
File file = new File(someBaseDir, assembleLocalCacheFileName());
String someValue = "someValue";
Files.write(defaultKey + "=" + someValue, file, Charsets.UTF_8);
LocalFileConfigRepository localRepo = new LocalFileConfigRepository(someNamespace, upstreamRepo);
localRepo.setLocalCacheDir(someBaseDir, true);
Properties properties = localRepo.getConfig();
assertEquals(defaultValue, properties.getProperty(defaultKey));
}
@Test
public void testLoadConfigWithNoLocalFile() throws Exception {
LocalFileConfigRepository
localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo);
localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
Properties result = localFileConfigRepository.getConfig();
assertThat(
"LocalFileConfigRepository's properties should be the same as fallback repo's when there is no local cache",
result.entrySet(), equalTo(someProperties.entrySet()));
}
@Test
public void testLoadConfigWithNoLocalFileMultipleTimes() throws Exception {
LocalFileConfigRepository localRepo =
new LocalFileConfigRepository(someNamespace, upstreamRepo);
localRepo.setLocalCacheDir(someBaseDir, true);
Properties someProperties = localRepo.getConfig();
LocalFileConfigRepository
anotherLocalRepoWithNoFallback =
new LocalFileConfigRepository(someNamespace);
anotherLocalRepoWithNoFallback.setLocalCacheDir(someBaseDir, true);
Properties anotherProperties = anotherLocalRepoWithNoFallback.getConfig();
assertThat(
"LocalFileConfigRepository should persist local cache files and return that afterwards",
someProperties.entrySet(), equalTo(anotherProperties.entrySet()));
}
@Test
public void testOnRepositoryChange() throws Exception {
RepositoryChangeListener someListener = mock(RepositoryChangeListener.class);
LocalFileConfigRepository localFileConfigRepository =
new LocalFileConfigRepository(someNamespace, upstreamRepo);
localFileConfigRepository.setLocalCacheDir(someBaseDir, true);
localFileConfigRepository.addChangeListener(someListener);
localFileConfigRepository.getConfig();
Properties anotherProperties = new Properties();
anotherProperties.put("anotherKey", "anotherValue");
localFileConfigRepository.onRepositoryChange(someNamespace, anotherProperties);
final ArgumentCaptor<Properties> captor = ArgumentCaptor.forClass(Properties.class);
verify(someListener, times(1)).onRepositoryChange(eq(someNamespace), captor.capture());
assertEquals(anotherProperties, captor.getValue());
}
public static class MockConfigUtil extends ConfigUtil {
@Override
public String getAppId() {
return someAppId;
}
@Override
public String getCluster() {
return someCluster;
}
}
private File createLocalCachePropertyFile(Properties properties) throws IOException {
File file = new File(someBaseDir, assembleLocalCacheFileName());
FileOutputStream in = null;
try {
in = new FileOutputStream(file);
properties.store(in, "Persisted by LocalFileConfigRepositoryTest");
} finally {
if (in != null) {
in.close();
}
}
return file;
}
}