opentelemetry-java-instrume.../instrumentation/mongo/mongo-async-3.3/src/test/groovy/MongoAsyncClientTest.groovy

315 lines
9.9 KiB
Groovy

/*
* Copyright 2020, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.mongodb.ConnectionString
import com.mongodb.async.SingleResultCallback
import com.mongodb.async.client.MongoClient
import com.mongodb.async.client.MongoClientSettings
import com.mongodb.async.client.MongoClients
import com.mongodb.async.client.MongoCollection
import com.mongodb.async.client.MongoDatabase
import com.mongodb.client.result.DeleteResult
import com.mongodb.client.result.UpdateResult
import com.mongodb.connection.ClusterSettings
import io.opentelemetry.auto.instrumentation.api.MoreTags
import io.opentelemetry.auto.instrumentation.api.SpanTypes
import io.opentelemetry.auto.instrumentation.api.Tags
import io.opentelemetry.auto.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.SpanData
import org.bson.BsonDocument
import org.bson.BsonString
import org.bson.Document
import spock.lang.Shared
import spock.lang.Timeout
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CountDownLatch
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
import static io.opentelemetry.trace.Span.Kind.CLIENT
@Timeout(10)
class MongoAsyncClientTest extends MongoBaseTest {
@Shared
MongoClient client
def setup() throws Exception {
client = MongoClients.create(
MongoClientSettings.builder()
.clusterSettings(
ClusterSettings.builder()
.description("some-description")
.applyConnectionString(new ConnectionString("mongodb://localhost:$port"))
.build())
.build())
}
def cleanup() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName, toCallback {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test create collection no description"() {
setup:
MongoDatabase db = MongoClients.create("mongodb://localhost:$port").getDatabase(dbName)
when:
db.createCollection(collectionName, toCallback {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, {
assert it.replaceAll(" ", "") == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}, dbName)
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test get collection"() {
setup:
MongoDatabase db = client.getDatabase(dbName)
when:
def count = new CompletableFuture()
db.getCollection(collectionName).count toCallback { count.complete(it) }
then:
count.get() == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
db.createCollection(collectionName, toCallback { latch1.countDown() })
latch1.await()
return db.getCollection(collectionName)
}
TEST_WRITER.waitForTraces(1)
TEST_WRITER.clear()
when:
def count = new CompletableFuture()
collection.insertOne(new Document("password", "SECRET"), toCallback {
collection.count toCallback { count.complete(it) }
})
then:
count.get() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}" ||
it == "{\"insert\": \"$collectionName\", \"ordered\": \"?\", \"\$db\": \"?\", \"documents\": [{\"_id\": \"?\", \"password\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
db.createCollection(collectionName, toCallback { latch1.countDown() })
latch1.await()
def coll = db.getCollection(collectionName)
def latch2 = new CountDownLatch(1)
coll.insertOne(new Document("password", "OLDPW"), toCallback { latch2.countDown() })
latch2.await()
return coll
}
TEST_WRITER.waitForTraces(1)
TEST_WRITER.clear()
when:
def result = new CompletableFuture<UpdateResult>()
def count = new CompletableFuture()
collection.updateOne(
new BsonDocument("password", new BsonString("OLDPW")),
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))), toCallback {
result.complete(it)
collection.count toCallback { count.complete(it) }
})
then:
result.get().modifiedCount == 1
count.get() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"update\":\"?\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
db.createCollection(collectionName, toCallback { latch1.countDown() })
latch1.await()
def coll = db.getCollection(collectionName)
def latch2 = new CountDownLatch(1)
coll.insertOne(new Document("password", "SECRET"), toCallback { latch2.countDown() })
latch2.await()
return coll
}
TEST_WRITER.waitForTraces(1)
TEST_WRITER.clear()
when:
def result = new CompletableFuture<DeleteResult>()
def count = new CompletableFuture()
collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")), toCallback {
result.complete(it)
collection.count toCallback { count.complete(it) }
})
then:
result.get().deletedCount == 1
count.get() == 0
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"delete\":\"?\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
SingleResultCallback toCallback(Closure closure) {
return new SingleResultCallback() {
@Override
void onResult(Object result, Throwable t) {
if (t) {
closure.call(t)
} else {
closure.call(result)
}
}
}
}
def mongoSpan(TraceAssert trace, int index, Closure<Boolean> statementEval, String instance = "some-description", Object parentSpan = null, Throwable exception = null) {
trace.span(index) {
operationName "mongo.query"
spanKind CLIENT
if (parentSpan == null) {
parent()
} else {
childOf((SpanData) parentSpan)
}
tags {
"$MoreTags.SERVICE_NAME" "mongo"
"$MoreTags.RESOURCE_NAME" statementEval
"$MoreTags.SPAN_TYPE" SpanTypes.MONGO
"$Tags.COMPONENT" "java-mongo"
"$MoreTags.NET_PEER_NAME" "localhost"
"$MoreTags.NET_PEER_IP" "127.0.0.1"
"$MoreTags.NET_PEER_PORT" port
"$Tags.DB_STATEMENT" statementEval
"$Tags.DB_TYPE" "mongo"
"$Tags.DB_INSTANCE" instance
}
}
}
}