MongoDb jako testcontainer - problem z połączenem

0

Cześć, mam problem z testem integracyjnym z użyciem MongoDbConatner.
Wcześniej znalazłem te źródła: https://java.testcontainers.org/modules/databases/mongodb/
https://www.baeldung.com/java-mongodb-testcontainers
https://medium.com/@soham2312/database-integration-tests-with-mongo-and-testcontainers-8ae17ebd4d8c

Generalnie tak, zrobiłem abstrakcyjny test:

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@Testcontainers
@SpringBootTest
@ActiveProfiles("test")
public abstract class AbstractBaseIntegrationTest {

  @Container
  static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:7.0").withExposedPorts(27017)
      .withEnv("MONGO_INITDB_DATABASE", "test_db")
      .withEnv("MONGO_INIT_ROOT_USERNAME", "test_user")
      .withEnv("MONGO_INIT_ROOT_PASSWORD", "test_password");

  @DynamicPropertySource
  static void containersProperties(DynamicPropertyRegistry registry) {
    mongoDBContainer.start();
    registry.add("spring.data.mongodb.host", mongoDBContainer::getHost);
    registry.add("spring.data.mongodb.port", mongoDBContainer::getFirstMappedPort);

  }
}

application-test.yaml:

spring:
  data:
    mongodb:
      host: localhost
      database: test_db
      username: test_user
      password: test_password
      authentication-database: admin
      uri: mongodb://test_user:test_password@localhost:27017/test_db?authSource=admin

Testy się uruchamiają i dostaję taki error:

org.springframework.dao.DataAccessResourceFailureException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Połączenie odrzucone}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Połączenie odrzucone}}]

Wcześniej miałem problem z authentykacją, ale ta zmiana to poprawiła:

uri: mongodb://test_user:test_password@localhost:27017/test_db?authSource=admin

Może ktoś kto ma większe doświadczenie w pracy z Mongo spotkał się z czymś takim?
Ja z tym na codzień nie pracuję 😐

Dodam że docker ps zwraca mi, że ten kontener działa i jest na tym porcie dostępny

0

w Logach kontera leci to:

{"t":{"$date":"2024-09-17T06:07:19.289+00:00"},"s":"I",  "c":"STORAGE",  "id":22315,   "ctx":"initandlisten","msg":"Opening WiredTiger","attr":{"config":"create,cache_size=15380M,session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,remove=true,path=journal,compressor=snappy),builtin_extension_config=(zstd=(compression_level=6)),file_manager=(close_idle_time=600,close_scan_interval=10,close_handle_minimum=2000),statistics_log=(wait=0),json_output=(error,message),verbose=[recovery_progress:1,checkpoint_progress:1,compact_progress:1,backup:0,checkpoint:0,compact:0,evict:0,history_store:0,recovery:0,rts:0,salvage:0,tiered:0,timestamp:0,transaction:0,verify:0,log:0],"}}
{"t":{"$date":"2024-09-17T06:07:19.499+00:00"},"s":"I",  "c":"-",        "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"ReadConcernMajorityNotAvailableYet: Read concern majority reads are currently not possible.","nextWakeupMillis":200}}
{"t":{"$date":"2024-09-17T06:07:19.553+00:00"},"s":"I",  "c":"REPL",     "id":21313,   "ctx":"initandlisten","msg":"Did not find local replica set configuration document at startup","attr":{"error":{"code":47,"codeName":"NoMatchingDocument","errmsg":"Did not find replica set configuration document in local.system.replset"}}}
{"t":{"$date":"2024-09-17T06:07:19.571+00:00"},"s":"I",  "c":"CONTROL",  "id":20710,   "ctx":"LogicalSessionCacheRefresh","msg":"Failed to refresh session cache, will try again at the next refresh interval","attr":{"error":"NotYetInitialized: Replication has not yet been configured"}}
{"t":{"$date":"2024-09-17T06:07:19.572+00:00"},"s":"I",  "c":"CONTROL",  "id":20712,   "ctx":"LogicalSessionCacheReap","msg":"Sessions collection is not set up; waiting until next sessions reap interval","attr":{"error":"NamespaceNotFound: config.system.sessions does not exist"}}
{"t":{"$date":"2024-09-17T06:07:19.699+00:00"},"s":"I",  "c":"-",        "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"ReadConcernMajorityNotAvailableYet: Read concern majority reads are currently not possible.","nextWakeupMillis":400}}
{"t":{"$date":"2024-09-17T06:07:20.004+00:00"},"s":"W",  "c":"QUERY",    "id":23799,   "ctx":"ftdc","msg":"Aggregate command executor error","attr":{"error":{"code":26,"codeName":"NamespaceNotFound","errmsg":"Unable to retrieve storageStats in $collStats stage :: caused by :: Collection [local.oplog.rs] not found."},"stats":{},"cmd":{"aggregate":"oplog.rs","cursor":{},"pipeline":[{"$collStats":{"storageStats":{"waitForLock":false,"numericOnly":true}}}],"$db":"local"}}}
{"t":{"$date":"2024-09-17T06:07:20.105+00:00"},"s":"I",  "c":"-",        "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"ReadConcernMajorityNotAvailableYet: Read concern majority reads are currently not possible.","nextWakeupMillis":600}

Więc teraz zostaje wujek google :)

0

Ja np w swoich testach integracyjnych:

  • zazwyczaj nie mam adnotacji @Container (reszta z tym polem bez zmian)
  • mongoDBContainer.start(); mam w statycznym bloku, nie w tej metodzie z @DynamicPropertySource
  • w metodzie containersProperties miałbym jeszcze dodany property spring.data.mongodb.database

Także możesz spróbować z takim zestawem. Ogólnie to stawianie tych testcontainers to zawsze wrzód na tylnej części ciała - robi się to raz na projekt (raz per mongo, raz per S3, raz per kafka), mijają 2-3 lata i znowu trzeba to postawić i znowu tysiąc błędów :D za to jak już działa no to fajnie xd

0

Może chodzi o to, że na świat (z kontenera) wystawiasz port 27017, który jest mapowany na dynamiczny port na zewnątrz.

W yamlu masz:
uri: mongodb://test_user:test_password@localhost:27017/test_db?authSource=admin

zaś

uri: mongodb://test_user:test_password@localhost:<dynamiczny port na hoście, wcale nie musi być tym 27017 z kontenera>/test_db?authSource=admin

Próbowałbym tak:

registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);  // +/-  dodanie nazwy bazy, properties "/test_db?authSource=admin", albo użyucie dodatkowych properties via .add()
1

@Pinek i @yarel

Dziękuję, bardzo mi pomogliście:

@Testcontainers
@SpringBootTest
@ActiveProfiles("test")
public abstract class AbstractBaseIntegrationTest {


  public static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:7.0").withExposedPorts(27017)
      .withEnv("MONGO_INITDB_DATABASE", "test_db")
      .withEnv("MONGO_INIT_ROOT_USERNAME", "test_user")
      .withEnv("MONGO_INIT_ROOT_PASSWORD", "test_password")
      .withStartupTimeout(Duration.ofSeconds(30));

  static {
    mongoDBContainer.start();
  }

  @DynamicPropertySource
  static void containersProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.data.mongodb.host", mongoDBContainer::getHost);
    registry.add("spring.data.mongodb.port", mongoDBContainer::getFirstMappedPort);
    registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);

  }
}

i śmiga :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.