Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/modules/databases/mssqlserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Testcontainers module for [MS SQL Server](https://mcr.microsoft.com/en-us/artifa
You can start a MS SQL Server container instance from any Java application by using:

<!--codeinclude-->
[Container definition](../../../modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java) inside_block:container
[Container definition](../../../modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/MSSQLServerContainerTest.java) inside_block:container
<!--/codeinclude-->

!!! warning "EULA Acceptance"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
* Supported image: {@code mcr.microsoft.com/mssql/server}
* <p>
* Exposed ports: 1433
*
* @deprecated use {@link org.testcontainers.mssqlserver.MSSQLServerContainer} instead.
*/
@Deprecated
public class MSSQLServerContainer<SELF extends MSSQLServerContainer<SELF>> extends JdbcDatabaseContainer<SELF> {

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/mssql/server");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package org.testcontainers.mssqlserver;

import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.LicenseAcceptance;

import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
* Testcontainers implementation for Microsoft SQL Server.
* <p>
* Supported image: {@code mcr.microsoft.com/mssql/server}
* <p>
* Exposed ports: 1433
*/
public class MSSQLServerContainer extends JdbcDatabaseContainer<MSSQLServerContainer> {

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/mssql/server");

public static final String NAME = "sqlserver";

public static final String IMAGE = DEFAULT_IMAGE_NAME.getUnversionedPart();

public static final Integer MS_SQL_SERVER_PORT = 1433;

static final String DEFAULT_USER = "sa";

static final String DEFAULT_PASSWORD = "A_Str0ng_Required_Password";

private String password = DEFAULT_PASSWORD;

private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240;

private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 240;

private static final Pattern[] PASSWORD_CATEGORY_VALIDATION_PATTERNS = new Pattern[] {
Pattern.compile("[A-Z]+"),
Pattern.compile("[a-z]+"),
Pattern.compile("[0-9]+"),
Pattern.compile("[^a-zA-Z0-9]+", Pattern.CASE_INSENSITIVE),
};

public MSSQLServerContainer(final String dockerImageName) {
this(DockerImageName.parse(dockerImageName));
}

public MSSQLServerContainer(final DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);

withStartupTimeoutSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS);
withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS);
addExposedPort(MS_SQL_SERVER_PORT);
}

@Override
public Set<Integer> getLivenessCheckPortNumbers() {
return super.getLivenessCheckPortNumbers();
}

@Override
protected void configure() {
// If license was not accepted programmatically, check if it was accepted via resource file
if (!getEnvMap().containsKey("ACCEPT_EULA")) {
LicenseAcceptance.assertLicenseAccepted(this.getDockerImageName());
acceptLicense();
}

addEnv("MSSQL_SA_PASSWORD", password);
}

/**
* Accepts the license for the SQLServer container by setting the ACCEPT_EULA=Y
* variable as described at <a href="https://hub.docker.com/_/microsoft-mssql-server">https://hub.docker.com/_/microsoft-mssql-server</a>
*/
public MSSQLServerContainer acceptLicense() {
addEnv("ACCEPT_EULA", "Y");
return self();
}

@Override
public String getDriverClassName() {
return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
}

@Override
protected String constructUrlForConnection(String queryString) {
// The JDBC driver of MS SQL Server enables encryption by default for versions > 10.1.0.
// We need to disable it by default to be able to use the container without having to pass extra params.
// See https://github.com/microsoft/mssql-jdbc/releases/tag/v10.1.0
if (urlParameters.keySet().stream().map(String::toLowerCase).noneMatch("encrypt"::equals)) {
urlParameters.put("encrypt", "false");
}
return super.constructUrlForConnection(queryString);
}

@Override
public String getJdbcUrl() {
String additionalUrlParams = constructUrlParameters(";", ";");
return "jdbc:sqlserver://" + getHost() + ":" + getMappedPort(MS_SQL_SERVER_PORT) + additionalUrlParams;
}

@Override
public String getUsername() {
return DEFAULT_USER;
}

@Override
public String getPassword() {
return password;
}

@Override
public String getTestQueryString() {
return "SELECT 1";
}

@Override
public MSSQLServerContainer withPassword(final String password) {
checkPasswordStrength(password);
this.password = password;
return self();
}

