Skip to content

Commit 4c15d96

Browse files
committed
adds unit tets for replay exporter
1 parent 33a2f9e commit 4c15d96

File tree

3 files changed

+482
-29
lines changed

3 files changed

+482
-29
lines changed

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/RRwebGraphQLReplayLogExporter.kt

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,21 @@ private const val REPLAY_EXPORTER_NAME = "RRwebGraphQLReplayLogExporter"
2121
*
2222
* @param organizationVerboseId the organization verbose id for the LaunchDarkly customer
2323
* @param backendUrl The backend URL the GraphQL operations
24+
* @param serviceName The service name
25+
* @param serviceVersion The service version
26+
* @param injectedReplayApiService Optional SessionReplayApiService for testing. If null, a default service will be created.
2427
*/
2528
class RRwebGraphQLReplayLogExporter(
2629
val organizationVerboseId: String,
2730
val backendUrl: String,
2831
val serviceName: String,
2932
val serviceVersion: String,
33+
private val injectedReplayApiService: SessionReplayApiService? = null
3034
) : LogRecordExporter {
3135
private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
3236

3337
private var graphqlClient: GraphQLClient = GraphQLClient(backendUrl)
34-
private var replayApiService: SessionReplayApiService = SessionReplayApiService(
38+
private val replayApiService: SessionReplayApiService = injectedReplayApiService ?: SessionReplayApiService(
3539
graphqlClient = graphqlClient,
3640
serviceName = serviceName,
3741
serviceVersion = serviceVersion,
@@ -49,8 +53,6 @@ class RRwebGraphQLReplayLogExporter(
4953

5054
coroutineScope.launch {
5155
try {
52-
var allSuccessful = true
53-
5456
for (log in logs) {
5557
val capture = extractCaptureFromLog(log)
5658
if (capture != null) {
@@ -63,19 +65,18 @@ class RRwebGraphQLReplayLogExporter(
6365
sendCaptureIncremental(capture)
6466
}
6567
if (!success) {
66-
allSuccessful = false
68+
// Stop processing immediately on first failure
69+
resultCode.fail()
70+
return@launch
6771
}
6872
}
6973
}
7074

71-
if (allSuccessful) {
72-
resultCode.succeed()
73-
} else {
74-
resultCode.fail()
75-
}
75+
// All captures processed successfully
76+
resultCode.succeed()
7677
} catch (e: Exception) {
7778
// TODO: O11Y-627 - pass in logger to implementation and use here
78-
Log.e("RRwebGraphQLReplayLogExporter", "Error during export: ${e.message}", e)
79+
// Log.e("RRwebGraphQLReplayLogExporter", "Error during export: ${e.message}", e)
7980
resultCode.fail()
8081
}
8182
}
@@ -160,20 +161,21 @@ class RRwebGraphQLReplayLogExporter(
160161
)
161162
)
162163

163-
// record last sent state
164+
replayApiService.pushPayload(capture.session, "${nextPayloadId()}", eventsBatch)
165+
166+
// record last sent state only after successful completion
164167
lastSessionId = capture.session
165168
lastSentWidth = capture.origWidth
166169
lastSentHeight = capture.origHeight
167-
168-
replayApiService.pushPayload(capture.session, "${nextPayloadId()}", eventsBatch)
170+
169171
true
170172
} catch (e: Exception) {
171173
// TODO: O11Y-627 - pass in logger to implementation and use here
172-
Log.e(
173-
REPLAY_EXPORTER_NAME,
174-
"Error sending incremental capture for session: ${e.message}",
175-
e
176-
)
174+
// Log.e(
175+
// REPLAY_EXPORTER_NAME,
176+
// "Error sending incremental capture for session: ${e.message}",
177+
// e
178+
// )
177179
false
178180
}
179181
}
@@ -272,22 +274,22 @@ class RRwebGraphQLReplayLogExporter(
272274
)
273275
eventBatch.add(viewportEvent)
274276

275-
// record last sent state
277+
// TODO: O11Y-624 - double check error case handling, may need to add retries per api service request, should subsequent requests wait for previous requests to succeed?
278+
replayApiService.pushPayload(capture.session, "${nextPayloadId()}", eventBatch)
279+
280+
// record last sent state only after successful completion
276281
lastSessionId = capture.session
277282
lastSentWidth = capture.origWidth
278283
lastSentHeight = capture.origHeight
279284

280-
// TODO: O11Y-624 - double check error case handling, may need to add retries per api service request, should subsequent requests wait for previous requests to succeed?
281-
replayApiService.pushPayload(capture.session, "${nextPayloadId()}", eventBatch)
282-
283285
true
284286
} catch (e: Exception) {
285287
// TODO: O11Y-627 - pass in logger to implementation and use here
286-
Log.e(
287-
REPLAY_EXPORTER_NAME,
288-
"Error sending initial capture for session: ${e.message}",
289-
e
290-
)
288+
// Log.e(
289+
// REPLAY_EXPORTER_NAME,
290+
// "Error sending initial capture for session: ${e.message}",
291+
// e
292+
// )
291293
false
292294
}
293295
}

sdk/@launchdarkly/observability-android/lib/src/test/kotlin/com/launchdarkly/observability/network/SamplingApiServiceTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.mockk.coEvery
44
import io.mockk.coVerify
55
import io.mockk.mockk
66
import kotlinx.coroutines.test.runTest
7+
import kotlinx.serialization.json.JsonPrimitive
78
import org.junit.jupiter.api.Assertions.assertEquals
89
import org.junit.jupiter.api.Assertions.assertNull
910
import org.junit.jupiter.api.Test
@@ -54,7 +55,7 @@ class SamplingApiServiceTest {
5455
coEvery {
5556
mockGraphqlClient.execute(
5657
"graphql/GetSamplingConfigQuery.graphql",
57-
mapOf("organization_verbose_id" to organizationId),
58+
mapOf("organization_verbose_id" to JsonPrimitive(organizationId)),
5859
SamplingResponse.serializer()
5960
)
6061
} returns graphqlResponse
@@ -67,7 +68,7 @@ class SamplingApiServiceTest {
6768
coVerify(exactly = 1) {
6869
mockGraphqlClient.execute(
6970
"graphql/GetSamplingConfigQuery.graphql",
70-
mapOf("organization_verbose_id" to organizationId),
71+
mapOf("organization_verbose_id" to JsonPrimitive(organizationId)),
7172
SamplingResponse.serializer()
7273
)
7374
}

0 commit comments

Comments
 (0)