opentelemetry-java-instrume.../dd-java-agent/instrumentation/lettuce-5/src/test/groovy/LettuceSyncClientTest.groovy

386 lines
8.6 KiB
Groovy

import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.agent.test.utils.PortUtils
import datadog.trace.api.DDSpanTypes
import io.lettuce.core.ClientOptions
import io.lettuce.core.RedisClient
import io.lettuce.core.RedisConnectionException
import io.lettuce.core.api.StatefulConnection
import io.lettuce.core.api.sync.RedisCommands
import redis.embedded.RedisServer
import spock.lang.Shared
import java.util.concurrent.CompletionException
import static datadog.trace.instrumentation.lettuce.LettuceInstrumentationUtil.AGENT_CRASHING_COMMAND_PREFIX
class LettuceSyncClientTest extends AgentTestRunner {
public static final String HOST = "127.0.0.1"
public static final int DB_INDEX = 0
// Disable autoreconnect so we do not get stray traces popping up on server shutdown
public static final ClientOptions CLIENT_OPTIONS = ClientOptions.builder().autoReconnect(false).build()
@Shared
int port
@Shared
int incorrectPort
@Shared
String dbAddr
@Shared
String dbAddrNonExistent
@Shared
String dbUriNonExistent
@Shared
String embeddedDbUri
@Shared
RedisServer redisServer
@Shared
Map<String, String> testHashMap = [
firstname: "John",
lastname : "Doe",
age : "53"
]
RedisClient redisClient
StatefulConnection connection
RedisCommands<String, ?> syncCommands
def setupSpec() {
port = PortUtils.randomOpenPort()
incorrectPort = PortUtils.randomOpenPort()
dbAddr = HOST + ":" + port + "/" + DB_INDEX
dbAddrNonExistent = HOST + ":" + incorrectPort + "/" + DB_INDEX
dbUriNonExistent = "redis://" + dbAddrNonExistent
embeddedDbUri = "redis://" + dbAddr
redisServer = RedisServer.builder()
// bind to localhost to avoid firewall popup
.setting("bind " + HOST)
// set max memory to avoid problems in CI
.setting("maxmemory 128M")
.port(port).build()
}
def setup() {
redisClient = RedisClient.create(embeddedDbUri)
redisServer.start()
connection = redisClient.connect()
syncCommands = connection.sync()
syncCommands.set("TESTKEY", "TESTVAL")
syncCommands.hmset("TESTHM", testHashMap)
// 2 sets + 1 connect trace
TEST_WRITER.waitForTraces(3)
TEST_WRITER.clear()
}
def cleanup() {
connection.close()
redisServer.stop()
}
def "connect"() {
setup:
RedisClient testConnectionClient = RedisClient.create(embeddedDbUri)
testConnectionClient.setOptions(CLIENT_OPTIONS)
when:
StatefulConnection connection = testConnectionClient.connect()
then:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "CONNECT:" + dbAddr
errored false
tags {
defaultTags()
"component" "redis-client"
"db.redis.dbIndex" 0
"db.type" "redis"
"peer.hostname" HOST
"peer.port" port
"span.kind" "client"
}
}
}
}
cleanup:
connection.close()
}
def "connect exception"() {
setup:
RedisClient testConnectionClient = RedisClient.create(dbUriNonExistent)
testConnectionClient.setOptions(CLIENT_OPTIONS)
when:
testConnectionClient.connect()
then:
thrown RedisConnectionException
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "CONNECT:" + dbAddrNonExistent
errored true
tags {
defaultTags()
"component" "redis-client"
"db.redis.dbIndex" 0
"db.type" "redis"
errorTags CompletionException, String
"peer.hostname" HOST
"peer.port" incorrectPort
"span.kind" "client"
}
}
}
}
}
def "set command"() {
setup:
String res = syncCommands.set("TESTSETKEY", "TESTSETVAL")
expect:
res == "OK"
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "SET"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "get command"() {
setup:
String res = syncCommands.get("TESTKEY")
expect:
res == "TESTVAL"
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "GET"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "get non existent key command"() {
setup:
String res = syncCommands.get("NON_EXISTENT_KEY")
expect:
res == null
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "GET"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "command with no arguments"() {
setup:
def keyRetrieved = syncCommands.randomkey()
expect:
keyRetrieved != null
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "RANDOMKEY"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "list command"() {
setup:
long res = syncCommands.lpush("TESTLIST", "TESTLIST ELEMENT")
expect:
res == 1
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "LPUSH"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "hash set command"() {
setup:
def res = syncCommands.hmset("user", testHashMap)
expect:
res == "OK"
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "HMSET"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "hash getall command"() {
setup:
Map<String, String> res = syncCommands.hgetall("TESTHM")
expect:
res == testHashMap
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "HGETALL"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "debug segfault command (returns void) with no argument should produce span"() {
setup:
syncCommands.debugSegfault()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName AGENT_CRASHING_COMMAND_PREFIX + "DEBUG"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
def "shutdown command (returns void) should produce a span"() {
setup:
syncCommands.shutdown(false)
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "redis"
operationName "redis.query"
spanType DDSpanTypes.REDIS
resourceName "SHUTDOWN"
errored false
tags {
defaultTags()
"component" "redis-client"
"db.type" "redis"
"span.kind" "client"
}
}
}
}
}
}