Cleanup mongodb tests (#2732)

* Cleanup mongodb tests

* Drift

* Cleanup

* Timeout

* Cleanup
This commit is contained in:
Anuraag Agrawal 2021-04-07 14:02:56 +09:00 committed by GitHub
parent d8f6018ba6
commit 826d8ac781
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 515 additions and 948 deletions

View File

@ -17,135 +17,63 @@ import org.bson.BsonString
import org.bson.Document
import spock.lang.Shared
class MongoClientTest extends MongoBaseTest {
class MongoClientTest extends AbstractMongoClientTest {
@Shared
MongoClient client
def setup() throws Exception {
def setupSpec() throws Exception {
client = new MongoClient(new ServerAddress("localhost", port),
MongoClientOptions.builder()
.description("some-description")
.build())
}
def cleanup() throws Exception {
def cleanupSpec() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
@Override
void createCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void createCollectionNoDescription(String dbName, String collectionName) {
MongoDatabase db = new MongoClient("localhost", port).getDatabase(dbName)
db.createCollection(collectionName)
}
// Tests the fix for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/457
// TracingCommandListener might get added multiple times if clientOptions are built using existing clientOptions or when calling a build method twice.
// This test asserts that duplicate traces are not created in those cases.
def "test create collection with already built ClientOptions"() {
setup:
@Override
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
def clientOptions = client.mongoClientOptions
def newClientOptions = MongoClientOptions.builder(clientOptions).build()
MongoDatabase db = new MongoClient(new ServerAddress("localhost", port), newClientOptions).getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test create collection no description"() {
setup:
MongoDatabase db = new MongoClient("localhost", port).getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test get collection"() {
setup:
@Override
int getCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
int count = db.getCollection(collectionName).count()
then:
count == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return db.getCollection(collectionName).count()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
@Override
int insert(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.insertOne(new Document("password", "SECRET"))
then:
collection.count() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "insert", collectionName, dbName, "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return collection.count()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
@Override
int update(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -154,31 +82,15 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.updateOne(
new BsonDocument("password", new BsonString("OLDPW")),
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))))
then:
result.modifiedCount == 1
collection.count() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.count()
return result.modifiedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
@Override
int delete(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -187,29 +99,13 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")))
then:
result.deletedCount == 1
collection.count() == 0
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.count()
return result.deletedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test collection name for getMore command"() {
setup:
@Override
void getMore(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def coll = db.getCollection(collectionName)
@ -217,46 +113,19 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
collection.find().filter(new Document("_id", new Document('$gte', 0)))
.batchSize(2).into(new ArrayList())
then:
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "find", collectionName, dbName, '{"find":"testCollection","filter":{"_id":{"$gte":"?"}},"batchSize":"?"}')
}
trace(1, 1) {
mongoSpan(it, 0, "getMore", collectionName, dbName, '{"getMore":"?","collection":"?","batchSize":"?"}')
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test error"() {
setup:
@Override
void error(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.updateOne(new BsonDocument(), new BsonDocument())
then:
thrown(IllegalArgumentException)
// Unfortunately not caught by our instrumentation.
assertTraces(0) {}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test client failure"() {
@ -275,6 +144,6 @@ class MongoClientTest extends MongoBaseTest {
where:
dbName = "test_db"
collectionName = "testCollection"
collectionName = createCollectionName()
}
}

View File

@ -18,12 +18,12 @@ import org.bson.BsonString
import org.bson.Document
import spock.lang.Shared
class MongoClientTest extends MongoBaseTest {
class MongoClientTest extends AbstractMongoClientTest {
@Shared
MongoClient client
def setup() throws Exception {
def setupSpec() throws Exception {
client = MongoClients.create(MongoClientSettings.builder()
.applyToClusterSettings({ builder ->
builder.hosts(Arrays.asList(
@ -33,35 +33,25 @@ class MongoClientTest extends MongoBaseTest {
.build())
}
def cleanup() throws Exception {
def cleanupSpec() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
@Override
void createCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void createCollectionNoDescription(String dbName, String collectionName) {
MongoDatabase db = MongoClients.create("mongodb://localhost:${port}").getDatabase(dbName)
db.createCollection(collectionName)
}
// Tests the fix for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/457
// TracingCommandListener might get added multiple times if ClientSettings are built using existing ClientSettings or when calling a build method twice.
// This test asserts that duplicate traces are not created in those cases.
def "test create collection with already built ClientSettings"() {
setup:
@Override
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
def clientSettings = MongoClientSettings.builder()
.applyToClusterSettings({ builder ->
builder.hosts(Arrays.asList(
@ -71,91 +61,29 @@ class MongoClientTest extends MongoBaseTest {
.build()
def newClientSettings = MongoClientSettings.builder(clientSettings).build()
MongoDatabase db = MongoClients.create(newClientSettings).getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
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)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test get collection"() {
setup:
@Override
int getCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
int count = db.getCollection(collectionName).count()
then:
count == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return db.getCollection(collectionName).count()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
@Override
int insert(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.insertOne(new Document("password", "SECRET"))
then:
collection.count() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "insert", collectionName, dbName, "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return collection.count()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
@Override
int update(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -164,31 +92,15 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.updateOne(
new BsonDocument("password", new BsonString("OLDPW")),
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))))
then:
result.modifiedCount == 1
collection.count() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.count()
return result.modifiedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
@Override
int delete(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -197,29 +109,13 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")))
then:
result.deletedCount == 1
collection.count() == 0
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.count()
return result.deletedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test collection name for getMore command"() {
setup:
@Override
void getMore(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def coll = db.getCollection(collectionName)
@ -227,46 +123,19 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
collection.find().filter(new Document("_id", new Document('$gte', 0)))
.batchSize(2).into(new ArrayList())
then:
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "find", collectionName, dbName, '{"find":"testCollection","filter":{"_id":{"$gte":"?"}},"batchSize":"?"}')
}
trace(1, 1) {
mongoSpan(it, 0, "getMore", collectionName, dbName, '{"getMore":"?","collection":"?","batchSize":"?"}')
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test error"() {
setup:
@Override
void error(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.updateOne(new BsonDocument(), new BsonDocument())
then:
thrown(IllegalArgumentException)
// Unfortunately not caught by our instrumentation.
assertTraces(0) {}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test client failure"() {
@ -284,6 +153,6 @@ class MongoClientTest extends MongoBaseTest {
where:
dbName = "test_db"
collectionName = "testCollection"
collectionName = createCollectionName()
}
}

View File

@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
import com.mongodb.client.result.DeleteResult
@ -12,105 +11,57 @@ import com.mongodb.reactivestreams.client.MongoClient
import com.mongodb.reactivestreams.client.MongoClients
import com.mongodb.reactivestreams.client.MongoCollection
import com.mongodb.reactivestreams.client.MongoDatabase
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CountDownLatch
import org.bson.BsonDocument
import org.bson.BsonString
import org.bson.Document
import org.junit.AssumptionViolatedException
import org.reactivestreams.Subscriber
import org.reactivestreams.Subscription
import spock.lang.Shared
class Mongo4ReactiveClientTest extends MongoBaseTest {
class Mongo4ReactiveClientTest extends AbstractMongoClientTest {
@Shared
MongoClient client
def setup() throws Exception {
def setupSpec() throws Exception {
client = MongoClients.create("mongodb://localhost:$port")
}
def cleanup() throws Exception {
def cleanupSpec() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
@Override
void createCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName).subscribe(toSubscriber {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName) {
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:
@Override
void createCollectionNoDescription(String dbName, String collectionName) {
MongoDatabase db = MongoClients.create("mongodb://localhost:${port}").getDatabase(dbName)
db.createCollection(collectionName).subscribe(toSubscriber {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, {
assert it.replaceAll(" ", "") == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
})
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
throw new AssumptionViolatedException("not tested on 4.0")
}
def "test get collection"() {
setup:
@Override
int getCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
def count = new CompletableFuture()
def count = new CompletableFuture<Integer>()
db.getCollection(collectionName).estimatedDocumentCount().subscribe(toSubscriber { count.complete(it) })
then:
count.get() == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return count.join()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
@Override
int insert(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -120,39 +71,15 @@ class Mongo4ReactiveClientTest extends MongoBaseTest {
return db.getCollection(collectionName)
}
ignoreTracesAndClear(2)
when:
def count = new CompletableFuture()
def count = new CompletableFuture<Integer>()
collection.insertOne(new Document("password", "SECRET")).subscribe(toSubscriber {
collection.estimatedDocumentCount().subscribe(toSubscriber { count.complete(it) })
})
then:
count.get() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "insert", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}" ||
it == "{\"insert\": \"$collectionName\", \"ordered\": \"?\", \"\$db\": \"?\", \"documents\": [{\"_id\": \"?\", \"password\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return count.join()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
@Override
int update(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -165,8 +92,6 @@ class Mongo4ReactiveClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = new CompletableFuture<UpdateResult>()
def count = new CompletableFuture()
collection.updateOne(
@ -175,34 +100,11 @@ class Mongo4ReactiveClientTest extends MongoBaseTest {
result.complete(it)
collection.estimatedDocumentCount().subscribe(toSubscriber { count.complete(it) })
})
then:
result.get().modifiedCount == 1
count.get() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "update", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return result.join().modifiedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
@Override
int delete(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -215,38 +117,37 @@ class Mongo4ReactiveClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = new CompletableFuture<DeleteResult>()
def count = new CompletableFuture()
collection.deleteOne(new BsonDocument("password", new BsonString("SECRET"))).subscribe(toSubscriber {
result.complete(it)
collection.estimatedDocumentCount().subscribe(toSubscriber { count.complete(it) })
})
then:
result.get().deletedCount == 1
count.get() == 0
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "delete", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return result.join().deletedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void getMore(String dbName, String collectionName) {
throw new AssumptionViolatedException("not tested on reactive")
}
@Override
void error(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch = new CountDownLatch(1)
db.createCollection(collectionName).subscribe(toSubscriber {
latch.countDown()
})
latch.await()
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
def result = new CompletableFuture<Throwable>()
collection.updateOne(new BsonDocument(), new BsonDocument()).subscribe(toSubscriber {
result.complete(it)
})
throw result.join()
}
def Subscriber<?> toSubscriber(Closure closure) {
@ -273,30 +174,4 @@ class Mongo4ReactiveClientTest extends MongoBaseTest {
}
}
}
def mongoSpan(TraceAssert trace, int index,
String operation, String collection,
String dbName, Closure<Boolean> statementEval,
Object parentSpan = null, Throwable exception = null) {
trace.span(index) {
name { operation + " " + dbName + "." + collection }
kind CLIENT
if (parentSpan == null) {
hasNoParent()
} else {
childOf((SpanData) parentSpan)
}
attributes {
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
"$SemanticAttributes.NET_PEER_PORT.key" port
"$SemanticAttributes.DB_CONNECTION_STRING.key" "mongodb://localhost:" + port
"$SemanticAttributes.DB_STATEMENT.key" statementEval
"$SemanticAttributes.DB_SYSTEM.key" "mongodb"
"$SemanticAttributes.DB_NAME.key" dbName
"$SemanticAttributes.DB_OPERATION.key" operation
"$SemanticAttributes.DB_MONGODB_COLLECTION.key" collection
}
}
}
}

View File

@ -3,10 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import static io.opentelemetry.instrumentation.test.utils.PortUtils.UNUSABLE_PORT
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
import com.mongodb.MongoTimeoutException
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import com.mongodb.client.MongoCollection
@ -14,110 +12,60 @@ import com.mongodb.client.MongoDatabase
import org.bson.BsonDocument
import org.bson.BsonString
import org.bson.Document
import org.junit.AssumptionViolatedException
import spock.lang.Shared
class MongoClientTest extends MongoBaseTest {
class MongoClientTest extends AbstractMongoClientTest {
@Shared
MongoClient client
def setup() throws Exception {
def setupSpec() throws Exception {
client = MongoClients.create("mongodb://localhost:$port")
}
def cleanup() throws Exception {
def cleanupSpec() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
@Override
void createCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test create collection no description"() {
setup:
MongoDatabase db = MongoClients.create("mongodb://localhost:$port").getDatabase(dbName)
when:
@Override
void createCollectionNoDescription(String dbName, String collectionName) {
MongoDatabase db = MongoClients.create("mongodb://localhost:${port}").getDatabase(dbName)
db.createCollection(collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, "{\"create\":\"$collectionName\",\"capped\":\"?\"}")
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
throw new AssumptionViolatedException("not tested on 4.0")
}
def "test get collection"() {
setup:
@Override
int getCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
int count = db.getCollection(collectionName).estimatedDocumentCount()
then:
count == 0
assertTraces(1) {
trace(0,1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return db.getCollection(collectionName).estimatedDocumentCount()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
@Override
int insert(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.insertOne(new Document("password", "SECRET"))
then:
collection.estimatedDocumentCount() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "insert", collectionName, dbName, "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
return collection.estimatedDocumentCount()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
@Override
int update(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -126,31 +74,15 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.updateOne(
new BsonDocument("password", new BsonString("OLDPW")),
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))))
then:
result.modifiedCount == 1
collection.estimatedDocumentCount() == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.estimatedDocumentCount()
return result.modifiedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
@Override
int delete(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
@ -159,65 +91,32 @@ class MongoClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")))
then:
result.deletedCount == 1
collection.estimatedDocumentCount() == 0
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
}
collection.estimatedDocumentCount()
return result.deletedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void getMore(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def coll = db.getCollection(collectionName)
coll.insertMany([new Document("_id", 0), new Document("_id", 1), new Document("_id", 2)])
return coll
}
ignoreTracesAndClear(1)
collection.find().filter(new Document("_id", new Document('$gte', 0)))
.batchSize(2).into(new ArrayList())
}
def "test error"() {
setup:
@Override
void error(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
collection.updateOne(new BsonDocument(), new BsonDocument())
then:
thrown(IllegalArgumentException)
// Unfortunately not caught by our instrumentation.
assertTraces(0) {}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test client failure"() {
setup:
def client = MongoClients.create("mongodb://localhost:$UNUSABLE_PORT/?serverselectiontimeoutms=10")
when:
MongoDatabase db = client.getDatabase(dbName)
db.createCollection(collectionName)
then:
thrown(MongoTimeoutException)
// Unfortunately not caught by our instrumentation.
assertTraces(0) {}
where:
dbName = "test_db"
collectionName = "testCollection"
}
}

View File

@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
import com.mongodb.ConnectionString
@ -16,22 +15,20 @@ 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.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CountDownLatch
import org.bson.BsonDocument
import org.bson.BsonString
import org.bson.Document
import org.junit.AssumptionViolatedException
import spock.lang.Shared
class MongoAsyncClientTest extends MongoBaseTest {
class MongoAsyncClientTest extends AbstractMongoClientTest {
@Shared
MongoClient client
def setup() throws Exception {
def setupSpec() throws Exception {
client = MongoClients.create(
MongoClientSettings.builder()
.clusterSettings(
@ -42,112 +39,41 @@ class MongoAsyncClientTest extends MongoBaseTest {
.build())
}
def cleanup() throws Exception {
def cleanupSpec() throws Exception {
client?.close()
client = null
}
def "test create collection"() {
setup:
@Override
void createCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
db.createCollection(collectionName, toCallback {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void createCollectionNoDescription(String dbName, String collectionName) {
MongoDatabase db = MongoClients.create("mongodb://localhost:$port").getDatabase(dbName)
db.createCollection(collectionName, toCallback {})
}
// Tests the fix for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/457
// TracingCommandListener might get added multiple times if ClientSettings are built using existing ClientSettings or when calling a build method twice.
// This test asserts that duplicate traces are not created in those cases.
def "test create collection with already built ClientSettings"() {
setup:
@Override
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
def clientSettings = client.settings
def newClientSettings = MongoClientSettings.builder(clientSettings).build()
MongoDatabase db = MongoClients.create(newClientSettings).getDatabase(dbName)
when:
db.createCollection(collectionName, toCallback {})
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName) {
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, "create", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test get collection"() {
setup:
@Override
int getCollection(String dbName, String collectionName) {
MongoDatabase db = client.getDatabase(dbName)
when:
def count = new CompletableFuture()
def count = new CompletableFuture<Integer>()
db.getCollection(collectionName).count toCallback { count.complete(it) }
then:
count.get() == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return count.join()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test insert"() {
setup:
@Override
int insert(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -156,39 +82,15 @@ class MongoAsyncClientTest extends MongoBaseTest {
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
when:
def count = new CompletableFuture()
def count = new CompletableFuture<Integer>()
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, "insert", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}" ||
it == "{\"insert\": \"$collectionName\", \"ordered\": \"?\", \"\$db\": \"?\", \"documents\": [{\"_id\": \"?\", \"password\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return count.get()
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test update"() {
setup:
@Override
int update(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -201,8 +103,6 @@ class MongoAsyncClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
when:
def result = new CompletableFuture<UpdateResult>()
def count = new CompletableFuture()
collection.updateOne(
@ -211,34 +111,11 @@ class MongoAsyncClientTest extends MongoBaseTest {
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, "update", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return result.get().modifiedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
}
def "test delete"() {
setup:
@Override
int delete(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch1 = new CountDownLatch(1)
@ -251,38 +128,37 @@ class MongoAsyncClientTest extends MongoBaseTest {
return coll
}
ignoreTracesAndClear(1)
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, "delete", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it.replaceAll(" ", "") == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
return result.get().deletedCount
}
where:
dbName = "test_db"
collectionName = "testCollection"
@Override
void getMore(String dbName, String collectionName) {
throw new AssumptionViolatedException("not tested on async")
}
@Override
void error(String dbName, String collectionName) {
MongoCollection<Document> collection = runUnderTrace("setup") {
MongoDatabase db = client.getDatabase(dbName)
def latch = new CountDownLatch(1)
db.createCollection(collectionName, toCallback {
latch.countDown()
})
latch.await()
return db.getCollection(collectionName)
}
ignoreTracesAndClear(1)
def result = new CompletableFuture<Throwable>()
collection.updateOne(new BsonDocument(), new BsonDocument(), toCallback {
result.complete(it)
})
throw result.join()
}
SingleResultCallback toCallback(Closure closure) {
@ -297,30 +173,4 @@ class MongoAsyncClientTest extends MongoBaseTest {
}
}
}
def mongoSpan(TraceAssert trace, int index,
String operation, String collection,
String dbName, Closure<Boolean> statementEval,
Object parentSpan = null, Throwable exception = null) {
trace.span(index) {
name { operation + " " + dbName + "." + collection }
kind CLIENT
if (parentSpan == null) {
hasNoParent()
} else {
childOf((SpanData) parentSpan)
}
attributes {
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
"$SemanticAttributes.NET_PEER_PORT.key" port
"$SemanticAttributes.DB_CONNECTION_STRING.key" "mongodb://localhost:" + port
"$SemanticAttributes.DB_STATEMENT.key" statementEval
"$SemanticAttributes.DB_SYSTEM.key" "mongodb"
"$SemanticAttributes.DB_NAME.key" dbName
"$SemanticAttributes.DB_OPERATION.key" operation
"$SemanticAttributes.DB_MONGODB_COLLECTION.key" collection
}
}
}
}

View File

@ -2,7 +2,7 @@ apply from: "$rootDir/gradle/java.gradle"
dependencies {
api project(':testing-common')
api group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '1.50.5'
api group: 'org.testcontainers', name: 'mongodb', version: versions.testcontainers
implementation deps.groovy
implementation deps.opentelemetryApi

View File

@ -0,0 +1,307 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import java.util.concurrent.atomic.AtomicInteger
import org.slf4j.LoggerFactory
import org.testcontainers.containers.GenericContainer
import org.testcontainers.containers.output.Slf4jLogConsumer
import spock.lang.Shared
abstract class AbstractMongoClientTest extends AgentInstrumentationSpecification {
@Shared
GenericContainer mongodb
@Shared
int port
def setupSpec() {
mongodb = new GenericContainer("mongo:3.2")
.withExposedPorts(27017)
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("mongodb")))
mongodb.start()
port = mongodb.getMappedPort(27017)
}
def cleanupSpec() throws Exception {
mongodb.stop()
}
// Different client versions have different APIs to do these operations. If adding a test for a new
// version, refer to existing ones on how to implement these operations.
abstract void createCollection(String dbName, String collectionName)
abstract void createCollectionNoDescription(String dbName, String collectionName)
// Tests the fix for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/457
// TracingCommandListener might get added multiple times if clientOptions are built using existing clientOptions or when calling a build method twice.
// This test asserts that duplicate traces are not created in those cases.
abstract void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName)
abstract int getCollection(String dbName, String collectionName)
abstract int insert(String dbName, String collectionName)
abstract int update(String dbName, String collectionName)
abstract int delete(String dbName, String collectionName)
abstract void getMore(String dbName, String collectionName)
abstract void error(String dbName, String collectionName)
def "test port open"() {
when:
new Socket("localhost", port)
then:
noExceptionThrown()
}
def "test create collection"() {
when:
createCollection(dbName, collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName) {
assert it == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test create collection no description"() {
when:
createCollectionNoDescription(dbName, collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName, {
assert it == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
})
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test get collection"() {
when:
def count = getCollection(dbName, collectionName)
then:
count == 0
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test insert"() {
when:
def count = insert(dbName, collectionName)
then:
count == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "insert", collectionName, dbName) {
assert it == "{\"insert\":\"$collectionName\",\"ordered\":\"?\",\"documents\":[{\"_id\":\"?\",\"password\":\"?\"}]}" ||
it == "{\"insert\": \"$collectionName\", \"ordered\": \"?\", \"\$db\": \"?\", \"documents\": [{\"_id\": \"?\", \"password\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test update"() {
when:
int modifiedCount = update(dbName, collectionName)
then:
modifiedCount == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "update", collectionName, dbName) {
assert it == "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test delete"() {
when:
int deletedCount = delete(dbName, collectionName)
then:
deletedCount == 1
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "delete", collectionName, dbName) {
assert it == "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "count", collectionName, dbName) {
assert it == "{\"count\":\"$collectionName\",\"query\":{}}" ||
it == "{\"count\": \"$collectionName\", \"query\": {}, \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test collection name for getMore command"() {
when:
getMore(dbName, collectionName)
then:
assertTraces(2) {
trace(0, 1) {
mongoSpan(it, 0, "find", collectionName, dbName) {
assert it == '{"find":"' + collectionName + '","filter":{"_id":{"$gte":"?"}},"batchSize":"?"}'
true
}
}
trace(1, 1) {
mongoSpan(it, 0, "getMore", collectionName, dbName) {
assert it == '{"getMore":"?","collection":"?","batchSize":"?"}'
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test error"() {
when:
error(dbName, collectionName)
then:
thrown(IllegalArgumentException)
// Unfortunately not caught by our instrumentation.
assertTraces(0) {}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
def "test create collection with already built ClientOptions"() {
when:
createCollectionWithAlreadyBuiltClientOptions(dbName, collectionName)
then:
assertTraces(1) {
trace(0, 1) {
mongoSpan(it, 0, "create", collectionName, dbName) {
assert it == "{\"create\":\"$collectionName\",\"capped\":\"?\"}"
true
}
}
}
where:
dbName = "test_db"
collectionName = createCollectionName()
}
private static final AtomicInteger collectionIndex = new AtomicInteger()
def createCollectionName() {
return "testCollection-${collectionIndex.getAndIncrement()}"
}
def mongoSpan(TraceAssert trace, int index,
String operation, String collection,
String dbName, Closure<Boolean> statementEval,
Object parentSpan = null, Throwable exception = null) {
trace.span(index) {
name { operation + " " + dbName + "." + collection }
kind CLIENT
if (parentSpan == null) {
hasNoParent()
} else {
childOf((SpanData) parentSpan)
}
attributes {
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
"$SemanticAttributes.NET_PEER_PORT.key" port
"$SemanticAttributes.DB_STATEMENT.key" {
statementEval.call(it.replaceAll(" ", ""))
}
"$SemanticAttributes.DB_SYSTEM.key" "mongodb"
"$SemanticAttributes.DB_CONNECTION_STRING.key" "mongodb://localhost:" + port
"$SemanticAttributes.DB_NAME.key" dbName
"$SemanticAttributes.DB_OPERATION.key" operation
"$SemanticAttributes.DB_MONGODB_COLLECTION.key" collection
}
}
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import de.flapdoodle.embed.mongo.MongodExecutable
import de.flapdoodle.embed.mongo.MongodProcess
import de.flapdoodle.embed.mongo.MongodStarter
import de.flapdoodle.embed.mongo.config.IMongodConfig
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder
import de.flapdoodle.embed.mongo.config.Net
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.process.runtime.Network
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.trace.attributes.SemanticAttributes
import spock.lang.Shared
/**
* Testing needs to be in a centralized project.
* If tests in multiple different projects are using embedded mongo,
* they downloader is at risk of a race condition.
*/
class MongoBaseTest extends AgentInstrumentationSpecification {
// https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo#executable-collision
private static final MongodStarter STARTER = MongodStarter.getDefaultInstance()
@Shared
int port = PortUtils.findOpenPort()
@Shared
MongodExecutable mongodExe
@Shared
MongodProcess mongod
def setup() throws Exception {
IMongodConfig mongodConfig =
new MongodConfigBuilder()
.version(Version.Main.PRODUCTION)
.net(new Net("localhost", port, Network.localhostIsIPv6()))
.build()
// using a system-wide file lock to prevent other modules that may be running in parallel
// from clobbering each other while downloading and extracting mongodb
def lockFile = new File(System.getProperty("java.io.tmpdir"), "prepare-embedded-mongo.lock")
def channel = new RandomAccessFile(lockFile, "rw").getChannel()
def lock = channel.lock()
try {
mongodExe = STARTER.prepare(mongodConfig)
} finally {
lock.release()
channel.close()
}
mongod = mongodExe.start()
}
def cleanup() throws Exception {
mongod?.stop()
mongod = null
mongodExe?.stop()
mongodExe = null
}
def "test port open"() {
when:
new Socket("localhost", port)
then:
noExceptionThrown()
}
def mongoSpan(TraceAssert trace, int index,
String operation, String collection,
String dbName, String statement,
Object parentSpan = null, Throwable exception = null) {
trace.span(index) {
name { operation + " " + dbName + "." + collection }
kind CLIENT
if (parentSpan == null) {
hasNoParent()
} else {
childOf((SpanData) parentSpan)
}
attributes {
"$SemanticAttributes.NET_PEER_NAME.key" "localhost"
"$SemanticAttributes.NET_PEER_IP.key" "127.0.0.1"
"$SemanticAttributes.NET_PEER_PORT.key" port
"$SemanticAttributes.DB_STATEMENT.key" {
it.replace(" ", "") == statement
}
"$SemanticAttributes.DB_SYSTEM.key" "mongodb"
"$SemanticAttributes.DB_CONNECTION_STRING.key" "mongodb://localhost:" + port
"$SemanticAttributes.DB_NAME.key" dbName
"$SemanticAttributes.DB_OPERATION.key" operation
"$SemanticAttributes.DB_MONGODB_COLLECTION.key" collection
}
}
}
}