Skip to content

Commit

Permalink
Mssql server support (#952)
Browse files Browse the repository at this point in the history
* feat: autoconfigure mssql server

* fix: use default image in test

* lint: remove unused imports

* docs: fix output properties

Co-authored-by: Raphael Gruber <[email protected]>
  • Loading branch information
rapgru and Raphael Gruber authored Jul 26, 2022
1 parent 2fe18bf commit a0b78bd
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 0 deletions.
35 changes: 35 additions & 0 deletions embedded-mssqlserver/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
=== embedded-mssqlserver

==== Maven dependency

.pom.xml
[source,xml]
----
<dependency>
<groupId>com.playtika.testcontainers</groupId>
<artifactId>embedded-mssqlserver</artifactId>
<scope>test</scope>
</dependency>
----

==== Consumes (via `bootstrap.properties`)

* `embedded.mssqlserver.enabled` `(true|false, default is true)`
* `embedded.mssqlserver.reuseContainer` `(true|false, default is false)`
* `embedded.mssqlserver.dockerImage` `(default is 'mcr.microsoft.com/mssql/server:2017-CU12')`
** Image versions: https://hub.docker.com/_/microsoft-mssql-server
* `embedded.mssqlserver.password` `(default is foobar1234)`
* `embedded.mssqlserver.acceptLicence` `(default is 'false')`
* `embedded.mssqlserver.startupLogCheckRegex`
* `embedded.mssqlserver.initScriptPath`

The username and database name can intentionally not be supplied to this module, because the MS SQL Server images
do not allow to set those parameters.

==== Produces

* `embedded.mssqlserver.host`
* `embedded.mssqlserver.port`
* `embedded.mssqlserver.database`
* `embedded.mssqlserver.user`
* `embedded.mssqlserver.password`
48 changes: 48 additions & 0 deletions embedded-mssqlserver/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>testcontainers-spring-boot-parent</artifactId>
<groupId>com.playtika.testcontainers</groupId>
<version>2.2.4</version>
<relativePath>../testcontainers-spring-boot-parent</relativePath>
</parent>

<artifactId>embedded-mssqlserver</artifactId>

<properties>
<mssql-jdbc.version>10.2.0.jre11</mssql-jdbc.version>
</properties>

<dependencies>
<dependency>
<groupId>com.playtika.testcontainers</groupId>
<artifactId>testcontainers-common</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mssqlserver</artifactId>
<version>${testcontainers.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${mssql-jdbc.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.playtika.test.mssqlserver;

import com.playtika.test.common.spring.DockerPresenceBootstrapConfiguration;
import com.playtika.test.common.utils.ContainerUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.StringUtils;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.containers.wait.strategy.WaitStrategy;

import java.util.LinkedHashMap;

import static com.playtika.test.common.utils.ContainerUtils.configureCommonsAndStart;

@Slf4j
@Configuration
@ConditionalOnExpression("${embedded.containers.enabled:true}")
@AutoConfigureAfter(DockerPresenceBootstrapConfiguration.class)
@ConditionalOnProperty(name = "embedded.mssqlserver.enabled", matchIfMissing = true)
@EnableConfigurationProperties(MSSQLServerProperties.class)
public class EmbeddedMSSQLServerBootstrapConfiguration {

@Bean(name = MSSQLServerProperties.BEAN_NAME_EMBEDDED_MSSQLSERVER, destroyMethod = "stop")
public EmbeddedMSSQLServerContainer mssqlserver(ConfigurableEnvironment environment,
MSSQLServerProperties properties) {

EmbeddedMSSQLServerContainer mssqlServerContainer = new EmbeddedMSSQLServerContainer(ContainerUtils.getDockerImageName(properties))
.withPassword(properties.getPassword())
.withInitScript(properties.getInitScriptPath());

String startupLogCheckRegex = properties.getStartupLogCheckRegex();
if (StringUtils.hasLength(startupLogCheckRegex)) {
WaitStrategy waitStrategy = new LogMessageWaitStrategy()
.withRegEx(startupLogCheckRegex);
mssqlServerContainer.setWaitStrategy(waitStrategy);
}

if (properties.isAcceptLicence()) {
mssqlServerContainer.acceptLicense();
}

mssqlServerContainer = (EmbeddedMSSQLServerContainer) configureCommonsAndStart(mssqlServerContainer, properties, log);
registerMSSQLServerEnvironment(mssqlServerContainer, environment, properties);

return mssqlServerContainer;
}

private void registerMSSQLServerEnvironment(MSSQLServerContainer<?> mssqlServerContainer,
ConfigurableEnvironment environment,
MSSQLServerProperties properties) {
Integer mappedPort = mssqlServerContainer.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT);
String host = mssqlServerContainer.getContainerIpAddress();

LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("embedded.mssqlserver.port", mappedPort);
map.put("embedded.mssqlserver.host", host);
// Database and user cannot be chosen when starting the MSSQL image
map.put("embedded.mssqlserver.database", "master");
map.put("embedded.mssqlserver.user", "sa");
map.put("embedded.mssqlserver.password", properties.getPassword());

String jdbcURL = "jdbc:sqlserver://{}:{};databaseName={};trustServerCertificate=true";
log.info("Started mssql server. Connection details: {}, " +
"JDBC connection url: " + jdbcURL, map, host, mappedPort, "master");

MapPropertySource propertySource = new MapPropertySource("embeddedMSSQLServerInfo", map);
environment.getPropertySources().addFirst(propertySource);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.playtika.test.mssqlserver;

import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.utility.DockerImageName;

public class EmbeddedMSSQLServerContainer extends MSSQLServerContainer<EmbeddedMSSQLServerContainer> {

public EmbeddedMSSQLServerContainer(DockerImageName dockerImageName) {
super(dockerImageName);
}

public EmbeddedMSSQLServerContainer(String dockerImageName) {
super(dockerImageName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.playtika.test.mssqlserver;

import com.playtika.test.common.spring.DependsOnPostProcessor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnExpression("${embedded.containers.enabled:true}")
@ConditionalOnProperty(name = "embedded.mssqlserver.enabled", matchIfMissing = true)
@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")
public class EmbeddedMSSQLServerDependenciesAutoConfiguration {

@Bean
public static BeanFactoryPostProcessor datasourceMSSQLServerDependencyPostProcessor() {
return new DependsOnPostProcessor(DataSource.class, new String[]{MSSQLServerProperties.BEAN_NAME_EMBEDDED_MSSQLSERVER});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.playtika.test.mssqlserver;

import com.playtika.test.common.properties.CommonContainerProperties;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.FieldDefaults;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties("embedded.mssqlserver")
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MSSQLServerProperties extends CommonContainerProperties {
public static final String BEAN_NAME_EMBEDDED_MSSQLSERVER = "embeddedMSSQLServer";

String password = "Foobar1234!";

String initScriptPath;
boolean acceptLicence = false;

String startupLogCheckRegex;

@Override
public String getDefaultDockerImage() {
return "mcr.microsoft.com/mssql/server:2017-CU12";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.playtika.test.mssqlserver.EmbeddedMSSQLServerBootstrapConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.playtika.test.mssqlserver.EmbeddedMSSQLServerDependenciesAutoConfiguration
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.playtika.test.mssqlserver;

import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(
classes = EmbeddedMSSQLServerDependenciesAutoConfigurationTest.TestConfiguration.class,
properties = {
"embedded.mssqlserver.enabled=true"
}
)
class EmbeddedMSSQLServerDependenciesAutoConfigurationTest {
@Autowired(required = false)
private JdbcTemplate jdbcTemplate;

@Autowired
private EmbeddedMSSQLServerContainer mssqlServerContainer;

@Test
void injectedJdbs() {
assertThat(jdbcTemplate).isNotNull();
}

@Test
@SneakyThrows
void testCreateDb() {
Map<String, Object> map = jdbcTemplate.queryForMap("SELECT first_name, last_name FROM users WHERE first_name = 'Sam'");

assertThat(map)
.containsKey("first_name")
.containsKey("last_name")
.extractingByKey("last_name").isEqualTo("Brannen");
}

@EnableAutoConfiguration
@Configuration
static class TestConfiguration {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://${embedded.mssqlserver.host}:${embedded.mssqlserver.port};databaseName=${embedded.mssqlserver.database};trustServerCertificate=true
spring.datasource.username=${embedded.mssqlserver.user}
spring.datasource.password=${embedded.mssqlserver.password}
4 changes: 4 additions & 0 deletions embedded-mssqlserver/src/test/resources/bootstrap.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
embedded.mssqlserver.password=Foobar1234!
embedded.mssqlserver.accept-licence=true
embedded.mssqlserver.docker-image=mcr.microsoft.com/mssql/server:2017-CU12
embedded.mssqlserver.init-script-path=initScript.sql
7 changes: 7 additions & 0 deletions embedded-mssqlserver/src/test/resources/initScript.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE users (
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL
);
INSERT INTO
users(first_name, last_name)
values('Sam', 'Brannen');
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<module>embedded-artifactory</module>
<module>embedded-azurite</module>
<module>embedded-toxiproxy</module>
<module>embedded-mssqlserver</module>
</modules>

<properties>
Expand Down
5 changes: 5 additions & 0 deletions testcontainers-spring-boot-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@
<artifactId>embedded-db2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.playtika.testcontainers</groupId>
<artifactId>embedded-mssqlserver</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.playtika.testcontainers</groupId>
<artifactId>embedded-azurite</artifactId>
Expand Down

0 comments on commit a0b78bd

Please sign in to comment.