skyho
skyho

Reputation: 1903

Error when trying to run integration tests for ReplicaSet MongoDB

I use test container for integration testing. However, when used in ReplicaSet 3 nodes, the tests fail with an error

DEBUG 18112 --- [ Test worker] org.mongodb.driver.connection : Connection pool created for mongod3:27019 using options maxIdleTimeMS=0, minPoolSize=5, maxPoolSize=100, maxConnecting=2, waitQueueTimeoutMS=120000 2024-10-27T19:50:25.790+03:00 DEBUG 18112 --- [ Test worker] org.mongodb.driver.cluster : Updating cluster description to {type=REPLICA_SET, servers=[{address=mongod1:27017, type=UNKNOWN, state=CONNECTING}, {address=mongod2:27018, type=UNKNOWN, state=CONNECTING}, {address=mongod3:27019, type=UNKNOWN, state=CONNECTING}]

: ..... created with settings MongoClientSettings{readPreference=ReadPreference{name=primaryPreferred, hedgeOptions=null}, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='root', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@4bfe83d, com.mongodb.Jep395RecordCodecProvider@5906ebfb, com.mongodb.KotlinCodecProvider@10fc1a22]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[mongod1:27017, mongod2:27018, mongod3:27019], srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='rs0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=5, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=false, invalidHostNameAllowed=false, context=null}, applicationName='null', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null}

: Exception in monitor thread while connecting to server mongod3:27019

com.mongodb.MongoSocketOpenException: Exception opening socket

I have run an integration test and it seems that there is an attempt to initialize the connection data specified in application.yml and application-test.yml is ignored.

Testcontainers creates a mongo in which there is only one node, but this does not work.

….
@Transactional(readOnly = true)
public Flux<AccountDto> findAll(int page, int size) {

    Pageable pageable = PageRequest.of(page, size);
    return accountRepository.findAllByIdNotNullOrderByIdAsc(pageable)
            .map(this::mapToDto);
}
….
@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = DemoApplication.class)
@Testcontainers
@AutoConfigureWebTestClient
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AccountControllerIntegrationTest {


    @Autowired
    private WebTestClient webTestClient;

    @Autowired
    private AccountRepository accountRepository;

    @Container
    static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4.2")
            .withCommand("--replSet", "rs0")
            .withExposedPorts(27017);

    static{
        mongoDBContainer.start();
    }


    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {

        String replicaSetUrl = mongoDBContainer.getReplicaSetUrl();
        System.out.println("MongoDB URL: " + replicaSetUrl);
   
        String modifiedUrl = replicaSetUrl + "&readPreference=primary";
        registry.add("spring.data.mongodb.uri", () -> modifiedUrl);
    }

    @BeforeEach
    void setUp() {
        accountRepository.deleteAll().block();
    }
…..


```java
@Primary
@Validated
@Data
@ConfigurationProperties(prefix = "mongodb.uri", ignoreUnknownFields = false)
public class MongoCustomProperties {

    private SetMongoProperties set = new SetMongoProperties();

    @Data
    public static class SetMongoProperties {
        String prefix = "mongodb://";
        private String hostFirst = "localhost";
        private String hostSecond = "localhost";
        private String hostThird = "localhost";
        private int portFirstInstance = 27017;
        private int portSecondInstance = 27018;
        private int portThirdInstance = 27019;
        private String database = "accounts";
        private String username = "root";
        private String password = "root";
        private String authenticationDatabase = "admin";
        private String replicaSetName = "replicaSet";
        private int maxPoolSize = 100;
        private int minPoolSize = 5;
        private boolean retryWrites = true;
        private String writeAcknowledgement = "majority";           private String readPreference = "primaryPreferred"; 


@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MongoCustomProperties.class)
@EnableReactiveMongoRepositories(basePackages = "com.example.demo.repository")
public class MongoConfig extends AbstractReactiveMongoConfiguration {

    private final MongoCustomProperties mongoProperties;

    @Override
    protected String getDatabaseName() {
        return mongoProperties.getSet().getDatabase();
    }

    @Override
    public com.mongodb.reactivestreams.client.MongoClient reactiveMongoClient() {

        String mongoUri = mongoProperties.getSet().buildUri();

        return com.mongodb.reactivestreams.client.MongoClients.create(mongoUri);
    }

    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate() {
        return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName());
    }

    @Bean
    public ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory factory) {
        return new ReactiveMongoTransactionManager(factory);
    }
}

application.yml

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration
server:
  port: 9080

mongodb:
  uri:
    set:
      prefix: 'mongodb://'
      host-first: mongod1
      host-second: mongod2
      host-third: mongod3
      port-first-instance: 27017
      port-second-instance: 27018
      port-third-instance: 27019
      database: accounts
      username: root
      password: root
      authentication-database: admin
      replicaSet-name: rs0
      maxPoolSize: 100
      minPoolSize: 5
      retryWrites: true
      writeAcknowledgement: majority
      readPreference: primaryPreferred

application-test.yml

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration
      - org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
      - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration
      - org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration
      - org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration

I also used this approach

    @Container
    static MongoDBContainer mongoDBContainer1 = new MongoDBContainer(DockerImageName.parse("mongo:latest"))
            .withCommand("--replSet", "rs0")
            .withExposedPorts(27017);

    @Container
    static MongoDBContainer mongoDBContainer2 = new MongoDBContainer(DockerImageName.parse("mongo:latest"))
            .withCommand("--replSet", "rs0")
            .withExposedPorts(27018);

    @Container
    static MongoDBContainer mongoDBContainer3 = new MongoDBContainer(DockerImageName.parse("mongo:latest"))
            .withCommand("--replSet", "rs0")
            .withExposedPorts(27019);

    static {
        mongoDBContainer1.start();
        mongoDBContainer2.start();
        mongoDBContainer3.start();

        try {
            Thread.sleep(10000);
            String initCommand = String.format("mongo --host %s --port %d --eval \"rs.initiate({_id: 'rs0', members: [{_id: 0, host: '%s:%d'}, {_id: 1, host: '%s:%d'}, {_id: 2, host: '%s:%d'}]})\"",
                    mongoDBContainer1.getHost(), mongoDBContainer1.getMappedPort(27017),
                    mongoDBContainer2.getHost(), mongoDBContainer2.getMappedPort(27018),
                    mongoDBContainer3.getHost(), mongoDBContainer3.getMappedPort(27019));


            Runtime.getRuntime().exec(initCommand);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

2024-10-27T20:24:52.649+03:00 INFO 9636 - - - [- local host:2624] org.mongodb.driver.cluster:Server local host: 2629 is no longer a member of the replica set. Removing a cluster from the client view. 2024-10-27T20:24:52.651+03:00 DEBUGGING 9636 - - - [- local host:2624] org.mongodb.driver.connection : connection pool closed for local access:2629 2024-10-27T20:24:52.653+03:00 INFO 9636 - - - [- local host:2624] org.mongodb.driver.cluster:Server local host: 2624 is no longer a member of the replica set. Removing a cluster from the client view. 2024-10-27T20:24:52.654+03:00 INFO 9636 - - - [4961e6dbc:27017] org.mongodb.driver.cluster : Exception in the monitoring stream when connecting to the server f914961e6dbc:27017

com.mongodb.MongoSocketException: Not known yet (f914961e6dbc)

Who has any idea why this is happening?

Maybe someone has an understanding of how it works and what needs to be fixed here?

Upvotes: 0

Views: 34

Answers (0)

Related Questions