Moved JDBC integration tests to become unit tests
MODIFY
dd-java-agent-ittests/dd-java-agent-ittests.gradle
dd-java-agent-ittests/dd-java-agent-ittests.gradle
@@ -23,10 +23,6 @@ dependencies {
testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3'
testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0'
- // JDBC tests:
- testCompile group: 'com.h2database', name: 'h2', version: '1.4.196'
- testCompile group: 'org.hsqldb', name: 'hsqldb', version: '2.3.+'
- testCompile group: 'org.apache.derby', name: 'derby', version: '10.12.1.1'
}
tasks.withType(Test) {

DELETE
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/jdbc/JDBCInstrumentationTest.groovy
-package datadog.trace.agent.integration.jdbc
-
-import datadog.opentracing.DDTracer
-import datadog.trace.agent.test.IntegrationTestUtils
-import datadog.trace.common.writer.ListWriter
-import org.apache.derby.jdbc.EmbeddedDriver
-import org.h2.Driver
-import org.hsqldb.jdbc.JDBCDriver
-import spock.lang.Shared
-import spock.lang.Specification
-
-import java.sql.Connection
-import java.sql.PreparedStatement
-import java.sql.ResultSet
-import java.sql.Statement
-
-class JDBCInstrumentationTest extends Specification {
-
- final ListWriter writer = new ListWriter()
- final DDTracer tracer = new DDTracer(writer)
-
- @Shared
- private Map<String, Connection> connections
-
- def setupSpec() {
- Connection h2Connection = new Driver().connect("jdbc:h2:mem:integ-test", null)
- Connection hsqlConnection = new JDBCDriver().connect("jdbc:hsqldb:mem:integTest", null)
- Connection derbyConnection = new EmbeddedDriver().connect("jdbc:derby:memory:integTest;create=true", null)
-
- connections = [
- h2 : h2Connection,
- derby : derbyConnection,
- hsqldb: hsqlConnection,
- ]
- }
-
- def cleanupSpec() {
- connections.values().each {
- it.close()
- }
- }
-
- def setup() {
- IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer)
- writer.start()
- }
-
- def "basic statement on #driver generates spans"() {
- setup:
- Statement statement = connection.createStatement()
- ResultSet resultSet = statement.executeQuery(query)
-
- expect:
- resultSet.next()
- resultSet.getInt(1) == 3
- writer.size() == 1
-
- def trace = writer.firstTrace()
- trace.size() == 1
- def span = trace[0]
-
- span.context().operationName == "${driver}.query"
- span.serviceName == driver
- span.resourceName == query
- span.type == "sql"
- !span.context().getErrorFlag()
- span.context().parentId == 0
-
-
- def tags = span.context().tags
- tags["db.type"] == driver
- tags["db.user"] == username
- tags["span.kind"] == "client"
- tags["component"] == "java-jdbc-statement"
-
- tags["db.jdbc.url"].contains(driver)
- tags["span.origin.type"] != null
-
- tags["thread.name"] != null
- tags["thread.id"] != null
- tags.size() == username == null ? 7 : 8
-
- cleanup:
- statement.close()
-
- where:
- driver | connection | username | query
- "h2" | connections.get("h2") | null | "SELECT 3"
- "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
- "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
- }
-
- def "prepared statement execute on #driver generates a span"() {
- setup:
- PreparedStatement statement = connection.prepareStatement(query)
- assert statement.execute()
- ResultSet resultSet = statement.resultSet
-
- expect:
- resultSet.next()
- resultSet.getInt(1) == 3
- writer.size() == 1
-
- def trace = writer.firstTrace()
- trace.size() == 1
- def span = trace[0]
-
- span.context().operationName == "${driver}.query"
- span.serviceName == driver
- span.resourceName == query
- span.type == "sql"
- !span.context().getErrorFlag()
- span.context().parentId == 0
-
-
- def tags = span.context().tags
- tags["db.type"] == driver
- tags["db.user"] == username
- tags["span.kind"] == "client"
- tags["component"] == "java-jdbc-prepared_statement"
-
- tags["db.jdbc.url"].contains(driver)
- tags["span.origin.type"] != null
-
- tags["thread.name"] != null
- tags["thread.id"] != null
- tags.size() == username == null ? 7 : 8
-
- cleanup:
- statement.close()
-
- where:
- driver | connection | username | query
- "h2" | connections.get("h2") | null | "SELECT 3"
- "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
- "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
- }
-
- def "prepared statement query on #driver generates a span"() {
- setup:
- PreparedStatement statement = connection.prepareStatement(query)
- ResultSet resultSet = statement.executeQuery()
-
- expect:
- resultSet.next()
- resultSet.getInt(1) == 3
- writer.size() == 1
-
- def trace = writer.firstTrace()
- trace.size() == 1
- def span = trace[0]
-
- span.context().operationName == "${driver}.query"
- span.serviceName == driver
- span.resourceName == query
- span.type == "sql"
- !span.context().getErrorFlag()
- span.context().parentId == 0
-
-
- def tags = span.context().tags
- tags["db.type"] == driver
- tags["db.user"] == username
- tags["span.kind"] == "client"
- tags["component"] == "java-jdbc-prepared_statement"
-
- tags["db.jdbc.url"].contains(driver)
- tags["span.origin.type"] != null
-
- tags["thread.name"] != null
- tags["thread.id"] != null
- tags.size() == username == null ? 7 : 8
-
- cleanup:
- statement.close()
-
- where:
- driver | connection | username | query
- "h2" | connections.get("h2") | null | "SELECT 3"
- "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
- "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
- }
-
- def "statement update on #driver generates a span"() {
- setup:
- Statement statement = connection.createStatement()
- def sql = connection.nativeSQL(query)
-
- expect:
- !statement.execute(sql)
- statement.updateCount == 0
-
- writer.size() == 1
-
- def trace = writer.firstTrace()
- trace.size() == 1
- def span = trace[0]
-
- span.context().operationName == "${driver}.query"
- span.serviceName == driver
- span.resourceName == query
- span.type == "sql"
- !span.context().getErrorFlag()
- span.context().parentId == 0
-
-
- def tags = span.context().tags
- tags["db.type"] == driver
- tags["db.user"] == username
- tags["span.kind"] == "client"
- tags["component"] == "java-jdbc-statement"
-
- tags["db.jdbc.url"].contains(driver)
- tags["span.origin.type"] != null
-
- tags["thread.name"] != null
- tags["thread.id"] != null
- tags.size() == username == null ? 7 : 8
-
- cleanup:
- statement.close()
-
- where:
- driver | connection | username | query
- "h2" | connections.get("h2") | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
- "derby" | connections.get("derby") | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
- "hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
- }
-
- def "prepared statement update on #driver generates a span"() {
- setup:
- def sql = connection.nativeSQL(query)
- PreparedStatement statement = connection.prepareStatement(sql)
-
- expect:
- statement.executeUpdate() == 0
- writer.size() == 1
-
- def trace = writer.firstTrace()
- trace.size() == 1
- def span = trace[0]
-
- span.context().operationName == "${driver}.query"
- span.serviceName == driver
- span.resourceName == query
- span.type == "sql"
- !span.context().getErrorFlag()
- span.context().parentId == 0
-
-
- def tags = span.context().tags
- tags["db.type"] == driver
- tags["db.user"] == username
- tags["span.kind"] == "client"
- tags["component"] == "java-jdbc-prepared_statement"
-
- tags["db.jdbc.url"].contains(driver)
- tags["span.origin.type"] != null
-
- tags["thread.name"] != null
- tags["thread.id"] != null
- tags.size() == username == null ? 7 : 8
-
- cleanup:
- statement.close()
-
- where:
- driver | connection | username | query
- "h2" | connections.get("h2") | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
- "derby" | connections.get("derby") | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
- "hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.PS_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
- }
-}

