/* * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.cloud.aws.context.config.xml; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.cloudformation.AmazonCloudFormation; import com.amazonaws.services.cloudformation.AmazonCloudFormationClient; import com.amazonaws.services.cloudformation.model.DescribeStackResourcesRequest; import com.amazonaws.services.cloudformation.model.DescribeStackResourcesResult; import com.amazonaws.services.cloudformation.model.DescribeStacksRequest; import com.amazonaws.services.cloudformation.model.DescribeStacksResult; import com.amazonaws.services.cloudformation.model.ListStackResourcesRequest; import com.amazonaws.services.cloudformation.model.ListStackResourcesResult; import com.amazonaws.services.cloudformation.model.Stack; import com.amazonaws.services.cloudformation.model.StackResource; import com.amazonaws.services.cloudformation.model.StackResourceSummary; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpServer; import org.junit.After; import org.junit.Test; import org.mockito.Mockito; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.cloud.aws.context.MetaDataServer; import org.springframework.cloud.aws.core.env.ResourceIdResolver; import org.springframework.cloud.aws.core.env.stack.StackResourceRegistry; import org.springframework.context.support.GenericXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.test.util.ReflectionTestUtils; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.cloud.aws.core.config.AmazonWebserviceClientConfigurationUtils.getBeanName; /** * @author Agim Emruli * @author Alain Sahli */ public class StackConfigurationBeanDefinitionParserTest { @Test public void parseInternal_stackConfigurationWithExternallyConfiguredCloudFormationClient_returnsConfiguredStackWithExternallyConfiguredClient() throws Exception { //Arrange DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-withCustomCloudFormationClient.xml", getClass())); AmazonCloudFormation amazonCloudFormationMock = beanFactory.getBean(AmazonCloudFormation.class); when(amazonCloudFormationMock.listStackResources(new ListStackResourcesRequest().withStackName("test"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries(new StackResourceSummary())); when(amazonCloudFormationMock.describeStacks(new DescribeStacksRequest().withStackName("test"))). thenReturn(new DescribeStacksResult().withStacks(new Stack())); //Act StackResourceRegistry stackResourceRegistry = beanFactory.getBean(StackResourceRegistry.class); //Assert assertNotNull(stackResourceRegistry); assertFalse(beanFactory.containsBeanDefinition(getBeanName(AmazonCloudFormationClient.class.getName()))); verify(amazonCloudFormationMock, times(1)).listStackResources(new ListStackResourcesRequest().withStackName("test")); beanFactory.getBean("customStackTags"); verify(amazonCloudFormationMock, times(1)).describeStacks(new DescribeStacksRequest().withStackName("test")); } @Test public void parseInternal_withCustomRegion_shouldConfigureDefaultClientWithCustomRegion() throws Exception { //Arrange DefaultListableBeanFactory registry = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); //Act reader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-custom-region.xml", getClass())); // Assert AmazonCloudFormationClient amazonCloudFormation = registry.getBean(AmazonCloudFormationClient.class); assertEquals("https://" + Region.getRegion(Regions.SA_EAST_1).getServiceEndpoint("cloudformation"), ReflectionTestUtils.getField(amazonCloudFormation, "endpoint").toString()); } @Test public void parseInternal_withCustomRegionProvider_shouldConfigureDefaultClientWithCustomRegionReturnedByProvider() throws Exception { //Arrange DefaultListableBeanFactory registry = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry); //Act reader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-custom-region-provider.xml", getClass())); // Assert AmazonCloudFormationClient amazonCloudFormation = registry.getBean(AmazonCloudFormationClient.class); assertEquals("https://" + Region.getRegion(Regions.AP_SOUTHEAST_2).getServiceEndpoint("cloudformation"), ReflectionTestUtils.getField(amazonCloudFormation, "endpoint").toString()); } @Test public void resourceIdResolver_stackConfiguration_resourceIdResolverBeanExposed() { // Arrange GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("IntegrationTestStack"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries(new StackResourceSummary())); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-staticStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); // Act ResourceIdResolver resourceIdResolver = applicationContext.getBean(ResourceIdResolver.class); // Assert assertThat(resourceIdResolver, is(not(nullValue()))); } @Test public void stackResourceRegistry_stackConfigurationWithStaticName_stackResourceRegistryBeanExposedUnderStaticStackName() throws Exception { // Arrange GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("IntegrationTestStack"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries(new StackResourceSummary())); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-staticStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); // Act StackResourceRegistry staticStackNameProviderBasedStackResourceRegistry = applicationContext.getBean("IntegrationTestStack", StackResourceRegistry.class); // Assert assertThat(staticStackNameProviderBasedStackResourceRegistry, is(not(nullValue()))); } @Test public void stackResourceRegistry_stackConfigurationWithoutStaticName_stackResourceRegistryBeanExposedUnderGeneratedName() throws Exception { // Arrange HttpServer server = MetaDataServer.setupHttpServer(); HttpContext httpContext = server.createContext("/latest/meta-data/instance-id", new MetaDataServer.HttpResponseWriterHandler("foo")); GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.describeStackResources(new DescribeStackResourcesRequest().withPhysicalResourceId("foo"))). thenReturn(new DescribeStackResourcesResult().withStackResources(new StackResource().withStackName("test"))); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("test"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries(new StackResourceSummary())); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-autoDetectStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); // Act StackResourceRegistry autoDetectingStackNameProviderBasedStackResourceRegistry = applicationContext.getBean("org.springframework.cloud.aws.core.env.stack.config.StackResourceRegistryFactoryBean#0", StackResourceRegistry.class); // Assert assertThat(autoDetectingStackNameProviderBasedStackResourceRegistry, is(not(nullValue()))); server.removeContext(httpContext); } @Test public void resourceIdResolverResolveToPhysicalResourceId_stackConfigurationWithStaticNameAndLogicalResourceIdOfExistingResourceProvided_returnsPhysicalResourceId() { // Arrange GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("IntegrationTestStack"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries( new StackResourceSummary().withLogicalResourceId("EmptyBucket").withPhysicalResourceId("integrationteststack-emptybucket-foo"))); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-staticStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); ResourceIdResolver resourceIdResolver = applicationContext.getBean(ResourceIdResolver.class); // Act String physicalResourceId = resourceIdResolver.resolveToPhysicalResourceId("EmptyBucket"); // Assert assertThat(physicalResourceId, startsWith("integrationteststack-emptybucket-")); } @Test public void resourceIdResolverResolveToPhysicalResourceId_stackConfigurationWithoutStaticNameAndLogicalResourceIdOfExistingResourceProvided_returnsPhysicalResourceId() throws Exception { // Arrange HttpServer server = MetaDataServer.setupHttpServer(); HttpContext httpContext = server.createContext("/latest/meta-data/instance-id", new MetaDataServer.HttpResponseWriterHandler("foo")); GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.describeStackResources(new DescribeStackResourcesRequest().withPhysicalResourceId("foo"))). thenReturn(new DescribeStackResourcesResult().withStackResources(new StackResource().withStackName("test"))); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("test"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries( new StackResourceSummary().withLogicalResourceId("EmptyBucket").withPhysicalResourceId("integrationteststack-emptybucket-foo"))); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-autoDetectStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); ResourceIdResolver resourceIdResolver = applicationContext.getBean(ResourceIdResolver.class); // Act String physicalResourceId = resourceIdResolver.resolveToPhysicalResourceId("EmptyBucket"); // Assert assertThat(physicalResourceId, startsWith("integrationteststack-emptybucket-")); server.removeContext(httpContext); } @Test public void resourceIdResolverResolveToPhysicalResourceId_logicalResourceIdOfNonExistingResourceProvided_returnsLogicalResourceIdAsPhysicalResourceId() { // Arrange GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); AmazonCloudFormation amazonCloudFormation = Mockito.mock(AmazonCloudFormation.class); when(amazonCloudFormation.listStackResources(new ListStackResourcesRequest().withStackName("IntegrationTestStack"))). thenReturn(new ListStackResourcesResult().withStackResourceSummaries(new StackResourceSummary())); applicationContext.load(new ClassPathResource(getClass().getSimpleName() + "-staticStackName.xml", getClass())); applicationContext.getBeanFactory().registerSingleton(getBeanName(AmazonCloudFormation.class.getName()), amazonCloudFormation); applicationContext.refresh(); ResourceIdResolver resourceIdResolver = applicationContext.getBean(ResourceIdResolver.class); // Act String physicalResourceId = resourceIdResolver.resolveToPhysicalResourceId("nonExistingLogicalResourceId"); // Assert assertThat(physicalResourceId, is("nonExistingLogicalResourceId")); } @After public void destroyMetaDataServer() throws Exception { MetaDataServer.shutdownHttpServer(); } }