749 lines
27 KiB
Groovy
749 lines
27 KiB
Groovy
import com.mchange.v2.c3p0.ComboPooledDataSource
|
|
import com.zaxxer.hikari.HikariConfig
|
|
import com.zaxxer.hikari.HikariDataSource
|
|
import datadog.trace.agent.test.AgentTestRunner
|
|
import datadog.trace.api.Config
|
|
import datadog.trace.api.DDSpanTypes
|
|
import datadog.trace.instrumentation.api.Tags
|
|
import org.apache.derby.jdbc.EmbeddedDataSource
|
|
import org.apache.derby.jdbc.EmbeddedDriver
|
|
import org.h2.Driver
|
|
import org.h2.jdbcx.JdbcDataSource
|
|
import org.hsqldb.jdbc.JDBCDriver
|
|
import spock.lang.Shared
|
|
import spock.lang.Unroll
|
|
import test.TestConnection
|
|
import test.TestStatement
|
|
|
|
import javax.sql.DataSource
|
|
import java.sql.CallableStatement
|
|
import java.sql.Connection
|
|
import java.sql.PreparedStatement
|
|
import java.sql.ResultSet
|
|
import java.sql.Statement
|
|
|
|
import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride
|
|
import static datadog.trace.agent.test.utils.TraceUtils.basicSpan
|
|
import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
|
|
|
|
class JDBCInstrumentationTest extends AgentTestRunner {
|
|
static {
|
|
System.setProperty("dd.integration.jdbc-datasource.enabled", "true")
|
|
}
|
|
|
|
@Shared
|
|
def dbName = "jdbcUnitTest"
|
|
|
|
@Shared
|
|
private Map<String, String> jdbcUrls = [
|
|
"h2" : "jdbc:h2:mem:$dbName",
|
|
"derby" : "jdbc:derby:memory:$dbName",
|
|
"hsqldb": "jdbc:hsqldb:mem:$dbName",
|
|
]
|
|
|
|
@Shared
|
|
private Map<String, String> jdbcDriverClassNames = [
|
|
"h2" : "org.h2.Driver",
|
|
"derby" : "org.apache.derby.jdbc.EmbeddedDriver",
|
|
"hsqldb": "org.hsqldb.jdbc.JDBCDriver",
|
|
]
|
|
|
|
@Shared
|
|
private Map<String, String> jdbcUserNames = [
|
|
"h2" : null,
|
|
"derby" : "APP",
|
|
"hsqldb": "SA",
|
|
]
|
|
|
|
@Shared
|
|
private Properties connectionProps = {
|
|
def props = new Properties()
|
|
// props.put("user", "someUser")
|
|
// props.put("password", "somePassword")
|
|
props.put("databaseName", "someDb")
|
|
props.put("OPEN_NEW", "true") // So H2 doesn't complain about username/password.
|
|
return props
|
|
}()
|
|
|
|
// JDBC Connection pool name (i.e. HikariCP) -> Map<dbName, Datasource>
|
|
@Shared
|
|
private Map<String, Map<String, DataSource>> cpDatasources = new HashMap<>()
|
|
|
|
def prepareConnectionPoolDatasources() {
|
|
String[] connectionPoolNames = [
|
|
"tomcat", "hikari", "c3p0",
|
|
]
|
|
connectionPoolNames.each {
|
|
cpName ->
|
|
Map<String, DataSource> dbDSMapping = new HashMap<>()
|
|
jdbcUrls.each {
|
|
dbType, jdbcUrl ->
|
|
dbDSMapping.put(dbType, createDS(cpName, dbType, jdbcUrl))
|
|
}
|
|
cpDatasources.put(cpName, dbDSMapping)
|
|
}
|
|
}
|
|
|
|
def createTomcatDS(String dbType, String jdbcUrl) {
|
|
DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource()
|
|
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
|
ds.setUrl(jdbcUrlToSet)
|
|
ds.setDriverClassName(jdbcDriverClassNames.get(dbType))
|
|
String username = jdbcUserNames.get(dbType)
|
|
if (username != null) {
|
|
ds.setUsername(username)
|
|
}
|
|
ds.setPassword("")
|
|
ds.setMaxActive(1) // to test proper caching, having > 1 max active connection will be hard to
|
|
// determine whether the connection is properly cached
|
|
return ds
|
|
}
|
|
|
|
def createHikariDS(String dbType, String jdbcUrl) {
|
|
HikariConfig config = new HikariConfig()
|
|
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
|
config.setJdbcUrl(jdbcUrlToSet)
|
|
String username = jdbcUserNames.get(dbType)
|
|
if (username != null) {
|
|
config.setUsername(username)
|
|
}
|
|
config.setPassword("")
|
|
config.addDataSourceProperty("cachePrepStmts", "true")
|
|
config.addDataSourceProperty("prepStmtCacheSize", "250")
|
|
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
|
|
config.setMaximumPoolSize(1)
|
|
|
|
return new HikariDataSource(config)
|
|
}
|
|
|
|
def createC3P0DS(String dbType, String jdbcUrl) {
|
|
DataSource ds = new ComboPooledDataSource()
|
|
ds.setDriverClass(jdbcDriverClassNames.get(dbType))
|
|
def jdbcUrlToSet = dbType == "derby" ? jdbcUrl + ";create=true" : jdbcUrl
|
|
ds.setJdbcUrl(jdbcUrlToSet)
|
|
String username = jdbcUserNames.get(dbType)
|
|
if (username != null) {
|
|
ds.setUser(username)
|
|
}
|
|
ds.setPassword("")
|
|
ds.setMaxPoolSize(1)
|
|
return ds
|
|
}
|
|
|
|
def createDS(String connectionPoolName, String dbType, String jdbcUrl) {
|
|
DataSource ds = null
|
|
if (connectionPoolName == "tomcat") {
|
|
ds = createTomcatDS(dbType, jdbcUrl)
|
|
}
|
|
if (connectionPoolName == "hikari") {
|
|
ds = createHikariDS(dbType, jdbcUrl)
|
|
}
|
|
if (connectionPoolName == "c3p0") {
|
|
ds = createC3P0DS(dbType, jdbcUrl)
|
|
}
|
|
return ds
|
|
}
|
|
|
|
def setupSpec() {
|
|
prepareConnectionPoolDatasources()
|
|
}
|
|
|
|
def cleanupSpec() {
|
|
cpDatasources.values().each {
|
|
it.values().each {
|
|
datasource ->
|
|
if (datasource instanceof Closeable) {
|
|
datasource.close()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Unroll
|
|
def "basic statement with #connection.getClass().getCanonicalName() on #driver generates spans"() {
|
|
setup:
|
|
Statement statement = connection.createStatement()
|
|
ResultSet resultSet = runUnderTrace("parent") {
|
|
withConfigOverride(Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "$renameService") {
|
|
return statement.executeQuery(query)
|
|
}
|
|
}
|
|
|
|
expect:
|
|
resultSet.next()
|
|
resultSet.getInt(1) == 3
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
serviceName renameService ? dbName.toLowerCase() : driver
|
|
operationName "${driver}.query"
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | renameService | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | false | "SELECT 3"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | true | "SELECT 3"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | true | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | true | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | false | "SELECT 3"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | true | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | false | "SELECT 3"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | true | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | true | "SELECT 3"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
}
|
|
|
|
@Unroll
|
|
def "prepared statement execute on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
|
setup:
|
|
PreparedStatement statement = connection.prepareStatement(query)
|
|
ResultSet resultSet = runUnderTrace("parent") {
|
|
assert statement.execute()
|
|
return statement.resultSet
|
|
}
|
|
|
|
expect:
|
|
resultSet.next()
|
|
resultSet.getInt(1) == 3
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
}
|
|
|
|
@Unroll
|
|
def "prepared statement query on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
|
setup:
|
|
PreparedStatement statement = connection.prepareStatement(query)
|
|
ResultSet resultSet = runUnderTrace("parent") {
|
|
return statement.executeQuery()
|
|
}
|
|
|
|
expect:
|
|
resultSet.next()
|
|
resultSet.getInt(1) == 3
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
}
|
|
|
|
@Unroll
|
|
def "prepared call on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
|
setup:
|
|
CallableStatement statement = connection.prepareCall(query)
|
|
ResultSet resultSet = runUnderTrace("parent") {
|
|
return statement.executeQuery()
|
|
}
|
|
|
|
expect:
|
|
resultSet.next()
|
|
resultSet.getInt(1) == 3
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
}
|
|
|
|
@Unroll
|
|
def "statement update on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
|
setup:
|
|
Statement statement = connection.createStatement()
|
|
def sql = connection.nativeSQL(query)
|
|
|
|
expect:
|
|
runUnderTrace("parent") {
|
|
return !statement.execute(sql)
|
|
}
|
|
statement.updateCount == 0
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE S_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE S_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE S_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE S_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
}
|
|
|
|
@Unroll
|
|
def "prepared statement update on #driver with #connection.getClass().getCanonicalName() generates a span"() {
|
|
setup:
|
|
def sql = connection.nativeSQL(query)
|
|
PreparedStatement statement = connection.prepareStatement(sql)
|
|
|
|
expect:
|
|
runUnderTrace("parent") {
|
|
return statement.executeUpdate() == 0
|
|
}
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
statement.close()
|
|
connection.close()
|
|
|
|
where:
|
|
driver | connection | username | query
|
|
"h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "CREATE TABLE PS_H2_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_TOMCAT (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "CREATE TABLE PS_H2_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_HIKARI (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "CREATE TABLE PS_H2_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
"derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "CREATE TABLE PS_DERBY_C3P0 (id INTEGER not NULL, PRIMARY KEY ( id ))"
|
|
}
|
|
|
|
@Unroll
|
|
def "connection constructor throwing then generating correct spans after recovery using #driver connection (prepare statement = #prepareStatement)"() {
|
|
setup:
|
|
Connection connection = null
|
|
|
|
when:
|
|
try {
|
|
connection = new TestConnection(true)
|
|
} catch (Exception e) {
|
|
connection = driverClass.connect(url, null)
|
|
}
|
|
|
|
Statement statement = null
|
|
ResultSet rs = runUnderTrace("parent") {
|
|
if (prepareStatement) {
|
|
statement = connection.prepareStatement(query)
|
|
return statement.executeQuery()
|
|
}
|
|
|
|
statement = connection.createStatement()
|
|
return statement.executeQuery(query)
|
|
}
|
|
|
|
then:
|
|
rs.next()
|
|
rs.getInt(1) == 3
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${driver}.query"
|
|
serviceName driver
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
if (prepareStatement) {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
} else {
|
|
"$Tags.COMPONENT" "java-jdbc-statement"
|
|
}
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" driver
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
if (username != null) {
|
|
"$Tags.DB_USER" username
|
|
}
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (statement != null) {
|
|
statement.close()
|
|
}
|
|
if (connection != null) {
|
|
connection.close()
|
|
}
|
|
|
|
where:
|
|
prepareStatement | driver | driverClass | url | username | query
|
|
true | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;"
|
|
true | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
false | "h2" | new Driver() | "jdbc:h2:mem:" + dbName | null | "SELECT 3;"
|
|
false | "derby" | new EmbeddedDriver() | "jdbc:derby:memory:" + dbName + ";create=true" | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
|
|
}
|
|
|
|
def "calling #datasource.class.simpleName getConnection generates a span when under existing trace"() {
|
|
setup:
|
|
assert datasource instanceof DataSource
|
|
init?.call(datasource)
|
|
|
|
when:
|
|
datasource.getConnection().close()
|
|
|
|
then:
|
|
!TEST_WRITER.any { it.any { it.operationName == "database.connection" } }
|
|
TEST_WRITER.clear()
|
|
|
|
when:
|
|
runUnderTrace("parent") {
|
|
datasource.getConnection().close()
|
|
}
|
|
|
|
then:
|
|
assertTraces(1) {
|
|
trace(0, recursive ? 3 : 2) {
|
|
basicSpan(it, 0, "parent")
|
|
|
|
span(1) {
|
|
operationName "database.connection"
|
|
resourceName "${datasource.class.simpleName}.getConnection"
|
|
childOf span(0)
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-connection"
|
|
defaultTags()
|
|
}
|
|
}
|
|
if (recursive) {
|
|
span(2) {
|
|
operationName "database.connection"
|
|
resourceName "${datasource.class.simpleName}.getConnection"
|
|
childOf span(1)
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-connection"
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
where:
|
|
datasource | init
|
|
new JdbcDataSource() | { ds -> ds.setURL(jdbcUrls.get("h2")) }
|
|
new EmbeddedDataSource() | { ds -> ds.jdbcurl = jdbcUrls.get("derby") }
|
|
cpDatasources.get("hikari").get("h2") | null
|
|
cpDatasources.get("hikari").get("derby") | null
|
|
cpDatasources.get("c3p0").get("h2") | null
|
|
cpDatasources.get("c3p0").get("derby") | null
|
|
|
|
// Tomcat's pool doesn't work because the getConnection method is
|
|
// implemented in a parent class that doesn't implement DataSource
|
|
|
|
recursive = datasource instanceof EmbeddedDataSource
|
|
}
|
|
|
|
def "test getClientInfo exception"() {
|
|
setup:
|
|
Connection connection = new TestConnection(false)
|
|
|
|
when:
|
|
Statement statement = null
|
|
runUnderTrace("parent") {
|
|
statement = connection.createStatement()
|
|
return statement.executeQuery(query)
|
|
}
|
|
|
|
then:
|
|
assertTraces(1) {
|
|
trace(0, 2) {
|
|
basicSpan(it, 0, "parent")
|
|
span(1) {
|
|
operationName "${database}.query"
|
|
serviceName database
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
childOf span(0)
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" database
|
|
"span.origin.type" TestStatement.name
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (statement != null) {
|
|
statement.close()
|
|
}
|
|
if (connection != null) {
|
|
connection.close()
|
|
}
|
|
|
|
where:
|
|
database = "testdb"
|
|
query = "testing 123"
|
|
}
|
|
|
|
@Unroll
|
|
def "#connectionPoolName connections should be cached in case of wrapped connections"() {
|
|
setup:
|
|
String dbType = "hsqldb"
|
|
DataSource ds = createDS(connectionPoolName, dbType, jdbcUrls.get(dbType))
|
|
String query = "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
|
|
int numQueries = 5
|
|
Connection connection = null
|
|
Statement statement = null
|
|
ResultSet rs = null
|
|
int[] res = new int[numQueries]
|
|
|
|
when:
|
|
for (int i = 0; i < numQueries; ++i) {
|
|
try {
|
|
connection = ds.getConnection()
|
|
statement = connection.prepareStatement(query)
|
|
rs = statement.executeQuery()
|
|
if (rs.next()) {
|
|
res[i] = rs.getInt(1)
|
|
} else {
|
|
res[i] = 0
|
|
}
|
|
} finally {
|
|
connection.close()
|
|
}
|
|
}
|
|
|
|
then:
|
|
for (int i = 0; i < numQueries; ++i) {
|
|
res[i] == 3
|
|
}
|
|
assertTraces(5) {
|
|
trace(0, 1) {
|
|
span(0) {
|
|
operationName "${dbType}.query"
|
|
serviceName dbType
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" dbType
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
"$Tags.DB_USER" "SA"
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
for (int i = 1; i < numQueries; ++i) {
|
|
trace(i, 1) {
|
|
span(0) {
|
|
operationName "${dbType}.query"
|
|
serviceName dbType
|
|
resourceName query
|
|
spanType DDSpanTypes.SQL
|
|
errored false
|
|
tags {
|
|
"$Tags.COMPONENT" "java-jdbc-prepared_statement"
|
|
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
|
|
"$Tags.DB_TYPE" dbType
|
|
"$Tags.DB_INSTANCE" dbName.toLowerCase()
|
|
"$Tags.DB_USER" "SA"
|
|
"span.origin.type" String
|
|
defaultTags()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if (ds instanceof Closeable) {
|
|
ds.close()
|
|
}
|
|
|
|
where:
|
|
connectionPoolName | _
|
|
"hikari" | _
|
|
"tomcat" | _
|
|
"c3p0" | _
|
|
}
|
|
}
|