This commit is contained in:
Stephane Nicoll 2017-09-25 14:12:24 +02:00
parent d8cfae7300
commit c7eb0fb281
1 changed files with 177 additions and 205 deletions

View File

@ -25,21 +25,18 @@ import java.util.Random;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@ -62,96 +59,69 @@ import static org.junit.Assert.fail;
*/ */
public class DataSourceInitializerTests { public class DataSourceInitializerTests {
@Rule private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
public ExpectedException thrown = ExpectedException.none(); .withUserConfiguration(BasicConfiguration.class)
.withPropertyValues("spring.datasource.initialize=false",
"spring.datasource.url:jdbc:hsqldb:mem:testdb-"
+ new Random().nextInt());
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @Test
public void defaultDataSourceDoesNotExists() {
@Before this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(
public void init() { DataSource.class));
TestPropertyValues.of("spring.datasource.initialize:false",
"spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt())
.applyTo(this.context);
}
@After
public void restore() {
if (this.context != null) {
this.context.close();
}
} }
@Test @Test
public void testDefaultDataSourceDoesNotExists() throws Exception { public void twoDataSources() {
this.context.register(DataSourceInitializer.class, this.contextRunner.withUserConfiguration(TwoDataSources.class)
PropertyPlaceholderAutoConfiguration.class, DataSourceProperties.class); .withPropertyValues("datasource.one.url=jdbc:hsqldb:mem:/one",
this.context.refresh(); "datasource.two.url=jdbc:hsqldb:mem:/two").run((context) ->
assertThat(this.context.getBeanNamesForType(DataSource.class).length) assertThat(context.getBeanNamesForType(DataSource.class)).hasSize(2));
.isEqualTo(0);
} }
@Test @Test
public void testTwoDataSources() throws Exception { public void dataSourceInitialized() {
TestPropertyValues.of("datasource.one.url=jdbc:hsqldb:mem:/one", this.contextRunner.withConfiguration(AutoConfigurations.of(
"datasource.two.url=jdbc:hsqldb:mem:/two").applyTo(this.context); DataSourceAutoConfiguration.class)
this.context.register(TwoDataSources.class, DataSourceInitializer.class, ).withPropertyValues("spring.datasource.initialize:true").run((context) -> {
PropertyPlaceholderAutoConfiguration.class, DataSourceProperties.class); DataSource dataSource = context.getBean(DataSource.class);
this.context.refresh();
assertThat(this.context.getBeanNamesForType(DataSource.class).length)
.isEqualTo(2);
}
@Test
public void testDataSourceInitialized() throws Exception {
TestPropertyValues.of("spring.datasource.initialize:true").applyTo(this.context);
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class)) assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class))
.isEqualTo(1); .isEqualTo(1);
});
} }
@Test @Test
public void testDataSourceInitializedWithExplicitScript() throws Exception { public void dataSourceInitializedWithExplicitScript() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)
TestPropertyValues ).withPropertyValues(
.of("spring.datasource.initialize:true", "spring.datasource.initialize:true",
"spring.datasource.schema:" + ClassUtils "spring.datasource.schema:" + getRelativeLocationFor("schema.sql"),
.addResourcePathToPackagePath(getClass(), "schema.sql"), "spring.datasource.data:" + getRelativeLocationFor("data.sql")
"spring.datasource.data:" ).run((context) -> {
+ ClassUtils.addResourcePathToPackagePath(getClass(), "data.sql")) DataSource dataSource = context.getBean(DataSource.class);
.applyTo(this.context);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from FOO", Integer.class)) assertThat(template.queryForObject("SELECT COUNT(*) from FOO", Integer.class))
.isEqualTo(1); .isEqualTo(1);
});
} }
@Test @Test
public void testDataSourceInitializedWithMultipleScripts() throws Exception { public void dataSourceInitializedWithMultipleScripts() {
TestPropertyValues this.contextRunner.withConfiguration(AutoConfigurations.of(
.of("spring.datasource.initialize:true", DataSourceAutoConfiguration.class)
"spring.datasource.schema:" ).withPropertyValues(
+ ClassUtils.addResourcePathToPackagePath(getClass(), "spring.datasource.initialize:true",
"schema.sql") "spring.datasource.schema:" + getRelativeLocationFor("schema.sql") + ","
+ "," + getRelativeLocationFor("another.sql"),
+ ClassUtils.addResourcePathToPackagePath(getClass(), "spring.datasource.data:" + getRelativeLocationFor("data.sql")
"another.sql"), ).run((context) -> {
"spring.datasource.data:" DataSource dataSource = context.getBean(DataSource.class);
+ ClassUtils.addResourcePathToPackagePath(getClass(), "data.sql"))
.applyTo(this.context);
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
@ -159,42 +129,38 @@ public class DataSourceInitializerTests {
.isEqualTo(1); .isEqualTo(1);
assertThat(template.queryForObject("SELECT COUNT(*) from SPAM", Integer.class)) assertThat(template.queryForObject("SELECT COUNT(*) from SPAM", Integer.class))
.isEqualTo(0); .isEqualTo(0);
});
} }
@Test @Test
public void testDataSourceInitializedWithExplicitSqlScriptEncoding() public void dataSourceInitializedWithExplicitSqlScriptEncoding() {
throws Exception { this.contextRunner.withConfiguration(AutoConfigurations.of(
this.context.register(DataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class)
PropertyPlaceholderAutoConfiguration.class); ).withPropertyValues("spring.datasource.initialize:true",
TestPropertyValues.of("spring.datasource.initialize:true",
"spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.sqlScriptEncoding:UTF-8",
"spring.datasource.schema:" + ClassUtils "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"),
.addResourcePathToPackagePath(getClass(), "encoding-schema.sql"), "spring.datasource.data:" + getRelativeLocationFor("encoding-data.sql")
"spring.datasource.data:" + ClassUtils ).run((context) -> {
.addResourcePathToPackagePath(getClass(), "encoding-data.sql")) DataSource dataSource = context.getBean(DataSource.class);
.applyTo(this.context);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class)) assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class))
.isEqualTo(2); .isEqualTo(2);
assertThat( assertThat(template.queryForObject(
template.queryForObject("SELECT name from BAR WHERE id=1", String.class)) "SELECT name from BAR WHERE id=1", String.class)).isEqualTo("bar");
.isEqualTo("bar"); assertThat(template.queryForObject(
assertThat( "SELECT name from BAR WHERE id=2", String.class)).isEqualTo("ばー");
template.queryForObject("SELECT name from BAR WHERE id=2", String.class)) });
.isEqualTo("ばー");
} }
@Test @Test
public void testInitializationDisabled() throws Exception { public void initializationDisabled() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)).run((context) -> {
this.context.refresh(); DataSource dataSource = context.getBean(DataSource.class);
DataSource dataSource = this.context.getBean(DataSource.class); context.publishEvent(new DataSourceInitializedEvent(dataSource));
this.context.publishEvent(new DataSourceInitializedEvent(dataSource));
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
@ -207,102 +173,108 @@ public class DataSourceInitializerTests {
int expectedCode = -5501; // user lacks privilege or object not found int expectedCode = -5501; // user lacks privilege or object not found
assertThat(sqlException.getErrorCode()).isEqualTo(expectedCode); assertThat(sqlException.getErrorCode()).isEqualTo(expectedCode);
} }
});
} }
@Test @Test
public void testDataSourceInitializedWithSchemaCredentials() { public void dataSourceInitializedWithSchemaCredentials() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)
TestPropertyValues.of("spring.datasource.initialize:true", ).withPropertyValues("spring.datasource.initialize:true",
"spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.sqlScriptEncoding:UTF-8",
"spring.datasource.schema:" + ClassUtils "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"),
.addResourcePathToPackagePath(getClass(), "encoding-schema.sql"), "spring.datasource.data:" + getRelativeLocationFor("encoding-data.sql"),
"spring.datasource.data:" + ClassUtils
.addResourcePathToPackagePath(getClass(), "encoding-data.sql"),
"spring.datasource.schema-username:admin", "spring.datasource.schema-username:admin",
"spring.datasource.schema-password:admin").applyTo(this.context); "spring.datasource.schema-password:admin").run((context) -> {
try { assertThat(context).hasFailed();
this.context.refresh(); assertThat(context.getStartupFailure()).isInstanceOf(BeanCreationException.class);
fail("User does not exist"); });
}
catch (Exception ex) {
assertThat(ex).isInstanceOf(BeanCreationException.class);
}
} }
@Test @Test
public void testDataSourceInitializedWithDataCredentials() { public void dataSourceInitializedWithDataCredentials() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)
TestPropertyValues.of("spring.datasource.initialize:true", ).withPropertyValues("spring.datasource.initialize:true",
"spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.sqlScriptEncoding:UTF-8",
"spring.datasource.schema:" + ClassUtils "spring.datasource.schema:" + getRelativeLocationFor("encoding-schema.sql"),
.addResourcePathToPackagePath(getClass(), "encoding-schema.sql"), "spring.datasource.data:" + getRelativeLocationFor("encoding-data.sql"),
"spring.datasource.data:" + ClassUtils
.addResourcePathToPackagePath(getClass(), "encoding-data.sql"),
"spring.datasource.data-username:admin", "spring.datasource.data-username:admin",
"spring.datasource.data-password:admin").applyTo(this.context); "spring.datasource.data-password:admin").run((context) -> {
try { assertThat(context).hasFailed();
this.context.refresh(); assertThat(context.getStartupFailure()).isInstanceOf(BeanCreationException.class);
fail("User does not exist"); });
}
catch (Exception ex) {
assertThat(ex).isInstanceOf(BeanCreationException.class);
}
} }
@Test @Test
public void multipleScriptsAppliedInLexicalOrder() throws Exception { public void multipleScriptsAppliedInLexicalOrder() {
TestPropertyValues.of("spring.datasource.initialize:true", new ApplicationContextRunner(() -> {
"spring.datasource.schema:" + ClassUtils AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
.addResourcePathToPackagePath(getClass(), "lexical-schema-*.sql"), context.setResourceLoader(new ReverseOrderResourceLoader(new DefaultResourceLoader()));
"spring.datasource.data:" return context;
+ ClassUtils.addResourcePathToPackagePath(getClass(), "data.sql")) }
.applyTo(this.context); ).withUserConfiguration(BasicConfiguration.class).withConfiguration(
this.context.register(DataSourceAutoConfiguration.class, AutoConfigurations.of(DataSourceAutoConfiguration.class)
PropertyPlaceholderAutoConfiguration.class); ).withPropertyValues("spring.datasource.initialize=false",
ReverseOrderResourceLoader resourceLoader = new ReverseOrderResourceLoader( "spring.datasource.url:jdbc:hsqldb:mem:testdb-"
new DefaultResourceLoader()); + new Random().nextInt(),
this.context.setResourceLoader(resourceLoader); "spring.datasource.initialize:true",
this.context.refresh(); "spring.datasource.schema:" + getRelativeLocationFor("lexical-schema-*.sql"),
DataSource dataSource = this.context.getBean(DataSource.class); "spring.datasource.data:" + getRelativeLocationFor("data.sql")
).run((context) -> {
DataSource dataSource = context.getBean(DataSource.class);
assertThat(dataSource).isInstanceOf(HikariDataSource.class); assertThat(dataSource).isInstanceOf(HikariDataSource.class);
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from FOO", Integer.class)) assertThat(template.queryForObject("SELECT COUNT(*) from FOO", Integer.class))
.isEqualTo(1); .isEqualTo(1);
});
} }
@Test @Test
public void testDataSourceInitializedWithInvalidSchemaResource() { public void testDataSourceInitializedWithInvalidSchemaResource() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)).withPropertyValues(
TestPropertyValues "spring.datasource.initialize:true",
.of("spring.datasource.initialize:true", "spring.datasource.schema:classpath:does/not/exist.sql"
"spring.datasource.schema:classpath:does/not/exist.sql") ).run((context) -> {
.applyTo(this.context); assertThat(context).hasFailed();
assertThat(context.getStartupFailure())
this.thrown.expect(BeanCreationException.class); .isInstanceOf(BeanCreationException.class);
this.thrown.expectMessage("does/not/exist.sql"); assertThat(context.getStartupFailure())
this.thrown.expectMessage("spring.datasource.schema"); .hasMessageContaining("does/not/exist.sql");
this.context.refresh(); assertThat(context.getStartupFailure())
.hasMessageContaining("spring.datasource.schema");
});
} }
@Test @Test
public void testDataSourceInitializedWithInvalidDataResource() { public void dataSourceInitializedWithInvalidDataResource() {
this.context.register(DataSourceAutoConfiguration.class, this.contextRunner.withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class); DataSourceAutoConfiguration.class)
TestPropertyValues ).withPropertyValues("spring.datasource.initialize:true",
.of("spring.datasource.initialize:true", "spring.datasource.schema:" + getRelativeLocationFor("schema.sql"),
"spring.datasource.schema:" + ClassUtils "spring.datasource.data:classpath:does/not/exist.sql").run((context) -> {
.addResourcePathToPackagePath(getClass(), "schema.sql"), assertThat(context).hasFailed();
"spring.datasource.data:classpath:does/not/exist.sql") assertThat(context.getStartupFailure())
.applyTo(this.context); .isInstanceOf(BeanCreationException.class);
assertThat(context.getStartupFailure())
.hasMessageContaining("does/not/exist.sql");
assertThat(context.getStartupFailure())
.hasMessageContaining("spring.datasource.data");
});
}
private String getRelativeLocationFor(String resource) {
return ClassUtils
.addResourcePathToPackagePath(getClass(), resource);
}
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
@Import(DataSourceInitializer.class)
static class BasicConfiguration {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("does/not/exist.sql");
this.thrown.expectMessage("spring.datasource.data");
this.context.refresh();
} }
@Configuration @Configuration