From 7ecc6788668ef9278d2daee3ed801dcdaaaece79 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 12 Sep 2024 18:29:02 +0300 Subject: [PATCH] Convert couchbase tests to java (#12193) --- .../couchbase-2.0/javaagent/build.gradle.kts | 5 +- .../v2_0/CouchbaseInstrumentationModule.java | 5 + .../groovy/CouchbaseAsyncClientTest.groovy | 7 - .../test/groovy/CouchbaseClientTest.groovy | 7 - .../CouchbaseSpringRepositoryTest.groovy | 9 - .../CouchbaseSpringTemplateTest.groovy | 9 - .../v2_0/CouchbaseAsyncClientTest.java | 19 ++ .../couchbase/v2_0/CouchbaseClientTest.java | 19 ++ .../couchbase/v2_0/CouchbaseUtil.java | 41 +++ .../CouchbaseSpringRepositoryTest.java | 32 +++ .../CouchbaseSpringTemplateTest.java | 20 ++ .../v2_6/CouchbaseInstrumentationModule.java | 10 +- .../groovy/CouchbaseAsyncClient26Test.groovy | 21 -- .../test/groovy/CouchbaseClient26Test.groovy | 20 -- .../src/test/groovy/CouchbaseSpanUtil.groovy | 52 ---- .../CouchbaseSpringRepository26Test.groovy | 23 -- .../CouchbaseSpringTemplate26Test.groovy | 22 -- .../couchbase/v2_6/Couchbase26Util.java | 61 +++++ .../v2_6/CouchbaseAsyncClient26Test.java | 26 ++ .../couchbase/v2_6/CouchbaseClient26Test.java | 26 ++ .../CouchbaseSpringRepository26Test.java | 39 +++ .../CouchbaseSpringTemplate26Test.java | 27 ++ .../test/groovy/CouchbaseClient316Test.groovy | 74 ------ .../v3_1_6/CouchbaseClient316Test.java | 90 +++++++ .../AbstractCouchbaseAsyncClientTest.groovy | 187 -------------- .../groovy/AbstractCouchbaseClientTest.groovy | 123 --------- ...stractCouchbaseSpringRepositoryTest.groovy | 202 --------------- ...AbstractCouchbaseSpringTemplateTest.groovy | 136 ---------- .../groovy/springdata/CouchbaseConfig.groovy | 46 ---- .../src/main/groovy/springdata/Doc.groovy | 34 --- .../groovy/springdata/DocRepository.groovy | 10 - .../groovy/util/AbstractCouchbaseTest.groovy | 130 ---------- .../AbstractCouchbaseAsyncClientTest.java | 236 ++++++++++++++++++ .../AbstractCouchbaseClientTest.java | 159 ++++++++++++ .../couchbase/AbstractCouchbaseTest.java | 143 +++++++++++ ...AbstractCouchbaseSpringRepositoryTest.java | 198 +++++++++++++++ .../AbstractCouchbaseSpringTemplateTest.java | 146 +++++++++++ .../couchbase/springdata/CouchbaseConfig.java | 47 ++++ .../couchbase/springdata/TestDocument.java | 49 ++++ .../couchbase/springdata/TestRepository.java | 10 + 40 files changed, 1405 insertions(+), 1115 deletions(-) delete mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseAsyncClientTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseClientTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringRepositoryTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplateTest.groovy create mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java create mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java create mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java create mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java create mode 100644 instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java delete mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseAsyncClient26Test.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseClient26Test.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseSpanUtil.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringRepository26Test.groovy delete mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplate26Test.groovy create mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java create mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java create mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java create mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java create mode 100644 instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java delete mode 100644 instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/groovy/CouchbaseClient316Test.groovy create mode 100644 instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseAsyncClientTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseClientTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringRepositoryTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringTemplateTest.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/CouchbaseConfig.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/Doc.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/DocRepository.groovy delete mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/groovy/util/AbstractCouchbaseTest.groovy create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringRepositoryTest.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringTemplateTest.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/CouchbaseConfig.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestDocument.java create mode 100644 instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestRepository.java diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts index a8817b8995..d6504dc00f 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts @@ -26,8 +26,9 @@ dependencies { testImplementation(project(":instrumentation:couchbase:couchbase-common:testing")) - latestDepTestLibrary("org.springframework.data:spring-data-couchbase:3.+") - latestDepTestLibrary("com.couchbase.client:java-client:2.+") + // later versions are tested with couchbase-2.6 instrumentation + latestDepTestLibrary("org.springframework.data:spring-data-couchbase:2.+") + latestDepTestLibrary("com.couchbase.client:java-client:2.5.+") } tasks.withType().configureEach { diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseInstrumentationModule.java index 8c2889870c..363a608666 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseInstrumentationModule.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseInstrumentationModule.java @@ -32,6 +32,11 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule return asList(new CouchbaseBucketInstrumentation(), new CouchbaseClusterInstrumentation()); } + @Override + public String getModuleGroup() { + return "couchbase"; + } + @Override public List injectedClassNames() { return singletonList("rx.__OpenTelemetryTracingUtil"); diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseAsyncClientTest.groovy b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseAsyncClientTest.groovy deleted file mode 100644 index 43b302320f..0000000000 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseAsyncClientTest.groovy +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -class CouchbaseAsyncClientTest extends AbstractCouchbaseAsyncClientTest { -} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseClientTest.groovy b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseClientTest.groovy deleted file mode 100644 index aed568b0b0..0000000000 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/CouchbaseClientTest.groovy +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -class CouchbaseClientTest extends AbstractCouchbaseClientTest { -} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringRepositoryTest.groovy b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringRepositoryTest.groovy deleted file mode 100644 index b59b287da5..0000000000 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringRepositoryTest.groovy +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package springdata - -class CouchbaseSpringRepositoryTest extends AbstractCouchbaseSpringRepositoryTest { -} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplateTest.groovy b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplateTest.groovy deleted file mode 100644 index 3f355463f0..0000000000 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplateTest.groovy +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package springdata - -class CouchbaseSpringTemplateTest extends AbstractCouchbaseSpringTemplateTest { -} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java new file mode 100644 index 0000000000..a28658223a --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java @@ -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); + } +} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java new file mode 100644 index 0000000000..0890358a8e --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java @@ -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); + } +} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java new file mode 100644 index 0000000000..97a746fe0f --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java @@ -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() {} +} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java new file mode 100644 index 0000000000..db5ba3d313 --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java @@ -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); + } +} diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java new file mode 100644 index 0000000000..3f4c193bd7 --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java @@ -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); + } +} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseInstrumentationModule.java index 2ff3f09375..aa9ba653af 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseInstrumentationModule.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseInstrumentationModule.java @@ -10,10 +10,13 @@ import static java.util.Arrays.asList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; import java.util.List; @AutoService(InstrumentationModule.class) -public class CouchbaseInstrumentationModule extends InstrumentationModule { +public class CouchbaseInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { + public CouchbaseInstrumentationModule() { super("couchbase", "couchbase-2.6"); } @@ -22,4 +25,9 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return asList(new CouchbaseCoreInstrumentation(), new CouchbaseNetworkInstrumentation()); } + + @Override + public String getModuleGroup() { + return "couchbase"; + } } diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseAsyncClient26Test.groovy b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseAsyncClient26Test.groovy deleted file mode 100644 index fcb0e592db..0000000000 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseAsyncClient26Test.groovy +++ /dev/null @@ -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) - } -} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseClient26Test.groovy b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseClient26Test.groovy deleted file mode 100644 index 3b83151eec..0000000000 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseClient26Test.groovy +++ /dev/null @@ -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) - } -} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseSpanUtil.groovy b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseSpanUtil.groovy deleted file mode 100644 index 0686c76da4..0000000000 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/CouchbaseSpanUtil.groovy +++ /dev/null @@ -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 } - } - } - } -} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringRepository26Test.groovy b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringRepository26Test.groovy deleted file mode 100644 index 090caad318..0000000000 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringRepository26Test.groovy +++ /dev/null @@ -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) - } -} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplate26Test.groovy b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplate26Test.groovy deleted file mode 100644 index cad4310b62..0000000000 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/groovy/springdata/CouchbaseSpringTemplate26Test.groovy +++ /dev/null @@ -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) - } -} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java new file mode 100644 index 0000000000..f884a4857e --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java @@ -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 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() {} +} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java new file mode 100644 index 0000000000..8257d7014e --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java @@ -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 couchbaseAttributes() { + return Couchbase26Util.couchbaseAttributes(); + } +} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java new file mode 100644 index 0000000000..65ace4b6f3 --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java @@ -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 couchbaseAttributes() { + return Couchbase26Util.couchbaseAttributes(); + } +} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java new file mode 100644 index 0000000000..8f1765ad68 --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java @@ -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 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); + } +} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java new file mode 100644 index 0000000000..cb7e4a1d97 --- /dev/null +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java @@ -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 couchbaseAttributes() { + return Couchbase26Util.couchbaseAttributes(); + } +} diff --git a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/groovy/CouchbaseClient316Test.groovy b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/groovy/CouchbaseClient316Test.groovy deleted file mode 100644 index cd81dcb5f8..0000000000 --- a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/groovy/CouchbaseClient316Test.groovy +++ /dev/null @@ -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() - } -} diff --git a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java new file mode 100644 index 0000000000..59a0a49f0f --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java @@ -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"))); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseAsyncClientTest.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseAsyncClientTest.groovy deleted file mode 100644 index d5171ef338..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseAsyncClientTest.groovy +++ /dev/null @@ -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(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(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(TIMEOUT) - def found = new BlockingVariable(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(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() - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseClientTest.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseClientTest.groovy deleted file mode 100644 index fa8ca138ba..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/AbstractCouchbaseClientTest.groovy +++ /dev/null @@ -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() - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringRepositoryTest.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringRepositoryTest.groovy deleted file mode 100644 index 62673821ed..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringRepositoryTest.groovy +++ /dev/null @@ -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 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 }) - } - } - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringTemplateTest.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringTemplateTest.groovy deleted file mode 100644 index bbd5a864e8..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/AbstractCouchbaseSpringTemplateTest.groovy +++ /dev/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 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() - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/CouchbaseConfig.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/CouchbaseConfig.groovy deleted file mode 100644 index 88c5d24783..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/CouchbaseConfig.groovy +++ /dev/null @@ -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 getBootstrapHosts() { - return Collections.singletonList("127.0.0.1") - } - - @Override - protected String getBucketName() { - return bucketSettings.name() - } - - @Override - protected String getBucketPassword() { - return bucketSettings.password() - } - -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/Doc.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/Doc.groovy deleted file mode 100644 index 4ae0b77079..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/Doc.groovy +++ /dev/null @@ -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 - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/DocRepository.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/DocRepository.groovy deleted file mode 100644 index 520befd4af..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/springdata/DocRepository.groovy +++ /dev/null @@ -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 {} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/util/AbstractCouchbaseTest.groovy b/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/util/AbstractCouchbaseTest.groovy deleted file mode 100644 index e669562f19..0000000000 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/groovy/util/AbstractCouchbaseTest.groovy +++ /dev/null @@ -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) - } - } - } -} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java new file mode 100644 index 0000000000..fe917fa613 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java @@ -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 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 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 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 inserted = new CompletableFuture<>(); + CompletableFuture 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 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)))); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java new file mode 100644 index 0000000000..d0ea69c2cc --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java @@ -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 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 inserted = new AtomicReference<>(); + AtomicReference 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())); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java new file mode 100644 index 0000000000..0e1abd2d90 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java @@ -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 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 couchbaseAttributes() { + return Collections.emptyList(); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringRepositoryTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringRepositoryTest.java new file mode 100644 index 0000000000..426d912190 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringRepositoryTest.java @@ -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 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)))); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringTemplateTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringTemplateTest.java new file mode 100644 index 0000000000..c0c4c2eaa7 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/AbstractCouchbaseSpringTemplateTest.java @@ -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 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 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())); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/CouchbaseConfig.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/CouchbaseConfig.java new file mode 100644 index 0000000000..e324fc1838 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/CouchbaseConfig.java @@ -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 getBootstrapHosts() { + return Collections.singletonList("127.0.0.1"); + } + + @Override + protected String getBucketName() { + return bucketSettings.name(); + } + + @Override + protected String getBucketPassword() { + return bucketSettings.password(); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestDocument.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestDocument.java new file mode 100644 index 0000000000..af594c13a6 --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestDocument.java @@ -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); + } +} diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestRepository.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestRepository.java new file mode 100644 index 0000000000..467deb16bf --- /dev/null +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/springdata/TestRepository.java @@ -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 {}