Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dd-java-agent/instrumentation-testing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies {

implementation project(':dd-java-agent:agent-debugger')

implementation 'org.junit.platform:junit-platform-runner:1.9.0'
implementation "org.junit.platform:junit-platform-runner:${libs.versions.junit.platform.get()}"

testImplementation project(':dd-java-agent:instrumentation:trace-annotation')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,20 @@ import datadog.trace.agent.tooling.TracerInstaller
import datadog.trace.agent.tooling.bytebuddy.matcher.ClassLoaderMatchers
import datadog.trace.agent.tooling.bytebuddy.matcher.GlobalIgnores
import datadog.trace.api.Config
import datadog.trace.api.DDSpanId
import datadog.trace.api.IdGenerationStrategy
import datadog.trace.api.ProcessTags
import datadog.trace.api.StatsDClient
import datadog.trace.api.TraceConfig
import datadog.trace.api.config.GeneralConfig
import datadog.trace.api.config.TracerConfig
import datadog.trace.api.gateway.RequestContext
import datadog.trace.api.internal.TraceSegment
import datadog.trace.api.datastreams.AgentDataStreamsMonitoring
import datadog.trace.api.sampling.SamplingRule
import datadog.trace.api.time.SystemTimeSource
import datadog.trace.api.datastreams.AgentDataStreamsMonitoring
import datadog.trace.bootstrap.ActiveSubsystems
import datadog.trace.bootstrap.CallDepthThreadLocalMap
import datadog.trace.bootstrap.InstrumentationErrors
import datadog.trace.bootstrap.debugger.DebuggerContext
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI
import datadog.trace.bootstrap.instrumentation.api.AgentTracer
import datadog.trace.common.metrics.EventListener
import datadog.trace.common.metrics.Sink
import datadog.trace.common.writer.DDAgentWriter
Expand Down Expand Up @@ -70,7 +66,6 @@ import org.junit.jupiter.api.extension.ExtendWith
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.spockframework.mock.MockUtil
import org.spockframework.mock.runtime.MockInvocation
import spock.lang.Shared

import java.lang.instrument.ClassFileTransformer
Expand Down Expand Up @@ -152,7 +147,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A

@SuppressWarnings('PropertyName')
@Shared
TracerAPI TEST_TRACER
AgentTracer.TracerAPI TEST_TRACER

@SuppressWarnings('PropertyName')
@Shared
Expand All @@ -175,10 +170,6 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
@Shared
TestProfilingContextIntegration TEST_PROFILING_CONTEXT_INTEGRATION = new TestProfilingContextIntegration()

@SuppressWarnings('PropertyName')
@Shared
Set<DDSpanId> TEST_SPANS = Sets.newHashSet()

@SuppressWarnings('PropertyName')
@Shared
RecordingDatastreamsPayloadWriter TEST_DATA_STREAMS_WRITER
Expand Down Expand Up @@ -264,7 +255,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
@Shared
ConcurrentHashMap<DDSpan, List<Exception>> spanFinishLocations = new ConcurrentHashMap<>()
@Shared
ConcurrentHashMap<DDSpan, DDSpan> originalToSpySpan = new ConcurrentHashMap<>()
ConcurrentHashMap<DDSpan, DDSpan> originalToTrackingSpan = new ConcurrentHashMap<>()

protected boolean enabledFinishTimingChecks() {
false
Expand Down Expand Up @@ -399,67 +390,13 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
boolean enabledFinishTimingChecks = this.enabledFinishTimingChecks()
TEST_TRACER.startSpan(*_) >> {
AgentSpan agentSpan = callRealMethod()
TEST_SPANS.add(agentSpan.spanId)
if (!enabledFinishTimingChecks) {
return agentSpan
}

// rest of closure if for checking duplicate finishes and tags set after finish
AgentSpan spiedAgentSpan = Spy(agentSpan)
originalToSpySpan[agentSpan] = spiedAgentSpan
def handleFinish = { MockInvocation mi ->
def depth = CallDepthThreadLocalMap.incrementCallDepth(DDSpan)
try {
if (depth > 0) {
return
}
List<Exception> locations
List<Exception> newLocations
do {
locations = spanFinishLocations.get(agentSpan)
newLocations = (locations ?: []) + new Exception()
} while (!(locations == null ?
spanFinishLocations.putIfAbsent(agentSpan, newLocations) == null :
spanFinishLocations.replace(agentSpan, locations, newLocations)))
mi.callRealMethod()
} finally {
CallDepthThreadLocalMap.decrementCallDepth(DDSpan)
}
}
spiedAgentSpan.finish() >> {
handleFinish(delegate)
}
spiedAgentSpan.finish(_ as long) >> {
handleFinish(delegate)
}
spiedAgentSpan.finishWithDuration() >> {
handleFinish(delegate)
}
spiedAgentSpan.finishWithEndToEnd() >> {
handleFinish(delegate)
}
spiedAgentSpan.getLocalRootSpan() >> {
DDSpan unwrappedSpan = callRealMethod()
originalToSpySpan.getOrDefault(unwrappedSpan, unwrappedSpan)
}
RequestContext requestContext = agentSpan.getRequestContext()
TraceSegment segment = requestContext.getTraceSegment()
RequestContext spiedReqCtx = Spy(requestContext)
TraceSegment checkedSegment = new PreconditionCheckTraceSegment(
check: {
-> if (useStrictTraceWrites() && spiedAgentSpan.localRootSpan.isFinished()) {
throw new AssertionError("Interaction with TraceSegment after root span has already finished: $spiedAgentSpan")
}},
delegate: segment
)
spiedAgentSpan.getRequestContext() >> {
spiedReqCtx
}
spiedReqCtx.getTraceSegment() >> {
checkedSegment
}

spiedAgentSpan
def trackingSpan = new TrackingSpanDecorator(agentSpan, spanFinishLocations, originalToTrackingSpan, useStrictTraceWrites())
originalToTrackingSpan[agentSpan] = trackingSpan
return trackingSpan
}

// if a test enables the instrumentation it verifies,
Expand Down Expand Up @@ -498,7 +435,6 @@ abstract class InstrumentationSpecification extends DDSpecification implements A

println "Starting test: ${getSpecificationContext().getCurrentIteration().getName()} from ${specificationContext.currentSpec.name}"
TEST_TRACER.flush()
TEST_SPANS.clear()

if (isTestAgentEnabled()) {
TEST_AGENT_WRITER.flush()
Expand Down Expand Up @@ -561,7 +497,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
}
} finally {
spanFinishLocations.clear()
originalToSpySpan.clear()
originalToTrackingSpan.clear()
}
assert InstrumentationErrors.errorCount == 0
}
Expand All @@ -578,7 +514,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
pw.write "Location $i:\n"
def st = e.stackTrace
int loc = st.findIndexOf {
it.className.startsWith('datadog.trace.core.DDSpan$SpockMock$') &&
it.className.startsWith(TrackingSpanDecorator.class.name) &&
it.methodName.startsWith('finish')
}
for (int j = loc == -1 ? 0 : loc; j < st.length; j++) {
Expand All @@ -590,77 +526,6 @@ abstract class InstrumentationSpecification extends DDSpecification implements A
}
}

