Convert couchbase tests to java (#12193)
This commit is contained in:
parent
2a7a5530f3
commit
7ecc678866
|
@ -26,8 +26,9 @@ dependencies {
|
||||||
|
|
||||||
testImplementation(project(":instrumentation:couchbase:couchbase-common:testing"))
|
testImplementation(project(":instrumentation:couchbase:couchbase-common:testing"))
|
||||||
|
|
||||||
latestDepTestLibrary("org.springframework.data:spring-data-couchbase:3.+")
|
// later versions are tested with couchbase-2.6 instrumentation
|
||||||
latestDepTestLibrary("com.couchbase.client:java-client:2.+")
|
latestDepTestLibrary("org.springframework.data:spring-data-couchbase:2.+")
|
||||||
|
latestDepTestLibrary("com.couchbase.client:java-client:2.5.+")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test>().configureEach {
|
tasks.withType<Test>().configureEach {
|
||||||
|
|
|
@ -32,6 +32,11 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule
|
||||||
return asList(new CouchbaseBucketInstrumentation(), new CouchbaseClusterInstrumentation());
|
return asList(new CouchbaseBucketInstrumentation(), new CouchbaseClusterInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModuleGroup() {
|
||||||
|
return "couchbase";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> injectedClassNames() {
|
public List<String> injectedClassNames() {
|
||||||
return singletonList("rx.__OpenTelemetryTracingUtil");
|
return singletonList("rx.__OpenTelemetryTracingUtil");
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CouchbaseAsyncClientTest extends AbstractCouchbaseAsyncClientTest {
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CouchbaseClientTest extends AbstractCouchbaseClientTest {
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
class CouchbaseSpringRepositoryTest extends AbstractCouchbaseSpringRepositoryTest {
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
class CouchbaseSpringTemplateTest extends AbstractCouchbaseSpringTemplateTest {
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseAsyncClientTest;
|
||||||
|
|
||||||
|
class CouchbaseAsyncClientTest extends AbstractCouchbaseAsyncClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseClientTest;
|
||||||
|
|
||||||
|
class CouchbaseClientTest extends AbstractCouchbaseClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.metrics.DefaultLatencyMetricsCollectorConfig;
|
||||||
|
import com.couchbase.client.core.metrics.DefaultMetricsCollectorConfig;
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class CouchbaseUtil {
|
||||||
|
|
||||||
|
public static DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
// Couchbase seems to be really slow to start sometimes
|
||||||
|
long timeout = TimeUnit.SECONDS.toMillis(20);
|
||||||
|
return DefaultCouchbaseEnvironment.builder()
|
||||||
|
.bootstrapCarrierDirectPort(carrierDirectPort)
|
||||||
|
.bootstrapHttpDirectPort(httpDirectPort)
|
||||||
|
// settings to try to reduce variability in the tests:
|
||||||
|
.runtimeMetricsCollectorConfig(DefaultMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
||||||
|
.networkLatencyMetricsCollectorConfig(
|
||||||
|
DefaultLatencyMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
||||||
|
.computationPoolSize(1)
|
||||||
|
.connectTimeout(timeout)
|
||||||
|
.disconnectTimeout(timeout)
|
||||||
|
.kvTimeout(timeout)
|
||||||
|
.managementTimeout(timeout)
|
||||||
|
.queryTimeout(timeout)
|
||||||
|
.viewTimeout(timeout)
|
||||||
|
.keepAliveTimeout(timeout)
|
||||||
|
.searchTimeout(timeout)
|
||||||
|
.analyticsTimeout(timeout)
|
||||||
|
.socketConnectTimeout((int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CouchbaseUtil() {}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.springdata;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.AbstractCouchbaseSpringRepositoryTest;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.TestDocument;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.TestRepository;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.CouchbaseUtil;
|
||||||
|
|
||||||
|
class CouchbaseSpringRepositoryTest extends AbstractCouchbaseSpringRepositoryTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TestDocument findById(TestRepository repository, String id) {
|
||||||
|
return repository.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deleteById(TestRepository repository, String id) {
|
||||||
|
repository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.springdata;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.AbstractCouchbaseSpringTemplateTest;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.CouchbaseUtil;
|
||||||
|
|
||||||
|
class CouchbaseSpringTemplateTest extends AbstractCouchbaseSpringTemplateTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,13 @@ import static java.util.Arrays.asList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class CouchbaseInstrumentationModule extends InstrumentationModule {
|
public class CouchbaseInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public CouchbaseInstrumentationModule() {
|
public CouchbaseInstrumentationModule() {
|
||||||
super("couchbase", "couchbase-2.6");
|
super("couchbase", "couchbase-2.6");
|
||||||
}
|
}
|
||||||
|
@ -22,4 +25,9 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(new CouchbaseCoreInstrumentation(), new CouchbaseNetworkInstrumentation());
|
return asList(new CouchbaseCoreInstrumentation(), new CouchbaseNetworkInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModuleGroup() {
|
||||||
|
return "couchbase";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
|
|
||||||
class CouchbaseAsyncClient26Test extends AbstractCouchbaseAsyncClientTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object name,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
CouchbaseSpanUtil.assertCouchbaseCall(trace, index, name, parentSpan, bucketName, statement, operation)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
|
|
||||||
class CouchbaseClient26Test extends AbstractCouchbaseClientTest {
|
|
||||||
@Override
|
|
||||||
void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object name,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
CouchbaseSpanUtil.assertCouchbaseCall(trace, index, name, parentSpan, bucketName, statement, operation)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes
|
|
||||||
import io.opentelemetry.semconv.NetworkAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
|
||||||
|
|
||||||
class CouchbaseSpanUtil {
|
|
||||||
// Reusable span assertion method. Cannot directly override AbstractCouchbaseTest.assertCouchbaseSpan because
|
|
||||||
// Of the class hierarchy of these tests
|
|
||||||
static void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object spanName,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
trace.span(index) {
|
|
||||||
name spanName
|
|
||||||
kind CLIENT
|
|
||||||
if (parentSpan == null) {
|
|
||||||
hasNoParent()
|
|
||||||
} else {
|
|
||||||
childOf((SpanData) parentSpan)
|
|
||||||
}
|
|
||||||
attributes {
|
|
||||||
"$DbIncubatingAttributes.DB_SYSTEM" "couchbase"
|
|
||||||
"$DbIncubatingAttributes.DB_NAME" bucketName
|
|
||||||
"$DbIncubatingAttributes.DB_STATEMENT" statement
|
|
||||||
"$DbIncubatingAttributes.DB_OPERATION"(operation ?: spanName)
|
|
||||||
|
|
||||||
// Because of caching, not all requests hit the server so these attributes may be absent
|
|
||||||
"$NetworkAttributes.NETWORK_TYPE" { it == "ipv4" || it == null }
|
|
||||||
"$NetworkAttributes.NETWORK_PEER_ADDRESS" { it == "127.0.0.1" || it == null }
|
|
||||||
"$NetworkAttributes.NETWORK_PEER_PORT" { it instanceof Number || it == null }
|
|
||||||
|
|
||||||
// Because of caching, not all requests hit the server so this tag may be absent
|
|
||||||
"couchbase.local.address" { it == null || it instanceof String }
|
|
||||||
|
|
||||||
// Not all couchbase operations have operation id. Notably, 'ViewQuery's do not
|
|
||||||
// We assign a spanName of 'Bucket.query' and this is shared with n1ql queries
|
|
||||||
// that do have operation ids
|
|
||||||
"couchbase.operation_id" { it == null || it instanceof String }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
|
|
||||||
class CouchbaseSpringRepository26Test extends AbstractCouchbaseSpringRepositoryTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object name,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
CouchbaseSpanUtil.assertCouchbaseCall(trace, index, name, parentSpan, bucketName, statement, operation)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
|
|
||||||
class CouchbaseSpringTemplate26Test extends AbstractCouchbaseSpringTemplateTest {
|
|
||||||
@Override
|
|
||||||
void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object name,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
CouchbaseSpanUtil.assertCouchbaseCall(trace, index, name, parentSpan, bucketName, statement, operation)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.metrics.DefaultLatencyMetricsCollectorConfig;
|
||||||
|
import com.couchbase.client.core.metrics.DefaultMetricsCollectorConfig;
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.api.common.AttributeKey;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import io.opentelemetry.semconv.NetworkAttributes;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class Couchbase26Util {
|
||||||
|
|
||||||
|
public static DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
// Couchbase seems to be really slow to start sometimes
|
||||||
|
long timeout = TimeUnit.SECONDS.toMillis(20);
|
||||||
|
return DefaultCouchbaseEnvironment.builder()
|
||||||
|
.bootstrapCarrierDirectPort(carrierDirectPort)
|
||||||
|
.bootstrapHttpDirectPort(httpDirectPort)
|
||||||
|
// settings to try to reduce variability in the tests:
|
||||||
|
.runtimeMetricsCollectorConfig(DefaultMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
||||||
|
.networkLatencyMetricsCollectorConfig(
|
||||||
|
DefaultLatencyMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
||||||
|
.computationPoolSize(1)
|
||||||
|
.connectTimeout(timeout)
|
||||||
|
.disconnectTimeout(timeout)
|
||||||
|
.kvTimeout(timeout)
|
||||||
|
.managementTimeout(timeout)
|
||||||
|
.queryTimeout(timeout)
|
||||||
|
.viewTimeout(timeout)
|
||||||
|
.keepAliveTimeout(timeout)
|
||||||
|
.searchTimeout(timeout)
|
||||||
|
.analyticsTimeout(timeout)
|
||||||
|
.socketConnectTimeout((int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Arrays.asList(
|
||||||
|
equalTo(NetworkAttributes.NETWORK_TYPE, "ipv4"),
|
||||||
|
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
|
||||||
|
satisfies(NetworkAttributes.NETWORK_PEER_PORT, val -> assertThat(val).isNotNull()),
|
||||||
|
satisfies(
|
||||||
|
AttributeKey.stringKey("couchbase.local.address"), val -> assertThat(val).isNotNull()),
|
||||||
|
satisfies(
|
||||||
|
AttributeKey.stringKey("couchbase.operation_id"), val -> assertThat(val).isNotNull()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Couchbase26Util() {}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseAsyncClientTest;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CouchbaseAsyncClient26Test extends AbstractCouchbaseAsyncClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return Couchbase26Util.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Couchbase26Util.couchbaseAttributes();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseClientTest;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CouchbaseClient26Test extends AbstractCouchbaseClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return Couchbase26Util.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Couchbase26Util.couchbaseAttributes();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6.springdata;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.AbstractCouchbaseSpringRepositoryTest;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.TestDocument;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.TestRepository;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.couchbase.v2_6.Couchbase26Util;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CouchbaseSpringRepository26Test extends AbstractCouchbaseSpringRepositoryTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return Couchbase26Util.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Couchbase26Util.couchbaseAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TestDocument findById(TestRepository repository, String id) {
|
||||||
|
return repository.findById(id).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deleteById(TestRepository repository, String id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6.springdata;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.springdata.AbstractCouchbaseSpringTemplateTest;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.couchbase.v2_6.Couchbase26Util;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CouchbaseSpringTemplate26Test extends AbstractCouchbaseSpringTemplateTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) {
|
||||||
|
return Couchbase26Util.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Couchbase26Util.couchbaseAttributes();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.couchbase.client.core.error.DocumentNotFoundException
|
|
||||||
import com.couchbase.client.java.Cluster
|
|
||||||
import com.couchbase.client.java.Collection
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
|
||||||
import org.slf4j.Logger
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.testcontainers.containers.output.Slf4jLogConsumer
|
|
||||||
import org.testcontainers.couchbase.BucketDefinition
|
|
||||||
import org.testcontainers.couchbase.CouchbaseContainer
|
|
||||||
import org.testcontainers.couchbase.CouchbaseService
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
// Couchbase instrumentation is owned upstream so we don't assert on the contents of the spans, only
|
|
||||||
// that the instrumentation is properly registered by the agent, meaning some spans were generated.
|
|
||||||
class CouchbaseClient316Test extends AgentInstrumentationSpecification {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("couchbase-container")
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
CouchbaseContainer couchbase
|
|
||||||
@Shared
|
|
||||||
Cluster cluster
|
|
||||||
@Shared
|
|
||||||
Collection collection
|
|
||||||
|
|
||||||
def setupSpec() {
|
|
||||||
couchbase = new CouchbaseContainer()
|
|
||||||
.withExposedPorts(8091)
|
|
||||||
.withEnabledServices(CouchbaseService.KV)
|
|
||||||
.withBucket(new BucketDefinition("test"))
|
|
||||||
.withLogConsumer(new Slf4jLogConsumer(logger))
|
|
||||||
.withStartupTimeout(Duration.ofSeconds(120))
|
|
||||||
couchbase.start()
|
|
||||||
|
|
||||||
cluster = Cluster.connect(couchbase.connectionString, couchbase.username, couchbase.password)
|
|
||||||
def bucket = cluster.bucket("test")
|
|
||||||
collection = bucket.defaultCollection()
|
|
||||||
bucket.waitUntilReady(Duration.ofSeconds(30))
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupSpec() {
|
|
||||||
couchbase.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "emits spans"() {
|
|
||||||
when:
|
|
||||||
try {
|
|
||||||
collection.get("id")
|
|
||||||
} catch (DocumentNotFoundException e) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTracesWithoutScopeVersionVerification(1) {
|
|
||||||
trace(0, 2) {
|
|
||||||
span(0) {
|
|
||||||
name(~/.*get/)
|
|
||||||
}
|
|
||||||
span(1) {
|
|
||||||
name(~/.*dispatch_to_server/)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1_6;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.env.TimeoutConfig;
|
||||||
|
import com.couchbase.client.core.error.DocumentNotFoundException;
|
||||||
|
import com.couchbase.client.java.Bucket;
|
||||||
|
import com.couchbase.client.java.Cluster;
|
||||||
|
import com.couchbase.client.java.ClusterOptions;
|
||||||
|
import com.couchbase.client.java.Collection;
|
||||||
|
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import java.time.Duration;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||||
|
import org.testcontainers.couchbase.BucketDefinition;
|
||||||
|
import org.testcontainers.couchbase.CouchbaseContainer;
|
||||||
|
import org.testcontainers.couchbase.CouchbaseService;
|
||||||
|
|
||||||
|
// Couchbase instrumentation is owned upstream, so we don't assert on the contents of the spans,
|
||||||
|
// only that the instrumentation is properly registered by the agent, meaning some spans were
|
||||||
|
// generated.
|
||||||
|
class CouchbaseClient316Test {
|
||||||
|
@RegisterExtension
|
||||||
|
private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("couchbase-container");
|
||||||
|
|
||||||
|
private static CouchbaseContainer couchbase;
|
||||||
|
private static Cluster cluster;
|
||||||
|
private static Collection collection;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
couchbase =
|
||||||
|
new CouchbaseContainer("couchbase/server:7.6.0")
|
||||||
|
.withExposedPorts(8091)
|
||||||
|
.withEnabledServices(CouchbaseService.KV)
|
||||||
|
.withBucket(new BucketDefinition("test"))
|
||||||
|
.withLogConsumer(new Slf4jLogConsumer(logger))
|
||||||
|
.withStartupTimeout(Duration.ofMinutes(2));
|
||||||
|
couchbase.start();
|
||||||
|
|
||||||
|
ClusterEnvironment environment =
|
||||||
|
ClusterEnvironment.builder()
|
||||||
|
.timeoutConfig(TimeoutConfig.kvTimeout(Duration.ofSeconds(30)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
cluster =
|
||||||
|
Cluster.connect(
|
||||||
|
couchbase.getConnectionString(),
|
||||||
|
ClusterOptions.clusterOptions(couchbase.getUsername(), couchbase.getPassword())
|
||||||
|
.environment(environment));
|
||||||
|
|
||||||
|
Bucket bucket = cluster.bucket("test");
|
||||||
|
collection = bucket.defaultCollection();
|
||||||
|
|
||||||
|
// Wait 1 minute due to slow startup contributing to flakiness
|
||||||
|
bucket.waitUntilReady(Duration.ofMinutes(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void cleanup() {
|
||||||
|
cluster.disconnect();
|
||||||
|
couchbase.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEmitsSpans() {
|
||||||
|
try {
|
||||||
|
collection.get("id");
|
||||||
|
} catch (DocumentNotFoundException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
testing.waitAndAssertTracesWithoutScopeVersionVerification(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("get"), span -> span.hasName("dispatch_to_server")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,187 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.couchbase.client.java.AsyncCluster
|
|
||||||
import com.couchbase.client.java.CouchbaseAsyncCluster
|
|
||||||
import com.couchbase.client.java.document.JsonDocument
|
|
||||||
import com.couchbase.client.java.document.json.JsonObject
|
|
||||||
import com.couchbase.client.java.env.CouchbaseEnvironment
|
|
||||||
import com.couchbase.client.java.query.N1qlQuery
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
|
||||||
import spock.lang.Unroll
|
|
||||||
import spock.util.concurrent.BlockingVariable
|
|
||||||
import util.AbstractCouchbaseTest
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
@Unroll
|
|
||||||
abstract class AbstractCouchbaseAsyncClientTest extends AbstractCouchbaseTest {
|
|
||||||
static final int TIMEOUT = 10
|
|
||||||
|
|
||||||
def "test hasBucket #type"() {
|
|
||||||
setup:
|
|
||||||
def hasBucket = new BlockingVariable<Boolean>(TIMEOUT)
|
|
||||||
|
|
||||||
when:
|
|
||||||
cluster.openBucket(bucketSettings.name(), bucketSettings.password()).subscribe({ bkt ->
|
|
||||||
manager.hasBucket(bucketSettings.name()).subscribe({ result -> hasBucket.set(result) })
|
|
||||||
})
|
|
||||||
|
|
||||||
then:
|
|
||||||
assert hasBucket.get()
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 2) {
|
|
||||||
assertCouchbaseCall(it, 0, "Cluster.openBucket")
|
|
||||||
assertCouchbaseCall(it, 1, "ClusterManager.hasBucket", span(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()?.timeout(TIMEOUT, TimeUnit.SECONDS)?.toBlocking()?.single()
|
|
||||||
environment.shutdown()
|
|
||||||
|
|
||||||
where:
|
|
||||||
bucketSettings << [bucketCouchbase, bucketMemcache]
|
|
||||||
|
|
||||||
environment = envBuilder(bucketSettings).build()
|
|
||||||
cluster = CouchbaseAsyncCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
manager = cluster.clusterManager(AbstractCouchbaseTest.USERNAME, AbstractCouchbaseTest.PASSWORD).toBlocking().single()
|
|
||||||
type = bucketSettings.type().name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test upsert #type"() {
|
|
||||||
setup:
|
|
||||||
JsonObject content = JsonObject.create().put("hello", "world")
|
|
||||||
def inserted = new BlockingVariable<JsonDocument>(TIMEOUT)
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
// Connect to the bucket and open it
|
|
||||||
cluster.openBucket(bucketSettings.name(), bucketSettings.password()).subscribe({ bkt ->
|
|
||||||
bkt.upsert(JsonDocument.create("helloworld", content)).subscribe({ result -> inserted.set(result) })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
inserted.get().content().getString("hello") == "world"
|
|
||||||
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertCouchbaseCall(it, 1, "Cluster.openBucket", span(0))
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.upsert", span(1), bucketSettings.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()?.timeout(TIMEOUT, TimeUnit.SECONDS)?.toBlocking()?.single()
|
|
||||||
environment.shutdown()
|
|
||||||
|
|
||||||
where:
|
|
||||||
bucketSettings << [bucketCouchbase, bucketMemcache]
|
|
||||||
|
|
||||||
environment = envBuilder(bucketSettings).build()
|
|
||||||
cluster = CouchbaseAsyncCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
type = bucketSettings.type().name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test upsert and get #type"() {
|
|
||||||
setup:
|
|
||||||
JsonObject content = JsonObject.create().put("hello", "world")
|
|
||||||
def inserted = new BlockingVariable<JsonDocument>(TIMEOUT)
|
|
||||||
def found = new BlockingVariable<JsonDocument>(TIMEOUT)
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
cluster.openBucket(bucketSettings.name(), bucketSettings.password()).subscribe({ bkt ->
|
|
||||||
bkt.upsert(JsonDocument.create("helloworld", content))
|
|
||||||
.subscribe({ result ->
|
|
||||||
inserted.set(result)
|
|
||||||
bkt.get("helloworld")
|
|
||||||
.subscribe({ searchResult -> found.set(searchResult)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a JSON document and store it with the ID "helloworld"
|
|
||||||
then:
|
|
||||||
found.get() == inserted.get()
|
|
||||||
found.get().content().getString("hello") == "world"
|
|
||||||
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 4) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertCouchbaseCall(it, 1, "Cluster.openBucket", span(0))
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.upsert", span(1), bucketSettings.name())
|
|
||||||
assertCouchbaseCall(it, 3, "Bucket.get", span(2), bucketSettings.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()?.timeout(TIMEOUT, TimeUnit.SECONDS)?.toBlocking()?.single()
|
|
||||||
environment.shutdown()
|
|
||||||
|
|
||||||
where:
|
|
||||||
bucketSettings << [bucketCouchbase, bucketMemcache]
|
|
||||||
|
|
||||||
environment = envBuilder(bucketSettings).build()
|
|
||||||
cluster = CouchbaseAsyncCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
type = bucketSettings.type().name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test query"() {
|
|
||||||
setup:
|
|
||||||
// Only couchbase buckets support queries.
|
|
||||||
CouchbaseEnvironment environment = envBuilder(bucketCouchbase).build()
|
|
||||||
AsyncCluster cluster = CouchbaseAsyncCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
def queryResult = new BlockingVariable<JsonObject>(TIMEOUT)
|
|
||||||
|
|
||||||
when:
|
|
||||||
// Mock expects this specific query.
|
|
||||||
// See com.couchbase.mock.http.query.QueryServer.handleString.
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
cluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password()).subscribe({
|
|
||||||
bkt ->
|
|
||||||
bkt.query(N1qlQuery.simple("SELECT mockrow"))
|
|
||||||
.flatMap({ query -> query.rows() })
|
|
||||||
.single()
|
|
||||||
.subscribe({ row -> queryResult.set(row.value()) })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
queryResult.get().get("row") == "value"
|
|
||||||
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
|
|
||||||
assertCouchbaseCall(it, 1, "Cluster.openBucket", span(0))
|
|
||||||
|
|
||||||
def dbName = bucketCouchbase.name()
|
|
||||||
assertCouchbaseCall(it, 2, "SELECT $dbName", span(1), dbName, 'SELECT mockrow', 'SELECT')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()?.timeout(TIMEOUT, TimeUnit.SECONDS)?.toBlocking()?.single()
|
|
||||||
environment.shutdown()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.couchbase.client.java.Bucket
|
|
||||||
import com.couchbase.client.java.Cluster
|
|
||||||
import com.couchbase.client.java.CouchbaseCluster
|
|
||||||
import com.couchbase.client.java.document.JsonDocument
|
|
||||||
import com.couchbase.client.java.document.json.JsonObject
|
|
||||||
import com.couchbase.client.java.env.CouchbaseEnvironment
|
|
||||||
import com.couchbase.client.java.query.N1qlQuery
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
|
||||||
import spock.lang.Unroll
|
|
||||||
import util.AbstractCouchbaseTest
|
|
||||||
|
|
||||||
@Unroll
|
|
||||||
abstract class AbstractCouchbaseClientTest extends AbstractCouchbaseTest {
|
|
||||||
def "test hasBucket #type"() {
|
|
||||||
when:
|
|
||||||
def hasBucket = manager.hasBucket(bucketSettings.name())
|
|
||||||
|
|
||||||
then:
|
|
||||||
assert hasBucket
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
assertCouchbaseCall(it, 0, "ClusterManager.hasBucket")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()
|
|
||||||
environment.shutdown()
|
|
||||||
|
|
||||||
where:
|
|
||||||
bucketSettings << [bucketCouchbase, bucketMemcache]
|
|
||||||
|
|
||||||
environment = envBuilder(bucketSettings).build()
|
|
||||||
cluster = CouchbaseCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
manager = cluster.clusterManager(AbstractCouchbaseTest.USERNAME, AbstractCouchbaseTest.PASSWORD)
|
|
||||||
type = bucketSettings.type().name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test upsert and get #type"() {
|
|
||||||
when:
|
|
||||||
// Connect to the bucket and open it
|
|
||||||
Bucket bkt = cluster.openBucket(bucketSettings.name(), bucketSettings.password())
|
|
||||||
|
|
||||||
// Create a JSON document and store it with the ID "helloworld"
|
|
||||||
JsonObject content = JsonObject.create().put("hello", "world")
|
|
||||||
|
|
||||||
def inserted
|
|
||||||
def found
|
|
||||||
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
inserted = bkt.upsert(JsonDocument.create("helloworld", content))
|
|
||||||
found = bkt.get("helloworld")
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
found == inserted
|
|
||||||
found.content().getString("hello") == "world"
|
|
||||||
|
|
||||||
assertTraces(2) {
|
|
||||||
trace(0, 1) {
|
|
||||||
assertCouchbaseCall(it, 0, "Cluster.openBucket")
|
|
||||||
}
|
|
||||||
trace(1, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), bucketSettings.name())
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.get", span(0), bucketSettings.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()
|
|
||||||
environment.shutdown()
|
|
||||||
|
|
||||||
where:
|
|
||||||
bucketSettings << [bucketCouchbase, bucketMemcache]
|
|
||||||
|
|
||||||
environment = envBuilder(bucketSettings).build()
|
|
||||||
cluster = CouchbaseCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
type = bucketSettings.type().name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test query"() {
|
|
||||||
setup:
|
|
||||||
// Only couchbase buckets support queries.
|
|
||||||
CouchbaseEnvironment environment = envBuilder(bucketCouchbase).build()
|
|
||||||
Cluster cluster = CouchbaseCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
Bucket bkt = cluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password())
|
|
||||||
|
|
||||||
when:
|
|
||||||
// Mock expects this specific query.
|
|
||||||
// See com.couchbase.mock.http.query.QueryServer.handleString.
|
|
||||||
def result = bkt.query(N1qlQuery.simple("SELECT mockrow"))
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.parseSuccess()
|
|
||||||
result.finalSuccess()
|
|
||||||
result.first().value().get("row") == "value"
|
|
||||||
|
|
||||||
and:
|
|
||||||
assertTraces(2) {
|
|
||||||
trace(0, 1) {
|
|
||||||
assertCouchbaseCall(it, 0, "Cluster.openBucket")
|
|
||||||
}
|
|
||||||
trace(1, 1) {
|
|
||||||
def dbName = bucketCouchbase.name()
|
|
||||||
assertCouchbaseCall(it, 0, "SELECT $dbName", null, dbName, 'SELECT mockrow', 'SELECT')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
cluster?.disconnect()
|
|
||||||
environment.shutdown()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,202 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
|
|
||||||
import com.couchbase.client.java.Cluster
|
|
||||||
import com.couchbase.client.java.CouchbaseCluster
|
|
||||||
import com.couchbase.client.java.env.CouchbaseEnvironment
|
|
||||||
import com.couchbase.client.java.view.DefaultView
|
|
||||||
import com.couchbase.client.java.view.DesignDocument
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
|
||||||
import org.springframework.data.repository.CrudRepository
|
|
||||||
import spock.lang.Shared
|
|
||||||
import spock.lang.Unroll
|
|
||||||
import util.AbstractCouchbaseTest
|
|
||||||
|
|
||||||
@Unroll
|
|
||||||
abstract class AbstractCouchbaseSpringRepositoryTest extends AbstractCouchbaseTest {
|
|
||||||
static final Closure<Doc> FIND
|
|
||||||
static {
|
|
||||||
// This method is different in Spring Data 2+
|
|
||||||
try {
|
|
||||||
CrudRepository.getMethod("findOne", Serializable)
|
|
||||||
FIND = { DocRepository repo, String id ->
|
|
||||||
repo.findOne(id)
|
|
||||||
}
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
FIND = { DocRepository repo, String id ->
|
|
||||||
repo.findById(id).get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Shared
|
|
||||||
ConfigurableApplicationContext applicationContext
|
|
||||||
@Shared
|
|
||||||
DocRepository repo
|
|
||||||
|
|
||||||
def setupSpec() {
|
|
||||||
CouchbaseEnvironment environment = envBuilder(bucketCouchbase).build()
|
|
||||||
Cluster couchbaseCluster = CouchbaseCluster.create(environment, Arrays.asList("127.0.0.1"))
|
|
||||||
|
|
||||||
// Create view for SpringRepository's findAll()
|
|
||||||
couchbaseCluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password()).bucketManager()
|
|
||||||
.insertDesignDocument(
|
|
||||||
DesignDocument.create("doc", Collections.singletonList(DefaultView.create("all",
|
|
||||||
'''
|
|
||||||
function (doc, meta) {
|
|
||||||
if (doc._class == "springdata.Doc") {
|
|
||||||
emit(meta.id, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''.stripIndent()
|
|
||||||
)))
|
|
||||||
)
|
|
||||||
CouchbaseConfig.setEnvironment(environment)
|
|
||||||
CouchbaseConfig.setBucketSettings(bucketCouchbase)
|
|
||||||
|
|
||||||
// Close all buckets and disconnect
|
|
||||||
couchbaseCluster.disconnect()
|
|
||||||
|
|
||||||
applicationContext = new AnnotationConfigApplicationContext(CouchbaseConfig)
|
|
||||||
repo = applicationContext.getBean(DocRepository)
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupSpec() {
|
|
||||||
applicationContext.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test empty repo"() {
|
|
||||||
when:
|
|
||||||
def result = repo.findAll()
|
|
||||||
|
|
||||||
then:
|
|
||||||
!result.iterator().hasNext()
|
|
||||||
|
|
||||||
and:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
def dbName = bucketCouchbase.name()
|
|
||||||
assertCouchbaseCall(it, 0, dbName, null, dbName, ~/^ViewQuery\(doc\/all\).*/, { it == null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test save"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
|
|
||||||
when:
|
|
||||||
def result = repo.save(doc)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == doc
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
assertCouchbaseCall(it, 0, "Bucket.upsert", null, bucketCouchbase.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
clearExportedData()
|
|
||||||
repo.deleteAll()
|
|
||||||
ignoreTracesAndClear(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test save and retrieve"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
def result
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
repo.save(doc)
|
|
||||||
result = FIND(repo, "1")
|
|
||||||
}
|
|
||||||
|
|
||||||
then: // RETRIEVE
|
|
||||||
result == doc
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), bucketCouchbase.name())
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.get", span(0), bucketCouchbase.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
clearExportedData()
|
|
||||||
repo.deleteAll()
|
|
||||||
ignoreTracesAndClear(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test save and update"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
repo.save(doc)
|
|
||||||
doc.data = "other data"
|
|
||||||
repo.save(doc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), bucketCouchbase.name())
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.upsert", span(0), bucketCouchbase.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
clearExportedData()
|
|
||||||
repo.deleteAll()
|
|
||||||
ignoreTracesAndClear(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "save and delete"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
def result
|
|
||||||
|
|
||||||
when: // DELETE
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
repo.save(doc)
|
|
||||||
repo.delete("1")
|
|
||||||
result = repo.findAll().iterator().hasNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
assert !result
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 4) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
|
|
||||||
def dbName = bucketCouchbase.name()
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), dbName)
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.remove", span(0), dbName)
|
|
||||||
assertCouchbaseCall(it, 3, dbName, span(0), dbName, ~/^ViewQuery\(doc\/all\).*/, { it == null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
|
|
||||||
import com.couchbase.client.java.Bucket
|
|
||||||
import com.couchbase.client.java.Cluster
|
|
||||||
import com.couchbase.client.java.CouchbaseCluster
|
|
||||||
import com.couchbase.client.java.cluster.ClusterManager
|
|
||||||
import com.couchbase.client.java.env.CouchbaseEnvironment
|
|
||||||
import io.opentelemetry.api.trace.SpanKind
|
|
||||||
import org.springframework.data.couchbase.core.CouchbaseTemplate
|
|
||||||
import spock.lang.Retry
|
|
||||||
import spock.lang.Shared
|
|
||||||
import spock.lang.Unroll
|
|
||||||
import util.AbstractCouchbaseTest
|
|
||||||
|
|
||||||
@Retry(count = 10, delay = 500)
|
|
||||||
@Unroll
|
|
||||||
class AbstractCouchbaseSpringTemplateTest extends AbstractCouchbaseTest {
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
List<CouchbaseTemplate> templates
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
Cluster couchbaseCluster
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
Cluster memcacheCluster
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
protected CouchbaseEnvironment couchbaseEnvironment
|
|
||||||
@Shared
|
|
||||||
protected CouchbaseEnvironment memcacheEnvironment
|
|
||||||
|
|
||||||
def setupSpec() {
|
|
||||||
couchbaseEnvironment = envBuilder(bucketCouchbase).build()
|
|
||||||
memcacheEnvironment = envBuilder(bucketMemcache).build()
|
|
||||||
|
|
||||||
couchbaseCluster = CouchbaseCluster.create(couchbaseEnvironment, Arrays.asList("127.0.0.1"))
|
|
||||||
memcacheCluster = CouchbaseCluster.create(memcacheEnvironment, Arrays.asList("127.0.0.1"))
|
|
||||||
ClusterManager couchbaseManager = couchbaseCluster.clusterManager(AbstractCouchbaseTest.USERNAME, AbstractCouchbaseTest.PASSWORD)
|
|
||||||
ClusterManager memcacheManager = memcacheCluster.clusterManager(AbstractCouchbaseTest.USERNAME, AbstractCouchbaseTest.PASSWORD)
|
|
||||||
|
|
||||||
Bucket bucketCouchbase = couchbaseCluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password())
|
|
||||||
Bucket bucketMemcache = memcacheCluster.openBucket(bucketMemcache.name(), bucketMemcache.password())
|
|
||||||
|
|
||||||
runWithSpan("getting info") {
|
|
||||||
templates = [new CouchbaseTemplate(couchbaseManager.info(), bucketCouchbase),
|
|
||||||
new CouchbaseTemplate(memcacheManager.info(), bucketMemcache)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupSpec() {
|
|
||||||
couchbaseCluster?.disconnect()
|
|
||||||
memcacheCluster?.disconnect()
|
|
||||||
couchbaseEnvironment.shutdown()
|
|
||||||
memcacheEnvironment.shutdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test write #testName"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
def result
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
template.save(doc)
|
|
||||||
result = template.findById("1", Doc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
then:
|
|
||||||
result != null
|
|
||||||
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), testName)
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.get", span(0), testName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
where:
|
|
||||||
template << templates
|
|
||||||
testName = template.couchbaseBucket.name()
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test remove #testName"() {
|
|
||||||
setup:
|
|
||||||
def doc = new Doc()
|
|
||||||
|
|
||||||
when:
|
|
||||||
runWithSpan("someTrace") {
|
|
||||||
template.save(doc)
|
|
||||||
template.remove(doc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 3) {
|
|
||||||
span(0) {
|
|
||||||
name "someTrace"
|
|
||||||
kind SpanKind.INTERNAL
|
|
||||||
hasNoParent()
|
|
||||||
}
|
|
||||||
assertCouchbaseCall(it, 1, "Bucket.upsert", span(0), testName)
|
|
||||||
assertCouchbaseCall(it, 2, "Bucket.remove", span(0), testName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clearExportedData()
|
|
||||||
|
|
||||||
when:
|
|
||||||
def result = template.findById("1", Doc)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
assertCouchbaseCall(it, 0, "Bucket.get", null, testName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
where:
|
|
||||||
template << templates
|
|
||||||
testName = template.couchbaseBucket.name()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
import com.couchbase.client.java.cluster.BucketSettings
|
|
||||||
import com.couchbase.client.java.env.CouchbaseEnvironment
|
|
||||||
import org.springframework.context.annotation.ComponentScan
|
|
||||||
import org.springframework.context.annotation.Configuration
|
|
||||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration
|
|
||||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories
|
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableCouchbaseRepositories(basePackages = "springdata")
|
|
||||||
@ComponentScan(basePackages = "springdata")
|
|
||||||
class CouchbaseConfig extends AbstractCouchbaseConfiguration {
|
|
||||||
|
|
||||||
// These need to be set before this class can be used by Spring
|
|
||||||
static CouchbaseEnvironment environment
|
|
||||||
static BucketSettings bucketSettings
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CouchbaseEnvironment getEnvironment() {
|
|
||||||
return requireNonNull(environment)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getBootstrapHosts() {
|
|
||||||
return Collections.singletonList("127.0.0.1")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getBucketName() {
|
|
||||||
return bucketSettings.name()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getBucketPassword() {
|
|
||||||
return bucketSettings.password()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
|
||||||
import org.springframework.data.annotation.Id
|
|
||||||
import org.springframework.data.couchbase.core.mapping.Document
|
|
||||||
|
|
||||||
@Document
|
|
||||||
@EqualsAndHashCode
|
|
||||||
class Doc {
|
|
||||||
@Id
|
|
||||||
private String id = "1"
|
|
||||||
private String data = "some data"
|
|
||||||
|
|
||||||
String getId() {
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
void setId(String id) {
|
|
||||||
this.id = id
|
|
||||||
}
|
|
||||||
|
|
||||||
String getData() {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
void setData(String data) {
|
|
||||||
this.data = data
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package springdata
|
|
||||||
|
|
||||||
import org.springframework.data.couchbase.repository.CouchbaseRepository
|
|
||||||
|
|
||||||
interface DocRepository extends CouchbaseRepository<Doc, String> {}
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package util
|
|
||||||
|
|
||||||
import com.couchbase.client.core.metrics.DefaultLatencyMetricsCollectorConfig
|
|
||||||
import com.couchbase.client.core.metrics.DefaultMetricsCollectorConfig
|
|
||||||
import com.couchbase.client.java.bucket.BucketType
|
|
||||||
import com.couchbase.client.java.cluster.BucketSettings
|
|
||||||
import com.couchbase.client.java.cluster.DefaultBucketSettings
|
|
||||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment
|
|
||||||
import com.couchbase.mock.Bucket
|
|
||||||
import com.couchbase.mock.BucketConfiguration
|
|
||||||
import com.couchbase.mock.CouchbaseMock
|
|
||||||
import com.couchbase.mock.http.query.QueryServer
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
|
||||||
import io.opentelemetry.instrumentation.test.utils.PortUtils
|
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
|
||||||
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
|
||||||
|
|
||||||
abstract class AbstractCouchbaseTest extends AgentInstrumentationSpecification {
|
|
||||||
|
|
||||||
static final USERNAME = "Administrator"
|
|
||||||
static final PASSWORD = "password"
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
private int port = PortUtils.findOpenPort()
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
private String testBucketName = this.getClass().simpleName
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
protected bucketCouchbase = DefaultBucketSettings.builder()
|
|
||||||
.enableFlush(true)
|
|
||||||
.name("$testBucketName-cb")
|
|
||||||
.password("test-pass")
|
|
||||||
.type(BucketType.COUCHBASE)
|
|
||||||
.quota(100)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
protected bucketMemcache = DefaultBucketSettings.builder()
|
|
||||||
.enableFlush(true)
|
|
||||||
.name("$testBucketName-mem")
|
|
||||||
.password("test-pass")
|
|
||||||
.type(BucketType.MEMCACHED)
|
|
||||||
.quota(100)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
CouchbaseMock mock
|
|
||||||
|
|
||||||
def setupSpec() {
|
|
||||||
mock = new CouchbaseMock("127.0.0.1", port, 1, 1)
|
|
||||||
mock.httpServer.register("/query", new QueryServer())
|
|
||||||
mock.start()
|
|
||||||
println "CouchbaseMock listening on localhost:$port"
|
|
||||||
|
|
||||||
mock.createBucket(convert(bucketCouchbase))
|
|
||||||
mock.createBucket(convert(bucketMemcache))
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BucketConfiguration convert(BucketSettings bucketSettings) {
|
|
||||||
def configuration = new BucketConfiguration()
|
|
||||||
configuration.name = bucketSettings.name()
|
|
||||||
configuration.password = bucketSettings.password()
|
|
||||||
configuration.type = Bucket.BucketType.valueOf(bucketSettings.type().name())
|
|
||||||
configuration.numNodes = 1
|
|
||||||
configuration.numReplicas = 0
|
|
||||||
return configuration
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupSpec() {
|
|
||||||
mock?.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DefaultCouchbaseEnvironment.Builder envBuilder(BucketSettings bucketSettings) {
|
|
||||||
// Couchbase seems to be really slow to start sometimes
|
|
||||||
def timeout = TimeUnit.SECONDS.toMillis(20)
|
|
||||||
return DefaultCouchbaseEnvironment.builder()
|
|
||||||
.bootstrapCarrierDirectPort(mock.getCarrierPort(bucketSettings.name()))
|
|
||||||
.bootstrapHttpDirectPort(port)
|
|
||||||
// settings to try to reduce variability in the tests:
|
|
||||||
.runtimeMetricsCollectorConfig(DefaultMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
|
||||||
.networkLatencyMetricsCollectorConfig(DefaultLatencyMetricsCollectorConfig.create(0, TimeUnit.DAYS))
|
|
||||||
.computationPoolSize(1)
|
|
||||||
.connectTimeout(timeout)
|
|
||||||
.disconnectTimeout(timeout)
|
|
||||||
.kvTimeout(timeout)
|
|
||||||
.managementTimeout(timeout)
|
|
||||||
.queryTimeout(timeout)
|
|
||||||
.viewTimeout(timeout)
|
|
||||||
.keepAliveTimeout(timeout)
|
|
||||||
.searchTimeout(timeout)
|
|
||||||
.analyticsTimeout(timeout)
|
|
||||||
.socketConnectTimeout(timeout.intValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertCouchbaseCall(TraceAssert trace,
|
|
||||||
int index,
|
|
||||||
Object spanName,
|
|
||||||
SpanData parentSpan = null,
|
|
||||||
String bucketName = null,
|
|
||||||
Object statement = null,
|
|
||||||
Object operation = null) {
|
|
||||||
trace.span(index) {
|
|
||||||
name spanName
|
|
||||||
kind CLIENT
|
|
||||||
if (parentSpan == null) {
|
|
||||||
hasNoParent()
|
|
||||||
} else {
|
|
||||||
childOf((SpanData) parentSpan)
|
|
||||||
}
|
|
||||||
attributes {
|
|
||||||
"$DbIncubatingAttributes.DB_SYSTEM" "couchbase"
|
|
||||||
"$DbIncubatingAttributes.DB_NAME" bucketName
|
|
||||||
"$DbIncubatingAttributes.DB_STATEMENT" statement
|
|
||||||
"$DbIncubatingAttributes.DB_OPERATION"(operation ?: spanName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Named.named;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.CouchbaseAsyncCluster;
|
||||||
|
import com.couchbase.client.java.cluster.AsyncClusterManager;
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.document.JsonDocument;
|
||||||
|
import com.couchbase.client.java.document.json.JsonObject;
|
||||||
|
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||||
|
import com.couchbase.client.java.query.AsyncN1qlQueryResult;
|
||||||
|
import com.couchbase.client.java.query.N1qlQuery;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
public abstract class AbstractCouchbaseAsyncClientTest extends AbstractCouchbaseTest {
|
||||||
|
|
||||||
|
private static final int TIMEOUT_SECONDS = 10;
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create();
|
||||||
|
|
||||||
|
private static Stream<Arguments> bucketSettings() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(named(bucketCouchbase.type().name(), bucketCouchbase)),
|
||||||
|
Arguments.of(named(bucketMemcache.type().name(), bucketMemcache)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CouchbaseAsyncCluster prepareCluster(BucketSettings bucketSettings) {
|
||||||
|
CouchbaseEnvironment environment = envBuilder(bucketSettings).build();
|
||||||
|
CouchbaseAsyncCluster cluster =
|
||||||
|
CouchbaseAsyncCluster.create(environment, Collections.singletonList("127.0.0.1"));
|
||||||
|
cleanup.deferCleanup(
|
||||||
|
() -> cluster.disconnect().timeout(10, TimeUnit.SECONDS).toBlocking().single());
|
||||||
|
cleanup.deferCleanup(environment::shutdown);
|
||||||
|
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("bucketSettings")
|
||||||
|
void hasBucket(BucketSettings bucketSettings)
|
||||||
|
throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
CouchbaseAsyncCluster cluster = prepareCluster(bucketSettings);
|
||||||
|
AsyncClusterManager manager = cluster.clusterManager(USERNAME, PASSWORD).toBlocking().single();
|
||||||
|
|
||||||
|
testing.waitForTraces(1);
|
||||||
|
testing.clearData();
|
||||||
|
|
||||||
|
CompletableFuture<Boolean> hasBucket = new CompletableFuture<>();
|
||||||
|
cluster
|
||||||
|
.openBucket(bucketSettings.name(), bucketSettings.password())
|
||||||
|
.subscribe(
|
||||||
|
bucket -> manager.hasBucket(bucketSettings.name()).subscribe(hasBucket::complete));
|
||||||
|
|
||||||
|
assertThat(hasBucket.get(TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasNoParent()
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket")),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "ClusterManager.hasBucket")
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("bucketSettings")
|
||||||
|
void upsert(BucketSettings bucketSettings)
|
||||||
|
throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
CouchbaseAsyncCluster cluster = prepareCluster(bucketSettings);
|
||||||
|
|
||||||
|
JsonObject content = JsonObject.create().put("hello", "world");
|
||||||
|
CompletableFuture<JsonDocument> inserted = new CompletableFuture<>();
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
cluster
|
||||||
|
.openBucket(bucketSettings.name(), bucketSettings.password())
|
||||||
|
.subscribe(
|
||||||
|
bucket ->
|
||||||
|
bucket
|
||||||
|
.upsert(JsonDocument.create("helloworld", content))
|
||||||
|
.subscribe(inserted::complete));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(inserted.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).content().getString("hello"))
|
||||||
|
.isEqualTo("world");
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasParent(trace.getSpan(0))
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket")),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketSettings.name())
|
||||||
|
.hasParent(trace.getSpan(1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("bucketSettings")
|
||||||
|
void upsertAndGet(BucketSettings bucketSettings)
|
||||||
|
throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
CouchbaseAsyncCluster cluster = prepareCluster(bucketSettings);
|
||||||
|
|
||||||
|
JsonObject content = JsonObject.create().put("hello", "world");
|
||||||
|
CompletableFuture<JsonDocument> inserted = new CompletableFuture<>();
|
||||||
|
CompletableFuture<JsonDocument> found = new CompletableFuture<>();
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
cluster
|
||||||
|
.openBucket(bucketSettings.name(), bucketSettings.password())
|
||||||
|
.subscribe(
|
||||||
|
bucket ->
|
||||||
|
bucket
|
||||||
|
.upsert(JsonDocument.create("helloworld", content))
|
||||||
|
.subscribe(
|
||||||
|
result -> {
|
||||||
|
inserted.complete(result);
|
||||||
|
bucket.get("helloworld").subscribe(found::complete);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
JsonDocument insertedResult = inserted.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||||
|
JsonDocument foundResult = found.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||||
|
assertThat(foundResult).isEqualTo(insertedResult);
|
||||||
|
assertThat(foundResult.content().getString("hello")).isEqualTo("world");
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasParent(trace.getSpan(0))
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket")),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketSettings.name())
|
||||||
|
.hasParent(trace.getSpan(1)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.get", bucketSettings.name())
|
||||||
|
.hasParent(trace.getSpan(2))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void query() throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
// Only couchbase buckets support queries.
|
||||||
|
CouchbaseAsyncCluster cluster = prepareCluster(bucketCouchbase);
|
||||||
|
|
||||||
|
CompletableFuture<JsonObject> queryResult = new CompletableFuture<>();
|
||||||
|
// Mock expects this specific query.
|
||||||
|
// See com.couchbase.mock.http.query.QueryServer.handleString.
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
cluster
|
||||||
|
.openBucket(bucketCouchbase.name(), bucketCouchbase.password())
|
||||||
|
.subscribe(
|
||||||
|
bucket ->
|
||||||
|
bucket
|
||||||
|
.query(N1qlQuery.simple("SELECT mockrow"))
|
||||||
|
.flatMap(AsyncN1qlQueryResult::rows)
|
||||||
|
.single()
|
||||||
|
.subscribe(row -> queryResult.complete(row.value())));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(queryResult.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).get("row")).isEqualTo("value");
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasParent(trace.getSpan(0))
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket")),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(
|
||||||
|
span,
|
||||||
|
"SELECT " + bucketCouchbase.name(),
|
||||||
|
"SELECT",
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
"SELECT mockrow")
|
||||||
|
.hasParent(trace.getSpan(1))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Named.named;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.Bucket;
|
||||||
|
import com.couchbase.client.java.CouchbaseCluster;
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.cluster.ClusterManager;
|
||||||
|
import com.couchbase.client.java.document.JsonDocument;
|
||||||
|
import com.couchbase.client.java.document.json.JsonObject;
|
||||||
|
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||||
|
import com.couchbase.client.java.query.N1qlQuery;
|
||||||
|
import com.couchbase.client.java.query.N1qlQueryResult;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
public abstract class AbstractCouchbaseClientTest extends AbstractCouchbaseTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create();
|
||||||
|
|
||||||
|
private static Stream<Arguments> bucketSettings() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(named(bucketCouchbase.type().name(), bucketCouchbase)),
|
||||||
|
Arguments.of(named(bucketMemcache.type().name(), bucketMemcache)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CouchbaseCluster prepareCluster(BucketSettings bucketSettings) {
|
||||||
|
CouchbaseEnvironment environment = envBuilder(bucketSettings).build();
|
||||||
|
CouchbaseCluster cluster =
|
||||||
|
CouchbaseCluster.create(environment, Collections.singletonList("127.0.0.1"));
|
||||||
|
cleanup.deferCleanup(cluster::disconnect);
|
||||||
|
cleanup.deferCleanup(environment::shutdown);
|
||||||
|
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("bucketSettings")
|
||||||
|
void hasBucket(BucketSettings bucketSettings) {
|
||||||
|
CouchbaseCluster cluster = prepareCluster(bucketSettings);
|
||||||
|
ClusterManager manager = cluster.clusterManager(USERNAME, PASSWORD);
|
||||||
|
|
||||||
|
testing.waitForTraces(1);
|
||||||
|
testing.clearData();
|
||||||
|
|
||||||
|
boolean hasBucket = manager.hasBucket(bucketSettings.name());
|
||||||
|
assertThat(hasBucket).isTrue();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> assertCouchbaseSpan(span, "ClusterManager.hasBucket").hasNoParent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("bucketSettings")
|
||||||
|
void upsertAndGet(BucketSettings bucketSettings) {
|
||||||
|
CouchbaseCluster cluster = prepareCluster(bucketSettings);
|
||||||
|
|
||||||
|
// Connect to the bucket and open it
|
||||||
|
Bucket bucket = cluster.openBucket(bucketSettings.name(), bucketSettings.password());
|
||||||
|
|
||||||
|
// Create a JSON document and store it with the ID "helloworld"
|
||||||
|
JsonObject content = JsonObject.create().put("hello", "world");
|
||||||
|
|
||||||
|
AtomicReference<JsonDocument> inserted = new AtomicReference<>();
|
||||||
|
AtomicReference<JsonDocument> found = new AtomicReference<>();
|
||||||
|
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
inserted.set(bucket.upsert(JsonDocument.create("helloworld", content)));
|
||||||
|
found.set(bucket.get("helloworld"));
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(found.get()).isEqualTo(inserted.get());
|
||||||
|
assertThat(found.get().content().getString("hello")).isEqualTo("world");
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasNoParent()
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket"))),
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketSettings.name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.get", bucketSettings.name())
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void query() {
|
||||||
|
// Only couchbase buckets support queries.
|
||||||
|
CouchbaseCluster cluster = prepareCluster(bucketCouchbase);
|
||||||
|
Bucket bucket = cluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password());
|
||||||
|
|
||||||
|
// Mock expects this specific query.
|
||||||
|
// See com.couchbase.mock.http.query.QueryServer.handleString.
|
||||||
|
N1qlQueryResult result = bucket.query(N1qlQuery.simple("SELECT mockrow"));
|
||||||
|
assertThat(result.parseSuccess()).isTrue();
|
||||||
|
assertThat(result.finalSuccess()).isTrue();
|
||||||
|
assertThat(result.rows().next().value().get("row")).isEqualTo("value");
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("Cluster.openBucket")
|
||||||
|
.hasKind(SpanKind.CLIENT)
|
||||||
|
.hasNoParent()
|
||||||
|
.hasAttributesSatisfyingExactly(
|
||||||
|
equalTo(
|
||||||
|
DbIncubatingAttributes.DB_SYSTEM,
|
||||||
|
DbIncubatingAttributes.DbSystemValues.COUCHBASE),
|
||||||
|
equalTo(DbIncubatingAttributes.DB_OPERATION, "Cluster.openBucket"))),
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(
|
||||||
|
span,
|
||||||
|
"SELECT " + bucketCouchbase.name(),
|
||||||
|
"SELECT",
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
"SELECT mockrow")
|
||||||
|
.hasNoParent()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.bucket.BucketType;
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.cluster.DefaultBucketSettings;
|
||||||
|
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||||
|
import com.couchbase.mock.Bucket;
|
||||||
|
import com.couchbase.mock.BucketConfiguration;
|
||||||
|
import com.couchbase.mock.CouchbaseMock;
|
||||||
|
import com.couchbase.mock.http.query.QueryServer;
|
||||||
|
import com.couchbase.mock.httpio.HttpServer;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.test.utils.PortUtils;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||||
|
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
public abstract class AbstractCouchbaseTest {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AbstractCouchbaseTest.class);
|
||||||
|
|
||||||
|
protected static final String USERNAME = "Administrator";
|
||||||
|
protected static final String PASSWORD = "password";
|
||||||
|
|
||||||
|
private static final int port = PortUtils.findOpenPort();
|
||||||
|
protected static final BucketSettings bucketCouchbase =
|
||||||
|
DefaultBucketSettings.builder()
|
||||||
|
.enableFlush(true)
|
||||||
|
.name("$testBucketName-cb")
|
||||||
|
.password("test-pass")
|
||||||
|
.type(BucketType.COUCHBASE)
|
||||||
|
.quota(100)
|
||||||
|
.build();
|
||||||
|
protected static final BucketSettings bucketMemcache =
|
||||||
|
DefaultBucketSettings.builder()
|
||||||
|
.enableFlush(true)
|
||||||
|
.name("$testBucketName-mem")
|
||||||
|
.password("test-pass")
|
||||||
|
.type(BucketType.MEMCACHED)
|
||||||
|
.quota(100)
|
||||||
|
.build();
|
||||||
|
private CouchbaseMock mock;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
void setUp() throws Exception {
|
||||||
|
mock = new CouchbaseMock("127.0.0.1", port, 1, 1);
|
||||||
|
Field httpServerFiled = CouchbaseMock.class.getDeclaredField("httpServer");
|
||||||
|
httpServerFiled.setAccessible(true);
|
||||||
|
HttpServer httpServer = (HttpServer) httpServerFiled.get(mock);
|
||||||
|
httpServer.register("/query", new QueryServer());
|
||||||
|
mock.start();
|
||||||
|
logger.info("CouchbaseMock listening on localhost:{}", port);
|
||||||
|
|
||||||
|
mock.createBucket(convert(bucketCouchbase));
|
||||||
|
mock.createBucket(convert(bucketMemcache));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BucketConfiguration convert(BucketSettings bucketSettings) {
|
||||||
|
BucketConfiguration configuration = new BucketConfiguration();
|
||||||
|
configuration.name = bucketSettings.name();
|
||||||
|
configuration.password = bucketSettings.password();
|
||||||
|
configuration.type = Bucket.BucketType.valueOf(bucketSettings.type().name());
|
||||||
|
configuration.numNodes = 1;
|
||||||
|
configuration.numReplicas = 0;
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
void cleanUp() {
|
||||||
|
mock.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
EnvBuilder envBuilder, BucketSettings bucketSettings) {
|
||||||
|
return envBuilder.apply(bucketSettings, mock.getCarrierPort(bucketSettings.name()), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract DefaultCouchbaseEnvironment.Builder envBuilder(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort);
|
||||||
|
|
||||||
|
protected DefaultCouchbaseEnvironment.Builder envBuilder(BucketSettings bucketSettings) {
|
||||||
|
return envBuilder(this::envBuilder, bucketSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface EnvBuilder {
|
||||||
|
DefaultCouchbaseEnvironment.Builder apply(
|
||||||
|
BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SpanDataAssert assertCouchbaseSpan(SpanDataAssert span, String operation) {
|
||||||
|
return assertCouchbaseSpan(span, operation, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SpanDataAssert assertCouchbaseSpan(
|
||||||
|
SpanDataAssert span, String operation, String bucketName) {
|
||||||
|
return assertCouchbaseSpan(span, operation, operation, bucketName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SpanDataAssert assertCouchbaseSpan(
|
||||||
|
SpanDataAssert span, String spanName, String operation, String bucketName, String statement) {
|
||||||
|
span.hasName(spanName).hasKind(SpanKind.CLIENT);
|
||||||
|
|
||||||
|
List<AttributeAssertion> assertions = new ArrayList<>();
|
||||||
|
assertions.add(
|
||||||
|
equalTo(DbIncubatingAttributes.DB_SYSTEM, DbIncubatingAttributes.DbSystemValues.COUCHBASE));
|
||||||
|
if (operation != null) {
|
||||||
|
assertions.add(equalTo(DbIncubatingAttributes.DB_OPERATION, operation));
|
||||||
|
}
|
||||||
|
if (bucketName != null) {
|
||||||
|
assertions.add(equalTo(DbIncubatingAttributes.DB_NAME, bucketName));
|
||||||
|
}
|
||||||
|
if (statement != null) {
|
||||||
|
assertions.add(satisfies(DbIncubatingAttributes.DB_STATEMENT, s -> s.startsWith(statement)));
|
||||||
|
}
|
||||||
|
assertions.addAll(couchbaseAttributes());
|
||||||
|
|
||||||
|
span.hasAttributesSatisfyingExactly(assertions);
|
||||||
|
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<AttributeAssertion> couchbaseAttributes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase.springdata;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.Cluster;
|
||||||
|
import com.couchbase.client.java.CouchbaseCluster;
|
||||||
|
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||||
|
import com.couchbase.client.java.view.DefaultView;
|
||||||
|
import com.couchbase.client.java.view.DesignDocument;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
|
||||||
|
public abstract class AbstractCouchbaseSpringRepositoryTest extends AbstractCouchbaseTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext applicationContext;
|
||||||
|
private TestRepository repository;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
void setUp() {
|
||||||
|
CouchbaseEnvironment environment = envBuilder(bucketCouchbase).build();
|
||||||
|
Cluster couchbaseCluster =
|
||||||
|
CouchbaseCluster.create(environment, Collections.singletonList("127.0.0.1"));
|
||||||
|
|
||||||
|
// Create view for SpringRepository's findAll()
|
||||||
|
couchbaseCluster
|
||||||
|
.openBucket(bucketCouchbase.name(), bucketCouchbase.password())
|
||||||
|
.bucketManager()
|
||||||
|
.insertDesignDocument(
|
||||||
|
DesignDocument.create(
|
||||||
|
"testDocument",
|
||||||
|
Collections.singletonList(
|
||||||
|
DefaultView.create(
|
||||||
|
"all",
|
||||||
|
"function (doc, meta) {"
|
||||||
|
+ " if (doc._class == \"io.opentelemetry.instrumentation.couchbase.springdata.TestDocument\") {"
|
||||||
|
+ " emit(meta.id, null);"
|
||||||
|
+ " }"
|
||||||
|
+ "}"))));
|
||||||
|
CouchbaseConfig.environment = environment;
|
||||||
|
CouchbaseConfig.bucketSettings = bucketCouchbase;
|
||||||
|
|
||||||
|
// Close all buckets and disconnect
|
||||||
|
couchbaseCluster.disconnect();
|
||||||
|
|
||||||
|
applicationContext = new AnnotationConfigApplicationContext(CouchbaseConfig.class);
|
||||||
|
repository = applicationContext.getBean(TestRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void cleanUpTest() {
|
||||||
|
testing.clearData();
|
||||||
|
repository.deleteAll();
|
||||||
|
testing.waitForTraces(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
void cleanUp() {
|
||||||
|
applicationContext.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract TestDocument findById(TestRepository repository, String id);
|
||||||
|
|
||||||
|
protected abstract void deleteById(TestRepository repository, String id);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emptyRepo() {
|
||||||
|
Iterable<TestDocument> result = repository.findAll();
|
||||||
|
|
||||||
|
assertThat(result.iterator().hasNext()).isFalse();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(
|
||||||
|
span,
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
null,
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
"ViewQuery(testDocument/all)")
|
||||||
|
.hasNoParent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void save() {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
TestDocument result = repository.save(document);
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo(document);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketCouchbase.name())
|
||||||
|
.hasNoParent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveAndRetrieve() {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
TestDocument result =
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
repository.save(document);
|
||||||
|
return findById(repository, "1");
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo(document);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.get", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveAndUpdate() {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
repository.save(document);
|
||||||
|
document.setData("other data");
|
||||||
|
repository.save(document);
|
||||||
|
});
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveAndDelete() {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
boolean found =
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
repository.save(document);
|
||||||
|
deleteById(repository, "1");
|
||||||
|
return repository.findAll().iterator().hasNext();
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(found).isFalse();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.remove", bucketCouchbase.name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(
|
||||||
|
span,
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
null,
|
||||||
|
bucketCouchbase.name(),
|
||||||
|
"ViewQuery(testDocument/all)")
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase.springdata;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Named.named;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.Bucket;
|
||||||
|
import com.couchbase.client.java.Cluster;
|
||||||
|
import com.couchbase.client.java.CouchbaseCluster;
|
||||||
|
import com.couchbase.client.java.cluster.ClusterManager;
|
||||||
|
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||||
|
|
||||||
|
public abstract class AbstractCouchbaseSpringTemplateTest extends AbstractCouchbaseTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
private static final List<AutoCloseable> cleanup = new ArrayList<>();
|
||||||
|
private static CouchbaseTemplate couchbaseTemplate;
|
||||||
|
private static CouchbaseTemplate memcacheTemplate;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
void setUp() {
|
||||||
|
CouchbaseEnvironment couchbaseEnvironment = envBuilder(bucketCouchbase).build();
|
||||||
|
CouchbaseEnvironment memcacheEnvironment = envBuilder(bucketMemcache).build();
|
||||||
|
|
||||||
|
Cluster couchbaseCluster =
|
||||||
|
CouchbaseCluster.create(couchbaseEnvironment, Collections.singletonList("127.0.0.1"));
|
||||||
|
Cluster memcacheCluster =
|
||||||
|
CouchbaseCluster.create(memcacheEnvironment, Collections.singletonList("127.0.0.1"));
|
||||||
|
ClusterManager couchbaseManager = couchbaseCluster.clusterManager(USERNAME, PASSWORD);
|
||||||
|
ClusterManager memcacheManager = memcacheCluster.clusterManager(USERNAME, PASSWORD);
|
||||||
|
|
||||||
|
Bucket couchbaseBucket =
|
||||||
|
couchbaseCluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password());
|
||||||
|
Bucket memcacheBucket =
|
||||||
|
memcacheCluster.openBucket(bucketMemcache.name(), bucketMemcache.password());
|
||||||
|
|
||||||
|
cleanup.add(couchbaseBucket::close);
|
||||||
|
cleanup.add(memcacheBucket::close);
|
||||||
|
cleanup.add(couchbaseCluster::disconnect);
|
||||||
|
cleanup.add(memcacheCluster::disconnect);
|
||||||
|
cleanup.add(couchbaseEnvironment::shutdown);
|
||||||
|
cleanup.add(memcacheEnvironment::shutdown);
|
||||||
|
|
||||||
|
testing.runWithSpan(
|
||||||
|
"getting info",
|
||||||
|
() -> {
|
||||||
|
couchbaseTemplate = new CouchbaseTemplate(couchbaseManager.info(), couchbaseBucket);
|
||||||
|
memcacheTemplate = new CouchbaseTemplate(memcacheManager.info(), memcacheBucket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
void cleanUp() throws Exception {
|
||||||
|
for (AutoCloseable closeable : cleanup) {
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> templates() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(named(bucketCouchbase.type().name(), couchbaseTemplate)),
|
||||||
|
Arguments.of(named(bucketMemcache.type().name(), memcacheTemplate)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("templates")
|
||||||
|
void write(CouchbaseTemplate template) {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
TestDocument result =
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
template.save(document);
|
||||||
|
return template.findById("1", TestDocument.class);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", template.getCouchbaseBucket().name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.get", template.getCouchbaseBucket().name())
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("templates")
|
||||||
|
void remove(CouchbaseTemplate template) {
|
||||||
|
TestDocument document = new TestDocument();
|
||||||
|
testing.runWithSpan(
|
||||||
|
"someTrace",
|
||||||
|
() -> {
|
||||||
|
template.save(document);
|
||||||
|
template.remove(document);
|
||||||
|
});
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span -> span.hasName("someTrace").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.upsert", template.getCouchbaseBucket().name())
|
||||||
|
.hasParent(trace.getSpan(0)),
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.remove", template.getCouchbaseBucket().name())
|
||||||
|
.hasParent(trace.getSpan(0))));
|
||||||
|
|
||||||
|
testing.clearData();
|
||||||
|
|
||||||
|
TestDocument result = template.findById("1", TestDocument.class);
|
||||||
|
assertThat(result).isNull();
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
assertCouchbaseSpan(span, "Bucket.get", template.getCouchbaseBucket().name())
|
||||||
|
.hasNoParent()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase.springdata;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import com.couchbase.client.java.cluster.BucketSettings;
|
||||||
|
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||||
|
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableCouchbaseRepositories(basePackages = "io.opentelemetry.instrumentation.couchbase.springdata")
|
||||||
|
@ComponentScan(basePackages = "io.opentelemetry.instrumentation.couchbase.springdata")
|
||||||
|
class CouchbaseConfig extends AbstractCouchbaseConfiguration {
|
||||||
|
|
||||||
|
// These need to be set before this class can be used by Spring
|
||||||
|
static CouchbaseEnvironment environment;
|
||||||
|
static BucketSettings bucketSettings;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CouchbaseEnvironment getEnvironment() {
|
||||||
|
return requireNonNull(environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getBootstrapHosts() {
|
||||||
|
return Collections.singletonList("127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBucketName() {
|
||||||
|
return bucketSettings.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBucketPassword() {
|
||||||
|
return bucketSettings.password();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase.springdata;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.couchbase.core.mapping.Document;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class TestDocument {
|
||||||
|
@Id private String id = "1";
|
||||||
|
private String data = "some data";
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(object instanceof TestDocument)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TestDocument doc = (TestDocument) object;
|
||||||
|
return Objects.equals(id, doc.id) && Objects.equals(data, doc.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.couchbase.springdata;
|
||||||
|
|
||||||
|
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||||
|
|
||||||
|
public interface TestRepository extends CouchbaseRepository<TestDocument, String> {}
|
Loading…
Reference in New Issue