-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1505 from embrace-io/otel-export-assertions
Add otel export assertions to integration tests
- Loading branch information
Showing
11 changed files
with
218 additions
and
18 deletions.
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
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
31 changes: 31 additions & 0 deletions
31
...o/embrace/android/embracesdk/testframework/actions/EmbraceOtelExportAssertionInterface.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,31 @@ | ||
package io.embrace.android.embracesdk.testframework.actions | ||
|
||
import io.embrace.android.embracesdk.internal.arch.schema.EmbType | ||
import io.embrace.android.embracesdk.testframework.export.ExportedSpanValidator | ||
import io.embrace.android.embracesdk.testframework.export.FilteredSpanExporter | ||
import io.opentelemetry.sdk.trace.data.SpanData | ||
|
||
/** | ||
* Provides assertions that can be used in integration tests to validate the behavior of the SDK, | ||
* specifically in what its OTel export looks like. | ||
*/ | ||
internal class EmbraceOtelExportAssertionInterface( | ||
private val spanExporter: FilteredSpanExporter, | ||
private val validator: ExportedSpanValidator = ExportedSpanValidator() | ||
) { | ||
|
||
/** | ||
* Retrieves spans with the specified type and waits until either the expected | ||
* number of spans is reached or a timeout is exceeded. | ||
*/ | ||
fun awaitSpansWithType(type: EmbType, expectedCount: Int): List<SpanData> { | ||
return spanExporter.awaitSpansWithType(type, expectedCount) | ||
} | ||
|
||
/** | ||
* Asserts that the provided spans match the golden file. | ||
*/ | ||
fun assertSpansMatchGoldenFile(spans: List<SpanData>, goldenFile: String) { | ||
validator.validate(spans, goldenFile) | ||
} | ||
} |
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
57 changes: 57 additions & 0 deletions
57
...onTest/kotlin/io/embrace/android/embracesdk/testframework/export/ExportedSpanValidator.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,57 @@ | ||
package io.embrace.android.embracesdk.testframework.export | ||
|
||
import com.squareup.moshi.Types | ||
import io.embrace.android.embracesdk.ResourceReader | ||
import io.embrace.android.embracesdk.fakes.TestPlatformSerializer | ||
import io.embrace.android.embracesdk.internal.utils.threadLocal | ||
import io.opentelemetry.sdk.trace.data.SpanData | ||
import org.junit.Assert.assertEquals | ||
|
||
internal class ExportedSpanValidator { | ||
|
||
private val serializer: TestPlatformSerializer by threadLocal { | ||
TestPlatformSerializer() | ||
} | ||
|
||
private val type = | ||
Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java) | ||
private val listType = Types.newParameterizedType(List::class.java, type) | ||
|
||
fun validate(spanDataList: List<SpanData>, goldenFile: String) { | ||
val expected: List<Map<String, Any>> = readExpectedSpan(goldenFile) | ||
val actual = spanDataList.map { it.representAsMap() } | ||
assertEquals(expected, actual) | ||
} | ||
|
||
private fun readExpectedSpan(goldenFile: String): List<Map<String, String>> { | ||
val inputStream = ResourceReader.readResource(goldenFile) | ||
return serializer.fromJson(inputStream, listType) | ||
} | ||
|
||
private fun SpanData.representAsMap(): Map<String, Any> { | ||
val attrs: Map<String, String> = representAttributes() | ||
return mapOf( | ||
"name" to name, | ||
"kind" to kind.toString(), | ||
"status" to status.statusCode.toString(), | ||
"startEpochNanos" to startEpochNanos.toString(), | ||
"endEpochNanos" to endEpochNanos.toString(), | ||
"hasEnded" to hasEnded().toString(), | ||
"totalAttributeCount" to totalAttributeCount.toString(), | ||
"attributes" to attrs, | ||
"totalRecordedEvents" to totalRecordedEvents.toString(), | ||
"events" to events, | ||
"instrumentationScopeName" to instrumentationScopeInfo.name, | ||
) | ||
} | ||
|
||
private fun SpanData.representAttributes(): Map<String, String> { | ||
val ignoreList = listOf("emb.process_identifier", "emb.private.sequence_id") | ||
val attrs: Map<String, String> = attributes.asMap().map { | ||
it.key.key to it.value.toString() | ||
}.toMap() | ||
.filter { it.key !in ignoreList } | ||
.toSortedMap(compareBy { it }) | ||
return attrs | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
...ionTest/kotlin/io/embrace/android/embracesdk/testframework/export/FilteredSpanExporter.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,54 @@ | ||
package io.embrace.android.embracesdk.testframework.export | ||
|
||
import io.embrace.android.embracesdk.assertions.returnIfConditionMet | ||
import io.embrace.android.embracesdk.internal.arch.schema.EmbType | ||
import io.opentelemetry.sdk.common.CompletableResultCode | ||
import io.opentelemetry.sdk.trace.data.SpanData | ||
import io.opentelemetry.sdk.trace.export.SpanExporter | ||
|
||
/** | ||
* A [SpanExporter] used in the integration tests that allows retrieving exported spans | ||
* to perform assertions against. | ||
*/ | ||
internal class FilteredSpanExporter : SpanExporter { | ||
|
||
private val spanData = mutableListOf<SpanData>() | ||
|
||
override fun export(spans: MutableCollection<SpanData>): CompletableResultCode { | ||
spanData.addAll(spans) | ||
return CompletableResultCode.ofSuccess() | ||
} | ||
|
||
override fun flush(): CompletableResultCode { | ||
return CompletableResultCode.ofSuccess() | ||
} | ||
|
||
override fun shutdown(): CompletableResultCode { | ||
return CompletableResultCode.ofSuccess() | ||
} | ||
|
||
fun awaitSpansWithType(type: EmbType, expectedCount: Int): List<SpanData> { | ||
return awaitSpanExport({ | ||
it.attributes.asMap().any { entry -> | ||
entry.key.key == "emb.type" && entry.value == type.value | ||
} | ||
}, expectedCount) | ||
} | ||
|
||
private fun awaitSpanExport( | ||
spanFilter: (SpanData) -> Boolean, | ||
expectedCount: Int, | ||
): List<SpanData> { | ||
val supplier = { spanData.filter(spanFilter) } | ||
return returnIfConditionMet( | ||
desiredValueSupplier = supplier, | ||
dataProvider = supplier, | ||
condition = { data -> | ||
data.size == expectedCount | ||
}, | ||
errorMessageSupplier = { | ||
"Timeout. Expected $expectedCount spans, but got ${supplier().size}." | ||
} | ||
) | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
embrace-android-sdk/src/integrationTest/resources/system-low-power-export.json
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,17 @@ | ||
[ | ||
{ | ||
"name": "emb-device-low-power", | ||
"kind": "INTERNAL", | ||
"status": "UNSET", | ||
"startEpochNanos": "169220160000000000", | ||
"endEpochNanos": "169220163000000000", | ||
"hasEnded": "true", | ||
"totalAttributeCount": "3", | ||
"attributes": { | ||
"emb.type": "sys.low_power" | ||
}, | ||
"totalRecordedEvents": "0", | ||
"events": [], | ||
"instrumentationScopeName": "io.embrace.android.embracesdk.core" | ||
} | ||
] |
18 changes: 18 additions & 0 deletions
18
embrace-android-sdk/src/integrationTest/resources/ux-view-export.json
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,18 @@ | ||
[ | ||
{ | ||
"name": "emb-screen-view", | ||
"kind": "INTERNAL", | ||
"status": "UNSET", | ||
"startEpochNanos": "169220160000000000", | ||
"endEpochNanos": "169220190000000000", | ||
"hasEnded": "true", | ||
"totalAttributeCount": "4", | ||
"attributes": { | ||
"emb.type": "ux.view", | ||
"view.name": "android.app.Activity" | ||
}, | ||
"totalRecordedEvents": "0", | ||
"events": [], | ||
"instrumentationScopeName": "io.embrace.android.embracesdk.core" | ||
} | ||
] |