-
Notifications
You must be signed in to change notification settings - Fork 6
MBX-2529: Add parsing and validation models for abtests #357
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,19 @@ | ||
| package cloud.mindbox.mobile_sdk.inapp.data.repositories | ||
|
|
||
| import cloud.mindbox.mobile_sdk.inapp.data.mapper.InAppMapper | ||
| import cloud.mindbox.mobile_sdk.inapp.data.validators.ABTestValidator | ||
| import cloud.mindbox.mobile_sdk.inapp.data.validators.OperationNameValidator | ||
| import cloud.mindbox.mobile_sdk.inapp.data.validators.OperationValidator | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.MobileConfigSerializationManager | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.repositories.MobileConfigRepository | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.validators.InAppValidator | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.models.InApp | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.models.InAppConfig | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.models.OperationName | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.models.OperationSystemName | ||
| import cloud.mindbox.mobile_sdk.inapp.domain.models.* | ||
| import cloud.mindbox.mobile_sdk.logger.MindboxLoggerImpl | ||
| import cloud.mindbox.mobile_sdk.logger.mindboxLogD | ||
| import cloud.mindbox.mobile_sdk.logger.mindboxLogE | ||
| import cloud.mindbox.mobile_sdk.managers.DbManager | ||
| import cloud.mindbox.mobile_sdk.managers.GatewayManager | ||
| import cloud.mindbox.mobile_sdk.models.operation.response.InAppConfigResponse | ||
| import cloud.mindbox.mobile_sdk.models.operation.response.OperationDto | ||
| import cloud.mindbox.mobile_sdk.models.operation.response.* | ||
| import cloud.mindbox.mobile_sdk.monitoring.data.validators.MonitoringValidator | ||
| import cloud.mindbox.mobile_sdk.monitoring.domain.models.LogRequest | ||
| import cloud.mindbox.mobile_sdk.repository.MindboxPreferences | ||
|
|
@@ -29,6 +28,7 @@ internal class MobileConfigRepositoryImpl( | |
| private val mobileConfigSerializationManager: MobileConfigSerializationManager, | ||
| private val inAppValidator: InAppValidator, | ||
| private val monitoringValidator: MonitoringValidator, | ||
| private val abTestValidator: ABTestValidator, | ||
| private val operationNameValidator: OperationNameValidator, | ||
| private val operationValidator: OperationValidator, | ||
| private val gatewayManager: GatewayManager, | ||
|
|
@@ -38,6 +38,7 @@ internal class MobileConfigRepositoryImpl( | |
|
|
||
| private var inApps: List<InApp>? = null | ||
| private var operations: Map<OperationName, OperationSystemName>? = null | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Возможно стоит вынести в мобильный бэклог, перенос этих штук в sessionManager, выглядит, что в будущем это будет правильнее
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Добавил тикет на исправление. Из-за этих штук тригерится парсинг несколько раз |
||
| private var abtests: List<ABTest>? = null | ||
|
|
||
| override suspend fun fetchMobileConfig() { | ||
| val configuration = DbManager.listenConfigurations().first() | ||
|
|
@@ -49,49 +50,17 @@ internal class MobileConfigRepositoryImpl( | |
| private fun listenInAppConfig(): Flow<InAppConfig?> { | ||
| return MindboxPreferences.inAppConfigFlow.map { inAppConfigString -> | ||
| mutex.withLock { | ||
| MindboxLoggerImpl.d( | ||
| parent = this@MobileConfigRepositoryImpl, | ||
| this@MobileConfigRepositoryImpl.mindboxLogD( | ||
| message = "CachedConfig : $inAppConfigString" | ||
| ) | ||
| val configBlank = | ||
| mobileConfigSerializationManager.deserializeToConfigDtoBlank(inAppConfigString) | ||
| val filteredInApps = configBlank?.inApps | ||
| ?.filter { inAppDtoBlank -> | ||
| inAppValidator.validateInAppVersion(inAppDtoBlank) | ||
| } | ||
| ?.map { inAppDtoBlank -> | ||
| inAppMapper.mapToInAppDto( | ||
| inAppDtoBlank = inAppDtoBlank, | ||
| formDto = mobileConfigSerializationManager.deserializeToInAppFormDto( | ||
| inAppDtoBlank.form | ||
| ), | ||
| targetingDto = mobileConfigSerializationManager.deserializeToInAppTargetingDto( | ||
| inAppDtoBlank.targeting | ||
| ) | ||
| ) | ||
| }?.filter { inAppDto -> | ||
| inAppValidator.validateInApp(inAppDto) | ||
| } | ||
| val filteredMonitoring = | ||
| configBlank?.monitoring?.logs?.filter { logRequestDtoBlank -> | ||
| monitoringValidator.validateLogRequestDtoBlank(logRequestDtoBlank) | ||
| }?.map { logRequestDtoBlank -> | ||
| inAppMapper.mapToLogRequestDto(logRequestDtoBlank) | ||
| } | ||
|
|
||
| val filteredSettings = configBlank?.settings?.operations | ||
| ?.filter { (name, operation) -> | ||
| operationNameValidator.isValid(name) | ||
| && operationValidator.isValid(operation) | ||
| }?.map { (name, operation) -> | ||
| name!! to OperationDto(operation!!.systemName!!) | ||
| }?.toMap() | ||
| ?: emptyMap() | ||
|
|
||
| val filteredConfig = InAppConfigResponse( | ||
| inApps = filteredInApps, | ||
| monitoring = filteredMonitoring, | ||
| settings = filteredSettings, | ||
| inApps = getInApps(configBlank), | ||
| monitoring = getMonitoring(configBlank), | ||
| settings = getSettings(configBlank), | ||
| abtests = getABTests(configBlank), | ||
| ) | ||
|
|
||
| return@map inAppMapper.mapToInAppConfig(filteredConfig) | ||
|
|
@@ -105,6 +74,56 @@ internal class MobileConfigRepositoryImpl( | |
| } | ||
| } | ||
|
|
||
| private fun getInApps(configBlank: InAppConfigResponseBlank?): List<InAppDto>? = | ||
| configBlank?.inApps | ||
| ?.filter { inAppDtoBlank -> | ||
| inAppValidator.validateInAppVersion(inAppDtoBlank) | ||
| } | ||
| ?.map { inAppDtoBlank -> | ||
| inAppMapper.mapToInAppDto( | ||
| inAppDtoBlank = inAppDtoBlank, | ||
| formDto = mobileConfigSerializationManager.deserializeToInAppFormDto( | ||
| inAppDtoBlank.form | ||
| ), | ||
| targetingDto = mobileConfigSerializationManager.deserializeToInAppTargetingDto( | ||
| inAppDtoBlank.targeting | ||
| ) | ||
| ) | ||
| }?.filter { inAppDto -> | ||
| inAppValidator.validateInApp(inAppDto) | ||
| } | ||
|
|
||
| private fun getMonitoring(configBlank: InAppConfigResponseBlank?): List<LogRequestDto>? = | ||
| configBlank?.monitoring?.logs?.filter { logRequestDtoBlank -> | ||
| monitoringValidator.validateLogRequestDtoBlank(logRequestDtoBlank) | ||
| }?.map { logRequestDtoBlank -> | ||
| inAppMapper.mapToLogRequestDto(logRequestDtoBlank) | ||
| } | ||
|
|
||
| private fun getSettings(configBlank: InAppConfigResponseBlank?): Map<String, OperationDto> = | ||
| configBlank?.settings?.operations | ||
| ?.filter { (name, operation) -> | ||
| operationNameValidator.isValid(name) | ||
| && operationValidator.isValid(operation) | ||
| }?.map { (name, operation) -> | ||
| name!! to OperationDto(operation!!.systemName!!) | ||
| }?.toMap() | ||
| ?: emptyMap() | ||
|
|
||
|
|
||
| private fun getABTests(configBlank: InAppConfigResponseBlank?): List<ABTestDto> { | ||
| return try { | ||
| if (configBlank?.abtests == null) return listOf() | ||
|
|
||
| return configBlank.abtests.takeIf { abtests -> | ||
| abtests.all { abTestValidator.isValid(it) } | ||
| } ?: listOf() | ||
| } catch (e: Exception) { | ||
| mindboxLogE("Error parse abtests", e) | ||
dbvasilyev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| listOf() | ||
| } | ||
| } | ||
|
|
||
| override fun listenMonitoringSection(): Flow<List<LogRequest>?> { | ||
| return listenInAppConfig().map { inAppConfig -> | ||
| inAppConfig?.monitoring | ||
|
|
@@ -131,4 +150,14 @@ internal class MobileConfigRepositoryImpl( | |
| inAppList | ||
| } | ||
| } | ||
|
|
||
| override suspend fun getABTests(): List<ABTest> { | ||
| return abtests ?: run { | ||
| val list: List<ABTest> = listenInAppConfig().map { inAppConfig -> | ||
| inAppConfig?.abtests | ||
| }.first() ?: listOf() | ||
| abtests = list | ||
| list | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package cloud.mindbox.mobile_sdk.inapp.data.validators | ||
|
|
||
| import cloud.mindbox.mobile_sdk.logger.mindboxLogW | ||
| import cloud.mindbox.mobile_sdk.models.operation.response.ABTestDto | ||
|
|
||
| internal class ABTestValidator(private val sdkVersionValidator: SdkVersionValidator) : | ||
| Validator<ABTestDto?> { | ||
|
|
||
| private val variantsValidator by lazy { VariantValidator() } | ||
|
|
||
| override fun isValid(item: ABTestDto?): Boolean { | ||
| if (item == null) { | ||
| mindboxLogW("The element in abtests block cannot be null. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| if (item.id.isBlank()) { | ||
| mindboxLogW("The field 'id' in abtests block cannot be null. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| if (item.sdkVersion == null || !sdkVersionValidator.isValid(item.sdkVersion)) { | ||
| mindboxLogW("In abtest ${item.id} 'sdkVersion' field is invalid. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| if (item.salt.isNullOrBlank()) { | ||
| mindboxLogW("In abtest ${item.id} 'salt' field is invalid. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| if (item.variants == null || | ||
| item.variants.size < 2 | ||
| ) { | ||
| mindboxLogW("In abtest ${item.id} 'variants' field must have at least two items. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| if (item.variants.any { !variantsValidator.isValid(it) }) { | ||
| mindboxLogW("In abtest ${item.id} 'variants' field is invalid. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| var start = 0 | ||
| item.variants.sortedBy { it.modulus!!.lower } | ||
| .onEach { abtest -> | ||
| if (abtest.modulus?.lower == start) { | ||
| start = abtest.modulus.upper!! | ||
| } else { | ||
| mindboxLogW("In abtest ${item.id} 'variants' field not have full cover. All abtests will not be used.") | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| if (start !in 99..100) { | ||
| mindboxLogW("In abtest ${item.id} 'variants' field not have full cover. All abtests will not be used.") | ||
| return false | ||
| } | ||
|
|
||
| return true | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.