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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import cloud.mindbox.mobile_sdk.models.operation.response.FrequencyDto.Frequency
import cloud.mindbox.mobile_sdk.models.operation.response.FrequencyDto.FrequencyOnceDto.Companion.FREQUENCY_KIND_SESSION
import cloud.mindbox.mobile_sdk.models.toMilliseconds
import cloud.mindbox.mobile_sdk.monitoring.domain.models.LogRequest
import cloud.mindbox.mobile_sdk.monitoring.domain.models.Md5Hash
import kotlin.math.roundToInt

internal class InAppMapper {
Expand Down Expand Up @@ -73,7 +74,7 @@ internal class InAppMapper {
): LogRequestDto {
return LogRequestDto(
requestId = logRequestDtoBlank.requestId,
deviceId = logRequestDtoBlank.deviceId,
target = logRequestDtoBlank.target!!,
from = logRequestDtoBlank.from,
to = logRequestDtoBlank.to
)
Expand Down Expand Up @@ -311,7 +312,7 @@ internal class InAppMapper {
monitoring = inAppConfigResponse.monitoring?.map {
LogRequest(
requestId = it.requestId,
deviceId = it.deviceId,
target = Md5Hash.ofHex(it.target),
from = it.from.convertToZonedDateTime(),
to = it.to.convertToZonedDateTime()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ internal data class InappSettingsDto(
internal data class LogRequestDto(
@SerializedName("requestId")
val requestId: String,
@SerializedName("deviceUUID")
val deviceId: String,
@SerializedName("target")
val target: String,
@SerializedName("from")
val from: String,
@SerializedName("to")
Expand Down Expand Up @@ -204,8 +204,8 @@ internal data class MonitoringDto(
internal data class LogRequestDtoBlank(
@SerializedName("requestId")
val requestId: String,
@SerializedName("deviceUUID")
val deviceId: String,
@SerializedName("target")

@enotniy enotniy Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сериализовать сразу в Md5Hash нельзя?
Или норм, что мы из перехода из Blank делаем

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В целом можно, через кастомный сериализатор. Но тут скорее не нужно кмк, есть StringStrictAdapter уже и мы в Blank сырые данные храним, в потом маппим после валидации в DTO

val target: String?,
@SerializedName("from")
val from: String,
@SerializedName("to")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.threeten.bp.format.DateTimeFormatter
internal class MonitoringValidator {

fun validateLogRequestDtoBlank(logRequest: LogRequestDtoBlank): Boolean {
return validateRequestId(logRequest) && validateDeviceId(logRequest) && validateFrom(
return validateRequestId(logRequest) && validateTarget(logRequest) && validateFrom(
logRequest
) && validateTo(logRequest)
}
Expand All @@ -20,8 +20,8 @@ internal class MonitoringValidator {
return logRequest.requestId.isNullOrBlank().not()
}

private fun validateDeviceId(logRequest: LogRequestDtoBlank): Boolean {
return logRequest.deviceId.isNullOrBlank().not()
private fun validateTarget(logRequest: LogRequestDtoBlank): Boolean {
return logRequest.target.isNullOrBlank().not()
}

private fun validateFrom(logRequest: LogRequestDtoBlank): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ package cloud.mindbox.mobile_sdk.monitoring.domain.managers

import cloud.mindbox.mobile_sdk.monitoring.domain.interfaces.LogRequestDataManager
import cloud.mindbox.mobile_sdk.monitoring.domain.models.LogRequest
import cloud.mindbox.mobile_sdk.monitoring.domain.models.Md5Hash
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences

internal class LogRequestDataManagerImpl : LogRequestDataManager {

override fun filterCurrentDeviceUuidLogs(logs: List<LogRequest>?): List<LogRequest> {
if (logs.isNullOrEmpty()) return emptyList()
val deviceUuid = MindboxPreferences.deviceUuid
if (deviceUuid.isBlank()) return emptyList()
val deviceUuidHash = Md5Hash.ofDeviceUuid(deviceUuid)
return logs.filter { logRequest ->
logRequest.deviceId == MindboxPreferences.deviceUuid
logRequest.target == deviceUuidHash
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
package cloud.mindbox.mobile_sdk.monitoring.domain.models

import org.threeten.bp.ZonedDateTime
import java.security.MessageDigest

internal data class LogRequest(
val requestId: String,
val deviceId: String,
val target: Md5Hash,
val from: ZonedDateTime,
val to: ZonedDateTime,
)

@JvmInline
internal value class Md5Hash private constructor(private val hex: String) {

companion object {
fun ofHex(hex: String): Md5Hash = Md5Hash(hex.lowercase())

fun ofDeviceUuid(deviceUuid: String): Md5Hash = Md5Hash(
MessageDigest.getInstance("MD5")
.digest(deviceUuid.lowercase().toByteArray(Charsets.UTF_8))
.joinToString(separator = "") { byte -> "%02x".format(byte) }
)
Comment thread
sergeysozinov marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ class MonitoringMobileConfigSerializationManagerTest {
assertEquals(2, config.logs?.size)
}

@Test
fun monitoringConfig_withOldDeviceUuidFormat_shouldParseWithNullTarget() {
val json = getJson("ConfigParsing/Monitoring/MonitoringLogsOldDeviceUuidFormat.json")
val config = manager.deserializeMonitoring(json)!!

assertEquals(2, config.logs?.size)
assertNull(config.logs?.first()?.target)
assertEquals("248eccb79da2bbca61c133c59e4a1516", config.logs?.last()?.target)
}

@Test
fun monitoringConfig_withLogsError_shouldSetMonitoringToNull() {
// Key is `logsTests` instead of `logs`
Expand Down Expand Up @@ -78,7 +88,7 @@ class MonitoringMobileConfigSerializationManagerTest {

@Test
fun monitoringConfig_withLogsTwoElementsError_shouldParseSuccessfullyRemainsElements() {
// Key is `request` instead `requestId` and key is `device` instead of `deviceUUID`
// Key is `request` instead of `requestId` and key is `toTest` instead of `to`
mockkObject(MindboxLoggerImpl)

val json = getJson("ConfigParsing/Monitoring/MonitoringLogsTwoElementsError.json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ package cloud.mindbox.mobile_sdk.monitoring

import cloud.mindbox.mobile_sdk.models.operation.response.LogRequestDtoBlank
import cloud.mindbox.mobile_sdk.monitoring.domain.models.LogRequest
import cloud.mindbox.mobile_sdk.monitoring.domain.models.Md5Hash
import org.threeten.bp.ZonedDateTime

internal class LogRequestStub {
companion object {
fun getLogRequest(): LogRequest = LogRequest(
requestId = "",
deviceId = "",
target = Md5Hash.ofHex(""),
from = ZonedDateTime.now(),
to = ZonedDateTime.now()
)

fun getLogRequestDtoBlank(): LogRequestDtoBlank = LogRequestDtoBlank(
requestId = "",
deviceId = "",
target = "",
from = "",
to = ""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal class MonitoringValidatorTest {
assertTrue(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "123", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
.copy(requestId = "123", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -32,7 +32,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
.copy(requestId = "", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -42,27 +42,27 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
.copy(requestId = "", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
)
)
}

@Test
fun `monitoring validation deviceId error empty string`() {
fun `monitoring validation target error empty string`() {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "", deviceId = "", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
.copy(requestId = "asd", target = "", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
)
)
}

@Test
fun `monitoring validation deviceId error null`() {
fun `monitoring validation target error null`() {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "", from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
.copy(requestId = "asd", target = null, from = "2023-01-15T00:00:00", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -72,7 +72,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "123", deviceId = "abvc", from = "", to = "2023-01-30T00:00:00")
.copy(requestId = "123", target = "334db432a8f72f64a89664682f7bc032", from = "", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -82,7 +82,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "123", deviceId = "abvc", from = "", to = "2023-01-30T00:00:00")
.copy(requestId = "123", target = "334db432a8f72f64a89664682f7bc032", from = "", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -92,7 +92,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "123", deviceId = "abvc", from = "null", to = "2023-01-30T00:00:00")
.copy(requestId = "123", target = "334db432a8f72f64a89664682f7bc032", from = "null", to = "2023-01-30T00:00:00")
)
)
}
Expand All @@ -102,7 +102,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "")
.copy(requestId = "asd", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "")
)
)
}
Expand All @@ -112,7 +112,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "")
.copy(requestId = "asd", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "")
)
)
}
Expand All @@ -122,7 +122,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "abc")
.copy(requestId = "asd", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "abc")
)
)
}
Expand All @@ -132,7 +132,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "abvc", from = "1970-01-01T00:00:00", to = "2023-01-15T00:00:00")
.copy(requestId = "asd", target = "334db432a8f72f64a89664682f7bc032", from = "1970-01-01T00:00:00", to = "2023-01-15T00:00:00")
)
)
}
Expand All @@ -142,7 +142,7 @@ internal class MonitoringValidatorTest {
assertFalse(
monitoringValidator.validateLogRequestDtoBlank(
LogRequestStub.getLogRequestDtoBlank()
.copy(requestId = "asd", deviceId = "abvc", from = "2023-01-15T00:00:00", to = "1970-01-01T00:00:00")
.copy(requestId = "asd", target = "334db432a8f72f64a89664682f7bc032", from = "2023-01-15T00:00:00", to = "1970-01-01T00:00:00")
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cloud.mindbox.mobile_sdk.monitoring.domain.managers
import androidx.test.core.app.ApplicationProvider
import cloud.mindbox.mobile_sdk.monitoring.LogRequestStub
import cloud.mindbox.mobile_sdk.monitoring.domain.models.LogRequest
import cloud.mindbox.mobile_sdk.monitoring.domain.models.Md5Hash
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
import com.jakewharton.threetenabp.AndroidThreeTen
import io.mockk.every
Expand Down Expand Up @@ -30,7 +31,7 @@ internal class LogRequestDataManagerImplTest {
mockkObject(MindboxPreferences)
every {
MindboxPreferences.deviceUuid
} returns "456"
} returns DEVICE_UUID
AndroidThreeTen.init(ApplicationProvider.getApplicationContext())
}

Expand All @@ -51,11 +52,45 @@ internal class LogRequestDataManagerImplTest {
@Test
fun `test monitoring checks only current deviceUuid success`() {
val testLogRequests = listOf(
LogRequestStub.getLogRequest().copy(deviceId = "456"),
LogRequestStub.getLogRequest().copy(deviceId = "123")
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex(DEVICE_UUID_HASH)),
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex(OTHER_DEVICE_UUID_HASH))
)
val actualResult = logRequestDataManager.filterCurrentDeviceUuidLogs(testLogRequests)
assertTrue(actualResult.size == 1 && actualResult.first().deviceId == "456")
assertTrue(actualResult.size == 1 && actualResult.first().target == Md5Hash.ofHex(DEVICE_UUID_HASH))
}

@Test
fun `test uppercase deviceUuid is lowercased before hashing`() {
every {
MindboxPreferences.deviceUuid
} returns DEVICE_UUID.uppercase()
val testLogRequests = listOf(
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex(DEVICE_UUID_HASH))
)
val actualResult = logRequestDataManager.filterCurrentDeviceUuidLogs(testLogRequests)
assertEquals(1, actualResult.size)
}

@Test
fun `test target hash comparison is case insensitive`() {
val testLogRequests = listOf(
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex(DEVICE_UUID_HASH.uppercase()))
)
val actualResult = logRequestDataManager.filterCurrentDeviceUuidLogs(testLogRequests)
assertEquals(1, actualResult.size)
}

@Test
fun `test blank deviceUuid matches nothing`() {
every {
MindboxPreferences.deviceUuid
} returns ""
val testLogRequests = listOf(
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex("d41d8cd98f00b204e9800998ecf8427e")),
LogRequestStub.getLogRequest().copy(target = Md5Hash.ofHex(DEVICE_UUID_HASH))
)
val actualResult = logRequestDataManager.filterCurrentDeviceUuidLogs(testLogRequests)
assertEquals(emptyList<LogRequest>(), actualResult)
}

@Test
Expand All @@ -72,4 +107,28 @@ internal class LogRequestDataManagerImplTest {
val testHashSet = hashSetOf(processedId)
assertFalse(logRequestDataManager.checkRequestIdProcessed(testHashSet, unprocessedId))
}

@Test
fun `md5 matches shared deviceUUID vectors`() {
val vectors = mapOf(
DEVICE_UUID to DEVICE_UUID_HASH,
"126e6225-3170-4089-a6f0-3d1ed8f64153" to OTHER_DEVICE_UUID_HASH,
"7e570ddf-8270-40a8-a369-b584ff5e9ff0" to "000baa91b37b3c201e3f8604c7845201",
DEVICE_UUID.uppercase() to DEVICE_UUID_HASH,
)
vectors.forEach { (deviceUuid, expectedTarget) ->
assertEquals(Md5Hash.ofHex(expectedTarget), Md5Hash.ofDeviceUuid(deviceUuid))
}
}

@Test
fun `md5 of empty string is the well-known constant`() {
assertEquals(Md5Hash.ofHex("d41d8cd98f00b204e9800998ecf8427e"), Md5Hash.ofDeviceUuid(""))
}

companion object {
private const val DEVICE_UUID = "216e6225-3170-4089-a6f0-3d1ed8f64153"
private const val DEVICE_UUID_HASH = "334db432a8f72f64a89664682f7bc032"
private const val OTHER_DEVICE_UUID_HASH = "248eccb79da2bbca61c133c59e4a1516"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -374,13 +374,13 @@
"logs": [
{
"requestId": "bb978cd7-ce4c-4239-a5d2-4b7e5d4fb5b9",
"deviceUUID": "216e6225-3170-4089-a6f0-3d1ed8f64153",
"target": "334db432a8f72f64a89664682f7bc032",
"from": "2024-02-12T10:00:00",
"to": "2024-02-14T20:30:00"
},
{
"requestId": "8e829a63-a5c3-4e1c-a772-41fd61f8f331",
"deviceUUID": "126e6225-3170-4089-a6f0-3d1ed8f64153",
"target": "248eccb79da2bbca61c133c59e4a1516",
"from": "2023-02-10T00:00:00",
"to": "2023-03-01T20:30:00"
}
Expand Down
Loading