private void checkPasswordStrength(String password) {
if (password == null) {
throw new IllegalArgumentException("Null password is not allowed");
}

if (password.length() < 8) {
throw new IllegalArgumentException("Password should be at least 8 characters long");
}

if (password.length() > 128) {
throw new IllegalArgumentException("Password can be up to 128 characters long");
}

long satisfiedCategories = Stream
.of(PASSWORD_CATEGORY_VALIDATION_PATTERNS)
.filter(p -> p.matcher(password).find())
.count();

if (satisfiedCategories < 3) {
throw new IllegalArgumentException(
"Password must contain characters from three of the following four categories:\n" +
" - Latin uppercase letters (A through Z)\n" +
" - Latin lowercase letters (a through z)\n" +
" - Base 10 digits (0 through 9)\n" +
" - Non-alphanumeric characters such as: exclamation point (!), dollar sign ($), number sign (#), " +
"or percent (%)."
);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.testcontainers.junit.mssqlserver;
package org.testcontainers.mssqlserver;

import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.testcontainers.junit.mssqlserver;
package org.testcontainers.mssqlserver;

import org.junit.jupiter.api.Test;
import org.testcontainers.MSSQLServerTestImages;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.db.AbstractContainerDatabaseTest;
import org.testcontainers.utility.DockerImageName;

import java.sql.ResultSet;
import java.sql.SQLException;
Expand All @@ -13,12 +13,12 @@

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

class SimpleMSSQLServerTest extends AbstractContainerDatabaseTest {
class MSSQLServerContainerTest extends AbstractContainerDatabaseTest {

@Test
void testSimple() throws SQLException {
try ( // container {
MSSQLServerContainer<?> mssqlServer = new MSSQLServerContainer<>(
MSSQLServerContainer mssqlServer = new MSSQLServerContainer(
"mcr.microsoft.com/mssql/server:2022-CU20-ubuntu-22.04"
)
.acceptLicense()
Expand All @@ -36,7 +36,7 @@ void testSimple() throws SQLException {
@Test
void testWithAdditionalUrlParamInJdbcUrl() {
try (
MSSQLServerContainer<?> mssqlServer = new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE)
MSSQLServerContainer mssqlServer = new MSSQLServerContainer(MSSQLServerTestImages.MSSQL_SERVER_IMAGE)
.withUrlParam("integratedSecurity", "false")
.withUrlParam("applicationName", "MyApp")
) {
Expand All @@ -49,9 +49,7 @@ void testWithAdditionalUrlParamInJdbcUrl() {

@Test
void testSetupDatabase() throws SQLException {
try (
MSSQLServerContainer<?> mssqlServer = new MSSQLServerContainer<>(MSSQLServerTestImages.MSSQL_SERVER_IMAGE)
) {
try (MSSQLServerContainer mssqlServer = new MSSQLServerContainer(MSSQLServerTestImages.MSSQL_SERVER_IMAGE)) {
mssqlServer.start();
DataSource ds = getDataSource(mssqlServer);
Statement statement = ds.getConnection().createStatement();
Expand All @@ -70,7 +68,23 @@ void testSetupDatabase() throws SQLException {
}
}

private void assertHasCorrectExposedAndLivenessCheckPorts(MSSQLServerContainer<?> mssqlServer) {
@Test
void testSqlServerConnection() throws SQLException {
try (
MSSQLServerContainer mssqlServerContainer = new MSSQLServerContainer(
DockerImageName.parse("mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
)
.withPassword("myStrong(!)Password")
) {
mssqlServerContainer.start();

ResultSet resultSet = performQuery(mssqlServerContainer, mssqlServerContainer.getTestQueryString());
int resultSetInt = resultSet.getInt(1);
assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1);
}
}

private void assertHasCorrectExposedAndLivenessCheckPorts(MSSQLServerContainer mssqlServer) {
assertThat(mssqlServer.getExposedPorts()).containsExactly(MSSQLServerContainer.MS_SQL_SERVER_PORT);
assertThat(mssqlServer.getLivenessCheckPortNumbers())
.containsExactly(mssqlServer.getMappedPort(MSSQLServerContainer.MS_SQL_SERVER_PORT));
Expand Down
Loading