/*
* 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.jdbc.config.xml;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.model.GetUserResult;
import com.amazonaws.services.identitymanagement.model.User;
import com.amazonaws.services.rds.AmazonRDS;
import com.amazonaws.services.rds.AmazonRDSClient;
import com.amazonaws.services.rds.model.DBInstance;
import com.amazonaws.services.rds.model.DescribeDBInstancesRequest;
import com.amazonaws.services.rds.model.DescribeDBInstancesResult;
import com.amazonaws.services.rds.model.Endpoint;
import com.amazonaws.services.rds.model.ListTagsForResourceRequest;
import com.amazonaws.services.rds.model.ListTagsForResourceResult;
import com.amazonaws.services.rds.model.Tag;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.cloud.aws.core.config.AmazonWebserviceClientConfigurationUtils;
import org.springframework.cloud.aws.jdbc.rds.AmazonRdsReadReplicaAwareDataSourceFactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.util.ReflectionTestUtils;
import javax.sql.DataSource;
import java.util.Date;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
/**
* Tests for the {@link AmazonRdsDataSourceBeanDefinitionParser} bean definition parser
*
* @author Agim Emruli
* @since 1.0
*/
public class AmazonRdsDataSourceBeanDefinitionParserTest {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
@Test
public void parseInternal_minimalConfiguration_createsBeanDefinitionWithoutReadReplicas() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
beanDefinitionBuilder.setFactoryMethod("mock");
beanDefinitionBuilder.addConstructorArgValue(AmazonRDS.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), beanDefinitionBuilder.getBeanDefinition());
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-minimal.xml", getClass()));
AmazonRDS client = beanFactory.getBean(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), AmazonRDS.class);
when(client.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))).thenReturn(
new DescribeDBInstancesResult().
withDBInstances(new DBInstance().
withDBInstanceStatus("available").
withDBName("test").
withDBInstanceIdentifier("test").
withEngine("mysql").
withMasterUsername("admin").
withEndpoint(new Endpoint().
withAddress("localhost").
withPort(3306)
).withReadReplicaDBInstanceIdentifiers("read1")
)
);
//Act
DataSource dataSource = beanFactory.getBean(DataSource.class);
//Assert
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);
}
@Test
public void parseInternal_readReplicaSupportEnabled_configuresReadReplicaEnabledFactoryBean() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
beanDefinitionBuilder.setFactoryMethod("mock");
beanDefinitionBuilder.addConstructorArgValue(AmazonRDS.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), beanDefinitionBuilder.getBeanDefinition());
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-readReplicaEnabled.xml", getClass()));
//Act
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("test");
//Assert
assertEquals(AmazonRdsReadReplicaAwareDataSourceFactoryBean.class.getName(), beanDefinition.getBeanClassName());
}
@Test
public void parseInternal_noCredentialsDefined_returnsClientWithDefaultCredentialsProvider() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
beanDefinitionBuilder.setFactoryMethod("mock");
beanDefinitionBuilder.addConstructorArgValue(AmazonRDS.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), beanDefinitionBuilder.getBeanDefinition());
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-noCredentials.xml", getClass()));
AmazonRDS client = beanFactory.getBean(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), AmazonRDS.class);
when(client.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))).thenReturn(
new DescribeDBInstancesResult().
withDBInstances(new DBInstance().
withDBInstanceStatus("available").
withDBName("test").
withDBInstanceIdentifier("test").
withEngine("mysql").
withMasterUsername("admin").
withEndpoint(new Endpoint().
withAddress("localhost").
withPort(3306)
).withReadReplicaDBInstanceIdentifiers("read1")
)
);
//Act
DataSource dataSource = beanFactory.getBean(DataSource.class);
//Assert
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);
}
@Test
public void parseInternal_fullConfiguration_createsBeanDefinitionWithoutReadReplicas() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
beanDefinitionBuilder.setFactoryMethod("mock");
beanDefinitionBuilder.addConstructorArgValue(AmazonRDS.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), beanDefinitionBuilder.getBeanDefinition());
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-fullConfiguration.xml", getClass()));
AmazonRDS client = beanFactory.getBean(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), AmazonRDS.class);
when(client.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))).thenReturn(
new DescribeDBInstancesResult().
withDBInstances(new DBInstance().
withDBInstanceStatus("available").
withDBName("test").
withDBInstanceIdentifier("test").
withEngine("mysql").
withEndpoint(new Endpoint().
withAddress("localhost").
withPort(3306)
)
)
);
BeanDefinition definition = beanFactory.getBeanDefinition("test");
assertEquals("test", definition.getConstructorArgumentValues().getArgumentValue(1, String.class).getValue());
assertEquals("password", definition.getConstructorArgumentValues().getArgumentValue(2, String.class).getValue());
assertEquals("myUser", definition.getPropertyValues().getPropertyValue("username").getValue());
assertEquals("fooDb", definition.getPropertyValues().getPropertyValue("databaseName").getValue());
DataSource dataSource = beanFactory.getBean(DataSource.class);
//Assert
assertNotNull(dataSource);
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);
}
@Test
public void parseInternal_dataSourceWithConfiguredPoolAttributes_poolAttributesConfigured() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-poolAttributes.xml", getClass()));
BeanDefinition definition = beanFactory.getBeanDefinition("test");
//Act
BeanDefinition dataSourceFactory = (BeanDefinition) definition.getPropertyValues().getPropertyValue("dataSourceFactory").getValue();
//Assert
assertEquals("foo=bar", dataSourceFactory.getPropertyValues().getPropertyValue("connectionProperties").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("defaultAutoCommit").getValue());
assertEquals("mySchema", dataSourceFactory.getPropertyValues().getPropertyValue("defaultCatalog").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("defaultReadOnly").getValue());
assertEquals("2", dataSourceFactory.getPropertyValues().getPropertyValue("defaultTransactionIsolation").getValue());
assertEquals("10", dataSourceFactory.getPropertyValues().getPropertyValue("initialSize").getValue());
assertEquals("SET CURRENT SCHEMA", dataSourceFactory.getPropertyValues().getPropertyValue("initSQL").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("logAbandoned").getValue());
assertEquals("10", dataSourceFactory.getPropertyValues().getPropertyValue("maxActive").getValue());
assertEquals("5", dataSourceFactory.getPropertyValues().getPropertyValue("maxIdle").getValue());
assertEquals("10000", dataSourceFactory.getPropertyValues().getPropertyValue("maxWait").getValue());
assertEquals("60000", dataSourceFactory.getPropertyValues().getPropertyValue("minEvictableIdleTimeMillis").getValue());
assertEquals("20", dataSourceFactory.getPropertyValues().getPropertyValue("minIdle").getValue());
assertEquals("61", dataSourceFactory.getPropertyValues().getPropertyValue("removeAbandonedTimeout").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("testOnBorrow").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("testOnReturn").getValue());
assertEquals(Boolean.TRUE.toString(), dataSourceFactory.getPropertyValues().getPropertyValue("testWhileIdle").getValue());
assertEquals("4000", dataSourceFactory.getPropertyValues().getPropertyValue("timeBetweenEvictionRunsMillis").getValue());
assertEquals("SELECT 1", dataSourceFactory.getPropertyValues().getPropertyValue("validationQuery").getValue());
assertEquals(SampleValidator.class.getName(), dataSourceFactory.getPropertyValues().getPropertyValue("validatorClassName").getValue());
}
@Test
//As we provide default in the schema for better code completion we should check if they match to the underlying pool defaults
public void parseInternal_defaultPoolAttribute_matchesPoolConfiguration() throws Exception {
//Arrange
PoolProperties poolProperties = new PoolProperties();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-defaultPoolAttributes.xml", getClass()));
//Act
BeanDefinition definition = beanFactory.getBeanDefinition("test");
BeanDefinition dataSourceFactory = (BeanDefinition) definition.getPropertyValues().getPropertyValue("dataSourceFactory").getValue();
//Assert
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(poolProperties);
for (PropertyValue propertyValue : dataSourceFactory.getPropertyValues().getPropertyValueList()) {
assertEquals(beanWrapper.getPropertyValue(propertyValue.getName()).toString(), propertyValue.getValue());
}
}
@Test
public void parseInternal_customRegionConfigured_amazonRdsClientWithCustomRegionConfigured() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-customRegion.xml", getClass()));
//Act
AmazonRDS amazonRDS = beanFactory.getBean(AmazonRDS.class);
//Assert
//have to use reflection utils
assertEquals("https://rds.eu-west-1.amazonaws.com", ReflectionTestUtils.getField(amazonRDS, "endpoint").toString());
}
@Test
public void parseInternal_customRegionProviderConfigured_amazonRdsClientWithCustomRegionConfiguredThatIsReturnedFromRegionProvider() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-customRegionProvider.xml", getClass()));
//Act
AmazonRDS amazonRDS = beanFactory.getBean(AmazonRDS.class);
//Assert
//have to use reflection utils
assertEquals("https://rds.eu-west-1.amazonaws.com", ReflectionTestUtils.getField(amazonRDS, "endpoint").toString());
}
@Test
public void parseInternal_customRegionProviderAndRegionConfigured_reportsError() throws Exception {
//Arrange
this.expectedException.expect(BeanDefinitionStoreException.class);
//Act
//noinspection ResultOfObjectAllocationIgnored
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-customRegionProviderAndRegion.xml", getClass());
//Assert
}
@Test
public void parseInternal_userTagsDefined_createsUserTagBeanDefinition() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
beanDefinitionBuilder.setFactoryMethod("mock");
beanDefinitionBuilder.addConstructorArgValue(AmazonRDS.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), beanDefinitionBuilder.getBeanDefinition());
BeanDefinitionBuilder identityBuilder = BeanDefinitionBuilder.rootBeanDefinition(Mockito.class);
identityBuilder.setFactoryMethod("mock");
identityBuilder.addConstructorArgValue(AmazonIdentityManagement.class);
beanFactory.registerBeanDefinition(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonIdentityManagement.class.getName()), identityBuilder.getBeanDefinition());
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-userTags.xml", getClass()));
AmazonRDS client = beanFactory.getBean(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonRDSClient.class.getName()), AmazonRDS.class);
AmazonIdentityManagement amazonIdentityManagement = beanFactory.getBean(AmazonWebserviceClientConfigurationUtils.getBeanName(AmazonIdentityManagement.class.getName()), AmazonIdentityManagement.class);
when(amazonIdentityManagement.getUser()).thenReturn(new GetUserResult().withUser(new User("/", "aemruli", "123456789012", "arn:aws:iam::1234567890:user/aemruli", new Date())));
when(client.listTagsForResource(new ListTagsForResourceRequest().withResourceName("arn:aws:rds:us-west-2:1234567890:db:test"))).thenReturn(new ListTagsForResourceResult().withTagList(
new Tag().withKey("key1").withValue("value2")
));
//Act
Map<?, ?> dsTags = beanFactory.getBean("dsTags", Map.class);
//Assert
assertEquals("value2", dsTags.get("key1"));
}
@Test
public void parseInternal_customRdsInstance_createsRdsBeanAndUserTagsWithCustomRdsInstance() throws Exception {
//Arrange
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource(getClass().getSimpleName() + "-customRdsInstance.xml", getClass()));
AmazonRDS clientMock = beanFactory.getBean("amazonRds", AmazonRDS.class);
when(clientMock.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))).thenReturn(
new DescribeDBInstancesResult().
withDBInstances(new DBInstance().
withDBInstanceStatus("available").
withDBName("test").
withDBInstanceIdentifier("test").
withEngine("mysql").
withMasterUsername("admin").
withEndpoint(new Endpoint().
withAddress("localhost").
withPort(3306)
).withReadReplicaDBInstanceIdentifiers("read1")
)
);
AmazonIdentityManagement amazonIdentityManagement = beanFactory.getBean("myIdentityService", AmazonIdentityManagement.class);
when(amazonIdentityManagement.getUser()).thenReturn(new GetUserResult().withUser(new User("/", "aemruli", "123456789012", "arn:aws:iam::1234567890:user/aemruli", new Date())));
when(clientMock.listTagsForResource(new ListTagsForResourceRequest().withResourceName("arn:aws:rds:us-west-2:1234567890:db:test"))).thenReturn(new ListTagsForResourceResult().withTagList(
new Tag().withKey("key1").withValue("value2")
));
//Act
Map<?, ?> dsTags = beanFactory.getBean("dsTags", Map.class);
DataSource dataSource = beanFactory.getBean(DataSource.class);
//Assert
assertEquals("value2", dsTags.get("key1"));
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);
}
}