Skip to content

Commit

Permalink
Replace spy with mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanmos committed Feb 15, 2024
1 parent a31af69 commit ef39f54
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package com.datadog.android.sessionreplay.internal.net
import androidx.annotation.VisibleForTesting
import com.datadog.android.api.InternalLogger
import com.datadog.android.api.storage.RawBatchEvent
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_RESOURCE_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.FILENAME_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.ID_KEY
Expand Down Expand Up @@ -92,7 +92,7 @@ internal class ResourceRequestBodyFactory(
val applicationId = MiscUtils.safeGetStringFromJsonObject(
internalLogger,
resourceMetadata,
APPLICATION_ID_RESOURCE_KEY
APPLICATION_ID_KEY
)
val filename = MiscUtils.safeGetStringFromJsonObject(
internalLogger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal data class EnrichedResource(
}

internal companion object {
internal const val APPLICATION_ID_RESOURCE_KEY = "applicationId"
internal const val APPLICATION_ID_KEY = "applicationId"
internal const val APPLICATION_KEY = "application"
internal const val ID_KEY = "id"
internal const val FILENAME_KEY = "filename"
Expand All @@ -43,7 +43,7 @@ internal fun EnrichedResource.asBinaryMetadata(): ByteArray {
val applicationId = this.applicationId
val filename = this.filename
val jsonObject = JsonObject()
jsonObject.addProperty(EnrichedResource.APPLICATION_ID_RESOURCE_KEY, applicationId)
jsonObject.addProperty(EnrichedResource.APPLICATION_ID_KEY, applicationId)
jsonObject.addProperty(EnrichedResource.FILENAME_KEY, filename)
return jsonObject.toString().toByteArray(Charsets.UTF_8)
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ internal class Base64Serializer private constructor(
private var isBase64CacheRegisteredForCallbacks: Boolean = false
private var isBitmapPoolRegisteredForCallbacks: Boolean = false

// resources previously sent in this session -
// resource IDs previously sent in this session -
// optimization to avoid sending the same resource multiple times
// atm this set is unbounded but expected to use relatively little space (~80kb per 1k items)
private val resourcesSeen: MutableSet<String> =
private val resourceIdsSeen: MutableSet<String> =
Collections.synchronizedSet(HashSet<String>())

// region internal
Expand Down Expand Up @@ -154,8 +154,8 @@ internal class Base64Serializer private constructor(
return
}

if (!resourcesSeen.contains(resourceId)) {
resourcesSeen.add(resourceId)
if (!resourceIdsSeen.contains(resourceId)) {
resourceIdsSeen.add(resourceId)

// We probably don't want this here. In the next pr we'll
// refactor this class and extract logic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,6 @@ internal class RecordedDataQueueHandlerTest {
@Forgery
lateinit var fakeSnapshotQueueItem: SnapshotRecordedDataQueueItem

@Forgery
lateinit var fakeTouchEventItem: TouchEventRecordedDataQueueItem

@Forgery
lateinit var fakeResourceItem: ResourceRecordedDataQueueItem

@Spy
private lateinit var fakeRecordedDataQueue: ConcurrentLinkedQueue<RecordedDataQueueItem>

Expand Down Expand Up @@ -351,16 +345,19 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M remove item from queue W tryToConsumeItems() { invalid snapshot item }`() {
fun `M remove item from queue W tryToConsumeItems() { invalid snapshot item }`(
@Mock mockSnapshotItem: SnapshotRecordedDataQueueItem
) {
// Given
val spy = spy(fakeSnapshotQueueItem)
spy.nodes = emptyList()
doReturn(false).whenever(spy).isValid()
testedHandler.recordedDataQueue.offer(spy)
whenever(mockSnapshotItem.nodes).thenReturn(emptyList())
whenever(mockSnapshotItem.isValid()).thenReturn(false)
whenever(mockSnapshotItem.recordedQueuedItemContext).thenReturn(fakeRecordedQueuedItemContext)

testedHandler.recordedDataQueue.offer(mockSnapshotItem)

val spyTimestamp = spy.recordedQueuedItemContext.timestamp
val timestamp = mockSnapshotItem.recordedQueuedItemContext.timestamp
whenever(mockTimeProvider.getDeviceTimestamp())
.thenReturn(spyTimestamp)
.thenReturn(timestamp)

// When
testedHandler.tryToConsumeItems()
Expand All @@ -382,14 +379,16 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M remove item from queue W tryToConsumeItems() { invalid touch event item }`() {
fun `M remove item from queue W tryToConsumeItems() { invalid touch event item }`(
@Mock mockTouchEventItem: TouchEventRecordedDataQueueItem
) {
// Given
val spy = spy(fakeTouchEventItem)
whenever(mockTouchEventItem.isValid()).thenReturn(false)
whenever(mockTouchEventItem.recordedQueuedItemContext).thenReturn(fakeRecordedQueuedItemContext)

doReturn(false).whenever(spy).isValid()
testedHandler.recordedDataQueue.offer(spy)
testedHandler.recordedDataQueue.offer(mockTouchEventItem)

val spyTimestamp = spy.recordedQueuedItemContext.timestamp
val spyTimestamp = mockTouchEventItem.recordedQueuedItemContext.timestamp
whenever(mockTimeProvider.getDeviceTimestamp())
.thenReturn(spyTimestamp)

Expand All @@ -414,16 +413,17 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M remove item from queue W tryToConsumeItems() { invalid resource item }`() {
fun `M remove item from queue W tryToConsumeItems() { invalid resource item }`(
@Mock mockResourceItem: ResourceRecordedDataQueueItem
) {
// Given
val spy = spy(fakeResourceItem)

doReturn(false).whenever(spy).isValid()
testedHandler.recordedDataQueue.offer(spy)
whenever(mockResourceItem.isValid()).thenReturn(false)
whenever(mockResourceItem.recordedQueuedItemContext).thenReturn(fakeRecordedQueuedItemContext)
testedHandler.recordedDataQueue.offer(mockResourceItem)

val spyTimestamp = spy.recordedQueuedItemContext.timestamp
val timestamp = mockResourceItem.recordedQueuedItemContext.timestamp
whenever(mockTimeProvider.getDeviceTimestamp())
.thenReturn(spyTimestamp)
.thenReturn(timestamp)

// When
testedHandler.tryToConsumeItems()
Expand All @@ -446,14 +446,14 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M do nothing W tryToConsumeItems() { snapshot item not ready }`() {
fun `M do nothing W tryToConsumeItems() { snapshot item not ready }`(
@Mock mockSnapshotItem: SnapshotRecordedDataQueueItem
) {
// Given
val spy = spy(fakeSnapshotQueueItem)
doReturn(true).whenever(mockSnapshotItem).isValid()
doReturn(false).whenever(mockSnapshotItem).isReady()

doReturn(true).whenever(spy).isValid()
doReturn(false).whenever(spy).isReady()

testedHandler.recordedDataQueue.add(spy)
testedHandler.recordedDataQueue.add(mockSnapshotItem)

whenever(mockTimeProvider.getDeviceTimestamp())
.thenReturn(fakeRecordedQueuedItemContext.timestamp)
Expand Down Expand Up @@ -570,56 +570,45 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M not consume items that are not ready W tryToConsumeItems() { some items not ready }`() {
fun `M not consume items that are not ready W tryToConsumeItems() { some items not ready }`(
@Mock mockSnapshotItem1: SnapshotRecordedDataQueueItem,
@Mock mockSnapshotItem2: SnapshotRecordedDataQueueItem,
@Mock mockSnapshotItem3: SnapshotRecordedDataQueueItem
) {
// Given
// item1
val item1RumContextData = fakeRecordedQueuedItemContext.copy(timestamp = 1)

val item1 = spy(
SnapshotRecordedDataQueueItem(
recordedQueuedItemContext = item1RumContextData,
systemInformation = mockSystemInformation
)
)

item1.nodes = fakeNodeData
doReturn(true).whenever(item1).isValid()
doReturn(true).whenever(item1).isReady()
whenever(mockSnapshotItem1.recordedQueuedItemContext).thenReturn(item1RumContextData)
whenever(mockSnapshotItem1.systemInformation).thenReturn(mockSystemInformation)
whenever(mockSnapshotItem1.nodes).thenReturn(fakeNodeData)
doReturn(true).whenever(mockSnapshotItem1).isValid()
doReturn(true).whenever(mockSnapshotItem1).isReady()

// item2
val item2RumContextData = fakeRecordedQueuedItemContext.copy(timestamp = 2)

val item2 = spy(
SnapshotRecordedDataQueueItem(
recordedQueuedItemContext = item2RumContextData,
systemInformation = mockSystemInformation
)
)

item2.nodes = emptyList()
doReturn(true).whenever(item2).isValid()
doReturn(false).whenever(item2).isReady()
whenever(mockSnapshotItem2.recordedQueuedItemContext).thenReturn(item2RumContextData)
whenever(mockSnapshotItem2.systemInformation).thenReturn(mockSystemInformation)
whenever(mockSnapshotItem2.nodes).thenReturn(emptyList())
doReturn(true).whenever(mockSnapshotItem2).isValid()
doReturn(false).whenever(mockSnapshotItem2).isReady()

// item3
val item3RumContextData = fakeRecordedQueuedItemContext.copy(timestamp = 3)

val item3 = spy(
SnapshotRecordedDataQueueItem(
recordedQueuedItemContext = item3RumContextData,
systemInformation = mockSystemInformation
)
)

item3.nodes = fakeNodeData
doReturn(true).whenever(item3).isValid()
doReturn(true).whenever(item3).isReady()
whenever(mockSnapshotItem3.recordedQueuedItemContext).thenReturn(item3RumContextData)
whenever(mockSnapshotItem3.systemInformation).thenReturn(mockSystemInformation)
whenever(mockSnapshotItem3.nodes).thenReturn(fakeNodeData)
doReturn(true).whenever(mockSnapshotItem3).isValid()
doReturn(true).whenever(mockSnapshotItem3).isReady()

testedHandler.recordedDataQueue.offer(item1)
testedHandler.recordedDataQueue.offer(item2)
testedHandler.recordedDataQueue.offer(item3)
testedHandler.recordedDataQueue.offer(mockSnapshotItem1)
testedHandler.recordedDataQueue.offer(mockSnapshotItem2)
testedHandler.recordedDataQueue.offer(mockSnapshotItem3)

assertThat(testedHandler.recordedDataQueue.size).isEqualTo(3)
val item1Time = item1.recordedQueuedItemContext.timestamp
val item1Time = mockSnapshotItem1.recordedQueuedItemContext.timestamp

whenever(mockTimeProvider.getDeviceTimestamp())
.thenReturn(item1Time + 1)
Expand Down Expand Up @@ -651,23 +640,28 @@ internal class RecordedDataQueueHandlerTest {
}

@Test
fun `M handle concurrency W clearAndStopProcessing() { pending items }`() {
fun `M handle concurrency W clearAndStopProcessing() { pending items }`(
@Mock mockSnapshotItem1: SnapshotRecordedDataQueueItem,
@Mock mockSnapshotItem2: SnapshotRecordedDataQueueItem
) {
// Given
List(2) {
val itemRumContextData = fakeRecordedQueuedItemContext.copy(timestamp = 1)
spy(
SnapshotRecordedDataQueueItem(
recordedQueuedItemContext = itemRumContextData,
systemInformation = mockSystemInformation
)
).apply {
this.nodes = fakeNodeData
doReturn(true).whenever(this).isValid()
doReturn(false).whenever(this).isReady()
}
}.forEach {
testedHandler.recordedDataQueue.offer(it)
}

val itemRumContextData = fakeRecordedQueuedItemContext.copy(timestamp = 1)

whenever(mockSnapshotItem1.recordedQueuedItemContext).thenReturn(itemRumContextData)
whenever(mockSnapshotItem1.systemInformation).thenReturn(mockSystemInformation)
whenever(mockSnapshotItem1.nodes).thenReturn(fakeNodeData)
whenever(mockSnapshotItem1.isValid()).thenReturn(true)
whenever(mockSnapshotItem1.isReady()).thenReturn(false)

whenever(mockSnapshotItem2.recordedQueuedItemContext).thenReturn(itemRumContextData)
whenever(mockSnapshotItem2.systemInformation).thenReturn(mockSystemInformation)
whenever(mockSnapshotItem2.nodes).thenReturn(fakeNodeData)
whenever(mockSnapshotItem2.isValid()).thenReturn(true)
whenever(mockSnapshotItem2.isReady()).thenReturn(false)

testedHandler.recordedDataQueue.offer(mockSnapshotItem1)
testedHandler.recordedDataQueue.offer(mockSnapshotItem2)

// When
val countDownLatch = CountDownLatch(3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import com.datadog.android.sessionreplay.internal.net.ResourceRequestBodyFactory
import com.datadog.android.sessionreplay.internal.net.ResourceRequestBodyFactory.Companion.NO_RESOURCES_TO_SEND_ERROR
import com.datadog.android.sessionreplay.internal.net.ResourceRequestBodyFactory.Companion.TYPE_KEY
import com.datadog.android.sessionreplay.internal.net.ResourceRequestBodyFactory.Companion.TYPE_RESOURCE
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_RESOURCE_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.FILENAME_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.ID_KEY
Expand Down Expand Up @@ -68,7 +68,7 @@ internal class ResourceRequestBodyFactoryTest {
@BeforeEach
fun `set up`() {
fakeMetaData = JsonObject()
fakeMetaData.addProperty(APPLICATION_ID_RESOURCE_KEY, fakeApplicationId)
fakeMetaData.addProperty(APPLICATION_ID_KEY, fakeApplicationId)
fakeMetaData.addProperty(FILENAME_KEY, fakeFilename)

testedRequestBodyFactory = ResourceRequestBodyFactory(mockInternalLogger)
Expand Down Expand Up @@ -140,7 +140,7 @@ internal class ResourceRequestBodyFactoryTest {
val missingApplicationIdData = fakeMetaData.deepCopy()
val missingFilenameData = fakeMetaData.deepCopy()

missingApplicationIdData.remove(APPLICATION_ID_RESOURCE_KEY)
missingApplicationIdData.remove(APPLICATION_ID_KEY)
val missingApplicationIdBatchEvent = RawBatchEvent(
data = fakeImageRepresentation.toByteArray(),
metadata = missingApplicationIdData.toString().toByteArray(Charsets.UTF_8)
Expand Down Expand Up @@ -183,8 +183,8 @@ internal class ResourceRequestBodyFactoryTest {
metadata = fakeMetaData.toString().toByteArray(Charsets.UTF_8)
)

fakeMetaData.remove(APPLICATION_ID_RESOURCE_KEY)
fakeMetaData.addProperty(APPLICATION_ID_RESOURCE_KEY, fakeSecondApplicationId)
fakeMetaData.remove(APPLICATION_ID_KEY)
fakeMetaData.addProperty(APPLICATION_ID_KEY, fakeSecondApplicationId)
fakeMetaData.remove(FILENAME_KEY)
fakeMetaData.addProperty(FILENAME_KEY, fakeSecondFilename)

Expand Down Expand Up @@ -251,7 +251,7 @@ internal class ResourceRequestBodyFactoryTest {
private fun generateValidRawBatchEvent(forge: Forge): RawBatchEvent {
val fakeEvent = forge.getForgery<RawBatchEvent>()
val fakeMetadata = JsonObject()
fakeMetadata.addProperty(APPLICATION_ID_RESOURCE_KEY, forge.getForgery<UUID>().toString())
fakeMetadata.addProperty(APPLICATION_ID_KEY, forge.getForgery<UUID>().toString())
fakeMetadata.addProperty(FILENAME_KEY, forge.getForgery<UUID>().toString())
return fakeEvent.copy(
metadata = fakeMetadata.toString().toByteArray(Charsets.UTF_8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package com.datadog.android.sessionreplay.internal.processor

import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.forge.ForgeConfigurator
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_RESOURCE_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.APPLICATION_ID_KEY
import com.datadog.android.sessionreplay.internal.processor.EnrichedResource.Companion.FILENAME_KEY
import com.datadog.android.sessionreplay.internal.utils.MiscUtils.safeDeserializeToJsonObject
import com.datadog.android.sessionreplay.internal.utils.MiscUtils.safeGetStringFromJsonObject
Expand Down Expand Up @@ -54,7 +54,7 @@ internal class EnrichedResourceTest : ObjectTest<EnrichedResource>() {
}

@Test
fun `M return valid binary metadata W asBinaryMetadat`(
fun `M return valid binary metadata W asBinaryMetadata`(
@Forgery enrichedResource: EnrichedResource
) {
// Given
Expand All @@ -81,7 +81,7 @@ internal class EnrichedResourceTest : ObjectTest<EnrichedResource>() {
val actualApplicationId = safeGetStringFromJsonObject(
mockInternalLogger,
deserializedData,
APPLICATION_ID_RESOURCE_KEY
APPLICATION_ID_KEY
)

assertThat(actualIdentifier).isEqualTo(expectedIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,7 @@ internal class RecordedDataProcessorTest {
assertThat(capturedResource.resource).isEqualTo(fakeByteArray)
val jsonString = capturedResource.asBinaryMetadata().toString(Charsets.UTF_8)
val metadataJson = JsonParser.parseString(jsonString).asJsonObject
val itemApplicationId = metadataJson.get(EnrichedResource.APPLICATION_ID_RESOURCE_KEY).asString
val itemApplicationId = metadataJson.get(EnrichedResource.APPLICATION_ID_KEY).asString
val itemFilename = metadataJson.get(EnrichedResource.FILENAME_KEY).asString
assertThat(itemApplicationId).isEqualTo(fakeRumContext.applicationId)
assertThat(itemFilename).isEqualTo(fakeIdentifier)
Expand Down

0 comments on commit ef39f54

Please sign in to comment.