Merge branch '4.0.x' into 4.1.x

Closes gh-52084
This commit is contained in:
Stéphane Nicoll
2026-10-07 15:33:18 +02:00
2 changed files with 103 additions and 2 deletions
@@ -16,6 +16,9 @@
package org.springframework.boot.mongodb.docker.compose;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import com.mongodb.ConnectionString;
import org.jspecify.annotations.Nullable;
@@ -69,9 +72,9 @@ class MongoDockerComposeConnectionDetailsFactory extends DockerComposeConnection
MongoEnvironment environment = new MongoEnvironment(service.env());
StringBuilder builder = new StringBuilder("mongodb://");
if (environment.getUsername() != null) {
builder.append(environment.getUsername());
builder.append(encode(environment.getUsername()));
builder.append(":");
builder.append((environment.getPassword() != null) ? environment.getPassword() : "");
builder.append((environment.getPassword() != null) ? encode(environment.getPassword()) : "");
builder.append("@");
}
builder.append(service.host());
@@ -85,6 +88,10 @@ class MongoDockerComposeConnectionDetailsFactory extends DockerComposeConnection
return new ConnectionString(builder.toString());
}
private static String encode(String input) {
return URLEncoder.encode(input, StandardCharsets.UTF_8).replace("+", "%20");
}
@Override
public @Nullable SslBundle getSslBundle() {
return this.sslBundle;
@@ -0,0 +1,94 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.mongodb.docker.compose;
import java.util.Collections;
import java.util.Map;
import com.mongodb.ConnectionString;
import com.mongodb.MongoCredential;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.ConnectionPorts;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.mongodb.docker.compose.MongoDockerComposeConnectionDetailsFactory.MongoDockerComposeConnectionDetails;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MongoDockerComposeConnectionDetailsFactory}.
*
* @author Iram Tazim Hoque
*/
class MongoDockerComposeConnectionDetailsFactoryTests {
@Test
void createConnectionDetails() {
RunningService runningService = mockRunningService();
given(runningService.env()).willReturn(Map.of("MONGO_INITDB_ROOT_USERNAME", "root",
"MONGO_INITDB_ROOT_PASSWORD", "secret", "MONGO_INITDB_DATABASE", "mydatabase"));
ConnectionString connectionString = new MongoDockerComposeConnectionDetails(runningService)
.getConnectionString();
assertThat(connectionString.getHosts()).containsExactly("localhost:30001");
assertThat(connectionString.getDatabase()).isEqualTo("mydatabase");
MongoCredential credential = connectionString.getCredential();
assertThat(credential).isNotNull();
assertThat(credential.getUserName()).isEqualTo("root");
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
assertThat(credential.getSource()).isEqualTo("admin");
}
@Test
void createConnectionDetailsWhenCredentialsContainReservedCharacters() {
RunningService runningService = mockRunningService();
given(runningService.env()).willReturn(Map.of("MONGO_INITDB_ROOT_USERNAME", "us@r:name",
"MONGO_INITDB_ROOT_PASSWORD", "p@ss:w/rd%?#[] +", "MONGO_INITDB_DATABASE", "mydatabase"));
ConnectionString connectionString = new MongoDockerComposeConnectionDetails(runningService)
.getConnectionString();
assertThat(connectionString.getHosts()).containsExactly("localhost:30001");
assertThat(connectionString.getDatabase()).isEqualTo("mydatabase");
MongoCredential credential = connectionString.getCredential();
assertThat(credential).isNotNull();
assertThat(credential.getUserName()).isEqualTo("us@r:name");
assertThat(credential.getPassword()).isEqualTo("p@ss:w/rd%?#[] +".toCharArray());
assertThat(credential.getSource()).isEqualTo("admin");
}
@Test
void createConnectionDetailsWithoutCredentials() {
RunningService runningService = mockRunningService();
given(runningService.env()).willReturn(Collections.emptyMap());
ConnectionString connectionString = new MongoDockerComposeConnectionDetails(runningService)
.getConnectionString();
assertThat(connectionString.getHosts()).containsExactly("localhost:30001");
assertThat(connectionString.getDatabase()).isEqualTo("test");
assertThat(connectionString.getCredential()).isNull();
}
private static RunningService mockRunningService() {
RunningService service = mock(RunningService.class);
given(service.labels()).willReturn(Collections.emptyMap());
ConnectionPorts connectionPorts = mock(ConnectionPorts.class);
given(service.ports()).willReturn(connectionPorts);
given(service.host()).willReturn("localhost");
given(connectionPorts.get(27017)).willReturn(30001);
return service;
}
}