class PreconditionCheckTraceSegment implements TraceSegment {
Closure check
TraceSegment delegate

@Override
void setTagTop(String key, Object value, boolean sanitize) {
check()
delegate.setTagTop(key, value, sanitize)
}

@Override
void setTagCurrent(String key, Object value, boolean sanitize) {
check()
delegate.setTagCurrent(key, value, sanitize)
}

@Override
Object getTagTop(String key, boolean sanitize) {
check()
return delegate.getTagTop(key, sanitize)
}

@Override
Object getTagCurrent(String key, boolean sanitize) {
check()
return delegate.getTagCurrent(key, sanitize)
}

@Override
void setDataTop(String key, Object value) {
check()
delegate.setDataTop(key, value)
}

@Override
Object getDataTop(String key) {
check()
return delegate.getDataTop(key)
}

@Override
void setMetaStructTop(String key, Object value) {
check()
delegate.setMetaStructTop(key, value)
}

@Override
void setMetaStructCurrent(String key, Object value) {
check()
delegate.setMetaStructCurrent(key, value)
}

@Override
void effectivelyBlocked() {
check()
delegate.effectivelyBlocked()
}

@Override
void setDataCurrent(String key, Object value) {
check()
delegate.setDataCurrent(key, value)
}

@Override
Object getDataCurrent(String key) {
check()
return delegate.getDataCurrent(key)
}
}

/** Override to clean up things after the agent is removed */
protected void cleanupAfterAgent() {}

Expand Down Expand Up @@ -793,5 +658,3 @@ class AbortTransformationException extends RuntimeException {
super(message)
}
}


Loading