-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RUM-1520 Single Feature Integration Tests: Trace #1786
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3ce4e8b
RUM-1520 Add missing log tags assertions
xgouchet 804a669
RUM-1520 improve shared StubSdkCore
xgouchet 22761fc
RUM-1520 Add Trace integration tests
xgouchet 8733d29
RUM-1520 improve the coverage tools
xgouchet 988c2f2
RUM-1520 fix code review comments
xgouchet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
...bility/single-fit/logs/src/test/kotlin/com/datadog/android/logs/integration/LoggerTest.kt
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
479 changes: 479 additions & 0 deletions
479
...ngle-fit/trace/src/test/kotlin/com/datadog/android/trace/integration/AndroidTracerTest.kt
Large diffs are not rendered by default.
Oops, something went wrong.
37 changes: 0 additions & 37 deletions
37
...single-fit/trace/src/test/kotlin/com/datadog/android/trace/integration/ScaffoldingTest.kt
This file was deleted.
Oops, something went wrong.
47 changes: 47 additions & 0 deletions
47
...ability/single-fit/trace/src/test/kotlin/com/datadog/android/trace/integration/SpanExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
package com.datadog.android.trace.integration | ||
|
||
import com.datadog.android.core.internal.utils.toHexString | ||
import io.opentracing.Span | ||
import io.opentracing.SpanContext | ||
|
||
/** | ||
* Returns the span's traceId in hex format. | ||
* The [SpanContext.toTraceId] method returns a string in decimal format, | ||
* which doesn't match what we send in our events | ||
*/ | ||
fun Span.traceIdAsHexString(): String { | ||
return context().toTraceId().toLong().toHexString() | ||
} | ||
|
||
/** | ||
* Returns the span's spanId in hex format. | ||
* The [SpanContext.toSpanId] method returns a string in decimal format, | ||
* which doesn't match what we send in our events | ||
*/ | ||
fun Span.spanIdAsHexString(): String { | ||
return context().toSpanId().toLong().toHexString() | ||
} | ||
|
||
/** | ||
* Returns the span's traceId in hex format. | ||
0xnm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* The [SpanContext.toTraceId] method returns a string in decimal format, | ||
* which doesn't match what we send in our events | ||
*/ | ||
fun Span.traceIdAsLong(): Long { | ||
return context().toTraceId().toLong() | ||
} | ||
|
||
/** | ||
* Returns the span's spanId in as Long. | ||
* The [SpanContext.toSpanId] method returns a string in decimal format, | ||
* which doesn't match what we send in our events | ||
*/ | ||
fun Span.spanIdAsLong(): Long { | ||
return context().toSpanId().toLong() | ||
} |
261 changes: 261 additions & 0 deletions
261
...fit/trace/src/test/kotlin/com/datadog/android/trace/integration/TraceConfigurationTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
package com.datadog.android.trace.integration | ||
|
||
import com.datadog.android.api.feature.Feature | ||
import com.datadog.android.api.feature.StorageBackedFeature | ||
import com.datadog.android.api.storage.RawBatchEvent | ||
import com.datadog.android.core.stub.StubSDKCore | ||
import com.datadog.android.tests.ktx.getInt | ||
import com.datadog.android.tests.ktx.getLong | ||
import com.datadog.android.tests.ktx.getString | ||
import com.datadog.android.trace.AndroidTracer | ||
import com.datadog.android.trace.Trace | ||
import com.datadog.android.trace.TraceConfiguration | ||
import com.datadog.android.trace.event.SpanEventMapper | ||
import com.datadog.android.trace.integration.tests.elmyr.TraceIntegrationForgeConfigurator | ||
import com.datadog.android.trace.model.SpanEvent | ||
import com.datadog.tools.unit.extensions.TestConfigurationExtension | ||
import com.datadog.tools.unit.setStaticValue | ||
import com.google.gson.JsonObject | ||
import com.google.gson.JsonParser | ||
import fr.xgouchet.elmyr.Forge | ||
import fr.xgouchet.elmyr.annotation.Forgery | ||
import fr.xgouchet.elmyr.annotation.StringForgery | ||
import fr.xgouchet.elmyr.junit5.ForgeConfiguration | ||
import fr.xgouchet.elmyr.junit5.ForgeExtension | ||
import io.opentracing.util.GlobalTracer | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.AfterEach | ||
import org.junit.jupiter.api.BeforeEach | ||
import org.junit.jupiter.api.RepeatedTest | ||
import org.junit.jupiter.api.extension.ExtendWith | ||
import org.junit.jupiter.api.extension.Extensions | ||
import org.mockito.junit.jupiter.MockitoExtension | ||
import org.mockito.junit.jupiter.MockitoSettings | ||
import org.mockito.quality.Strictness | ||
import java.util.concurrent.TimeUnit | ||
import kotlin.system.measureNanoTime | ||
|
||
@Extensions( | ||
ExtendWith(MockitoExtension::class), | ||
ExtendWith(ForgeExtension::class), | ||
ExtendWith(TestConfigurationExtension::class) | ||
) | ||
@ForgeConfiguration(TraceIntegrationForgeConfigurator::class) | ||
@MockitoSettings(strictness = Strictness.LENIENT) | ||
class TraceConfigurationTest { | ||
|
||
private lateinit var stubSdkCore: StubSDKCore | ||
|
||
@BeforeEach | ||
fun `set up`(forge: Forge) { | ||
stubSdkCore = StubSDKCore(forge) | ||
|
||
val fakeTraceConfiguration = TraceConfiguration.Builder().build() | ||
Trace.enable(fakeTraceConfiguration, stubSdkCore) | ||
} | ||
|
||
@AfterEach | ||
fun `tear down`() { | ||
GlobalTracer::class.java.setStaticValue("isRegistered", false) | ||
} | ||
|
||
@RepeatedTest(16) | ||
fun `M create request to core site W RequestFactory#create()`( | ||
@Forgery fakeBatch: List<RawBatchEvent>, | ||
@StringForgery fakeMetadata: String | ||
) { | ||
// Given | ||
val expectedSite = stubSdkCore.getDatadogContext().site | ||
val expectedClientToken = stubSdkCore.getDatadogContext().clientToken | ||
val expectedSource = stubSdkCore.getDatadogContext().source | ||
val expectedSdkVersion = stubSdkCore.getDatadogContext().sdkVersion | ||
|
||
// When | ||
val traceFeature = stubSdkCore.getFeature(Feature.TRACING_FEATURE_NAME)?.unwrap<StorageBackedFeature>() | ||
val requestFactory = traceFeature?.requestFactory | ||
val request = requestFactory?.create(stubSdkCore.getDatadogContext(), fakeBatch, fakeMetadata.toByteArray()) | ||
|
||
// Then | ||
checkNotNull(request) | ||
assertThat(request.url).isEqualTo("${expectedSite.intakeEndpoint}/api/v2/spans") | ||
assertThat(request.headers).containsEntry("DD-API-KEY", expectedClientToken) | ||
assertThat(request.headers).containsEntry("DD-EVP-ORIGIN", expectedSource) | ||
assertThat(request.headers).containsEntry("DD-EVP-ORIGIN-VERSION", expectedSdkVersion) | ||
assertThat(request.contentType).isEqualTo("text/plain;charset=UTF-8") | ||
} | ||
|
||
@RepeatedTest(16) | ||
fun `M create request to custom endpoint W useCustomEndpoint() + RequestFactory#create`( | ||
@StringForgery fakeEndpoint: String, | ||
@Forgery fakeBatch: List<RawBatchEvent>, | ||
@StringForgery fakeMetadata: String | ||
) { | ||
// Given | ||
val expectedClientToken = stubSdkCore.getDatadogContext().clientToken | ||
val expectedSource = stubSdkCore.getDatadogContext().source | ||
val expectedSdkVersion = stubSdkCore.getDatadogContext().sdkVersion | ||
val fakeTraceConfiguration = TraceConfiguration.Builder() | ||
.useCustomEndpoint(fakeEndpoint) | ||
.build() | ||
Trace.enable(fakeTraceConfiguration, stubSdkCore) | ||
|
||
// When | ||
val traceFeature = stubSdkCore.getFeature(Feature.TRACING_FEATURE_NAME)?.unwrap<StorageBackedFeature>() | ||
val requestFactory = traceFeature?.requestFactory | ||
val request = requestFactory?.create(stubSdkCore.getDatadogContext(), fakeBatch, fakeMetadata.toByteArray()) | ||
|
||
// Then | ||
checkNotNull(request) | ||
assertThat(request.url).isEqualTo("$fakeEndpoint/api/v2/spans") | ||
assertThat(request.headers).containsEntry("DD-API-KEY", expectedClientToken) | ||
assertThat(request.headers).containsEntry("DD-EVP-ORIGIN", expectedSource) | ||
assertThat(request.headers).containsEntry("DD-EVP-ORIGIN-VERSION", expectedSdkVersion) | ||
assertThat(request.contentType).isEqualTo("text/plain;charset=UTF-8") | ||
} | ||
|
||
@RepeatedTest(16) | ||
fun `M send span without network info W setNetworkInfoEnabled(false) + buildSpan() + start() + finish()`( | ||
@StringForgery fakeOperation: String | ||
) { | ||
// Given | ||
val fakeTraceConfiguration = TraceConfiguration.Builder() | ||
.setNetworkInfoEnabled(false) | ||
.build() | ||
Trace.enable(fakeTraceConfiguration, stubSdkCore) | ||
val testedTracer = AndroidTracer.Builder(stubSdkCore).build() | ||
|
||
// When | ||
var traceId: String | ||
var spanId: String | ||
val fullDuration = measureNanoTime { | ||
val span = testedTracer.buildSpan(fakeOperation).start() | ||
traceId = span.traceIdAsHexString() | ||
spanId = span.spanIdAsHexString() | ||
Thread.sleep(OP_DURATION_MS) | ||
span.finish() | ||
} | ||
|
||
// Then | ||
val eventsWritten = stubSdkCore.eventsWritten(Feature.TRACING_FEATURE_NAME) | ||
assertThat(eventsWritten).hasSize(1) | ||
val event0 = JsonParser.parseString(eventsWritten[0].eventData) as JsonObject | ||
println(event0) | ||
0xnm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assertThat(event0.getString("env")).isEqualTo(stubSdkCore.getDatadogContext().env) | ||
assertThat(event0.getString("spans[0].trace_id")).isEqualTo(traceId) | ||
assertThat(event0.getString("spans[0].span_id")).isEqualTo(spanId) | ||
assertThat(event0.getString("spans[0].service")).isEqualTo(stubSdkCore.getDatadogContext().service) | ||
assertThat(event0.getString("spans[0].meta.version")).isEqualTo(stubSdkCore.getDatadogContext().version) | ||
assertThat(event0.getString("spans[0].meta._dd.source")).isEqualTo(stubSdkCore.getDatadogContext().source) | ||
assertThat(event0.getString("spans[0].meta.tracer.version")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().sdkVersion) | ||
assertThat(event0.getInt("spans[0].error")).isEqualTo(0) | ||
assertThat(event0.getString("spans[0].name")).isEqualTo(fakeOperation) | ||
assertThat(event0.getString("spans[0].resource")).isEqualTo(fakeOperation) | ||
assertThat(event0.getLong("spans[0].duration")).isBetween(OP_DURATION_NS, fullDuration) | ||
assertThat(event0.getString("spans[0].meta.network.client.connectivity")).isNull() | ||
assertThat(event0.getString("spans[0].meta.network.client.sim_carrier.name")).isNull() | ||
assertThat(event0.getString("spans[0].meta.network.client.sim_carrier.id")).isNull() | ||
} | ||
|
||
@RepeatedTest(16) | ||
fun `M send span with network info W setNetworkInfoEnabled(true) + buildSpan() + start() + finish()`( | ||
@StringForgery fakeOperation: String | ||
) { | ||
// Given | ||
val fakeTraceConfiguration = TraceConfiguration.Builder() | ||
.setNetworkInfoEnabled(true) | ||
.build() | ||
Trace.enable(fakeTraceConfiguration, stubSdkCore) | ||
val testedTracer = AndroidTracer.Builder(stubSdkCore).build() | ||
|
||
// When | ||
var traceId: String | ||
var spanId: String | ||
val fullDuration = measureNanoTime { | ||
val span = testedTracer.buildSpan(fakeOperation).start() | ||
traceId = span.traceIdAsHexString() | ||
spanId = span.spanIdAsHexString() | ||
Thread.sleep(OP_DURATION_MS) | ||
span.finish() | ||
} | ||
|
||
// Then | ||
val eventsWritten = stubSdkCore.eventsWritten(Feature.TRACING_FEATURE_NAME) | ||
assertThat(eventsWritten).hasSize(1) | ||
val event0 = JsonParser.parseString(eventsWritten[0].eventData) as JsonObject | ||
println(event0) | ||
assertThat(event0.getString("env")).isEqualTo(stubSdkCore.getDatadogContext().env) | ||
assertThat(event0.getString("spans[0].trace_id")).isEqualTo(traceId) | ||
assertThat(event0.getString("spans[0].span_id")).isEqualTo(spanId) | ||
assertThat(event0.getString("spans[0].service")).isEqualTo(stubSdkCore.getDatadogContext().service) | ||
assertThat(event0.getString("spans[0].meta.version")).isEqualTo(stubSdkCore.getDatadogContext().version) | ||
assertThat(event0.getString("spans[0].meta._dd.source")).isEqualTo(stubSdkCore.getDatadogContext().source) | ||
assertThat(event0.getString("spans[0].meta.tracer.version")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().sdkVersion) | ||
assertThat(event0.getInt("spans[0].error")).isEqualTo(0) | ||
assertThat(event0.getString("spans[0].name")).isEqualTo(fakeOperation) | ||
assertThat(event0.getString("spans[0].resource")).isEqualTo(fakeOperation) | ||
assertThat(event0.getLong("spans[0].duration")).isBetween(OP_DURATION_NS, fullDuration) | ||
assertThat(event0.getString("spans[0].meta.network.client.connectivity")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().networkInfo.connectivity.name) | ||
assertThat(event0.getString("spans[0].meta.network.client.sim_carrier.name")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().networkInfo.carrierName) | ||
assertThat(event0.getLong("spans[0].meta.network.client.sim_carrier.id")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().networkInfo.carrierId) | ||
} | ||
|
||
@RepeatedTest(16) | ||
fun `M send mapped span W setEventMapper() + buildSpan() + start() + finish()`( | ||
@StringForgery fakeOperation: String, | ||
@StringForgery fakeMappedOperation: String, | ||
@StringForgery fakeMappedResource: String | ||
) { | ||
// Given | ||
val stubMapper = object : SpanEventMapper { | ||
override fun map(event: SpanEvent): SpanEvent { | ||
event.name = fakeMappedOperation | ||
event.resource = fakeMappedResource | ||
return event | ||
} | ||
} | ||
val fakeTraceConfiguration = TraceConfiguration.Builder() | ||
.setEventMapper(stubMapper) | ||
.build() | ||
Trace.enable(fakeTraceConfiguration, stubSdkCore) | ||
val testedTracer = AndroidTracer.Builder(stubSdkCore).build() | ||
|
||
// When | ||
val fullDuration = measureNanoTime { | ||
val span = testedTracer.buildSpan(fakeOperation).start() | ||
Thread.sleep(OP_DURATION_MS) | ||
span.finish() | ||
} | ||
|
||
// Then | ||
val eventsWritten = stubSdkCore.eventsWritten(Feature.TRACING_FEATURE_NAME) | ||
assertThat(eventsWritten).hasSize(1) | ||
val event0 = JsonParser.parseString(eventsWritten[0].eventData) as JsonObject | ||
println(event0) | ||
assertThat(event0.getString("env")).isEqualTo(stubSdkCore.getDatadogContext().env) | ||
assertThat(event0.getString("spans[0].service")).isEqualTo(stubSdkCore.getDatadogContext().service) | ||
assertThat(event0.getString("spans[0].meta.version")).isEqualTo(stubSdkCore.getDatadogContext().version) | ||
assertThat(event0.getString("spans[0].meta._dd.source")).isEqualTo(stubSdkCore.getDatadogContext().source) | ||
assertThat(event0.getString("spans[0].meta.tracer.version")) | ||
.isEqualTo(stubSdkCore.getDatadogContext().sdkVersion) | ||
assertThat(event0.getInt("spans[0].error")).isEqualTo(0) | ||
assertThat(event0.getString("spans[0].name")).isEqualTo(fakeMappedOperation) | ||
assertThat(event0.getString("spans[0].resource")).isEqualTo(fakeMappedResource) | ||
assertThat(event0.getLong("spans[0].duration")).isBetween(OP_DURATION_NS, fullDuration) | ||
} | ||
|
||
companion object { | ||
const val OP_DURATION_MS = 10L | ||
val OP_DURATION_NS = TimeUnit.MILLISECONDS.toNanos(OP_DURATION_MS) | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change is needed?
First, with this change we can have a false positive warning in LogCat about missing Logs features, when it is actually registered.
Second, we can have then a possibility to not send anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essentially this is to avoid sending a useless log: if the
fields
map is empty, then we will send a log with a default message (that just says "span log") with no custom attributes, providing no information whatsoever.But indeed we might get a false positive logcat message, I'll fix that.