MODIFY
dd-java-agent/instrumentation/jdbc/jdbc.gradle
dd-java-agent/instrumentation/jdbc/jdbc.gradle
@@ -12,5 +12,7 @@ dependencies {
// jdbc unit testing
testCompile group: 'com.h2database', name: 'h2', version: '1.4.197'
testCompile group: 'org.apache.derby', name: 'derby', version: '10.12.1.1'
+ // not using hsqldb 2.4 because org/hsqldb/jdbc/JDBCDriver : Unsupported major.minor version 52.0
+ testCompile group: 'org.hsqldb', name: 'hsqldb', version: '2.3.+'
}

MODIFY
dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy
dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy
import datadog.trace.agent.test.AgentTestRunner
import org.apache.derby.jdbc.EmbeddedDriver
import org.h2.Driver
+import org.hsqldb.jdbc.JDBCDriver
import spock.lang.Shared
import spock.lang.Unroll
import java.sql.Connection
+import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.Statement
@@ -12,8 +14,260 @@ class JDBCInstrumentationTest extends AgentTestRunner {
@Shared
def dbName = "jdbcUnitTest"
+ @Shared
+ private Map<String, Connection> connections
+
+ def setupSpec() {
+ Connection h2Connection = new Driver().connect("jdbc:h2:mem:" + dbName, null)
+ Connection hsqlConnection = new JDBCDriver().connect("jdbc:hsqldb:mem:" + dbName, null)
+ Connection derbyConnection = new EmbeddedDriver().connect("jdbc:derby:memory:" + dbName + ";create=true", null)
+
+ connections = [
+ h2 : h2Connection,
+ derby : derbyConnection,
+ hsqldb: hsqlConnection,
+ ]
+ }
+
+ def cleanupSpec() {
+ connections.values().each {
+ it.close()
+ }
+ }
+
+ @Unroll
+ def "basic statement on #driver generates spans"() {
+ setup:
+ Statement statement = connection.createStatement()
+ ResultSet resultSet = statement.executeQuery(query)
+
+ expect:
+ resultSet.next()
+ resultSet.getInt(1) == 3
+ TEST_WRITER.size() == 1
+
+ def trace = TEST_WRITER.firstTrace()
+ trace.size() == 1
+ def span = trace[0]
+
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
+ span.resourceName == query
+ span.type == "sql"
+ !span.context().getErrorFlag()
+ span.context().parentId == 0
+
+
+ def tags = span.context().tags
+ tags["db.type"] == driver
+ tags["db.user"] == username
+ tags["span.kind"] == "client"
+ tags["component"] == "java-jdbc-statement"
+
+ tags["db.jdbc.url"].contains(driver)
+ tags["span.origin.type"] != null
+
+ tags["thread.name"] != null
+ tags["thread.id"] != null
+ tags.size() == username == null ? 7 : 8
+
+ cleanup:
+ statement.close()
+
+ where:
+ driver | connection | username | query
+ "h2" | connections.get("h2") | null | "SELECT 3"
+ "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
+ "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
+ }
+
+ @Unroll
+ def "prepared statement execute on #driver generates a span"() {
+ setup:
+ PreparedStatement statement = connection.prepareStatement(query)
+ assert statement.execute()
+ ResultSet resultSet = statement.resultSet
+
+ expect:
+ resultSet.next()
+ resultSet.getInt(1) == 3
+ TEST_WRITER.size() == 1
+
+ def trace = TEST_WRITER.firstTrace()
+ trace.size() == 1
+ def span = trace[0]
+
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
+ span.resourceName == query
+ span.type == "sql"
+ !span.context().getErrorFlag()
+ span.context().parentId == 0
+
+
+ def tags = span.context().tags
+ tags["db.type"] == driver
+ tags["db.user"] == username
+ tags["span.kind"] == "client"
+ tags["component"] == "java-jdbc-prepared_statement"
+
+ tags["db.jdbc.url"].contains(driver)
+ tags["span.origin.type"] != null
+
+ tags["thread.name"] != null
+ tags["thread.id"] != null
+ tags.size() == username == null ? 7 : 8
+
+ cleanup:
+ statement.close()
+
+ where:
+ driver | connection | username | query
+ "h2" | connections.get("h2") | null | "SELECT 3"
+ "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
+ "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
+ }
+
+ @Unroll
+ def "prepared statement query on #driver generates a span"() {
+ setup:
+ PreparedStatement statement = connection.prepareStatement(query)
+ ResultSet resultSet = statement.executeQuery()
+
+ expect:
+ resultSet.next()
+ resultSet.getInt(1) == 3
+ TEST_WRITER.size() == 1
+
+ def trace = TEST_WRITER.firstTrace()
+ trace.size() == 1
+ def span = trace[0]
+
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
+ span.resourceName == query
+ span.type == "sql"
+ !span.context().getErrorFlag()
+ span.context().parentId == 0
+
+
+ def tags = span.context().tags
+ tags["db.type"] == driver
+ tags["db.user"] == username
+ tags["span.kind"] == "client"
+ tags["component"] == "java-jdbc-prepared_statement"
+
+ tags["db.jdbc.url"].contains(driver)
+ tags["span.origin.type"] != null
+
+ tags["thread.name"] != null
+ tags["thread.id"] != null
+ tags.size() == username == null ? 7 : 8
+
+ cleanup:
+ statement.close()
+
+ where:
+ driver | connection | username | query
+ "h2" | connections.get("h2") | null | "SELECT 3"
+ "derby" | connections.get("derby") | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1"
+ "hsqldb" | connections.get("hsqldb") | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
+ }
+
+ @Unroll
+ def "statement update on #driver generates a span"() {
+ setup:
+ Statement statement = connection.createStatement()
+ def sql = connection.nativeSQL(query)
+
+ expect:
+ !statement.execute(sql)
+ statement.updateCount == 0
+
+ TEST_WRITER.size() == 1
+
+ def trace = TEST_WRITER.firstTrace()
+ trace.size() == 1
+ def span = trace[0]
+
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
+ span.resourceName == query
+ span.type == "sql"
+ !span.context().getErrorFlag()
+ span.context().parentId == 0
+
+
+ def tags = span.context().tags
+ tags["db.type"] == driver
+ tags["db.user"] == username
+ tags["span.kind"] == "client"
+ tags["component"] == "java-jdbc-statement"
+
+ tags["db.jdbc.url"].contains(driver)
+ tags["span.origin.type"] != null
+
+ tags["thread.name"] != null
+ tags["thread.id"] != null
+ tags.size() == username == null ? 7 : 8
+
+ cleanup:
+ statement.close()
+
+ where:
+ driver | connection | username | query
+ "h2" | connections.get("h2") | null | "CREATE TABLE S_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ "derby" | connections.get("derby") | "APP" | "CREATE TABLE S_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ "hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.S_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ }
+
+ @Unroll
+ def "prepared statement update on #driver generates a span"() {
+ setup:
+ def sql = connection.nativeSQL(query)
+ PreparedStatement statement = connection.prepareStatement(sql)
+
+ expect:
+ statement.executeUpdate() == 0
+ TEST_WRITER.size() == 1
+
+ def trace = TEST_WRITER.firstTrace()
+ trace.size() == 1
+ def span = trace[0]
+
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
+ span.resourceName == query
+ span.type == "sql"
+ !span.context().getErrorFlag()
+ span.context().parentId == 0
+
+
+ def tags = span.context().tags
+ tags["db.type"] == driver
+ tags["db.user"] == username
+ tags["span.kind"] == "client"
+ tags["component"] == "java-jdbc-prepared_statement"
+
+ tags["db.jdbc.url"].contains(driver)
+ tags["span.origin.type"] != null
+
+ tags["thread.name"] != null
+ tags["thread.id"] != null
+ tags.size() == username == null ? 7 : 8
+
+ cleanup:
+ statement.close()
+
+ where:
+ driver | connection | username | query
+ "h2" | connections.get("h2") | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ "derby" | connections.get("derby") | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ "hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.PS_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
+ }
+
@Unroll
- def "Connection constructor throwing then generating correct spans after recovery using #db connection (prepare statement = #prepareStatement)"() {
+ def "connection constructor throwing then generating correct spans after recovery using #driver connection (prepare statement = #prepareStatement)"() {
setup:
Connection connection = null
@@ -21,7 +275,7 @@ class JDBCInstrumentationTest extends AgentTestRunner {
try {
connection = new DummyThrowingConnection()
} catch (Exception e) {
- connection = driver.connect(url, null)
+ connection = driverClass.connect(url, null)
}
Statement statement = null
@@ -44,15 +298,15 @@ class JDBCInstrumentationTest extends AgentTestRunner {
and:
def span = trace[0]
- span.context().operationName == "${db}.query"
- span.serviceName == db
+ span.context().operationName == "${driver}.query"
+ span.serviceName == driver
span.resourceName == query
span.type == "sql"
!span.context().getErrorFlag()
span.context().parentId == 0
def tags = span.context().tags
- tags["db.type"] == db
+ tags["db.type"] == driver
tags["db.user"] == user
tags["span.kind"] == "client"
if (prepareStatement) {
@@ -61,7 +315,7 @@ class JDBCInstrumentationTest extends AgentTestRunner {
tags["component"] == "java-jdbc-statement"
}
- tags["db.jdbc.url"].contains(db)
+ tags["db.jdbc.url"].contains(driver)
tags["span.origin.type"] != null
tags["thread.name"] != null
@@ -77,7 +331,7 @@ class JDBCInstrumentationTest extends AgentTestRunner {
}
where:
- prepareStatement | db | driver | url | user | query
+ prepareStatement | driver | driverClass | url | user | 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;"

Moved JDBC integration tests to become unit tests