Extract base test class and move Config class changes there.

This commit is contained in:
Tyler Benson 2019-10-07 18:51:02 +02:00
parent 654e09ee7f
commit 9ef3332140
51 changed files with 261 additions and 301 deletions

View File

@ -1,21 +1,16 @@
package datadog.trace.agent.decorator
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.DDTags
import datadog.trace.util.test.DDSpecification
import io.opentracing.Scope
import io.opentracing.Span
import io.opentracing.tag.Tags
import spock.lang.Shared
import spock.lang.Specification
import static io.opentracing.log.Fields.ERROR_OBJECT
class BaseDecoratorTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class BaseDecoratorTest extends DDSpecification {
@Shared
def decorator = newDecorator()

View File

@ -2,9 +2,9 @@ package datadog.trace.agent.test
import datadog.trace.agent.tooling.ClassLoaderMatcher
import datadog.trace.bootstrap.DatadogClassLoader
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
class ClassLoaderMatcherTest extends Specification {
class ClassLoaderMatcherTest extends DDSpecification {
def "skip non-delegating classloader"() {
setup:

View File

@ -2,18 +2,15 @@ package datadog.trace.agent.test
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.agent.tooling.Instrumenter
import datadog.trace.util.test.DDSpecification
import net.bytebuddy.agent.builder.AgentBuilder
import net.bytebuddy.description.type.TypeDescription
import net.bytebuddy.matcher.ElementMatcher
import org.junit.Rule
import org.junit.contrib.java.lang.system.EnvironmentVariables
import org.junit.contrib.java.lang.system.RestoreSystemProperties
import spock.lang.Specification
class DefaultInstrumenterTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DefaultInstrumenterTest extends DDSpecification {
@Rule
public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()

View File

@ -5,18 +5,18 @@ import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
import datadog.trace.agent.tooling.ExceptionHandlers
import datadog.trace.bootstrap.ExceptionLogger
import datadog.trace.util.test.DDSpecification
import net.bytebuddy.agent.ByteBuddyAgent
import net.bytebuddy.agent.builder.AgentBuilder
import net.bytebuddy.agent.builder.ResettableClassFileTransformer
import net.bytebuddy.dynamic.ClassFileLocator
import org.slf4j.LoggerFactory
import spock.lang.Shared
import spock.lang.Specification
import static net.bytebuddy.matcher.ElementMatchers.isMethod
import static net.bytebuddy.matcher.ElementMatchers.named
class ExceptionHandlerTest extends Specification {
class ExceptionHandlerTest extends DDSpecification {
@Shared
ListAppender testAppender = new ListAppender()
@Shared

View File

@ -1,14 +1,14 @@
package datadog.trace.agent.test
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.agent.tooling.AgentInstaller
import datadog.trace.agent.tooling.HelperInjector
import datadog.trace.agent.tooling.Utils
import datadog.trace.util.test.DDSpecification
import net.bytebuddy.agent.ByteBuddyAgent
import net.bytebuddy.description.type.TypeDescription
import net.bytebuddy.dynamic.ClassFileLocator
import net.bytebuddy.dynamic.loading.ClassInjector
import spock.lang.Specification
import spock.lang.Timeout
import java.lang.ref.WeakReference
@ -18,10 +18,7 @@ import static datadog.trace.agent.test.utils.ClasspathUtils.isClassLoaded
import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER
import static datadog.trace.util.gc.GCUtils.awaitGC
class HelperInjectionTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class HelperInjectionTest extends DDSpecification {
@Timeout(10)
def "helpers injected to non-delegating classloader"() {

View File

@ -1,12 +1,13 @@
package datadog.trace.agent.test
import datadog.trace.agent.tooling.DDLocationStrategy
import java.util.concurrent.atomic.AtomicReference
import datadog.trace.util.test.DDSpecification
import net.bytebuddy.agent.builder.AgentBuilder
import spock.lang.Shared
import spock.lang.Specification
class ResourceLocatingTest extends Specification {
import java.util.concurrent.atomic.AtomicReference
class ResourceLocatingTest extends DDSpecification {
@Shared
def lastLookup = new AtomicReference<String>()
@Shared

View File

@ -1,7 +1,7 @@
package datadog.trace.agent.tooling
import datadog.trace.util.gc.GCUtils
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import spock.lang.Subject
import java.lang.ref.WeakReference
@ -10,7 +10,7 @@ import java.util.concurrent.atomic.AtomicInteger
import static java.util.concurrent.TimeUnit.MILLISECONDS
class CleanerTest extends Specification {
class CleanerTest extends DDSpecification {
@Subject
def cleaner = new Cleaner()

View File

@ -1,9 +1,9 @@
package datadog.trace.agent.tooling
import datadog.trace.util.gc.GCUtils
import datadog.trace.util.test.DDSpecification
import net.bytebuddy.description.type.TypeDescription
import net.bytebuddy.pool.TypePool
import spock.lang.Specification
import spock.lang.Timeout
import java.lang.ref.WeakReference
@ -13,7 +13,7 @@ import java.util.concurrent.atomic.AtomicReference
import static datadog.trace.agent.tooling.AgentTooling.CLEANER
@Timeout(5)
class EvictingCacheProviderTest extends Specification {
class EvictingCacheProviderTest extends DDSpecification {
def "test provider"() {
setup:

View File

@ -1,9 +1,8 @@
package datadog.trace.agent.tooling
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
class UtilsTest extends Specification {
class UtilsTest extends DDSpecification {
def "getStackTraceAsString() returns the stack trace as a single new line separated string"() {
setup:

View File

@ -2,9 +2,9 @@ package datadog.trace.agent.tooling
import datadog.trace.bootstrap.WeakMap
import datadog.trace.util.gc.GCUtils
import datadog.trace.util.test.DDSpecification
import spock.lang.Retry
import spock.lang.Shared
import spock.lang.Specification
import java.lang.ref.WeakReference
import java.util.concurrent.TimeUnit
@ -13,7 +13,7 @@ import static datadog.trace.agent.tooling.AgentTooling.CLEANER
@Retry
// These tests fail sometimes in CI.
class WeakConcurrentSupplierTest extends Specification {
class WeakConcurrentSupplierTest extends DDSpecification {
@Shared
def weakConcurrentSupplier = new WeakMapSuppliers.WeakConcurrent(CLEANER)
@Shared

View File

@ -1,10 +1,10 @@
import datadog.trace.instrumentation.jdbc.DBInfo
import datadog.trace.util.test.DDSpecification
import spock.lang.Shared
import spock.lang.Specification
import static datadog.trace.instrumentation.jdbc.JDBCConnectionUrlParser.parse
class JDBCConnectionUrlParserTest extends Specification {
class JDBCConnectionUrlParserTest extends DDSpecification {
@Shared
def stdProps = {

View File

@ -20,7 +20,6 @@ dependencies {
testCompile group: 'com.twilio.sdk', name: 'twilio', version: '0.0.1'
testCompile project(':dd-java-agent:instrumentation:apache-httpclient-4')
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6' // Last version to support Java7
testCompile group: 'nl.jqno.equalsverifier', name: 'equalsverifier', version: '2.5.2' // Last version to support Java7
latestDepTestCompile group: 'com.twilio.sdk', name: 'twilio', version: '+'

View File

@ -7,13 +7,13 @@ import datadog.opentracing.DDSpan;
import datadog.opentracing.DDTracer;
import datadog.opentracing.PendingTrace;
import datadog.trace.agent.test.asserts.ListWriterAssert;
import datadog.trace.agent.test.utils.ConfigUtils;
import datadog.trace.agent.test.utils.GlobalTracerUtils;
import datadog.trace.agent.tooling.AgentInstaller;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.GlobalTracer;
import datadog.trace.common.writer.ListWriter;
import datadog.trace.common.writer.Writer;
import datadog.trace.util.test.DDSpecification;
import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import groovy.transform.stc.ClosureParams;
@ -41,7 +41,6 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.spockframework.runtime.model.SpecMetadata;
import spock.lang.Specification;
/**
* A spock test runner which automatically applies instrumentation and exposes a global trace
@ -61,7 +60,7 @@ import spock.lang.Specification;
@RunWith(SpockRunner.class)
@SpecMetadata(filename = "AgentTestRunner.java", line = 0)
@Slf4j
public abstract class AgentTestRunner extends Specification {
public abstract class AgentTestRunner extends DDSpecification {
private static final long TIMEOUT_MILLIS = 10 * 1000;
/**
* For test runs, agent's global tracer will report to this list writer.
@ -88,8 +87,6 @@ public abstract class AgentTestRunner extends Specification {
((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(Level.WARN);
((Logger) LoggerFactory.getLogger("datadog")).setLevel(Level.DEBUG);
ConfigUtils.makeConfigInstanceModifiable();
TEST_WRITER =
new ListWriter() {
@Override

View File

@ -2,44 +2,32 @@ package datadog.trace.agent.test.utils
import datadog.trace.api.Config
import lombok.SneakyThrows
import net.bytebuddy.agent.ByteBuddyAgent
import net.bytebuddy.agent.builder.AgentBuilder
import net.bytebuddy.dynamic.ClassFileLocator
import net.bytebuddy.dynamic.Transformer
import java.lang.reflect.Modifier
import java.util.concurrent.Callable
import static net.bytebuddy.description.modifier.FieldManifestation.VOLATILE
import static net.bytebuddy.description.modifier.Ownership.STATIC
import static net.bytebuddy.description.modifier.Visibility.PUBLIC
import static net.bytebuddy.matcher.ElementMatchers.named
import static net.bytebuddy.matcher.ElementMatchers.none
class ConfigUtils {
private static class ConfigInstance {
// Wrapped in a static class to lazy load.
static final FIELD = Config.getDeclaredField("INSTANCE")
static final RUNTIME_ID_FIELD = Config.getDeclaredField("runtimeId")
}
static final CONFIG_INSTANCE_FIELD = Config.getDeclaredField("INSTANCE")
static final RUNTIME_ID_FIELD = Config.getDeclaredField("runtimeId")
@SneakyThrows
synchronized static <T extends Object> Object withConfigOverride(final String name, final String value, final Callable<T> r) {
// Ensure the class was retransformed properly in AgentTestRunner.makeConfigInstanceModifiable()
assert Modifier.isPublic(ConfigInstance.FIELD.getModifiers())
assert Modifier.isStatic(ConfigInstance.FIELD.getModifiers())
assert Modifier.isVolatile(ConfigInstance.FIELD.getModifiers())
assert !Modifier.isFinal(ConfigInstance.FIELD.getModifiers())
// Ensure the class was retransformed properly in DDSpecification.makeConfigInstanceModifiable()
assert Modifier.isPublic(CONFIG_INSTANCE_FIELD.getModifiers())
assert Modifier.isStatic(CONFIG_INSTANCE_FIELD.getModifiers())
assert Modifier.isVolatile(CONFIG_INSTANCE_FIELD.getModifiers())
assert !Modifier.isFinal(CONFIG_INSTANCE_FIELD.getModifiers())
def existingConfig = Config.get()
Properties properties = new Properties()
properties.put(name, value)
ConfigInstance.FIELD.set(null, new Config(properties, existingConfig))
CONFIG_INSTANCE_FIELD.set(null, new Config(properties, existingConfig))
assert Config.get() != existingConfig
try {
return r.call()
} finally {
ConfigInstance.FIELD.set(null, existingConfig)
CONFIG_INSTANCE_FIELD.set(null, existingConfig)
}
}
@ -50,7 +38,6 @@ class ConfigUtils {
* @return
*/
static updateConfig(final Callable r) {
makeConfigInstanceModifiable()
r.call()
resetConfig()
}
@ -59,71 +46,22 @@ class ConfigUtils {
* Reset the global configuration. Please note that Runtime ID is preserved to the pre-existing value.
*/
static void resetConfig() {
// Ensure the class was re-transformed properly in AgentTestRunner.makeConfigInstanceModifiable()
assert Modifier.isPublic(ConfigInstance.FIELD.getModifiers())
assert Modifier.isStatic(ConfigInstance.FIELD.getModifiers())
assert Modifier.isVolatile(ConfigInstance.FIELD.getModifiers())
assert !Modifier.isFinal(ConfigInstance.FIELD.getModifiers())
// Ensure the class was re-transformed properly in DDSpecification.makeConfigInstanceModifiable()
assert Modifier.isPublic(CONFIG_INSTANCE_FIELD.getModifiers())
assert Modifier.isStatic(CONFIG_INSTANCE_FIELD.getModifiers())
assert Modifier.isVolatile(CONFIG_INSTANCE_FIELD.getModifiers())
assert !Modifier.isFinal(CONFIG_INSTANCE_FIELD.getModifiers())
assert Modifier.isPublic(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert !Modifier.isStatic(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert Modifier.isVolatile(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert !Modifier.isFinal(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert Modifier.isPublic(RUNTIME_ID_FIELD.getModifiers())
assert !Modifier.isStatic(RUNTIME_ID_FIELD.getModifiers())
assert Modifier.isVolatile(RUNTIME_ID_FIELD.getModifiers())
assert !Modifier.isFinal(RUNTIME_ID_FIELD.getModifiers())
def previousConfig = ConfigInstance.FIELD.get(null)
def previousConfig = CONFIG_INSTANCE_FIELD.get(null)
def newConfig = new Config()
ConfigInstance.FIELD.set(null, newConfig)
CONFIG_INSTANCE_FIELD.set(null, newConfig)
if (previousConfig != null) {
ConfigInstance.RUNTIME_ID_FIELD.set(newConfig, ConfigInstance.RUNTIME_ID_FIELD.get(previousConfig))
RUNTIME_ID_FIELD.set(newConfig, RUNTIME_ID_FIELD.get(previousConfig))
}
}
// Keep track of config instance already made modifiable
private static isConfigInstanceModifiable = false
static void makeConfigInstanceModifiable() {
if (isConfigInstanceModifiable) {
return
}
def instrumentation = ByteBuddyAgent.install()
final transformer =
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.RedefinitionStrategy.Listener.ErrorEscalating.FAIL_FAST)
// Config is injected into the bootstrap, so we need to provide a locator.
.with(
new AgentBuilder.LocationStrategy.Simple(
ClassFileLocator.ForClassLoader.ofSystemLoader()))
.ignore(none()) // Allow transforming bootstrap classes
.type(named("datadog.trace.api.Config"))
.transform { builder, typeDescription, classLoader, module ->
builder
.field(named("INSTANCE"))
.transform(Transformer.ForField.withModifiers(PUBLIC, STATIC, VOLATILE))
}
// Making runtimeId modifiable so that it can be preserved when resetting config in tests
.transform { builder, typeDescription, classLoader, module ->
builder
.field(named("runtimeId"))
.transform(Transformer.ForField.withModifiers(PUBLIC, VOLATILE))
}
.installOn(instrumentation)
isConfigInstanceModifiable = true
final field = ConfigInstance.FIELD
assert Modifier.isPublic(field.getModifiers())
assert Modifier.isStatic(field.getModifiers())
assert Modifier.isVolatile(field.getModifiers())
assert !Modifier.isFinal(field.getModifiers())
final runtimeIdField = ConfigInstance.RUNTIME_ID_FIELD
assert Modifier.isPublic(runtimeIdField.getModifiers())
assert !Modifier.isStatic(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert Modifier.isVolatile(runtimeIdField.getModifiers())
assert !Modifier.isFinal(runtimeIdField.getModifiers())
// No longer needed (Unless class gets retransformed somehow).
instrumentation.removeTransformer(transformer)
}
}

View File

@ -24,6 +24,7 @@ dependencies {
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '8.0.0.v20110901'
compile project(':dd-java-agent:agent-tooling')
compile project(':utils:test-utils')
annotationProcessor deps.autoservice
implementation deps.autoservice
@ -31,6 +32,7 @@ dependencies {
compile deps.groovy
testCompile project(':utils:gc-utils')
testCompile project(':utils:test-utils')
testCompile project(':dd-java-agent:instrumentation:trace-annotation')
testCompile group: 'cglib', name: 'cglib', version: '3.2.5'

View File

@ -15,5 +15,5 @@ excludedClassesCoverage += [
description = 'dd-trace-api'
dependencies {
compile deps.slf4j
testCompile deps.junit
testCompile project(':utils:test-utils')
}

View File

@ -1,9 +1,9 @@
package datadog.trace.api
import datadog.trace.util.test.DDSpecification
import org.junit.Rule
import org.junit.contrib.java.lang.system.EnvironmentVariables
import org.junit.contrib.java.lang.system.RestoreSystemProperties
import spock.lang.Specification
import static datadog.trace.api.Config.AGENT_HOST
import static datadog.trace.api.Config.AGENT_PORT_LEGACY
@ -41,7 +41,7 @@ import static datadog.trace.api.Config.TRACE_REPORT_HOSTNAME
import static datadog.trace.api.Config.TRACE_RESOLVER_ENABLED
import static datadog.trace.api.Config.WRITER_TYPE
class ConfigTest extends Specification {
class ConfigTest extends DDSpecification {
@Rule
public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()
@Rule

View File

@ -44,10 +44,7 @@ dependencies {
testCompile project(":dd-java-agent:testing")
testCompile project(':utils:gc-utils')
testCompile group: 'org.assertj', name: 'assertj-core', version: '2.9.+'
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.19.0'
testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6' // Last version to support Java7
testCompile group: 'cglib', name: 'cglib-nodep', version: '3.2.5'
// testCompile group: 'cglib', name: 'cglib-nodep', version: '3.2.5'
testCompile group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.17.1'
traceAgentTestCompile deps.testcontainers

View File

@ -1,10 +1,9 @@
package datadog.opentracing
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import spock.lang.Unroll
class ContainerInfoTest extends Specification {
class ContainerInfoTest extends DDSpecification {
@Unroll
def "CGroupInfo is parsed from individual lines"() {

View File

@ -2,24 +2,18 @@ package datadog.opentracing
import datadog.opentracing.propagation.ExtractedContext
import datadog.opentracing.propagation.TagContext
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.api.DDTags
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.Scope
import io.opentracing.noop.NoopSpan
import spock.lang.Specification
import static datadog.opentracing.DDSpanContext.ORIGIN_KEY
import static java.util.concurrent.TimeUnit.MILLISECONDS
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.when
class DDSpanBuilderTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DDSpanBuilderTest extends DDSpecification {
def writer = new ListWriter()
def config = Config.get()
@ -158,11 +152,12 @@ class DDSpanBuilderTest extends Specification {
final String spanId = "1"
final long expectedParentId = spanId
final DDSpanContext mockedContext = mock(DDSpanContext)
when(mockedContext.getTraceId()).thenReturn(spanId)
when(mockedContext.getSpanId()).thenReturn(spanId)
when(mockedContext.getServiceName()).thenReturn("foo")
when(mockedContext.getTrace()).thenReturn(new PendingTrace(tracer, "1", [:]))
final DDSpanContext mockedContext = Mock()
1 * mockedContext.getTraceId() >> spanId
1 * mockedContext.getSpanId() >> spanId
_ * mockedContext.getServiceName() >> "foo"
1 * mockedContext.getBaggageItems() >> [:]
1 * mockedContext.getTrace() >> new PendingTrace(tracer, "1", [:])
final String expectedName = "fakeName"

View File

@ -2,20 +2,16 @@ package datadog.opentracing
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.common.collect.Maps
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.DDTags
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import org.msgpack.core.MessagePack
import org.msgpack.core.buffer.ArrayBufferInput
import org.msgpack.jackson.dataformat.MessagePackFactory
import org.msgpack.value.ValueType
import spock.lang.Specification
class DDSpanSerializationTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DDSpanSerializationTest extends DDSpecification {
def "serialize spans with sampling #samplingPriority"() throws Exception {
setup:

View File

@ -1,26 +1,21 @@
package datadog.opentracing
import com.fasterxml.jackson.databind.ObjectMapper
import datadog.opentracing.propagation.ExtractedContext
import datadog.opentracing.propagation.TagContext
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.DDTags
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.sampling.RateByServiceSampler
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.SpanContext
import spock.lang.Shared
import spock.lang.Specification
import java.util.concurrent.TimeUnit
import static datadog.trace.api.Config.DEFAULT_SERVICE_NAME
class DDSpanTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DDSpanTest extends DDSpecification {
def writer = new ListWriter()
def sampler = new RateByServiceSampler()

View File

@ -1,10 +1,10 @@
package datadog.opentracing
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.gc.GCUtils
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import spock.lang.Subject
import spock.lang.Timeout
@ -14,10 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger
import static datadog.trace.api.Config.PARTIAL_FLUSH_MIN_SPANS
class PendingTraceTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class PendingTraceTest extends DDSpecification {
def traceCount = new AtomicInteger()
def writer = new ListWriter() {

View File

@ -1,13 +1,10 @@
package datadog.opentracing
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
class SpanFactory {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
static DDSpan newSpanOf(long timestampMicro, String threadName = Thread.currentThread().name) {
def writer = new ListWriter()

View File

@ -1,14 +1,11 @@
package datadog.opentracing
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.common.writer.ListWriter
import spock.lang.Shared
import spock.lang.Specification
class TraceCorrelationTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import spock.lang.Shared
class TraceCorrelationTest extends DDSpecification {
static final WRITER = new ListWriter()

View File

@ -1,18 +1,15 @@
package datadog.opentracing
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.GlobalTracer
import datadog.trace.api.interceptor.MutableSpan
import datadog.trace.api.interceptor.TraceInterceptor
import datadog.trace.common.writer.ListWriter
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import java.util.concurrent.atomic.AtomicBoolean
class TraceInterceptorTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class TraceInterceptorTest extends DDSpecification {
def writer = new ListWriter()
def tracer = new DDTracer(writer)

View File

@ -9,17 +9,16 @@ import datadog.trace.api.DDSpanTypes
import datadog.trace.api.DDTags
import datadog.trace.common.sampling.AllSampler
import datadog.trace.common.writer.LoggingWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.tag.StringTag
import io.opentracing.tag.Tags
import spock.lang.Specification
import static datadog.trace.api.Config.DEFAULT_SERVICE_NAME
import static datadog.trace.api.DDTags.EVENT_SAMPLE_RATE
import static java.util.Collections.emptyMap
class SpanDecoratorTest extends Specification {
class SpanDecoratorTest extends DDSpecification {
static {
ConfigUtils.makeConfigInstanceModifiable()
ConfigUtils.updateConfig {
System.setProperty("dd.$Config.SPLIT_BY_TAGS", "sn.tag1,sn.tag2")
}

View File

@ -3,17 +3,13 @@ package datadog.opentracing.decorators
import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.tag.Tags
import spock.lang.Specification
import spock.lang.Subject
class URLAsResourceNameTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class URLAsResourceNameTest extends DDSpecification {
def writer = new ListWriter()
def tracer = new DDTracer(writer)

View File

@ -1,16 +1,16 @@
package datadog.opentracing.propagation
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.util.test.DDSpecification
import io.opentracing.SpanContext
import io.opentracing.propagation.TextMapExtractAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.B3HttpCodec.SAMPLING_PRIORITY_KEY
import static datadog.opentracing.propagation.B3HttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.B3HttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class B3HttpExtractorTest extends Specification {
class B3HttpExtractorTest extends DDSpecification {
HttpCodec.Extractor extractor = new B3HttpCodec.Extractor(["SOME_HEADER": "some-tag"])

View File

@ -5,15 +5,15 @@ import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.B3HttpCodec.SAMPLING_PRIORITY_KEY
import static datadog.opentracing.propagation.B3HttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.B3HttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class B3HttpInjectorTest extends Specification {
class B3HttpInjectorTest extends DDSpecification {
HttpCodec.Injector injector = new B3HttpCodec.Injector()

View File

@ -1,9 +1,9 @@
package datadog.opentracing.propagation
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.util.test.DDSpecification
import io.opentracing.SpanContext
import io.opentracing.propagation.TextMapExtractAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.DatadogHttpCodec.ORIGIN_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
@ -12,7 +12,7 @@ import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class DatadogHttpExtractorTest extends Specification {
class DatadogHttpExtractorTest extends DDSpecification {
HttpCodec.Extractor extractor = new DatadogHttpCodec.Extractor(["SOME_HEADER": "some-tag"])

View File

@ -5,8 +5,8 @@ import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.DatadogHttpCodec.ORIGIN_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
@ -15,7 +15,7 @@ import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class DatadogHttpInjectorTest extends Specification {
class DatadogHttpInjectorTest extends DDSpecification {
HttpCodec.Injector injector = new DatadogHttpCodec.Injector()

View File

@ -1,16 +1,16 @@
package datadog.opentracing.propagation
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.util.test.DDSpecification
import io.opentracing.SpanContext
import io.opentracing.propagation.TextMapExtractAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.HaystackHttpCodec.OT_BAGGAGE_PREFIX
import static datadog.opentracing.propagation.HaystackHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.HaystackHttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class HaystackHttpExtractorTest extends Specification {
class HaystackHttpExtractorTest extends DDSpecification {
HttpCodec.Extractor extractor = new HaystackHttpCodec.Extractor(["SOME_HEADER": "some-tag"])
@ -53,8 +53,8 @@ class HaystackHttpExtractorTest extends Specification {
where:
headers | _
[SOME_HEADER: "my-interesting-info"] | _
headers | _
[SOME_HEADER: "my-interesting-info"] | _
}
def "extract empty headers returns null"() {

View File

@ -5,15 +5,15 @@ import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.HaystackHttpCodec.OT_BAGGAGE_PREFIX
import static datadog.opentracing.propagation.HaystackHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.HaystackHttpCodec.TRACE_ID_KEY
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
class HaystackHttpInjectorTest extends Specification {
class HaystackHttpInjectorTest extends DDSpecification {
HttpCodec.Injector injector = new HaystackHttpCodec.Injector()
@ -55,7 +55,6 @@ class HaystackHttpInjectorTest extends Specification {
1 * carrier.put(OT_BAGGAGE_PREFIX + "k2", "v2")
where:
traceId | spanId | samplingPriority | origin
"1" | "2" | PrioritySampling.SAMPLER_KEEP | null

View File

@ -1,20 +1,17 @@
package datadog.opentracing.propagation
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.util.test.DDSpecification
import io.opentracing.SpanContext
import io.opentracing.propagation.TextMapExtractAdapter
import spock.lang.Shared
import spock.lang.Specification
import static datadog.opentracing.propagation.HttpCodec.UINT64_MAX
import static datadog.trace.api.Config.PropagationStyle.B3
import static datadog.trace.api.Config.PropagationStyle.DATADOG
class HttpExtractorTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class HttpExtractorTest extends DDSpecification {
@Shared
String outOfRangeTraceId = UINT64_MAX.add(BigInteger.ONE)

View File

@ -3,20 +3,16 @@ package datadog.opentracing.propagation
import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Specification
import static datadog.trace.api.Config.PropagationStyle.B3
import static datadog.trace.api.Config.PropagationStyle.DATADOG
class HttpInjectorTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class HttpInjectorTest extends DDSpecification {
def "inject http headers"() {
setup:

View File

@ -1,15 +1,11 @@
package datadog.opentracing.resolver
import datadog.opentracing.DDTracer
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.util.test.DDSpecification
import io.opentracing.contrib.tracerresolver.TracerResolver
import spock.lang.Specification
class DDTracerResolverTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DDTracerResolverTest extends DDSpecification {
def resolver = new DDTracerResolver()

View File

@ -3,14 +3,13 @@ package datadog.opentracing.scopemanager
import datadog.opentracing.DDSpan
import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.common.writer.ListWriter
import datadog.trace.context.ScopeListener
import datadog.trace.util.gc.GCUtils
import datadog.trace.util.test.DDSpecification
import io.opentracing.Scope
import io.opentracing.Span
import io.opentracing.noop.NoopSpan
import spock.lang.Specification
import spock.lang.Subject
import spock.lang.Timeout
@ -22,10 +21,7 @@ import java.util.concurrent.atomic.AtomicReference
import static java.util.concurrent.TimeUnit.SECONDS
class ScopeManagerTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class ScopeManagerTest extends DDSpecification {
def latch
def writer
def tracer

View File

@ -2,9 +2,9 @@ package datadog.trace
import datadog.opentracing.SpanFactory
import datadog.trace.api.DDTags
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
class DDSpanContextTest extends Specification {
class DDSpanContextTest extends DDSpecification {
def "null values for tags delete existing tags"() {
setup:

View File

@ -2,17 +2,16 @@ package datadog.trace
import datadog.opentracing.DDTracer
import datadog.opentracing.propagation.HttpCodec
import datadog.trace.agent.test.utils.ConfigUtils
import datadog.trace.api.Config
import datadog.trace.common.sampling.AllSampler
import datadog.trace.common.sampling.RateByServiceSampler
import datadog.trace.common.writer.DDAgentWriter
import datadog.trace.common.writer.ListWriter
import datadog.trace.common.writer.LoggingWriter
import datadog.trace.util.test.DDSpecification
import org.junit.Rule
import org.junit.contrib.java.lang.system.EnvironmentVariables
import org.junit.contrib.java.lang.system.RestoreSystemProperties
import spock.lang.Specification
import static datadog.trace.api.Config.DEFAULT_SERVICE_NAME
import static datadog.trace.api.Config.HEADER_TAGS
@ -22,10 +21,7 @@ import static datadog.trace.api.Config.SERVICE_MAPPING
import static datadog.trace.api.Config.SPAN_TAGS
import static datadog.trace.api.Config.WRITER_TYPE
class DDTracerTest extends Specification {
static {
ConfigUtils.makeConfigInstanceModifiable()
}
class DDTracerTest extends DDSpecification {
@Rule
public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()

View File

@ -0,0 +1,42 @@
package datadog.trace.api.sampling
import datadog.opentracing.DDSpan
import datadog.trace.common.sampling.AllSampler
import datadog.trace.util.test.DDSpecification
import spock.lang.Subject
import java.util.regex.Pattern
class AllSamplerTest extends DDSpecification {
@Subject
DDSpan span = Mock()
private final AllSampler sampler = new AllSampler()
def "test AllSampler"() {
expect:
for (int i = 0; i < 500; i++) {
assert sampler.doSample(span)
}
}
def "test skip tag sampler"() {
setup:
final Map<String, Object> tags = new HashMap<>()
2 * span.getTags() >> tags
sampler.addSkipTagPattern("http.url", Pattern.compile(".*/hello"))
when:
tags.put("http.url", "http://a/hello")
then:
!sampler.sample(span)
when:
tags.put("http.url", "http://a/hello2")
then:
sampler.sample(span)
}
}

View File

@ -4,11 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper
import datadog.opentracing.DDSpan
import datadog.opentracing.SpanFactory
import datadog.trace.common.sampling.RateByServiceSampler
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import static datadog.trace.common.sampling.RateByServiceSampler.DEFAULT_KEY
class RateByServiceSamplerTest extends Specification {
class RateByServiceSamplerTest extends DDSpecification {
def "invalid rate -> 1"() {
setup:

View File

@ -7,7 +7,7 @@ import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.DDAgentWriter
import datadog.trace.common.writer.DDApi
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import spock.lang.Timeout
import java.util.concurrent.TimeUnit
@ -16,7 +16,7 @@ import static datadog.opentracing.SpanFactory.newSpanOf
import static datadog.trace.common.writer.DDAgentWriter.DISRUPTOR_BUFFER_SIZE
@Timeout(20)
class DDAgentWriterTest extends Specification {
class DDAgentWriterTest extends DDSpecification {
def api = Mock(DDApi)

View File

@ -5,14 +5,14 @@ import com.fasterxml.jackson.databind.JsonNode
import datadog.opentracing.SpanFactory
import datadog.trace.common.writer.DDApi
import datadog.trace.common.writer.DDApi.ResponseListener
import spock.lang.Specification
import datadog.trace.util.test.DDSpecification
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
class DDApiTest extends Specification {
class DDApiTest extends DDSpecification {
static mapper = DDApi.OBJECT_MAPPER
def "sending an empty list of traces returns no errors"() {

View File

@ -1,22 +1,21 @@
package datadog.trace.api.writer
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import datadog.trace.util.test.DDSpecification
import org.msgpack.core.MessagePack
import org.msgpack.jackson.dataformat.MessagePackFactory
import spock.lang.Shared
import spock.lang.Specification
import static java.util.Collections.singletonMap
class SerializationTest extends Specification {
class SerializationTest extends DDSpecification {
@Shared
def jsonMapper = new ObjectMapper()
@Shared
def mpMapper = new ObjectMapper(new MessagePackFactory())
def "test json mapper serialization"() {
setup:
def map = ["key1": "val1"]

View File

@ -1,44 +0,0 @@
package datadog.trace.api.sampling;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import datadog.opentracing.DDSpan;
import datadog.trace.common.sampling.AllSampler;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.junit.Test;
import org.mockito.Mock;
public class AllSamplerTest {
@Mock DDSpan mockSpan;
private final AllSampler sampler = new AllSampler();
@Test
public void testAllSampler() {
for (int i = 0; i < 500; i++) {
assertThat(sampler.doSample(mockSpan)).isTrue();
}
}
@Test
public void testSkipTagPatternSampler() {
final Map<String, Object> tags = new HashMap<>();
mockSpan = mock(DDSpan.class);
when(mockSpan.getTags()).thenReturn(tags).thenReturn(tags);
sampler.addSkipTagPattern("http.url", Pattern.compile(".*/hello"));
tags.put("http.url", "http://a/hello");
assertThat(sampler.sample(mockSpan)).isFalse();
tags.put("http.url", "http://a/hello2");
assertThat(sampler.sample(mockSpan)).isTrue();
}
}

View File

@ -6,11 +6,11 @@ import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.DDApi
import datadog.trace.common.writer.ListWriter
import datadog.trace.util.test.DDSpecification
import org.testcontainers.containers.GenericContainer
import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy
import spock.lang.Requires
import spock.lang.Shared
import spock.lang.Specification
import java.time.Duration
import java.util.concurrent.TimeUnit
@ -20,7 +20,7 @@ class DDApiIntegrationTest {
// Do not run tests locally on Java7 since testcontainers are not compatible with Java7
// It is fine to run on CI because CI provides rabbitmq externally, not through testcontainers
@Requires({ "true" == System.getenv("CI") || jvm.java8Compatible })
static class DDApiIntegrationV4Test extends Specification {
static class DDApiIntegrationV4Test extends DDSpecification {
static final WRITER = new ListWriter()
static final TRACER = new DDTracer(WRITER)
static final CONTEXT = new DDSpanContext(

View File

@ -49,9 +49,14 @@ ext {
],
// Testing
spock : dependencies.create("org.spockframework:spock-core:${versions.spock}", {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}),
spock : [
dependencies.create("org.spockframework:spock-core:${versions.spock}", {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}),
// Used by Spock for mocking:
dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '2.6') // Last version to support Java7
],
groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}",
junit : "junit:junit:${versions.junit}",
testcontainers : "org.testcontainers:testcontainers:1.7.3",

View File

@ -13,6 +13,7 @@ include ':dd-java-agent:agent-jmxfetch'
// misc
include ':dd-java-agent:testing'
include ':utils:gc-utils'
include ':utils:test-utils'
// smoke tests
include ':dd-smoke-tests:cli'

View File

@ -0,0 +1,78 @@
package datadog.trace.util.test
import net.bytebuddy.agent.ByteBuddyAgent
import net.bytebuddy.agent.builder.AgentBuilder
import net.bytebuddy.dynamic.ClassFileLocator
import net.bytebuddy.dynamic.Transformer
import spock.lang.Specification
import java.lang.reflect.Modifier
import static net.bytebuddy.description.modifier.FieldManifestation.VOLATILE
import static net.bytebuddy.description.modifier.Ownership.STATIC
import static net.bytebuddy.description.modifier.Visibility.PUBLIC
import static net.bytebuddy.matcher.ElementMatchers.named
import static net.bytebuddy.matcher.ElementMatchers.none
abstract class DDSpecification extends Specification {
private static final String CONFIG = "datadog.trace.api.Config"
static class ConfigInstance {
// Wrapped in a static class to lazy load.
static final CONFIG_INSTANCE_FIELD = Class.forName(CONFIG).getDeclaredField("INSTANCE")
static final RUNTIME_ID_FIELD = Class.forName(CONFIG).getDeclaredField("runtimeId")
}
static {
makeConfigInstanceModifiable()
}
// Keep track of config instance already made modifiable
private static isConfigInstanceModifiable = false
static void makeConfigInstanceModifiable() {
if (isConfigInstanceModifiable) {
return
}
def instrumentation = ByteBuddyAgent.install()
final transformer =
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.RedefinitionStrategy.Listener.ErrorEscalating.FAIL_FAST)
// Config is injected into the bootstrap, so we need to provide a locator.
.with(
new AgentBuilder.LocationStrategy.Simple(
ClassFileLocator.ForClassLoader.ofSystemLoader()))
.ignore(none()) // Allow transforming bootstrap classes
.type(named(CONFIG))
.transform { builder, typeDescription, classLoader, module ->
builder
.field(named("INSTANCE"))
.transform(Transformer.ForField.withModifiers(PUBLIC, STATIC, VOLATILE))
}
// Making runtimeId modifiable so that it can be preserved when resetting config in tests
.transform { builder, typeDescription, classLoader, module ->
builder
.field(named("runtimeId"))
.transform(Transformer.ForField.withModifiers(PUBLIC, VOLATILE))
}
.installOn(instrumentation)
isConfigInstanceModifiable = true
final field = ConfigInstance.CONFIG_INSTANCE_FIELD
assert Modifier.isPublic(field.getModifiers())
assert Modifier.isStatic(field.getModifiers())
assert Modifier.isVolatile(field.getModifiers())
assert !Modifier.isFinal(field.getModifiers())
final runtimeIdField = ConfigInstance.RUNTIME_ID_FIELD
assert Modifier.isPublic(runtimeIdField.getModifiers())
assert !Modifier.isStatic(ConfigInstance.RUNTIME_ID_FIELD.getModifiers())
assert Modifier.isVolatile(runtimeIdField.getModifiers())
assert !Modifier.isFinal(runtimeIdField.getModifiers())
// No longer needed (Unless class gets retransformed somehow).
instrumentation.removeTransformer(transformer)
}
}

View File

@ -0,0 +1,9 @@
apply from: "${rootDir}/gradle/java.gradle"
dependencies {
compile deps.groovy
compile deps.spock
compile deps.bytebuddy
compile deps.bytebuddyagent
}