quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.42k stars 2.58k forks source link

mongodb with multiple (named) connections not working + random container image in test (using testcontainers) #41400

Open constantin-ungureanu-github opened 1 month ago

constantin-ungureanu-github commented 1 month ago

Describe the bug

As per documentation, there is possible to use multiple mongodb clients quarkus.mongodb.[optional name.][mongo connection property] ex.: quarkus.mongodb.users.connection-string = mongodb://mongo2:27017/userdb

Then to inject the named client such as: @Inject @MongoClientName("users") MongoClient mongoClient1;

I try to use the @MongoEntity with multiple connection, as I see it has a field clientName. but when I try to run, it throws an exception.

Expected behavior

Possibility to use multiple MongoDB connections (clients).

Actual behavior

using multiple mongodb connection is not working, only default (single) one.

How to Reproduce?

  1. BacklogEntity class

    @MongoEntity(clientName = "inventory", collection = "backlog")
    @EqualsAndHashCode(callSuper = false)
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class BacklogEntity extends PanacheMongoEntityBase {
    
    @BsonId
    String id;
    
    public static PanacheQuery<BacklogEntity> findByIds(final List<String> list) {
        return find("_id in ?1", list);
    }
    }
  2. application.properties quarkus.mongodb.inventory.connection-string = mongodb://localhost:27017 quarkus.mongodb.inventory.database = inventory

  3. MongoDBLifecycleManager class

    public class MongoDBLifecycleManager implements QuarkusTestResourceLifecycleManager {
    
    private static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:7"));
    
    @Override
    public Map<String, String> start() {
        mongoDBContainer.waitingFor(new HostPortWaitStrategy()).start();
    
        return Map.of("quarkus.mongodb.inventory.connection-string", mongoDBContainer.getConnectionString());
    }
    
    @Override
    public void stop() {
        mongoDBContainer.stop();
    }
    }
  4. BacklogEntityTest test class

    @QuarkusTest
    @QuarkusTestResource(MongoDBLifecycleManager.class)
    @Slf4j
    class BacklogEntityTest {
    
    @Inject
    @MongoClientName("inventory")
    MongoClient mongoClient;
    
    @AfterEach
    public void afterEach() {
        mongoClient.getDatabase("inventory").drop();
    }
    
    @Test
    void testPersist() {
        BacklogEntity.builder().id("Record 1").build().persist();
        Assertions.assertEquals(1, BacklogEntity.count());
    
        BacklogEntity backlogEntity = BacklogEntity.findById("Record 1");
        backlogEntity.update();
        assertEquals(1, BacklogEntity.count());
    }
    
    @Test
    void testFindByIds() {
        BacklogEntity.builder().id("Record 1").build().persist();
        BacklogEntity.builder().id("Record 2").build().persist();
        BacklogEntity.builder().id("Record 3").build().persist();
        Assertions.assertEquals(3, BacklogEntity.count());
    
        final List<String> list = List.of("Record 1", "Record 3");
        final PanacheQuery<BacklogEntity> panacheQuery = BacklogEntity.findByIds(list);
        assertEquals(2, panacheQuery.count());
        panacheQuery.list().forEach(entity -> {
            assertTrue(list.contains(entity.getId()));
            log.info("Validated Entity {}", entity);
        });
    }
    }

When I run I get: java.lang.IllegalStateException: Unable to find MongoClient bean for entity @io.quarkus.mongodb.panache.common.MongoEntity(readPreference="", database="inventory", collection="backlog", clientName="inventory") at io.quarkus.mongodb.panache.common.runtime.BeanUtils.clientFromArc(BeanUtils.java:58) at io.quarkus.mongodb.panache.common.runtime.MongoOperations.mongoDatabase(MongoOperations.java:399) at io.quarkus.mongodb.panache.common.runtime.MongoOperations.mongoCollection(MongoOperations.java:193) at io.quarkus.mongodb.panache.common.runtime.MongoOperations.mongoCollection(MongoOperations.java:395) at io.quarkus.mongodb.panache.common.runtime.MongoOperations.persist(MongoOperations.java:73) at io.quarkus.mongodb.panache.PanacheMongoEntityBase.persist(PanacheMongoEntityBase.java:36) at com.asml.asml.vcp.datacontinuity.export.BacklogEntityTest.testPersist(BacklogEntityTest.java:40) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at io.quarkus.test.junit.QuarkusTestExtension.runExtensionMethod(QuarkusTestExtension.java:1017) at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:831) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

And in the logs I get both Creating container for image: docker.io/mongo:4.4 Creating container for image: mongo:7

Where did the "docker.io/mongo:4.4" come from ? In my MongoDBLifecycleManager I only specify the mongo:7 image to be used. I understand this is some default, but I am not interested in using this, that's why I specify a different version. This is also a bug !

If I try to use BacklogEntity defined with only @MongoEntity(database = "inventory", collection = "backlog"), of course it uses the default connection (no name) and therefore is decoupled from the named connection (inventory), and fails next test.

There is the need to run with named connection, as this is only one connection test, but I want to run with multiple ones, so just bypassing and use the default, no name connection is not an option.

From @interface MongoEntity I see /**

So it should work when setting the client name... therefore is a bug.

Output of uname -a or ver

windows

Output of java -version

21

Quarkus version or git rev

3.11.3, 3.12

Build tool (ie. output of mvnw --version or gradlew --version)

mvn 3.9.7

Additional information

Please don't be ignorant with these bugs.

quarkus-bot[bot] commented 1 month ago

/cc @loicmathieu (mongodb)