package org.cloudfoundry.reconfiguration; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.cloudfoundry.runtime.env.CloudEnvironment; import org.cloudfoundry.runtime.env.MysqlServiceInfo; import org.hibernate.SessionFactory; import org.hibernate.impl.SessionFactoryImpl; import org.hibernate.impl.SessionImpl; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource; /** * Unit-tests for {@link CloudAutoStagingBeanFactoryPostProcessor}. * <p> * This test uses a mock application context to introduce environment with services * to avoid the need of actual working application and services. The assertions * are made to check if the actual beans got replaced/not replaced with the mock beans. * * @author Ramnivas Laddad * */ public class CloudFactoryAutoStagingBeanFactoryPostProcessorTest { @Mock private MysqlServiceInfo mockMysqlServiceInfo1; @Mock private MysqlServiceInfo mockMysqlServiceInfo2; @Mock private CloudEnvironment mockEnvironment; private CloudAutoStagingBeanFactoryPostProcessor testBFPP; @Before public void setup() { MockitoAnnotations.initMocks(this); testBFPP = new CloudAutoStagingBeanFactoryPostProcessor(); } @Test public void cloudDataSourceReplacesUserDataSourceIfOneServiceDetected() { String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1"; List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>(); serviceInfos.add(mockMysqlServiceInfo1); when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl); when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos); ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml"); AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class); Assert.assertEquals(serviceJdbcUrl, replacedDataSource.getUrl()); } @Test public void cloudDataSourceLeavesOriginalInPlaceIfMultipleServicesDetected() { String serviceJdbcUrl1 = "jdbc:mysql://10.20.20.40:1234/mysql-1"; String serviceJdbcUrl2 = "jdbc:mysql://10.20.20.40:1234/mysql-2"; List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>(); serviceInfos.add(mockMysqlServiceInfo1); serviceInfos.add(mockMysqlServiceInfo2); when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl1); when(mockMysqlServiceInfo2.getUrl()).thenReturn(serviceJdbcUrl2); when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos); ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml"); AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class); Assert.assertEquals("jdbc:hsql:localdb", replacedDataSource.getUrl()); } @Test public void cloudDataSourceLeavesOriginalInPlaceIfNoServicesDetected() { List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>(); when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos); ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml"); AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class); Assert.assertEquals("jdbc:hsql:localdb", replacedDataSource.getUrl()); } @Test public void hibernateSessionFactoryDialectUpdated() { assertApplicationContextProcessing("test-hibernate-good-context.xml"); } @Test public void entityManagerFactoryDialectUpdated() { String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1"; List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>(); serviceInfos.add(mockMysqlServiceInfo1); when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl); when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos); ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml"); EntityManagerFactory entityManagerFactory = (EntityManagerFactory) context.getBean("entityManagerFactory", EntityManagerFactory.class); EntityManager entityManager = entityManagerFactory.createEntityManager(); SessionImpl entityManagerDelegate = (SessionImpl) entityManager.getDelegate(); SessionFactoryImpl underlyingSessionFactory = (SessionFactoryImpl) entityManagerDelegate.getSessionFactory(); Assert.assertEquals("org.hibernate.dialect.MySQLDialect", underlyingSessionFactory.getDialect().toString()); } @Test public void grailsLikeEmbeddedPropertyApplicationContextProcessed() { assertApplicationContextProcessing("test-grails-embedded-props-good-context.xml"); } @Test public void grailsLikeReferencedMapApplicationContextProcessed() { assertApplicationContextProcessing("test-grails-map-reference-good-context.xml"); } @Test public void grailsLikeReferencedPropertyFactoryApplicationContextProcessed() { assertApplicationContextProcessing("test-grails-propertyFactory-reference-good-context.xml"); } @Test public void typeStringValuePropertyApplicationContextProcessed() { assertApplicationContextProcessing("test-jpa-typedStringValue-good-context.xml"); } @Test public void autostagingOffWhenPropertyFileSpecifiedOff() { Assert.assertTrue(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-off.properties")); } @Test public void autostagingOnWhenPropertyFileSpecifiedOn() { Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-on.properties")); } @Test public void autostagingOnWhenPropertyFileEmpty() { Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-empty.properties")); } @Test public void autostagingOnWhenPropertyFileCorrupt() { Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-corrupt.properties")); } @Test public void autostagingOnWhenPropertyFileDoesntExist() { Assert.assertFalse(testBFPP.autoStagingOff("file-that-doesnt-exist")); } private void assertApplicationContextProcessing(String appContextFile) { String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1"; List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>(); serviceInfos.add(mockMysqlServiceInfo1); when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl); when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos); ApplicationContext context = getTestApplicationContext(appContextFile); SessionFactoryImpl sessionFactory = (SessionFactoryImpl) context.getBean("sessionFactory", SessionFactory.class); Assert.assertEquals("org.hibernate.dialect.MySQLDialect", sessionFactory.getDialect().toString()); } private ApplicationContext getTestApplicationContext(String fileName) { return new ClassPathXmlApplicationContext(new String[]{"org/cloudfoundry/reconfiguration/" + fileName, "META-INF/cloud/cloudfoundry-auto-reconfiguration-context.xml"}) { @Override protected void prepareBeanFactory( ConfigurableListableBeanFactory beanFactory) { getBeanFactory().registerSingleton("test-cloudEnvironment", mockEnvironment); super.prepareBeanFactory(beanFactory); } }; } }