package com.ctrip.framework.apollo.configservice.integration; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.core.ConfigConsts; import com.netflix.servo.util.Strings; import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.jdbc.Sql; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Jason Song(song_s@ctrip.com) */ public class ConfigFileControllerIntegrationTest extends AbstractBaseIntegrationTest { private String someAppId; private String somePublicAppId; private String someCluster; private String someNamespace; private String somePublicNamespace; private String someDC; private String someDefaultCluster; private String grayClientIp; private String nonGrayClientIp; private Gson gson = new Gson(); private ExecutorService executorService; private Type mapResponseType = new TypeToken<Map<String, String>>(){}.getType(); @Before public void setUp() throws Exception { someDefaultCluster = ConfigConsts.CLUSTER_NAME_DEFAULT; someAppId = "someAppId"; somePublicAppId = "somePublicAppId"; someCluster = "someCluster"; someNamespace = "someNamespace"; somePublicNamespace = "somePublicNamespace"; someDC = "someDC"; grayClientIp = "1.1.1.1"; nonGrayClientIp = "2.2.2.2"; executorService = Executors.newSingleThreadExecutor(); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryConfigAsProperties() throws Exception { ResponseEntity<String> response = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}", String.class, getHostUrl(), someAppId, someCluster, someNamespace); String result = response.getBody(); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(result.contains("k2=v2")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-gray-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryConfigAsPropertiesWithGrayRelease() throws Exception { AtomicBoolean stop = new AtomicBoolean(); periodicSendMessage(executorService, assembleKey(someAppId, ConfigConsts.CLUSTER_NAME_DEFAULT, ConfigConsts.NAMESPACE_APPLICATION), stop); TimeUnit.MILLISECONDS.sleep(500); stop.set(true); ResponseEntity<String> response = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}?ip={clientIp}", String.class, getHostUrl(), someAppId, someDefaultCluster, ConfigConsts.NAMESPACE_APPLICATION, grayClientIp); ResponseEntity<String> anotherResponse = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}?ip={clientIp}", String.class, getHostUrl(), someAppId, someDefaultCluster, ConfigConsts.NAMESPACE_APPLICATION, nonGrayClientIp); String result = response.getBody(); String anotherResult = anotherResponse.getBody(); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(result.contains("k1=v1-gray")); assertEquals(HttpStatus.OK, anotherResponse.getStatusCode()); assertFalse(anotherResult.contains("k1=v1-gray")); assertTrue(anotherResult.contains("k1=v1")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-release-public-dc-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryPublicConfigAsProperties() throws Exception { ResponseEntity<String> response = restTemplate .getForEntity( "{baseurl}/configfiles/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}", String.class, getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, someDC); String result = response.getBody(); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(result.contains("k1=override-someDC-v1")); assertTrue(result.contains("k2=someDC-v2")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryConfigAsJson() throws Exception { ResponseEntity<String> response = restTemplate .getForEntity("{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}", String.class, getHostUrl(), someAppId, someCluster, someNamespace); Map<String, String> configs = gson.fromJson(response.getBody(), mapResponseType); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("v2", configs.get("k2")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-release-public-dc-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryPublicConfigAsJson() throws Exception { ResponseEntity<String> response = restTemplate .getForEntity( "{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?dataCenter={dateCenter}", String.class, getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, someDC); Map<String, String> configs = gson.fromJson(response.getBody(), mapResponseType); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("override-someDC-v1", configs.get("k1")); assertEquals("someDC-v2", configs.get("k2")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-release-public-default-override.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/test-gray-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testQueryPublicConfigAsJsonWithGrayRelease() throws Exception { AtomicBoolean stop = new AtomicBoolean(); periodicSendMessage(executorService, assembleKey(somePublicAppId, ConfigConsts.CLUSTER_NAME_DEFAULT, somePublicNamespace), stop); TimeUnit.MILLISECONDS.sleep(500); stop.set(true); ResponseEntity<String> response = restTemplate .getForEntity( "{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?ip={clientIp}", String.class, getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, grayClientIp); ResponseEntity<String> anotherResponse = restTemplate .getForEntity( "{baseurl}/configfiles/json/{appId}/{clusterName}/{namespace}?ip={clientIp}", String.class, getHostUrl(), someAppId, someDefaultCluster, somePublicNamespace, nonGrayClientIp); Map<String, String> configs = gson.fromJson(response.getBody(), mapResponseType); Map<String, String> anotherConfigs = gson.fromJson(anotherResponse.getBody(), mapResponseType); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, anotherResponse.getStatusCode()); assertEquals("override-v1", configs.get("k1")); assertEquals("gray-v2", configs.get("k2")); assertEquals("override-v1", anotherConfigs.get("k1")); assertEquals("default-v2", anotherConfigs.get("k2")); } @Test @Sql(scripts = "/integration-test/test-release.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/integration-test/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testConfigChanged() throws Exception { ResponseEntity<String> response = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}", String.class, getHostUrl(), someAppId, someCluster, someNamespace); String result = response.getBody(); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(result.contains("k2=v2")); String someReleaseName = "someReleaseName"; String someReleaseComment = "someReleaseComment"; Namespace namespace = new Namespace(); namespace.setAppId(someAppId); namespace.setClusterName(someCluster); namespace.setNamespaceName(someNamespace); String someOwner = "someOwner"; Map<String, String> newConfigurations = ImmutableMap.of("k1", "v1-changed", "k2", "v2-changed"); buildRelease(someReleaseName, someReleaseComment, namespace, newConfigurations, someOwner); ResponseEntity<String> anotherResponse = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}", String.class, getHostUrl(), someAppId, someCluster, someNamespace); assertEquals(response.getBody(), anotherResponse.getBody()); List<String> keys = Lists.newArrayList(someAppId, someCluster, someNamespace); String message = Strings.join(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR, keys.iterator()); sendReleaseMessage(message); TimeUnit.MILLISECONDS.sleep(500); ResponseEntity<String> newResponse = restTemplate .getForEntity("{baseurl}/configfiles/{appId}/{clusterName}/{namespace}", String.class, getHostUrl(), someAppId, someCluster, someNamespace); result = newResponse.getBody(); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(result.contains("k1=v1-changed")); assertTrue(result.contains("k2=v2-changed")); } private String assembleKey(String appId, String cluster, String namespace) { return Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR).join(appId, cluster, namespace); } }