diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md
index f12365aaa18..bde933b1e72 100644
--- a/docs/modules/databases/mssqlserver.md
+++ b/docs/modules/databases/mssqlserver.md
@@ -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:
-[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
!!! warning "EULA Acceptance"
diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java
index 10ccbff2c36..a30de6549ba 100644
--- a/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java
+++ b/modules/mssqlserver/src/main/java/org/testcontainers/containers/MSSQLServerContainer.java
@@ -13,7 +13,10 @@
* Supported image: {@code mcr.microsoft.com/mssql/server}
*
* Exposed ports: 1433
+ *
+ * @deprecated use {@link org.testcontainers.mssqlserver.MSSQLServerContainer} instead.
*/
+@Deprecated
public class MSSQLServerContainer> extends JdbcDatabaseContainer {
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/mssql/server");
diff --git a/modules/mssqlserver/src/main/java/org/testcontainers/mssqlserver/MSSQLServerContainer.java b/modules/mssqlserver/src/main/java/org/testcontainers/mssqlserver/MSSQLServerContainer.java
new file mode 100644
index 00000000000..6ad74ea7e72
--- /dev/null
+++ b/modules/mssqlserver/src/main/java/org/testcontainers/mssqlserver/MSSQLServerContainer.java
@@ -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.
+ *
+ * Supported image: {@code mcr.microsoft.com/mssql/server}
+ *
+ * Exposed ports: 1433
+ */
+public class MSSQLServerContainer extends JdbcDatabaseContainer {
+
+ 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 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 https://hub.docker.com/_/microsoft-mssql-server
+ */
+ 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 (%)."
+ );
+ }
+ }
+}
diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java
deleted file mode 100644
index 630b6c5356c..00000000000
--- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomizableMSSQLServerTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.testcontainers.junit.mssqlserver;
-
-import org.junit.jupiter.api.Test;
-import org.testcontainers.containers.MSSQLServerContainer;
-import org.testcontainers.db.AbstractContainerDatabaseTest;
-import org.testcontainers.utility.DockerImageName;
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class CustomizableMSSQLServerTest extends AbstractContainerDatabaseTest {
-
- private static final String STRONG_PASSWORD = "myStrong(!)Password";
-
- @Test
- void testSqlServerConnection() throws SQLException {
- try (
- MSSQLServerContainer> mssqlServerContainer = new MSSQLServerContainer<>(
- DockerImageName.parse("mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
- )
- .withPassword(STRONG_PASSWORD)
- ) {
- mssqlServerContainer.start();
-
- ResultSet resultSet = performQuery(mssqlServerContainer, mssqlServerContainer.getTestQueryString());
- int resultSetInt = resultSet.getInt(1);
- assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1);
- }
- }
-}
diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/CustomPasswordMSSQLServerTest.java
similarity index 98%
rename from modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java
rename to modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/CustomPasswordMSSQLServerTest.java
index 06aa1dc4a61..faaaabd7d01 100644
--- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/CustomPasswordMSSQLServerTest.java
+++ b/modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/CustomPasswordMSSQLServerTest.java
@@ -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;
diff --git a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java b/modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/MSSQLServerContainerTest.java
similarity index 70%
rename from modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java
rename to modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/MSSQLServerContainerTest.java
index 0d995911893..52269f11b9e 100644
--- a/modules/mssqlserver/src/test/java/org/testcontainers/junit/mssqlserver/SimpleMSSQLServerTest.java
+++ b/modules/mssqlserver/src/test/java/org/testcontainers/mssqlserver/MSSQLServerContainerTest.java
@@ -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;
@@ -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()
@@ -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")
) {
@@ -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();
@@ -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));