测试容器 Couchbase 超时

Posted

技术标签:

【中文标题】测试容器 Couchbase 超时【英文标题】:Testcontainers Couchbase timeouts 【发布时间】:2021-09-05 22:29:26 【问题描述】:

我创建了一个最小、完整且可验证的示例来说明我的问题:https://github.com/Virkom/CouchbaseMCVE.

我使用 Testcontainers 和 CouchbaseContainer 创建了一个集成测试。 我的 gradle.build:

implementation "com.couchbase.client:java-client:3.1.3"
testImplementation "io.micronaut.test:micronaut-test-junit5"
testImplementation "org.testcontainers:junit-jupiter"
testImplementation "org.testcontainers:testcontainers"
testImplementation "org.testcontainers:couchbase"

Couchbase 客户端:

ClusterEnvironment env = ClusterEnvironment.builder()
    .transcoder(SerializableTranscoder.INSTANCE)
    .aggregatingMeterConfig(AggregatingMeterConfig.builder()
        .enabled(true)
        .emitInterval(Duration.ofSeconds(60)))
    .build();

ClusterOptions opts = ClusterOptions.clusterOptions(bucket, password).environment(env);
couchbaseCluster = Cluster.connect("localhost", opts);
couchbaseBucket = couchbaseCluster.bucket(bucket);

当bucket为“testBucket”,密码为“testtest”时。

测试中的容器创建代码:

BucketDefinition bucketDefinition = new BucketDefinition("testBucket");

CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server")
    .withCredentials("testBucket", "testtest")
    .withBucket(bucketDefinition);

couchbaseContainer.start();

容器启动,我可以通过webinterface连接它,testBucket存在并且一切都很好,但是当我尝试更新值时出现异常。

方法代码:

public void set(String key, Serializable o, int ttlSeconds) 
    UpsertOptions opts = UpsertOptions.upsertOptions()
        .durability(PersistTo.NONE, ReplicateTo.NONE)
        .expiry(Duration.ofSeconds(ttlSeconds));
    couchbaseBucket.defaultCollection().upsert(key, o, opts);

结果:

UpsertRequest, Reason: TIMEOUT
com.couchbase.client.core.error.AmbiguousTimeoutException: UpsertRequest, Reason: TIMEOUT "cancelled":true,"completed":true,"coreId":"0x48ac5a3200000001","idempotent":false,"reason":"TIMEOUT","requestId":5,"requestType":"UpsertRequest","retried":14,"retryReasons":["BUCKET_OPEN_IN_PROGRESS"],"service":"bucket":"testBucket","collection":"_default","documentId":"0","opaque":"0x3","scope":"_default","type":"kv","timeoutMs":2500,"timings":"encodingMicros":1434,"totalMicros":8118167

我在终端中也有很多警告,例如:

12:54:15.896 [cb-events] WARN  com.couchbase.endpoint - [com.couchbase.endpoint][EndpointConnectionFailedEvent][948us] Connect attempt 9 failed because of AnnotatedConnectException: finishConnect(..) failed: connection refused: localhost/127.0.0.1:8091 "circuitBreaker":"DISABLED","coreId":"0x48ac5a3200000001","remote":"localhost:8091","type":"MANAGER"
com.couchbase.client.core.deps.io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: connection refused: localhost/127.0.0.1:8091
Caused by: java.net.ConnectException: finishConnect(..) failed: connection refused

我花了很多时间寻找原因,尝试使用 couchbase 容器端口 couchbaseCluster = Cluster.connect(serverIp + ":" + serverPort, opts); 连接到集群,并尝试使用暴露端口 .withExposedPorts(8091, 8092, 8093, 8094, 11207, 11210, 11211, 18091, 18092, 18093) 创建容器,但它不起作用。有人可以帮帮我吗?

【问题讨论】:

你能发布你的测试的完整源代码吗(或者更好——MCVE)? 是的,当然。我已经创建了示例项目:github.com/Virkom/CouchbaseMCVE 你关注these instructions了吗? 是的,我是从这本手册开始的。但它适用于过时版本的 couchbase (2.6.2)。我在项目中有 3.1.3,我不能像那样更改它。所以在测试部分创建容器是一样的,但是我不能使用 CouchbaseEnvironment、DefaultCouchbaseEnvironment 类和CouchbaseCluster.create() 方法 couchbase的测试容器在哪个端口启动? 【参考方案1】:

集成测试设置的关键点是指示被测应用程序使用由测试容器启动的依赖项的随机端口。 在您的情况下,Couchbase DB。您的应用程序正在尝试使用默认的8091 端口(在application-test.yml 中设置)连接到数据库,但是正如您在 cmets 中提到的那样,docker 容器在随机端口上公开了 Couchbase。

例如,为了使用 Micronaut 和 JUnit5 执行此操作,您可以使用 TestPropertyProvider 接口。在 Micronaut documentation 中查看有关它的更多详细信息。

// @Testcontainers MUST be before @MicronautTest to make sure
// container is started before adjusting properties
@Testcontainers
@MicronautTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CouchbaseServiceTest implements TestPropertyProvider 

    @Inject
    private CouchbaseService couchbaseService;

    @Container
    private static final CouchbaseContainer couchbaseContainer = new CouchbaseContainer("couchbase/server")
            .withCredentials("testBucket", "testPassword")
            .withExposedPorts(8091, 8092, 8093, 8094, 11207, 11210, 11211, 18091, 18092, 18093)
            .withBucket(new BucketDefinition("testBucket"));

    @Override
    public Map<String, String> getProperties() 
        return Map.of(
                "app.server_port", String.valueOf(couchbaseContainer.getBootstrapHttpDirectPort()),
                "app.kv_port", String.valueOf(couchbaseContainer.getBootstrapCarrierDirectPort())
        );
    
    ...

但是你还需要稍微更改一下集群连接代码(CouchbaseClient.java):

...
SeedNode seedNode = SeedNode.create(
    serverIp, Optional.of(Integer.valueOf(kvPort)), Optional.of(Integer.valueOf(serverPort)));
couchbaseCluster = Cluster.connect(Set.of(seedNode), opts);

您可能已经注意到,您需要为kv_port 再公开一个属性。与 server_port 一样。

【讨论】:

是的,它运行良好。非常感谢。

以上是关于测试容器 Couchbase 超时的主要内容,如果未能解决你的问题,请参考以下文章

NoSQL文档型数据库Couchbase的生产部署最佳实践

测试容器超时等待容器端口打开,使用 Elasticsearch docker 镜像

如何在没有嵌入式服务器或新集群的情况下模拟 couchbase 进行验收测试?

Couchbase 集群中较慢的插入性能

YCSB测试Mysql,MongoDB,TokuMX,Couchbase性能

2. CouchBase集群安装和配置(01)-CouchBase从0到50