diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitChecker.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitChecker.kt index 8c1b1e5cf..b09d24069 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitChecker.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitChecker.kt @@ -18,7 +18,7 @@ internal class MaxInappsPerDayLimitChecker( override fun check(reservations: Collection): Boolean { mindboxLogI("Checking max inapps per day limit") - return when (val maxInappsPerDayCount = sessionStorageManager.inAppShowLimitsSettings.maxInappsPerDay) { + return when (val maxInappsPerDayCount = sessionStorageManager.state.inAppShowLimitsSettings.maxInappsPerDay) { null -> { mindboxLogI("Parameter limit inapp for show per day not specify. Work without limits for show per day") true diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitChecker.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitChecker.kt index 4cf54f4dc..38f7e1e41 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitChecker.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitChecker.kt @@ -11,14 +11,14 @@ internal class MaxInappsPerSessionLimitChecker( override fun check(reservations: Collection): Boolean { mindboxLogI("Checking max inapps show per session limit") - return when (val maxInappsPerSessionCount = sessionStorageManager.inAppShowLimitsSettings.maxInappsPerSession) { + return when (val maxInappsPerSessionCount = sessionStorageManager.state.inAppShowLimitsSettings.maxInappsPerSession) { null -> { mindboxLogI("Parameter limit inapp for show per session not specify. Work without limits for show per session") true } else -> { - val shownInSession = sessionStorageManager.inAppMessageShownInSession.size + val shownInSession = sessionStorageManager.state.inAppMessageShownInSession.size val isAllowed = maxInappsPerSessionCount > shownInSession + reservations.size mindboxLogI("Inapp shown in session count: $shownInSession, reserved: ${reservations.size}, limit: $maxInappsPerSessionCount, Show allowed: $isAllowed") isAllowed diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitChecker.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitChecker.kt index a7df0587d..24883f96b 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitChecker.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitChecker.kt @@ -17,7 +17,7 @@ internal class MinIntervalBetweenShowsLimitChecker( override fun check(reservations: Collection): Boolean { mindboxLogI("Checking min interval between shows limit") - return when (val minIntervalBetweenShowDuration = sessionStorageManager.inAppShowLimitsSettings.minIntervalBetweenShows) { + return when (val minIntervalBetweenShowDuration = sessionStorageManager.state.inAppShowLimitsSettings.minIntervalBetweenShows) { null -> { mindboxLogI("Parameter min interval between inapp show not specify. Work without limit") true diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/InAppFailureTrackerImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/InAppFailureTrackerImpl.kt index beb55d5b6..64a24de06 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/InAppFailureTrackerImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/InAppFailureTrackerImpl.kt @@ -40,7 +40,7 @@ internal class InAppFailureTrackerImpl( } val toSend = failures.toList() inAppRepository.sendInAppShowErrors(toSend) - toSend.forEach { failure -> sessionStorageManager.reportedShowFailures.add(failure.sessionKey()) } + toSend.forEach { failure -> sessionStorageManager.state.reportedShowFailures.add(failure.sessionKey()) } failures.clear() } @@ -83,7 +83,7 @@ internal class InAppFailureTrackerImpl( errorDetails: String?, tags: Map? ) { - if (sessionKey(inAppId, failureReason) in sessionStorageManager.reportedShowFailures) { + if (sessionKey(inAppId, failureReason) in sessionStorageManager.state.reportedShowFailures) { mindboxLogI("Failure $failureReason for in-app $inAppId already reported this session, not collecting it again") return } @@ -114,7 +114,7 @@ internal class InAppFailureTrackerImpl( mindboxLogI("Feature $SEND_INAPP_SHOW_ERROR_FEATURE is off. Skip send wait budget failure") return } - if (!sessionStorageManager.waitBudgetReportedPlaces.add(placeSystemName)) { + if (!sessionStorageManager.state.waitBudgetReportedPlaces.add(placeSystemName)) { mindboxLogI("Place '$placeSystemName' already reported its exceeded wait budget this session") return } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionState.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionState.kt new file mode 100644 index 000000000..424594061 --- /dev/null +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionState.kt @@ -0,0 +1,49 @@ +package cloud.mindbox.mobile_sdk.inapp.data.managers + +import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowBudgetOwner +import cloud.mindbox.mobile_sdk.inapp.domain.models.CustomerSegmentationFetchStatus +import cloud.mindbox.mobile_sdk.inapp.domain.models.GeoFetchStatus +import cloud.mindbox.mobile_sdk.inapp.domain.models.InApp +import cloud.mindbox.mobile_sdk.inapp.domain.models.InAppShowLimitsSettings +import cloud.mindbox.mobile_sdk.inapp.domain.models.ProductSegmentationFetchStatus +import cloud.mindbox.mobile_sdk.inapp.domain.models.ProductSegmentationResponseWrapper +import cloud.mindbox.mobile_sdk.inapp.domain.models.SegmentationCheckWrapper +import cloud.mindbox.mobile_sdk.inapp.domain.models.ShowReservation +import cloud.mindbox.mobile_sdk.inapp.domain.models.TargetingErrorKey +import cloud.mindbox.mobile_sdk.models.InAppEventType +import cloud.mindbox.mobile_sdk.models.PlaceKey +import cloud.mindbox.mobile_sdk.newConcurrentSet +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +internal class SessionState( + @Volatile var inAppCustomerSegmentations: SegmentationCheckWrapper? = null, + var unShownOperationalInApps: ConcurrentHashMap> = ConcurrentHashMap(), + var operationalInApps: ConcurrentHashMap> = ConcurrentHashMap(), + var inAppMessageShownInSession: MutableList = CopyOnWriteArrayList(), + val embeddedLastShownByPlace: ConcurrentHashMap = ConcurrentHashMap(), + val embeddedLastTargetedByPlace: ConcurrentHashMap = ConcurrentHashMap(), + val embeddedLastOperationByPlace: ConcurrentHashMap = ConcurrentHashMap(), + val placeTargetingReportedInSession: MutableSet = newConcurrentSet(), + val embeddedDelaysWaitedOut: MutableSet = newConcurrentSet(), + val requestedInAppTargetingReportedInSession: MutableSet = newConcurrentSet(), + val waitBudgetReportedPlaces: MutableSet = newConcurrentSet(), + val reportedShowFailures: MutableSet = newConcurrentSet(), + val showReservations: MutableMap = ConcurrentHashMap(), + var customerSegmentationFetchStatus: CustomerSegmentationFetchStatus = + CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED, + var geoFetchStatus: GeoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED, + var inAppProductSegmentations: MutableMap, Set> = + ConcurrentHashMap(), + var processedProductSegmentations: MutableMap, ProductSegmentationFetchStatus> = + ConcurrentHashMap(), + var lastTargetingErrors: MutableMap = ConcurrentHashMap(), + @Volatile var currentSessionInApps: List = emptyList(), + var shownInAppIdsWithEvents: ConcurrentHashMap> = ConcurrentHashMap(), + var configFetchingError: Boolean = false, + var sessionTime: Duration = 0L.milliseconds, + var inAppShowLimitsSettings: InAppShowLimitsSettings = InAppShowLimitsSettings(), + var inAppTriggerEvent: InAppEventType? = null, +) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManager.kt index 7ad101f95..7e788e894 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManager.kt @@ -1,61 +1,22 @@ package cloud.mindbox.mobile_sdk.inapp.data.managers -import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowBudgetOwner -import cloud.mindbox.mobile_sdk.inapp.domain.models.* import cloud.mindbox.mobile_sdk.logger.mindboxLogI -import cloud.mindbox.mobile_sdk.models.InAppEventType -import cloud.mindbox.mobile_sdk.models.PlaceKey -import cloud.mindbox.mobile_sdk.newConcurrentSet import cloud.mindbox.mobile_sdk.models.TrackVisitData import cloud.mindbox.mobile_sdk.utils.TimeProvider import cloud.mindbox.mobile_sdk.utils.loggingRunCatching -import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.atomic.AtomicLong -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds private typealias SessionExpirationListener = () -> Unit internal class SessionStorageManager(private val timeProvider: TimeProvider) { - @Volatile var inAppCustomerSegmentations: SegmentationCheckWrapper? = null - var unShownOperationalInApps: ConcurrentHashMap> = ConcurrentHashMap() - var operationalInApps: ConcurrentHashMap> = ConcurrentHashMap() - var inAppMessageShownInSession: MutableList = CopyOnWriteArrayList() - - val embeddedLastShownByPlace: ConcurrentHashMap = ConcurrentHashMap() - - val embeddedLastTargetedByPlace: ConcurrentHashMap = ConcurrentHashMap() - - val placeTargetingReportedInSession: MutableSet = newConcurrentSet() - - val embeddedDelaysWaitedOut: MutableSet = newConcurrentSet() - - val requestedInAppTargetingReportedInSession: MutableSet = newConcurrentSet() - - val waitBudgetReportedPlaces: MutableSet = newConcurrentSet() - - val reportedShowFailures: MutableSet = newConcurrentSet() - - val showReservations: MutableMap = ConcurrentHashMap() + @Volatile var state: SessionState = SessionState() + private set val showBudgetLock = Any() - var customerSegmentationFetchStatus: CustomerSegmentationFetchStatus = - CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED - var geoFetchStatus: GeoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED - var inAppProductSegmentations: MutableMap, Set> = - ConcurrentHashMap() - var processedProductSegmentations: MutableMap, ProductSegmentationFetchStatus> = ConcurrentHashMap() - var lastTargetingErrors: MutableMap = ConcurrentHashMap() - - @Volatile var currentSessionInApps: List = emptyList() - var shownInAppIdsWithEvents: ConcurrentHashMap> = ConcurrentHashMap() - var configFetchingError: Boolean = false - var sessionTime: Duration = 0L.milliseconds - var inAppShowLimitsSettings: InAppShowLimitsSettings = InAppShowLimitsSettings() + var lastTrackVisitData: TrackVisitData? = null - var inAppTriggerEvent: InAppEventType? = null val lastTrackVisitSendTime: AtomicLong = AtomicLong(0L) @@ -76,7 +37,7 @@ internal class SessionStorageManager(private val timeProvider: TimeProvider) { val currentTime = timeProvider.currentTimeMillis() val oldLastTrackVisitSendTime = lastTrackVisitSendTime.getAndSet(currentTime) val timeBetweenVisits = currentTime - oldLastTrackVisitSendTime - val currentSessionTime = sessionTime.inWholeMilliseconds + val currentSessionTime = state.sessionTime.inWholeMilliseconds val checkingSessionResultLog = when { oldLastTrackVisitSendTime == 0L -> "First track visit on sdk init" @@ -100,29 +61,7 @@ internal class SessionStorageManager(private val timeProvider: TimeProvider) { fun isSessionExpiredOnLastCheck() = wasSessionExpiredOnLastCheck fun clearSessionData() = synchronized(showBudgetLock) { - inAppCustomerSegmentations = null - unShownOperationalInApps.clear() - operationalInApps.clear() - inAppMessageShownInSession.clear() - embeddedLastShownByPlace.clear() - embeddedLastTargetedByPlace.clear() - placeTargetingReportedInSession.clear() - embeddedDelaysWaitedOut.clear() - requestedInAppTargetingReportedInSession.clear() - waitBudgetReportedPlaces.clear() - reportedShowFailures.clear() - showReservations.clear() - customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED - geoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED - inAppProductSegmentations.clear() - processedProductSegmentations.clear() - lastTargetingErrors.clear() - currentSessionInApps = emptyList() - shownInAppIdsWithEvents.clear() - configFetchingError = false - sessionTime = 0L.milliseconds - inAppShowLimitsSettings = InAppShowLimitsSettings() - inAppTriggerEvent = null + state = SessionState() } private fun notifySessionExpired() { diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImpl.kt index a33cb1df5..ba49b31fb 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImpl.kt @@ -31,7 +31,7 @@ internal class ShowBudgetManagerImpl( isPriority: Boolean ): ShowReservationOutcome { synchronized(lock) { - val reservations = sessionStorageManager.showReservations + val reservations = sessionStorageManager.state.showReservations val held = reservations[owner] if (held != null && held.inAppId == inAppId) { mindboxLogI("$owner already holds a show reservation for in-app $inAppId") @@ -62,11 +62,11 @@ internal class ShowBudgetManagerImpl( shownAt: Timestamp ) { synchronized(lock) { - val held = sessionStorageManager.showReservations[owner] + val held = sessionStorageManager.state.showReservations[owner] if (held != null && held.inAppId != inAppId) { mindboxLogI("$owner now holds a reservation for in-app ${held.inAppId}, the show of $inAppId leaves it in place") } else { - sessionStorageManager.showReservations.remove(owner) + sessionStorageManager.state.showReservations.remove(owner) } if (!frequency.countsShows()) { mindboxLogI("In-app $inAppId has unlimited frequency, nothing to count") @@ -81,7 +81,7 @@ internal class ShowBudgetManagerImpl( override fun release(owner: ShowBudgetOwner) { synchronized(lock) { - val released = sessionStorageManager.showReservations.remove(owner) ?: return + val released = sessionStorageManager.state.showReservations.remove(owner) ?: return mindboxLogI("$owner released its show reservation for in-app ${released.inAppId}") } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryImpl.kt index da3b8bf46..928618816 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryImpl.kt @@ -26,7 +26,7 @@ internal class InAppGeoRepositoryImpl( private val geoMutex = Mutex() override suspend fun fetchGeo() = geoMutex.withLock { - if (sessionStorageManager.geoFetchStatus == GeoFetchStatus.GEO_FETCH_SUCCESS) { + if (sessionStorageManager.state.geoFetchStatus == GeoFetchStatus.GEO_FETCH_SUCCESS) { return@withLock } val configuration = DbManager.listenConfigurations().first() @@ -37,16 +37,16 @@ internal class InAppGeoRepositoryImpl( ) MindboxPreferences.inAppGeo = geoSerializationManager.serializeToGeoString(geoTargeting) - sessionStorageManager.geoFetchStatus = GeoFetchStatus.GEO_FETCH_SUCCESS + sessionStorageManager.state.geoFetchStatus = GeoFetchStatus.GEO_FETCH_SUCCESS } override fun setGeoStatus(status: GeoFetchStatus) { - sessionStorageManager.geoFetchStatus = status + sessionStorageManager.state.geoFetchStatus = status } override fun getGeoFetchedStatus(): GeoFetchStatus { return LoggingExceptionHandler.runCatching(GeoFetchStatus.GEO_FETCH_ERROR) { - sessionStorageManager.geoFetchStatus + sessionStorageManager.state.geoFetchStatus } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryImpl.kt index 72007494d..5ca2fa6b1 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryImpl.kt @@ -33,41 +33,41 @@ internal class InAppRepositoryImpl( } override fun saveCurrentSessionInApps(inApps: List) { - sessionStorageManager.currentSessionInApps = inApps + sessionStorageManager.state.currentSessionInApps = inApps } override fun getCurrentSessionInApps(): List { - return sessionStorageManager.currentSessionInApps + return sessionStorageManager.state.currentSessionInApps } override fun getTargetedInApps(): Map> { - return sessionStorageManager.shownInAppIdsWithEvents + return sessionStorageManager.state.shownInAppIdsWithEvents } override fun saveTargetedInAppWithEvent(inAppId: String, eventHashcode: Int) { - sessionStorageManager.shownInAppIdsWithEvents + sessionStorageManager.state.shownInAppIdsWithEvents .getOrPut(inAppId) { newConcurrentSet() } .add(eventHashcode) } override fun saveUnShownOperationalInApp(operation: String, inApp: InApp) { - sessionStorageManager.unShownOperationalInApps + sessionStorageManager.state.unShownOperationalInApps .getOrPut(operation) { CopyOnWriteArrayList() } .add(inApp) } override fun getUnShownOperationalInAppsByOperation(operation: String): List { - return sessionStorageManager.unShownOperationalInApps[operation.lowercase()] ?: emptyList() + return sessionStorageManager.state.unShownOperationalInApps[operation.lowercase()] ?: emptyList() } override fun saveOperationalInApp(operation: String, inApp: InApp) { - sessionStorageManager.operationalInApps + sessionStorageManager.state.operationalInApps .getOrPut(operation) { CopyOnWriteArrayList() } .add(inApp) } override fun getOperationalInAppsByOperation(operation: String): List { - return sessionStorageManager.operationalInApps[operation.lowercase()] ?: emptyList() + return sessionStorageManager.state.operationalInApps[operation.lowercase()] ?: emptyList() } override fun getShownInApps(): Map> { @@ -146,7 +146,7 @@ internal class InAppRepositoryImpl( } override fun isInAppShown(inAppId: String): Boolean { - return sessionStorageManager.inAppMessageShownInSession.any { it == inAppId } + return sessionStorageManager.state.inAppMessageShownInSession.any { it == inAppId } } override fun clearInAppEvents() { @@ -154,12 +154,12 @@ internal class InAppRepositoryImpl( } override fun isTimeDelayInapp(inAppId: String): Boolean = - sessionStorageManager.currentSessionInApps + sessionStorageManager.state.currentSessionInApps .any { it.id == inAppId && it.frequency.delay is Frequency.Delay.TimeDelay } override fun setInAppShown(inAppId: String) { - mindboxLogI("Increase count of shown inapp per session, previous count ${sessionStorageManager.inAppMessageShownInSession.size}") - sessionStorageManager.inAppMessageShownInSession.add(inAppId) + mindboxLogI("Increase count of shown inapp per session, previous count ${sessionStorageManager.state.inAppMessageShownInSession.size}") + sessionStorageManager.state.inAppMessageShownInSession.add(inAppId) } override fun getLastInappDismissTime(): Timestamp = MindboxPreferences.lastInappChangeStateTime diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryImpl.kt index c7ea32adb..e0d68abcc 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryImpl.kt @@ -24,17 +24,17 @@ internal class InAppSegmentationRepositoryImpl( private val customerSegmentationsMutex = Mutex() override suspend fun fetchCustomerSegmentations() = customerSegmentationsMutex.withLock { - if (sessionStorageManager.customerSegmentationFetchStatus == + if (sessionStorageManager.state.customerSegmentationFetchStatus == CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS ) { return@withLock } - if (sessionStorageManager.currentSessionInApps.isEmpty()) { + if (sessionStorageManager.state.currentSessionInApps.isEmpty()) { MindboxLoggerImpl.d( this, "No unshown inapps. Do not request segmentations" ) - sessionStorageManager.customerSegmentationFetchStatus = + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR return@withLock } @@ -46,12 +46,12 @@ internal class InAppSegmentationRepositoryImpl( val response = gatewayManager.checkCustomerSegmentations( configuration = configuration, segmentationCheckRequest = inAppMapper.mapToCustomerSegmentationCheckRequest( - sessionStorageManager.currentSessionInApps + sessionStorageManager.state.currentSessionInApps ) ) - sessionStorageManager.inAppCustomerSegmentations = + sessionStorageManager.state.inAppCustomerSegmentations = inAppMapper.mapToSegmentationCheck(response) - sessionStorageManager.customerSegmentationFetchStatus = + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS return@withLock } @@ -63,14 +63,14 @@ internal class InAppSegmentationRepositoryImpl( val segmentationCheckRequest = inAppMapper.mapToProductSegmentationCheckRequest( product, - sessionStorageManager.currentSessionInApps + sessionStorageManager.state.currentSessionInApps ) val result = gatewayManager.checkProductSegmentation( configuration, segmentationCheckRequest ) - sessionStorageManager.inAppProductSegmentations[product] = - sessionStorageManager.inAppProductSegmentations.getOrElse(product) { + sessionStorageManager.state.inAppProductSegmentations[product] = + sessionStorageManager.state.inAppProductSegmentations.getOrElse(product) { mutableSetOf().apply { add( inAppMapper.mapToProductSegmentationResponse( @@ -79,7 +79,7 @@ internal class InAppSegmentationRepositoryImpl( ) } } - sessionStorageManager.processedProductSegmentations[product] = + sessionStorageManager.state.processedProductSegmentations[product] = ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS } @@ -87,29 +87,29 @@ internal class InAppSegmentationRepositoryImpl( productId: Pair, ): Set { return LoggingExceptionHandler.runCatching(emptySet()) { - sessionStorageManager.inAppProductSegmentations[productId] ?: emptySet() + sessionStorageManager.state.inAppProductSegmentations[productId] ?: emptySet() } } override fun setCustomerSegmentationStatus(status: CustomerSegmentationFetchStatus) { - sessionStorageManager.customerSegmentationFetchStatus = status + sessionStorageManager.state.customerSegmentationFetchStatus = status } override fun getCustomerSegmentationFetched(): CustomerSegmentationFetchStatus { return LoggingExceptionHandler.runCatching(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR) { - sessionStorageManager.customerSegmentationFetchStatus + sessionStorageManager.state.customerSegmentationFetchStatus } } override fun getProductSegmentationFetched(productId: Pair): ProductSegmentationFetchStatus { return LoggingExceptionHandler.runCatching(ProductSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR) { - sessionStorageManager.processedProductSegmentations[productId] ?: ProductSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED + sessionStorageManager.state.processedProductSegmentations[productId] ?: ProductSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED } } override fun getCustomerSegmentations(): List { return LoggingExceptionHandler.runCatching(emptyList()) { - sessionStorageManager.inAppCustomerSegmentations?.customerSegmentations ?: emptyList() + sessionStorageManager.state.inAppCustomerSegmentations?.customerSegmentations ?: emptyList() } } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryImpl.kt index a679604fb..c617a5ed6 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryImpl.kt @@ -9,14 +9,14 @@ internal class InAppTargetingErrorRepositoryImpl( private val sessionStorageManager: SessionStorageManager, ) : InAppTargetingErrorRepository { override fun saveError(key: TargetingErrorKey, error: Throwable) { - sessionStorageManager.lastTargetingErrors[key] = "${error.message}. ${error.cause?.getVolleyErrorDetails() ?: "volleyError = null"}" + sessionStorageManager.state.lastTargetingErrors[key] = "${error.message}. ${error.cause?.getVolleyErrorDetails() ?: "volleyError = null"}" } override fun getError(key: TargetingErrorKey): String? { - return sessionStorageManager.lastTargetingErrors[key] + return sessionStorageManager.state.lastTargetingErrors[key] } override fun clearErrors() { - sessionStorageManager.lastTargetingErrors.clear() + sessionStorageManager.state.lastTargetingErrors.clear() } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/MobileConfigRepositoryImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/MobileConfigRepositoryImpl.kt index a84ad213e..9aa608154 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/MobileConfigRepositoryImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/MobileConfigRepositoryImpl.kt @@ -148,7 +148,7 @@ internal class MobileConfigRepositoryImpl( val isValidConfig = inAppConfigTtlValidator.isValid( InAppTtlData( ttl = getInAppTtl(configBlank), - shouldCheckInAppTtl = sessionStorageManager.configFetchingError + shouldCheckInAppTtl = sessionStorageManager.state.configFetchingError ) ) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppInteractorImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppInteractorImpl.kt index 77967c764..e6ef3a48d 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppInteractorImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppInteractorImpl.kt @@ -111,7 +111,7 @@ internal class InAppInteractorImpl( InitializeLock.complete(InitializeLock.State.APP_STARTED) } inApp?.let { - sessionStorageManager.inAppTriggerEvent = event + sessionStorageManager.state.inAppTriggerEvent = event } inApp?.let { inapp -> inapp to timeProvider.elapsedSince(triggerTimeMillis) } } @@ -128,10 +128,11 @@ internal class InAppInteractorImpl( ): EmbeddedResolveResult? { val inApps = mobileConfigRepository.getInAppsSection() inAppRepository.saveCurrentSessionInApps(inApps) + val trigger = placeTrigger(placeSystemName, triggerEvent) val candidates = inAppFilteringManager.filterEmbeddedInAppsByPlace(inApps, placeSystemName) .let { inAppFilteringManager.filterOutDirectCallInApps(it) } val matched = candidates.filter { candidate -> - inAppProcessingManager.matchesTargeting(candidate, triggerEvent) + inAppProcessingManager.matchesTargeting(candidate, trigger) } logI("Place '$placeSystemName': ${matched.size} of ${candidates.size} candidate(s) matched targeting") val inAppsPool = inAppABTestLogic.getInAppsPool(inApps.map { inApp -> inApp.id }) @@ -150,7 +151,7 @@ internal class InAppInteractorImpl( inAppFailureTracker.clearFailures() val variant = winner.embeddedVariantFor(placeSystemName) ?: return null val delayTime = winner.delayTime?.takeIf { delay -> - delay.interval > 0 && waitedOutDelayKey(placeSystemName, winner.id) !in sessionStorageManager.embeddedDelaysWaitedOut + delay.interval > 0 && waitedOutDelayKey(placeSystemName, winner.id) !in sessionStorageManager.state.embeddedDelaysWaitedOut } if (winner.delayTime != null && delayTime == null) { logI("Place '$placeSystemName': in-app ${winner.id} waits no delay (already waited out this session or zero)") @@ -161,8 +162,18 @@ internal class InAppInteractorImpl( ) } + private fun placeTrigger(place: PlaceKey, triggerEvent: InAppEventType): InAppEventType { + if (triggerEvent is InAppEventType.OrdinalEvent) { + sessionStorageManager.state.embeddedLastOperationByPlace[place] = triggerEvent + return triggerEvent + } + val remembered = sessionStorageManager.state.embeddedLastOperationByPlace[place] ?: return triggerEvent + logI("Place '$place': resolving as if operation '${remembered.name}' were still in effect this session") + return remembered + } + override fun markEmbeddedDelayWaitedOut(placeSystemName: PlaceKey, inAppId: String) { - sessionStorageManager.embeddedDelaysWaitedOut.add(waitedOutDelayKey(placeSystemName, inAppId)) + sessionStorageManager.state.embeddedDelaysWaitedOut.add(waitedOutDelayKey(placeSystemName, inAppId)) } private fun waitedOutDelayKey(place: PlaceKey, inAppId: String): String = "$place|$inAppId" @@ -170,14 +181,14 @@ internal class InAppInteractorImpl( private fun sendPlaceTargetings(place: PlaceKey, matched: List, winner: InApp?) { for (inApp in matched) { if (inApp.id == winner?.id) { - if (sessionStorageManager.embeddedLastTargetedByPlace.put(place, inApp.id) == inApp.id) { + if (sessionStorageManager.state.embeddedLastTargetedByPlace.put(place, inApp.id) == inApp.id) { logI("Place '$place': winner ${inApp.id} is the last targeted here, no second targeting") } else { - sessionStorageManager.placeTargetingReportedInSession.add(inApp.id) + sessionStorageManager.state.placeTargetingReportedInSession.add(inApp.id) inAppProcessingManager.sendTargetedInApp(inApp) } } else { - if (sessionStorageManager.placeTargetingReportedInSession.add(inApp.id)) { + if (sessionStorageManager.state.placeTargetingReportedInSession.add(inApp.id)) { inAppProcessingManager.sendTargetedInApp(inApp) } else { logI("Place '$place': in-app ${inApp.id} already sent its targeting this session") @@ -284,7 +295,7 @@ internal class InAppInteractorImpl( private fun sendRequestedTargetings(hostInAppId: String, fullById: Map, matchedById: Map) { for ((id, matches) in matchedById) { if (!matches) continue - if (sessionStorageManager.requestedInAppTargetingReportedInSession.add("$hostInAppId|$id")) { + if (sessionStorageManager.state.requestedInAppTargetingReportedInSession.add("$hostInAppId|$id")) { inAppProcessingManager.sendTargetedInApp(fullById.getValue(id)) } } @@ -302,7 +313,7 @@ internal class InAppInteractorImpl( .also { matches -> if (!matches) logI("Requested id ${inApp.id} targeting did not match, cutting it") } override fun reservePlaceShow(placeSystemName: PlaceKey, content: InAppType.Embedded): Boolean { - if (sessionStorageManager.embeddedLastShownByPlace[placeSystemName] == content.inAppId) { + if (sessionStorageManager.state.embeddedLastShownByPlace[placeSystemName] == content.inAppId) { logI("Place '$placeSystemName' already shows in-app ${content.inAppId}, no new show to reserve") showBudgetManager.release(ShowBudgetOwner.Place(placeSystemName)) return true @@ -339,7 +350,7 @@ internal class InAppInteractorImpl( timeToDisplay: Milliseconds, tags: Map?, ) { - val lastShown = sessionStorageManager.embeddedLastShownByPlace.put(placeSystemName, inAppId) + val lastShown = sessionStorageManager.state.embeddedLastShownByPlace.put(placeSystemName, inAppId) if (lastShown == inAppId) { logI("Place '$placeSystemName': the block re-drew in-app $inAppId it already showed, nothing to report") return diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/interfaces/interactors/InAppInteractor.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/interfaces/interactors/InAppInteractor.kt index 6af96b487..6fb8fb340 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/interfaces/interactors/InAppInteractor.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/interfaces/interactors/InAppInteractor.kt @@ -30,7 +30,10 @@ internal interface InAppInteractor { * and the show limits — parity with the overlay. Only the `isInAppActive` lock and the * delayed queue stay out: those are overlay machinery. The pull side passes * [InAppEventType.EmbeddedPlaceRequested] as [triggerEvent]; the push side passes the - * matched operation. Suspends until the config arrives. + * matched operation. The place remembers the last operation that reached it for the + * session and a pull resolves as if that operation were still in effect, so content shown + * by an operation survives the block's next appearance and a config update; nothing is + * re-emitted, the memory only steers this selection. Suspends until the config arrives. */ suspend fun selectInAppForPlace( placeSystemName: PlaceKey, diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNode.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNode.kt index 0cbaa6808..f1137b9ac 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNode.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNode.kt @@ -31,7 +31,7 @@ internal data class ViewProductSegmentNode( ) }.onFailure { error -> if (error is ProductSegmentationError) { - sessionStorageManager.processedProductSegmentations[product] = + sessionStorageManager.state.processedProductSegmentations[product] = ProductSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR if (error.shouldTrackTargetingError()) { inAppTargetingErrorRepository.saveError( diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerImpl.kt index f55765cc6..a4f33174a 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerImpl.kt @@ -231,7 +231,7 @@ internal class InAppMessageManagerImpl( } else -> { - sessionStorageManager.configFetchingError = true + sessionStorageManager.state.configFetchingError = true // needed to trigger flow event MindboxPreferences.inAppConfig = MindboxPreferences.inAppConfig MindboxLoggerImpl.e(InAppMessageManagerImpl, "Failed to get config", error) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/WebViewInappViewHolder.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/WebViewInappViewHolder.kt index 8f6c323d9..bf1b15fff 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/WebViewInappViewHolder.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/WebViewInappViewHolder.kt @@ -241,7 +241,7 @@ internal class WebViewInAppViewHolder( operation = if (wrapper.isRequestedShow) { null } else { - sessionStorageManager.inAppTriggerEvent as? InAppEventType.OrdinalEvent + sessionStorageManager.state.inAppTriggerEvent as? InAppEventType.OrdinalEvent }, ).get() } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/InappSettingsManagerImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/InappSettingsManagerImpl.kt index 9aab081f5..6caf2e961 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/InappSettingsManagerImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/InappSettingsManagerImpl.kt @@ -14,7 +14,7 @@ internal class InappSettingsManagerImpl(val sessionStorageManager: SessionStorag minIntervalBetweenShows = ${config.settings?.inapp?.minIntervalBetweenShows?.interval} ms """.trimIndent()) - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = config.settings?.inapp?.maxInappsPerSession, maxInappsPerDay = config.settings?.inapp?.maxInappsPerDay, minIntervalBetweenShows = config.settings?.inapp?.minIntervalBetweenShows diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerImpl.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerImpl.kt index 23d84d92e..60a898c2a 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerImpl.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerImpl.kt @@ -24,8 +24,8 @@ internal class MobileConfigSettingsManagerImpl( config.settings?.slidingExpiration?.config?.interval ?.takeIf { it > 0 } ?.let { sessionTime -> - sessionStorageManager.sessionTime = sessionTime.milliseconds - mindboxLogI("Session time set to ${sessionStorageManager.sessionTime.inWholeMilliseconds} ms") + sessionStorageManager.state.sessionTime = sessionTime.milliseconds + mindboxLogI("Session time set to ${sessionStorageManager.state.sessionTime.inWholeMilliseconds} ms") } ?: mindboxLogI("SessionTime is not set") } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequest.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequest.kt index e910dff86..86927120a 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequest.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequest.kt @@ -35,6 +35,6 @@ internal class WebViewContentRequest( } private companion object { - val LOGGED_HEADERS = setOf("age", "cache-control", "x-cache", "content-type") + val LOGGED_HEADERS = setOf("cache-status", "cache-host", "etag", "last-modified", "cache-control") } } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitCheckerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitCheckerTest.kt index 94f8f8713..de10eff8b 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitCheckerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerDayLimitCheckerTest.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk.inapp.data.checkers +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.repositories.InAppRepository import cloud.mindbox.mobile_sdk.inapp.domain.models.InAppShowLimitsSettings @@ -16,6 +17,8 @@ import org.junit.Test class MaxInappsPerDayLimitCheckerTest { private lateinit var sessionStorageManager: SessionStorageManager + + private val sessionState = SessionState() private lateinit var inAppRepository: InAppRepository private lateinit var timeProvider: TimeProvider private lateinit var maxInappsPerDayLimitChecker: MaxInappsPerDayLimitChecker @@ -31,6 +34,7 @@ class MaxInappsPerDayLimitCheckerTest { @Before fun setup() { sessionStorageManager = mockk() + every { sessionStorageManager.state } returns sessionState inAppRepository = mockk() timeProvider = mockk() maxInappsPerDayLimitChecker = MaxInappsPerDayLimitChecker( @@ -42,7 +46,7 @@ class MaxInappsPerDayLimitCheckerTest { @Test fun `check returns true when setting maxInappsPerDay is null`() { - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = null ) every { timeProvider.currentTimeMillis() } returns TEST_TIME @@ -59,7 +63,7 @@ class MaxInappsPerDayLimitCheckerTest { fun `check returns true when shown inapps count is less than limit`() { val maxInappsPerDay = 3 - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = maxInappsPerDay ) every { timeProvider.currentTimestamp() } returns Timestamp(TEST_TIME) @@ -77,7 +81,7 @@ class MaxInappsPerDayLimitCheckerTest { fun `check returns false when shown inapps count equals limit`() { val maxInappsPerDay = 2 - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = maxInappsPerDay ) every { timeProvider.currentTimestamp() } returns Timestamp(TEST_TIME) @@ -95,7 +99,7 @@ class MaxInappsPerDayLimitCheckerTest { fun `check returns false when shown inapps count exceeds limit`() { val maxInappsPerDay = 1 - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = maxInappsPerDay ) every { timeProvider.currentTimestamp() } returns Timestamp(TEST_TIME) @@ -113,7 +117,7 @@ class MaxInappsPerDayLimitCheckerTest { fun `check ignores inapps shown on previous days`() { val maxInappsPerDay = 2 - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = maxInappsPerDay ) every { timeProvider.currentTimestamp() } returns Timestamp(TEST_TIME) @@ -129,7 +133,7 @@ class MaxInappsPerDayLimitCheckerTest { @Test fun `check counts held reservations against the daily limit`() { - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerDay = 2 ) every { timeProvider.currentTimestamp() } returns Timestamp(TEST_TIME) diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitCheckerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitCheckerTest.kt index 814bd491a..769980460 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitCheckerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MaxInappsPerSessionLimitCheckerTest.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk.inapp.data.checkers +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.models.InAppShowLimitsSettings import cloud.mindbox.mobile_sdk.inapp.domain.models.ShowReservation @@ -14,21 +15,24 @@ import org.junit.Test class MaxInappsPerSessionLimitCheckerTest { private lateinit var sessionStorageManager: SessionStorageManager + + private val sessionState = SessionState() private lateinit var maxInappsPerSessionLimitChecker: MaxInappsPerSessionLimitChecker @Before fun setup() { sessionStorageManager = mockk() + every { sessionStorageManager.state } returns sessionState maxInappsPerSessionLimitChecker = MaxInappsPerSessionLimitChecker(sessionStorageManager) } @Test fun `check returns true when setting maxInappsPerSession is null`() { val shownInapps = mutableListOf("inapp1", "inapp2") - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = null, ) - every { sessionStorageManager.inAppMessageShownInSession } returns shownInapps + sessionStorageManager.state.inAppMessageShownInSession = shownInapps val result = maxInappsPerSessionLimitChecker.check(emptyList()) @@ -40,10 +44,10 @@ class MaxInappsPerSessionLimitCheckerTest { val maxInappsPerSession = 3 val shownInapps = mutableListOf("inapp1", "inapp2") - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = maxInappsPerSession ) - every { sessionStorageManager.inAppMessageShownInSession } returns shownInapps + sessionStorageManager.state.inAppMessageShownInSession = shownInapps val result = maxInappsPerSessionLimitChecker.check(emptyList()) @@ -55,10 +59,10 @@ class MaxInappsPerSessionLimitCheckerTest { val maxInappsPerSession = 2 val shownInapps = mutableListOf("inapp1", "inapp2") - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = maxInappsPerSession ) - every { sessionStorageManager.inAppMessageShownInSession } returns shownInapps + sessionStorageManager.state.inAppMessageShownInSession = shownInapps val result = maxInappsPerSessionLimitChecker.check(emptyList()) @@ -70,10 +74,10 @@ class MaxInappsPerSessionLimitCheckerTest { val maxInappsPerSession = 1 val shownInapps = mutableListOf("inapp1", "inapp2") - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = maxInappsPerSession ) - every { sessionStorageManager.inAppMessageShownInSession } returns shownInapps + sessionStorageManager.state.inAppMessageShownInSession = shownInapps val result = maxInappsPerSessionLimitChecker.check(emptyList()) @@ -82,10 +86,10 @@ class MaxInappsPerSessionLimitCheckerTest { @Test fun `check counts held reservations against the session limit`() { - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( maxInappsPerSession = 2 ) - every { sessionStorageManager.inAppMessageShownInSession } returns mutableListOf("inapp1") + sessionStorageManager.state.inAppMessageShownInSession = mutableListOf("inapp1") val held = listOf(ShowReservation("inapp2", Timestamp(1L))) assertFalse(maxInappsPerSessionLimitChecker.check(held)) diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitCheckerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitCheckerTest.kt index 4f9a131af..79e356ee4 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitCheckerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/checkers/MinIntervalBetweenShowsLimitCheckerTest.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk.inapp.data.checkers +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.repositories.InAppRepository import cloud.mindbox.mobile_sdk.inapp.domain.models.InAppShowLimitsSettings @@ -17,6 +18,8 @@ import org.junit.Test class MinIntervalBetweenShowsLimitCheckerTest { private lateinit var sessionStorageManager: SessionStorageManager + + private val sessionState = SessionState() private lateinit var inAppRepository: InAppRepository private lateinit var timeProvider: TimeProvider private lateinit var minIntervalBetweenShowsLimitChecker: MinIntervalBetweenShowsLimitChecker @@ -24,6 +27,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { @Before fun setup() { sessionStorageManager = mockk() + every { sessionStorageManager.state } returns sessionState inAppRepository = mockk() timeProvider = mockk() minIntervalBetweenShowsLimitChecker = MinIntervalBetweenShowsLimitChecker( @@ -35,7 +39,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { @Test fun `check returns true when minIntervalBetweenShows is null`() { - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = null ) @@ -50,7 +54,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { val currentTime = 2000L val interval = Milliseconds(2000L) - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = interval ) every { inAppRepository.getLastInappDismissTime() } returns Timestamp(lastShowTime) @@ -67,7 +71,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { val currentTime = 3000L val interval = Milliseconds(2000L) - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = interval ) every { inAppRepository.getLastInappDismissTime() } returns Timestamp(lastShowTime) @@ -84,7 +88,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { val currentTime = 4000L val interval = Milliseconds(2000L) - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = interval ) every { inAppRepository.getLastInappDismissTime() } returns Timestamp(lastShowTime) @@ -98,7 +102,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { @Test fun `check counts the newest reservation as the last show`() { val interval = Milliseconds(2000L) - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = interval ) every { inAppRepository.getLastInappDismissTime() } returns Timestamp(0L) @@ -113,7 +117,7 @@ class MinIntervalBetweenShowsLimitCheckerTest { @Test fun `check keeps the dismiss time when it is newer than every reservation`() { - every { sessionStorageManager.inAppShowLimitsSettings } returns InAppShowLimitsSettings( + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings( minIntervalBetweenShows = Milliseconds(2000L) ) every { inAppRepository.getLastInappDismissTime() } returns Timestamp(9_000L) diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManagerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManagerTest.kt index 8adb9be48..678a2b2fe 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManagerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/SessionStorageManagerTest.kt @@ -7,6 +7,8 @@ import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowBudgetOwner import cloud.mindbox.mobile_sdk.inapp.domain.models.ShowReservation import cloud.mindbox.mobile_sdk.inapp.domain.models.ProductSegmentationFetchStatus import cloud.mindbox.mobile_sdk.inapp.domain.models.TargetingErrorKey +import cloud.mindbox.mobile_sdk.models.EventType +import cloud.mindbox.mobile_sdk.models.InAppEventType import cloud.mindbox.mobile_sdk.models.Milliseconds import cloud.mindbox.mobile_sdk.models.PlaceKey import cloud.mindbox.mobile_sdk.models.Timestamp @@ -29,7 +31,7 @@ class SessionStorageManagerTest { currentTime: Long ) { sessionStorageManager.lastTrackVisitSendTime.set(lastTrackTime) - sessionStorageManager.sessionTime = sessionTime.milliseconds + sessionStorageManager.state.sessionTime = sessionTime.milliseconds every { mockTimeProvider.currentTimeMillis() } returns currentTime } @@ -105,9 +107,28 @@ class SessionStorageManagerTest { verify(exactly = 0) { listener.invoke() } } + @Test + fun `every field of the manager is either session state or on the allow-list of what survives a session`() { + val survivesSession = setOf( + "timeProvider", + "state", + "showBudgetLock", + "lastTrackVisitData", + "lastTrackVisitSendTime", + "sessionExpirationListeners", + "wasSessionExpiredOnLastCheck", + ) + val declared = SessionStorageManager::class.java.declaredFields + .map { field -> field.name } + .filterNot { name -> name.contains('$') } + .toSet() + + assertEquals(survivesSession, declared) + } + @Test fun `clearSessionData should reset all fields to default values`() { - sessionStorageManager.apply { + sessionStorageManager.state.apply { inAppCustomerSegmentations = mockk() unShownOperationalInApps["test"] = mutableListOf(mockk()) operationalInApps["test"] = mutableListOf(mockk()) @@ -115,6 +136,8 @@ class SessionStorageManagerTest { inAppMessageShownInSession.add("test2") embeddedLastShownByPlace[PlaceKey.of("main-screen-top")] = "in-app-1" embeddedLastTargetedByPlace[PlaceKey.of("main-screen-top")] = "in-app-2" + embeddedLastOperationByPlace[PlaceKey.of("main-screen-top")] = + InAppEventType.OrdinalEvent(EventType.AsyncOperation("block-operation")) placeTargetingReportedInSession.add("in-app-3") requestedInAppTargetingReportedInSession.add("host|inapp") embeddedDelaysWaitedOut.add("main-screen-top|in-app-1") @@ -136,28 +159,29 @@ class SessionStorageManagerTest { sessionStorageManager.clearSessionData() - assertNull(sessionStorageManager.inAppCustomerSegmentations) - assertTrue(sessionStorageManager.unShownOperationalInApps.isEmpty()) - assertTrue(sessionStorageManager.operationalInApps.isEmpty()) - assertTrue(sessionStorageManager.inAppMessageShownInSession.isEmpty()) + assertNull(sessionStorageManager.state.inAppCustomerSegmentations) + assertTrue(sessionStorageManager.state.unShownOperationalInApps.isEmpty()) + assertTrue(sessionStorageManager.state.operationalInApps.isEmpty()) + assertTrue(sessionStorageManager.state.inAppMessageShownInSession.isEmpty()) // The block-event memory dies with the session, every cell together. - assertTrue(sessionStorageManager.embeddedLastShownByPlace.isEmpty()) - assertTrue(sessionStorageManager.embeddedLastTargetedByPlace.isEmpty()) - assertTrue(sessionStorageManager.placeTargetingReportedInSession.isEmpty()) - assertTrue(sessionStorageManager.requestedInAppTargetingReportedInSession.isEmpty()) - assertTrue(sessionStorageManager.embeddedDelaysWaitedOut.isEmpty()) - assertTrue(sessionStorageManager.waitBudgetReportedPlaces.isEmpty()) - assertTrue(sessionStorageManager.showReservations.isEmpty()) - assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED, sessionStorageManager.customerSegmentationFetchStatus) - assertEquals(GeoFetchStatus.GEO_NOT_FETCHED, sessionStorageManager.geoFetchStatus) - assertTrue(sessionStorageManager.processedProductSegmentations.isEmpty()) - assertTrue(sessionStorageManager.inAppProductSegmentations.isEmpty()) - assertTrue(sessionStorageManager.currentSessionInApps.isEmpty()) - assertTrue(sessionStorageManager.shownInAppIdsWithEvents.isEmpty()) - assertFalse(sessionStorageManager.configFetchingError) - assertEquals(0L, sessionStorageManager.sessionTime.inWholeMilliseconds) - assertEquals(InAppShowLimitsSettings(), sessionStorageManager.inAppShowLimitsSettings) - assertTrue(sessionStorageManager.lastTargetingErrors.isEmpty()) + assertTrue(sessionStorageManager.state.embeddedLastShownByPlace.isEmpty()) + assertTrue(sessionStorageManager.state.embeddedLastTargetedByPlace.isEmpty()) + assertTrue(sessionStorageManager.state.embeddedLastOperationByPlace.isEmpty()) + assertTrue(sessionStorageManager.state.placeTargetingReportedInSession.isEmpty()) + assertTrue(sessionStorageManager.state.requestedInAppTargetingReportedInSession.isEmpty()) + assertTrue(sessionStorageManager.state.embeddedDelaysWaitedOut.isEmpty()) + assertTrue(sessionStorageManager.state.waitBudgetReportedPlaces.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) + assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED, sessionStorageManager.state.customerSegmentationFetchStatus) + assertEquals(GeoFetchStatus.GEO_NOT_FETCHED, sessionStorageManager.state.geoFetchStatus) + assertTrue(sessionStorageManager.state.processedProductSegmentations.isEmpty()) + assertTrue(sessionStorageManager.state.inAppProductSegmentations.isEmpty()) + assertTrue(sessionStorageManager.state.currentSessionInApps.isEmpty()) + assertTrue(sessionStorageManager.state.shownInAppIdsWithEvents.isEmpty()) + assertFalse(sessionStorageManager.state.configFetchingError) + assertEquals(0L, sessionStorageManager.state.sessionTime.inWholeMilliseconds) + assertEquals(InAppShowLimitsSettings(), sessionStorageManager.state.inAppShowLimitsSettings) + assertTrue(sessionStorageManager.state.lastTargetingErrors.isEmpty()) } @Test @@ -165,13 +189,13 @@ class SessionStorageManagerTest { val inAppId1 = "inApp1" val inAppId2 = "inApp2" val expectedResult = 3 - assertTrue(sessionStorageManager.inAppMessageShownInSession.isEmpty()) + assertTrue(sessionStorageManager.state.inAppMessageShownInSession.isEmpty()) - sessionStorageManager.inAppMessageShownInSession.add(inAppId1) - sessionStorageManager.inAppMessageShownInSession.add(inAppId2) - sessionStorageManager.inAppMessageShownInSession.add(inAppId1) + sessionStorageManager.state.inAppMessageShownInSession.add(inAppId1) + sessionStorageManager.state.inAppMessageShownInSession.add(inAppId2) + sessionStorageManager.state.inAppMessageShownInSession.add(inAppId1) - assertEquals(expectedResult, sessionStorageManager.inAppMessageShownInSession.size) + assertEquals(expectedResult, sessionStorageManager.state.inAppMessageShownInSession.size) } @Test diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImplTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImplTest.kt index eb8397a05..c85d075cf 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImplTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/managers/ShowBudgetManagerImplTest.kt @@ -48,7 +48,7 @@ internal class ShowBudgetManagerImplTest { every { inAppRepository.getShownInApps() } returns emptyMap() every { inAppRepository.getLastInappDismissTime() } returns Timestamp(0L) sessionStorageManager = SessionStorageManager(timeProvider) - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1) manager = managerWith(inAppRepository) } @@ -66,7 +66,7 @@ internal class ShowBudgetManagerImplTest { assertEquals(ShowReservationOutcome.GRANTED, manager.reserve(place, "block", counting, isPriority = false)) assertEquals(ShowReservationOutcome.REFUSED, manager.reserve(overlay, "modal-1", counting, isPriority = false)) - assertEquals(setOf(place), sessionStorageManager.showReservations.keys) + assertEquals(setOf(place), sessionStorageManager.state.showReservations.keys) } @Test @@ -84,14 +84,14 @@ internal class ShowBudgetManagerImplTest { manager.commit(place, "block", counting, now) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) verifyOrder { inAppRepository.setInAppShown("block") inAppRepository.saveShownInApp("block", now.ms) inAppRepository.saveInAppStateChangeTime(now) } // The counter now stands where the hold stood (the repository writes it): still one, still spent. - sessionStorageManager.inAppMessageShownInSession.add("block") + sessionStorageManager.state.inAppMessageShownInSession.add("block") assertEquals(ShowReservationOutcome.REFUSED, manager.reserve(overlay, "modal-1", counting, isPriority = false)) } @@ -101,7 +101,7 @@ internal class ShowBudgetManagerImplTest { assertEquals(ShowReservationOutcome.NOT_NEEDED, manager.reserve(overlay, "unlimited", unlimited, isPriority = false)) assertEquals(ShowReservationOutcome.NOT_NEEDED, manager.reserve(ShowBudgetOwner.Overlay("prio"), "prio", counting, isPriority = true)) - assertEquals(setOf(place), sessionStorageManager.showReservations.keys) + assertEquals(setOf(place), sessionStorageManager.state.showReservations.keys) manager.commit(overlay, "unlimited", unlimited, now) verify(exactly = 0) { inAppRepository.setInAppShown("unlimited") } @@ -115,7 +115,7 @@ internal class ShowBudgetManagerImplTest { // The second asker owns nothing: it must not give the first one's hold back. assertEquals(ShowReservationOutcome.ALREADY_HELD, manager.reserve(place, "block", counting, isPriority = false)) - assertEquals(1, sessionStorageManager.showReservations.size) + assertEquals(1, sessionStorageManager.state.showReservations.size) } @Test @@ -124,18 +124,18 @@ internal class ShowBudgetManagerImplTest { assertEquals(ShowReservationOutcome.GRANTED, manager.reserve(place, "block-2", counting, isPriority = false)) - assertEquals("block-2", sessionStorageManager.showReservations.getValue(place).inAppId) + assertEquals("block-2", sessionStorageManager.state.showReservations.getValue(place).inAppId) } @Test fun `an unlimited or priority newcomer for the same owner drops the counted hold it replaces`() { manager.reserve(place, "block", counting, isPriority = false) assertEquals(ShowReservationOutcome.NOT_NEEDED, manager.reserve(place, "unlimited", unlimited, isPriority = false)) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) manager.reserve(place, "block", counting, isPriority = false) assertEquals(ShowReservationOutcome.NOT_NEEDED, manager.reserve(place, "prio", counting, isPriority = true)) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) } @Test @@ -145,27 +145,27 @@ internal class ShowBudgetManagerImplTest { manager.commit(place, "old", counting, now) - assertEquals("new", sessionStorageManager.showReservations[place]?.inAppId) + assertEquals("new", sessionStorageManager.state.showReservations[place]?.inAppId) verify(exactly = 1) { inAppRepository.setInAppShown("old") } manager.commit(place, "new", counting, now) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) } @Test fun `a replacement refused by the budget leaves the owner with no hold`() { - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1) manager.reserve(place, "block-1", counting, isPriority = false) - sessionStorageManager.inAppMessageShownInSession.add("someone-else") + sessionStorageManager.state.inAppMessageShownInSession.add("someone-else") assertEquals(ShowReservationOutcome.REFUSED, manager.reserve(place, "block-2", counting, isPriority = false)) - assertNull(sessionStorageManager.showReservations[place]) + assertNull(sessionStorageManager.state.showReservations[place]) } @Test fun `the daily budget counts the holds too`() { - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerDay = 2) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerDay = 2) every { inAppRepository.getShownInApps() } returns mapOf("earlier" to listOf(now.ms - 1_000L)) manager.reserve(place, "block", counting, isPriority = false) @@ -174,7 +174,7 @@ internal class ShowBudgetManagerImplTest { @Test fun `the cooldown runs from the latest of the last show and the last hold`() { - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(minIntervalBetweenShows = Milliseconds(60_000L)) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(minIntervalBetweenShows = Milliseconds(60_000L)) manager.reserve(place, "block", counting, isPriority = false) // A hold taken just now is as good as a show for the pause: the overlay waits. @@ -212,7 +212,7 @@ internal class ShowBudgetManagerImplTest { pool.shutdown() assertEquals(1, granted.get()) - assertEquals(1, sessionStorageManager.showReservations.size) + assertEquals(1, sessionStorageManager.state.showReservations.size) } @Test @@ -221,7 +221,7 @@ internal class ShowBudgetManagerImplTest { sessionStorageManager.clearSessionData() - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) assertEquals(ShowReservationOutcome.GRANTED, manager.reserve(overlay, "modal-1", counting, isPriority = false)) } @@ -229,7 +229,7 @@ internal class ShowBudgetManagerImplTest { fun `a reserve that blocks mid-read keeps the second asker out until it decides`() { // Deterministic version of the race: the first asker is held inside the critical section // (on the daily read), the second must wait for it and then find the budget taken. - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1, maxInappsPerDay = 5) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1, maxInappsPerDay = 5) val entered = CountDownLatch(1) val proceed = CountDownLatch(1) every { inAppRepository.getShownInApps() } answers { @@ -261,7 +261,7 @@ internal class ShowBudgetManagerImplTest { fun `a session reset waits for a reserve in flight and leaves no hold behind`() { // The reset used to wipe the holds outside the manager's lock: a reserve that had already // passed its check would then put its hold into the fresh session. - sessionStorageManager.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1, maxInappsPerDay = 5) + sessionStorageManager.state.inAppShowLimitsSettings = InAppShowLimitsSettings(maxInappsPerSession = 1, maxInappsPerDay = 5) val entered = CountDownLatch(1) val proceed = CountDownLatch(1) every { inAppRepository.getShownInApps() } answers { @@ -282,7 +282,7 @@ internal class ShowBudgetManagerImplTest { assertEquals(ShowReservationOutcome.GRANTED, reserve.get(5, TimeUnit.SECONDS)) reset.get(5, TimeUnit.SECONDS) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) workers.shutdown() } @@ -293,7 +293,7 @@ internal class ShowBudgetManagerImplTest { val counting = this.counting val blockingRepository = object : InAppRepository by inAppRepository { override fun setInAppShown(inAppId: String) { - sessionStorageManager.inAppMessageShownInSession.add(inAppId) + sessionStorageManager.state.inAppMessageShownInSession.add(inAppId) } override fun saveShownInApp(id: String, timeStamp: Long) { @@ -319,7 +319,7 @@ internal class ShowBudgetManagerImplTest { commit.get(5, TimeUnit.SECONDS) assertEquals(ShowReservationOutcome.REFUSED, rival.get(5, TimeUnit.SECONDS)) - assertTrue(sessionStorageManager.showReservations.isEmpty()) + assertTrue(sessionStorageManager.state.showReservations.isEmpty()) workers.shutdown() } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryTest.kt index baa24854f..3beadf4b1 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppGeoRepositoryTest.kt @@ -1,6 +1,7 @@ package cloud.mindbox.mobile_sdk.inapp.data.repositories import android.content.Context +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.data.mapper.InAppMapper import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.GeoSerializationManager @@ -48,17 +49,17 @@ internal class InAppGeoRepositoryTest { @MockK private lateinit var sessionStorageManager: SessionStorageManager + private val sessionState = SessionState() + @MockK private lateinit var gatewayManager: GatewayManager @Before fun onTestStart() { - every { sessionStorageManager.geoFetchStatus } returns GeoFetchStatus.GEO_NOT_FETCHED + every { sessionStorageManager.state } returns sessionState + sessionStorageManager.state.geoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED mockkObject(DbManager) mockkObject(MindboxPreferences) - every { - inAppGeoRepository.setGeoStatus(any()) - } just runs } @Test @@ -185,15 +186,13 @@ internal class InAppGeoRepositoryTest { @Test fun `get geo fetched status success`() { - every { sessionStorageManager.geoFetchStatus } returns GeoFetchStatus.GEO_FETCH_SUCCESS + sessionStorageManager.state.geoFetchStatus = GeoFetchStatus.GEO_FETCH_SUCCESS assertEquals(GeoFetchStatus.GEO_FETCH_SUCCESS, inAppGeoRepository.getGeoFetchedStatus()) } @Test fun `get segmentation not fetched`() { - every { - sessionStorageManager.geoFetchStatus - } returns GeoFetchStatus.GEO_NOT_FETCHED + sessionStorageManager.state.geoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED assertEquals( GeoFetchStatus.GEO_NOT_FETCHED, inAppGeoRepository.getGeoFetchedStatus() @@ -202,7 +201,7 @@ internal class InAppGeoRepositoryTest { @Test fun `get geo fetched status error`() { - every { sessionStorageManager.geoFetchStatus } throws Error() + every { sessionStorageManager.state } throws Error() assertEquals(GeoFetchStatus.GEO_FETCH_ERROR, inAppGeoRepository.getGeoFetchedStatus()) } } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryTest.kt index 24e50aa26..c21208fb3 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppRepositoryTest.kt @@ -1,6 +1,7 @@ package cloud.mindbox.mobile_sdk.inapp.data.repositories import android.content.Context +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.InAppSerializationManager import cloud.mindbox.mobile_sdk.inapp.domain.models.InApp @@ -30,6 +31,8 @@ class InAppRepositoryTest { @MockK private lateinit var sessionStorageManager: SessionStorageManager + private val sessionState = SessionState() + @MockK private lateinit var context: Context @@ -44,6 +47,7 @@ class InAppRepositoryTest { @Before fun onTestStart() { + every { sessionStorageManager.state } returns sessionState mockkObject(MindboxPreferences) mockkObject(MindboxEventManager) } @@ -54,13 +58,13 @@ class InAppRepositoryTest { val newInApp = InAppStub.getInApp().copy(id = "newInAppId") val existingInApp = InAppStub.getInApp().copy(id = "existingId") val expectedList = mutableListOf(existingInApp, newInApp) - every { sessionStorageManager.unShownOperationalInApps } returns ConcurrentHashMap(mapOf( + sessionStorageManager.state.unShownOperationalInApps = ConcurrentHashMap(mapOf( testOperation to mutableListOf( existingInApp ) )) inAppRepository.saveUnShownOperationalInApp(testOperation, newInApp) - assertEquals(expectedList, sessionStorageManager.unShownOperationalInApps[testOperation]) + assertEquals(expectedList, sessionStorageManager.state.unShownOperationalInApps[testOperation]) } @Test @@ -68,16 +72,14 @@ class InAppRepositoryTest { val testOperation = "testOperation" val newInApp = InAppStub.getInApp().copy(id = "newInAppId") val expectedList = mutableListOf(newInApp) - every { sessionStorageManager.unShownOperationalInApps } returns ConcurrentHashMap() inAppRepository.saveUnShownOperationalInApp(testOperation, newInApp) - assertEquals(expectedList, sessionStorageManager.unShownOperationalInApps[testOperation]) + assertEquals(expectedList, sessionStorageManager.state.unShownOperationalInApps[testOperation]) } @Test fun `get operation inApps returns null`() { val testOperation = "testOperation" val expectedResult = mutableListOf() - every { sessionStorageManager.unShownOperationalInApps[testOperation.lowercase()] } returns null val actualResult = inAppRepository.getUnShownOperationalInAppsByOperation(testOperation) assertEquals(expectedResult, actualResult) } @@ -86,7 +88,7 @@ class InAppRepositoryTest { fun `get operation inApps no inApps`() { val testOperation = "testOperation" val expectedResult = mutableListOf() - every { sessionStorageManager.unShownOperationalInApps[testOperation.lowercase()] } returns expectedResult + sessionStorageManager.state.unShownOperationalInApps[testOperation.lowercase()] = expectedResult val actualResult = inAppRepository.getUnShownOperationalInAppsByOperation(testOperation) assertEquals(expectedResult, actualResult) } @@ -97,7 +99,7 @@ class InAppRepositoryTest { val expectedResult = mutableListOf( InAppStub.getInApp() ) - every { sessionStorageManager.unShownOperationalInApps[testOperation.lowercase()] } returns expectedResult + sessionStorageManager.state.unShownOperationalInApps[testOperation.lowercase()] = expectedResult val actualResult = inAppRepository.getUnShownOperationalInAppsByOperation(testOperation) assertEquals(expectedResult, actualResult) } @@ -228,7 +230,7 @@ class InAppRepositoryTest { ) ) ) - every { sessionStorageManager.currentSessionInApps } returns listOf(inApp) + sessionStorageManager.state.currentSessionInApps = listOf(inApp) val result = inAppRepository.isTimeDelayInapp(inAppId) @@ -244,7 +246,7 @@ class InAppRepositoryTest { delay = Frequency.Delay.OneTimePerSession ) ) - every { sessionStorageManager.currentSessionInApps } returns listOf(inApp) + sessionStorageManager.state.currentSessionInApps = listOf(inApp) val result = inAppRepository.isTimeDelayInapp(inAppId) @@ -254,7 +256,6 @@ class InAppRepositoryTest { @Test fun `isTimeDelayInapp returns false when in-app does not exist`() { val inAppId = "nonExistentId" - every { sessionStorageManager.currentSessionInApps } returns emptyList() val result = inAppRepository.isTimeDelayInapp(inAppId) @@ -264,7 +265,7 @@ class InAppRepositoryTest { @Test fun `isInAppShown returns true when in-app was shown`() { val inAppId = "testId" - every { sessionStorageManager.inAppMessageShownInSession } returns mutableListOf(inAppId) + sessionStorageManager.state.inAppMessageShownInSession = mutableListOf(inAppId) val result = inAppRepository.isInAppShown(inAppId) @@ -275,7 +276,7 @@ class InAppRepositoryTest { fun `isInAppShown returns false when in-app was not shown`() { val inAppId = "testId" val otherInAppId = "otherId" - every { sessionStorageManager.inAppMessageShownInSession } returns mutableListOf(otherInAppId) + sessionStorageManager.state.inAppMessageShownInSession = mutableListOf(otherInAppId) val result = inAppRepository.isInAppShown(inAppId) @@ -285,7 +286,6 @@ class InAppRepositoryTest { @Test fun `isInAppShown returns false when no in-apps were shown`() { val inAppId = "testId" - every { sessionStorageManager.inAppMessageShownInSession } returns mutableListOf() val result = inAppRepository.isInAppShown(inAppId) @@ -356,7 +356,6 @@ class InAppRepositoryTest { @Test fun `concurrent saveUnShownOperationalInApp does not lose a write`() { val operation = "testOperation" - every { sessionStorageManager.unShownOperationalInApps } returns ConcurrentHashMap() val inApps = (1..8).map { index -> InAppStub.getInApp().copy(id = "in-app-$index") } val threads = inApps.map { inApp -> @@ -367,14 +366,13 @@ class InAppRepositoryTest { assertEquals( inApps.map { inApp -> inApp.id }.toSet(), - sessionStorageManager.unShownOperationalInApps[operation]?.map { inApp -> inApp.id }?.toSet() + sessionStorageManager.state.unShownOperationalInApps[operation]?.map { inApp -> inApp.id }?.toSet() ) } @Test fun `concurrent saveOperationalInApp does not lose a write`() { val operation = "testOperation" - every { sessionStorageManager.operationalInApps } returns ConcurrentHashMap() val inApps = (1..8).map { index -> InAppStub.getInApp().copy(id = "in-app-$index") } val threads = inApps.map { inApp -> @@ -385,14 +383,13 @@ class InAppRepositoryTest { assertEquals( inApps.map { inApp -> inApp.id }.toSet(), - sessionStorageManager.operationalInApps[operation]?.map { inApp -> inApp.id }?.toSet() + sessionStorageManager.state.operationalInApps[operation]?.map { inApp -> inApp.id }?.toSet() ) } @Test fun `concurrent saveTargetedInAppWithEvent does not lose a write`() { val inAppId = "testInAppId" - every { sessionStorageManager.shownInAppIdsWithEvents } returns ConcurrentHashMap() val hashes = (1..8).toList() val threads = hashes.map { hash -> @@ -401,6 +398,6 @@ class InAppRepositoryTest { threads.forEach { thread -> thread.start() } threads.forEach { thread -> thread.join() } - assertEquals(hashes.toSet(), sessionStorageManager.shownInAppIdsWithEvents[inAppId]) + assertEquals(hashes.toSet(), sessionStorageManager.state.shownInAppIdsWithEvents[inAppId]) } } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryTest.kt index c8268cdf0..b248bd52f 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppSegmentationRepositoryTest.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk.inapp.data.repositories +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.data.mapper.InAppMapper import cloud.mindbox.mobile_sdk.inapp.domain.models.CustomerSegmentationFetchStatus @@ -29,14 +30,8 @@ class InAppSegmentationRepositoryTest { val mockkRule = MockKRule(this) private val inAppMapper = mockk() - private val sessionStorageManager = mockk(relaxUnitFun = true) { - every { - currentSessionInApps - } returns emptyList() - every { - currentSessionInApps = any() - } just runs - } + private val sessionState = SessionState() + private val sessionStorageManager = mockk(relaxUnitFun = true) { every { state } returns sessionState } private val gatewayManager = mockk() @@ -54,15 +49,12 @@ class InAppSegmentationRepositoryTest { mockkObject(DbManager) mockkObject(MindboxPreferences) // The fetch pre-checks the latched status under its mutex before going to the network. - every { sessionStorageManager.customerSegmentationFetchStatus } returns - CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED } @Test fun `request customer segmentations success`() = runTest { - every { - sessionStorageManager.currentSessionInApps - } returns mutableListOf(InAppStub.getInApp()) + sessionStorageManager.state.currentSessionInApps = mutableListOf(InAppStub.getInApp()) coEvery { DbManager.listenConfigurations() } answers { flow { emit(configuration) @@ -75,40 +67,21 @@ class InAppSegmentationRepositoryTest { gatewayManager.checkCustomerSegmentations(any(), any()) } returns segCheckResponse - every { - inAppSegmentationRepository.setCustomerSegmentationStatus(any()) - } just runs - every { inAppMapper.mapToSegmentationCheck(any()) } returns SegmentationCheckInAppStub.getSegmentationCheckWrapper() - every { - sessionStorageManager setProperty "inAppCustomerSegmentations" value any() - } just runs inAppSegmentationRepository.fetchCustomerSegmentations() - verify { - sessionStorageManager setProperty "customerSegmentationFetchStatus" value - CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS - } - verify(exactly = 1) { - sessionStorageManager setProperty "inAppCustomerSegmentations" value any() - } + assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS, sessionStorageManager.state.customerSegmentationFetchStatus) + assertNotNull(sessionStorageManager.state.inAppCustomerSegmentations) } @Test fun `request customer segmentations no inApps`() = runTest { - sessionStorageManager.currentSessionInApps = mutableListOf() - every { - sessionStorageManager.customerSegmentationFetchStatus = - CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR - } just runs + sessionStorageManager.state.currentSessionInApps = mutableListOf() inAppSegmentationRepository.fetchCustomerSegmentations() - verify(exactly = 1) { - sessionStorageManager.customerSegmentationFetchStatus = - CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR - } + assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, sessionStorageManager.state.customerSegmentationFetchStatus) coVerify(exactly = 0) { gatewayManager.checkCustomerSegmentations( @@ -120,9 +93,7 @@ class InAppSegmentationRepositoryTest { @Test fun `request customer segmentation error`() = runTest { - every { - sessionStorageManager.currentSessionInApps - } returns mutableListOf(InAppStub.getInApp()) + sessionStorageManager.state.currentSessionInApps = mutableListOf(InAppStub.getInApp()) coEvery { DbManager.listenConfigurations() } answers { flow { emit(configuration) @@ -131,10 +102,6 @@ class InAppSegmentationRepositoryTest { every { inAppMapper.mapToSegmentationCheck(any()) } returns SegmentationCheckInAppStub.getSegmentationCheckWrapper() - every { - sessionStorageManager.inAppCustomerSegmentations = - SegmentationCheckInAppStub.getSegmentationCheckWrapper() - } just runs coEvery { gatewayManager.checkCustomerSegmentations(any(), any()) } throws VolleyError("test message") @@ -162,21 +129,12 @@ class InAppSegmentationRepositoryTest { ) ) ) - every { - sessionStorageManager.inAppProductSegmentations["testSystem" to "testValue"] - } answers { - expectedResult - } + sessionStorageManager.state.inAppProductSegmentations["testSystem" to "testValue"] = expectedResult assertEquals(expectedResult, inAppSegmentationRepository.getProductSegmentations("testSystem" to "testValue")) } @Test fun `get product segmentation no segmentation`() { - every { - sessionStorageManager.inAppProductSegmentations[any()] - } answers { - null - } assertEquals( emptySet>(), inAppSegmentationRepository.getProductSegmentations("testSystem" to "testValue") @@ -209,31 +167,13 @@ class InAppSegmentationRepositoryTest { every { inAppMapper.mapToProductSegmentationCheckRequest("testSystem" to "testValue", listOf()) } returns dtoResult - every { - sessionStorageManager.processedProductSegmentations["testSystem" to "testValue"] - } answers { - ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS - } - every { - sessionStorageManager.processedProductSegmentations["testSystem" to "testValue"] = ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS - } just runs + sessionStorageManager.state.processedProductSegmentations["testSystem" to "testValue"] = ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS coEvery { gatewayManager.checkProductSegmentation(any(), any()) } answers { result } - every { sessionStorageManager.inAppProductSegmentations } returns HashMap() - every { - sessionStorageManager.inAppProductSegmentations = any() - } just runs - every { - sessionStorageManager.inAppProductSegmentations["testSystem" to "testValue"] - } answers { - setOf(expectedResult) - } - every { - sessionStorageManager.inAppProductSegmentations["testSystem" to "testValue"] = setOf(expectedResult) - } just runs + sessionStorageManager.state.inAppProductSegmentations["testSystem" to "testValue"] = setOf(expectedResult) coEvery { DbManager.listenConfigurations() } answers { flow { emit(configuration) @@ -242,7 +182,7 @@ class InAppSegmentationRepositoryTest { inAppSegmentationRepository.fetchProductSegmentation("testSystem" to "testValue") assertEquals( expectedResult, - sessionStorageManager.inAppProductSegmentations["testSystem" to "testValue"]?.firstOrNull() + sessionStorageManager.state.inAppProductSegmentations["testSystem" to "testValue"]?.firstOrNull() ) } @@ -269,9 +209,7 @@ class InAppSegmentationRepositoryTest { @Test fun `get segmentation fetched success`() { - every { - sessionStorageManager.customerSegmentationFetchStatus - } returns CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS assertEquals( CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS, inAppSegmentationRepository.getCustomerSegmentationFetched() @@ -280,9 +218,7 @@ class InAppSegmentationRepositoryTest { @Test fun `get segmentation not fetched`() { - every { - sessionStorageManager.customerSegmentationFetchStatus - } returns CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED assertEquals( CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED, inAppSegmentationRepository.getCustomerSegmentationFetched() @@ -291,9 +227,7 @@ class InAppSegmentationRepositoryTest { @Test fun `get segmentation fetched error`() { - every { - sessionStorageManager.customerSegmentationFetchStatus - } throws Error() + every { sessionStorageManager.state } throws Error() assertEquals( CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, inAppSegmentationRepository.getCustomerSegmentationFetched() @@ -303,9 +237,7 @@ class InAppSegmentationRepositoryTest { @Test fun `get inApps segmentations success`() { val expectedResult = listOf(SegmentationCheckInAppStub.getCustomerSegmentation()) - every { - sessionStorageManager.inAppCustomerSegmentations?.customerSegmentations - } returns expectedResult + sessionStorageManager.state.inAppCustomerSegmentations = SegmentationCheckWrapper("", expectedResult) val actualResult = inAppSegmentationRepository.getCustomerSegmentations() assertEquals(expectedResult, actualResult) } @@ -313,9 +245,6 @@ class InAppSegmentationRepositoryTest { @Test fun `get inApps segmentations returns null`() { val expectedResult = emptyList() - every { - sessionStorageManager.inAppCustomerSegmentations?.customerSegmentations - } returns null val actualResult = inAppSegmentationRepository.getCustomerSegmentations() assertEquals(expectedResult, actualResult) } @@ -323,9 +252,7 @@ class InAppSegmentationRepositoryTest { @Test fun `get inApps segmentations error`() { val expectedResult = emptyList() - every { - sessionStorageManager.inAppCustomerSegmentations?.customerSegmentations - } throws Error() + every { sessionStorageManager.state } throws Error() val actualResult = inAppSegmentationRepository.getCustomerSegmentations() assertEquals(expectedResult, actualResult) } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryTest.kt index 4af7ea6fa..92bfccb1b 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/data/repositories/InAppTargetingErrorRepositoryTest.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk.inapp.data.repositories +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.models.CustomerSegmentationError import cloud.mindbox.mobile_sdk.inapp.domain.models.GeoError @@ -13,7 +14,8 @@ import org.junit.Assert.assertEquals import org.junit.Test internal class InAppTargetingErrorRepositoryTest { - private val sessionStorageManager = mockk(relaxUnitFun = true) + private val sessionState = SessionState() + private val sessionStorageManager = mockk(relaxUnitFun = true) { every { state } returns sessionState } private val repository = InAppTargetingErrorRepositoryImpl(sessionStorageManager) @Test @@ -22,7 +24,7 @@ internal class InAppTargetingErrorRepositoryTest { val responseBody = """{"error":"customer segmentation failed"}""" val volleyError = createVolleyError(statusCode = 500, responseBody = responseBody, networkTimeMs = 100) val throwable = CustomerSegmentationError(volleyError) - every { sessionStorageManager.lastTargetingErrors } returns errors + sessionStorageManager.state.lastTargetingErrors = errors repository.saveError(TargetingErrorKey.CustomerSegmentation, throwable) val expectedDetails = "statusCode=500, networkTimeMs=${volleyError.networkTimeMs}, body=$responseBody" assertEquals("${throwable.message}. $expectedDetails", errors[TargetingErrorKey.CustomerSegmentation]) @@ -34,7 +36,7 @@ internal class InAppTargetingErrorRepositoryTest { val responseBody = """{"error":"geo failed"}""" val volleyError = createVolleyError(statusCode = 503, responseBody = responseBody, networkTimeMs = 200) val throwable = GeoError(volleyError) - every { sessionStorageManager.lastTargetingErrors } returns errors + sessionStorageManager.state.lastTargetingErrors = errors repository.saveError(TargetingErrorKey.Geo, throwable) val expectedDetails = "statusCode=503, networkTimeMs=${volleyError.networkTimeMs}, body=$responseBody" assertEquals("${throwable.message}. $expectedDetails", errors[TargetingErrorKey.Geo]) @@ -48,7 +50,7 @@ internal class InAppTargetingErrorRepositoryTest { val responseBody = """{"error":"product segmentation failed"}""" val volleyError = createVolleyError(statusCode = 504, responseBody = responseBody, networkTimeMs = 300) val throwable = ProductSegmentationError(volleyError) - every { sessionStorageManager.lastTargetingErrors } returns errors + sessionStorageManager.state.lastTargetingErrors = errors repository.saveError(productKey, throwable) val expectedDetails = "statusCode=504, networkTimeMs=${volleyError.networkTimeMs}, body=$responseBody" assertEquals("${throwable.message}. $expectedDetails", errors[productKey]) @@ -59,14 +61,13 @@ internal class InAppTargetingErrorRepositoryTest { val product = "website" to "ProductRandomName" val productKey = TargetingErrorKey.ProductSegmentation(product) val errorDetails = "Product segmentation fetch failed" - every { sessionStorageManager.lastTargetingErrors[productKey] } returns errorDetails + sessionStorageManager.state.lastTargetingErrors[productKey] = errorDetails val result = repository.getError(productKey) assertEquals(errorDetails, result) } @Test fun `getError returns null when no error saved`() { - every { sessionStorageManager.lastTargetingErrors[TargetingErrorKey.Geo] } returns null val result = repository.getError(TargetingErrorKey.Geo) assertEquals(null, result) } @@ -77,7 +78,7 @@ internal class InAppTargetingErrorRepositoryTest { TargetingErrorKey.Geo to "Geo error", TargetingErrorKey.CustomerSegmentation to "Customer error" ) - every { sessionStorageManager.lastTargetingErrors } returns errors + sessionStorageManager.state.lastTargetingErrors = errors repository.clearErrors() assertEquals(emptyMap(), errors) } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/EmbeddedResolveInteractorTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/EmbeddedResolveInteractorTest.kt index 4e86110b6..185b94aab 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/EmbeddedResolveInteractorTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/EmbeddedResolveInteractorTest.kt @@ -6,6 +6,7 @@ import org.junit.Assert.assertTrue import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowReservationOutcome import app.cash.turbine.test import cloud.mindbox.mobile_sdk.abtests.InAppABTestLogic +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.InAppFailureTracker import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowBudgetManager @@ -46,7 +47,6 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNull -import java.util.concurrent.ConcurrentHashMap import org.junit.Before import org.junit.Rule import org.junit.Test @@ -83,6 +83,8 @@ class EmbeddedResolveInteractorTest { @RelaxedMockK private lateinit var sessionStorageManager: SessionStorageManager + private val sessionState = SessionState() + @RelaxedMockK private lateinit var inAppFailureTracker: InAppFailureTracker @@ -96,6 +98,7 @@ class EmbeddedResolveInteractorTest { @Before fun setUp() { + every { sessionStorageManager.state } returns sessionState frequencyManager = spyk(InAppFrequencyManagerImpl(inAppRepository)) interactor = InAppInteractorImpl( mobileConfigRepository = mobileConfigRepository, @@ -114,11 +117,6 @@ class EmbeddedResolveInteractorTest { every { inAppRepository.getShownInApps() } returns emptyMap() every { inAppProcessingManager.sendTargetedInApp(any()) } just runs coEvery { inAppProcessingManager.sendTargetedInApp(any(), any()) } just runs - every { sessionStorageManager.placeTargetingReportedInSession } returns ConcurrentHashMap.newKeySet() - every { sessionStorageManager.requestedInAppTargetingReportedInSession } returns ConcurrentHashMap.newKeySet() - every { sessionStorageManager.embeddedLastShownByPlace } returns ConcurrentHashMap() - every { sessionStorageManager.embeddedLastTargetedByPlace } returns ConcurrentHashMap() - every { sessionStorageManager.embeddedDelaysWaitedOut } returns ConcurrentHashMap.newKeySet() coEvery { inAppProcessingManager.matchesTargeting(any(), any()) } returns true every { showBudgetManager.reserve(any(), any(), any(), any()) } returns ShowReservationOutcome.GRANTED every { showBudgetManager.commit(any(), any(), any(), any()) } just runs @@ -486,6 +484,90 @@ class EmbeddedResolveInteractorTest { coVerify { inAppProcessingManager.matchesTargeting(any(), operation) } } + @Test + fun `a pull after an operation resolves as if that operation were still in effect`() = runTest { + givenConfig(embeddedInApp()) + val operation = InAppEventType.OrdinalEvent(EventType.AsyncOperation("block-operation")) + + interactor.selectInAppForPlace(place, triggerEvent = operation) + interactor.selectInAppForPlace(place, InAppEventType.EmbeddedPlaceRequested(place)) + + coVerify(exactly = 2) { inAppProcessingManager.matchesTargeting(any(), operation) } + coVerify(exactly = 0) { inAppProcessingManager.matchesTargeting(any(), ofType()) } + } + + @Test + fun `a later operation replaces the one the place remembers`() = runTest { + givenConfig(embeddedInApp()) + val first = InAppEventType.OrdinalEvent(EventType.AsyncOperation("first-operation")) + val second = InAppEventType.OrdinalEvent(EventType.AsyncOperation("second-operation")) + + interactor.selectInAppForPlace(place, triggerEvent = first) + interactor.selectInAppForPlace(place, triggerEvent = second) + interactor.selectInAppForPlace(place, InAppEventType.EmbeddedPlaceRequested(place)) + + coVerify(exactly = 1) { inAppProcessingManager.matchesTargeting(any(), first) } + coVerify(exactly = 2) { inAppProcessingManager.matchesTargeting(any(), second) } + } + + @Test + fun `a pull with no operation behind it keeps the place request`() = runTest { + givenConfig(embeddedInApp()) + val request = InAppEventType.EmbeddedPlaceRequested(place) + mockkObject(MindboxLoggerImpl) + try { + interactor.selectInAppForPlace(place, request) + + coVerify(exactly = 1) { inAppProcessingManager.matchesTargeting(any(), request) } + verify(exactly = 0) { + MindboxLoggerImpl.i(any(), match { it.contains("were still in effect") }) + } + } finally { + unmockkObject(MindboxLoggerImpl) + } + } + + @Test + fun `the remembered operation belongs to its place alone`() = runTest { + val otherPlace = PlaceKey.of("other-place") + givenConfig(embeddedInApp(id = "here"), embeddedInApp(id = "there", placeName = otherPlace)) + val operation = InAppEventType.OrdinalEvent(EventType.AsyncOperation("block-operation")) + val otherRequest = InAppEventType.EmbeddedPlaceRequested(otherPlace) + + interactor.selectInAppForPlace(place, triggerEvent = operation) + interactor.selectInAppForPlace(otherPlace, otherRequest) + + coVerify(exactly = 1) { inAppProcessingManager.matchesTargeting(any(), operation) } + coVerify(exactly = 1) { inAppProcessingManager.matchesTargeting(any(), otherRequest) } + } + + @Test + fun `an operation that found nothing to show is remembered all the same`() = runTest { + givenConfig(embeddedInApp()) + coEvery { inAppProcessingManager.matchesTargeting(any(), any()) } returns false + val operation = InAppEventType.OrdinalEvent(EventType.AsyncOperation("block-operation")) + + assertNull(interactor.selectInAppForPlace(place, triggerEvent = operation)) + interactor.selectInAppForPlace(place, InAppEventType.EmbeddedPlaceRequested(place)) + + coVerify(exactly = 2) { inAppProcessingManager.matchesTargeting(any(), operation) } + } + + @Test + fun `the remembered operation lives in the session storage and dies with it`() = runTest { + val memory = sessionStorageManager.state.embeddedLastOperationByPlace + givenConfig(embeddedInApp()) + val operation = InAppEventType.OrdinalEvent(EventType.AsyncOperation("block-operation")) + val request = InAppEventType.EmbeddedPlaceRequested(place) + + interactor.selectInAppForPlace(place, triggerEvent = operation) + assertEquals(operation, memory[place]) + memory.clear() + interactor.selectInAppForPlace(place, request) + + coVerify(exactly = 1) { inAppProcessingManager.matchesTargeting(any(), request) } + } + @Test fun `getInAppToShowById ignores every restriction`() = runTest { // directCall, already shown, whatever frequency — a drawn element must open. @@ -922,7 +1004,7 @@ class EmbeddedResolveInteractorTest { @Test fun `reservePlaceShow skips the budget for content the place already shows`() { - sessionStorageManager.embeddedLastShownByPlace[place] = "embedded-id" + sessionStorageManager.state.embeddedLastShownByPlace[place] = "embedded-id" assertTrue(interactor.reservePlaceShow(place, InAppStub.getEmbedded().copy(inAppId = "embedded-id"))) @@ -934,7 +1016,7 @@ class EmbeddedResolveInteractorTest { // B won the place and took its hold, then A — already on the block — was delivered again // before B drew. B is not coming: the hold under the place is B's and must not stay in the // budgets for the session (iOS: InappShowAccountant releases on the silent redraw). - sessionStorageManager.embeddedLastShownByPlace[place] = "embedded-id" + sessionStorageManager.state.embeddedLastShownByPlace[place] = "embedded-id" assertTrue(interactor.reservePlaceShow(place, InAppStub.getEmbedded().copy(inAppId = "embedded-id"))) diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppProcessingManagerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppProcessingManagerTest.kt index caba9f334..540151b84 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppProcessingManagerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppProcessingManagerTest.kt @@ -155,14 +155,14 @@ internal class InAppProcessingManagerTest { ) private fun setupTestGeoRepositoryForErrorScenario() { - sessionStorageManager.geoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED + sessionStorageManager.state.geoFetchStatus = GeoFetchStatus.GEO_NOT_FETCHED every { inAppGeoRepositoryTestImpl.getGeoFetchedStatus() } answers { callOriginal() } coEvery { inAppGeoRepositoryTestImpl.fetchGeo() } throws GeoError(VolleyError()) every { inAppGeoRepositoryTestImpl.setGeoStatus(any()) } answers { callOriginal() } } private fun setupTestSegmentationRepositoryForErrorScenario() { - sessionStorageManager.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED + sessionStorageManager.state.customerSegmentationFetchStatus = CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED every { inAppSegmentationRepositoryTestImpl.getCustomerSegmentationFetched() } answers { callOriginal() } coEvery { inAppSegmentationRepositoryTestImpl.fetchCustomerSegmentations() } throws CustomerSegmentationError(VolleyError()) coEvery { inAppSegmentationRepositoryTestImpl.setCustomerSegmentationStatus(any()) } answers { callOriginal() } @@ -567,7 +567,7 @@ internal class InAppProcessingManagerTest { inAppProcessingManagerTestImpl.sendTargetedInApp(testInApp, InAppEventType.AppStartup) verify(exactly = 1) { mockInAppRepository.sendUserTargeted(any(), any()) } - assertEquals(GeoFetchStatus.GEO_FETCH_ERROR, sessionStorageManager.geoFetchStatus) + assertEquals(GeoFetchStatus.GEO_FETCH_ERROR, sessionStorageManager.state.geoFetchStatus) } @Test @@ -585,7 +585,7 @@ internal class InAppProcessingManagerTest { ) inAppProcessingManagerTestImpl.sendTargetedInApp(testInApp, InAppEventType.AppStartup) verify(exactly = 1) { mockInAppRepository.sendUserTargeted(any(), any()) } - assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, sessionStorageManager.customerSegmentationFetchStatus) + assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, sessionStorageManager.state.customerSegmentationFetchStatus) } @Test @@ -617,7 +617,7 @@ internal class InAppProcessingManagerTest { ) inAppProcessingManagerTestImpl.sendTargetedInApp(testInApp, InAppEventType.AppStartup) verify(exactly = 0) { mockInAppRepository.sendUserTargeted(any(), any()) } - assertEquals(GeoFetchStatus.GEO_FETCH_ERROR, sessionStorageManager.geoFetchStatus) + assertEquals(GeoFetchStatus.GEO_FETCH_ERROR, sessionStorageManager.state.geoFetchStatus) } @Test @@ -629,7 +629,7 @@ internal class InAppProcessingManagerTest { ) inAppProcessingManagerTestImpl.sendTargetedInApp(testInApp, InAppEventType.AppStartup) verify(exactly = 0) { mockInAppRepository.sendUserTargeted(any(), any()) } - assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, sessionStorageManager.customerSegmentationFetchStatus) + assertEquals(CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR, sessionStorageManager.state.customerSegmentationFetchStatus) } @Test diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNodeTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNodeTest.kt index ff054048c..576550b39 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNodeTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/domain/models/ViewProductSegmentNodeTest.kt @@ -1,6 +1,7 @@ package cloud.mindbox.mobile_sdk.inapp.domain.models import cloud.mindbox.mobile_sdk.di.MindboxDI +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.data.repositories.InAppTargetingErrorRepositoryImpl import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.repositories.InAppSegmentationRepository @@ -32,7 +33,8 @@ class ViewProductSegmentNodeTest { } private val mockkInAppSegmentationRepository: InAppSegmentationRepository = mockk() - private val sessionStorageManagerMock = mockk() + private val sessionState = SessionState() + private val sessionStorageManagerMock = mockk { every { state } returns sessionState } private val inAppTargetingErrorRepositoryMock = mockk() @get:Rule @@ -268,7 +270,7 @@ class ViewProductSegmentNodeTest { "website" to "successProduct" to ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS, "website" to "errorProduct" to ProductSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR ) - every { sessionStorageManagerMock.processedProductSegmentations } returns processedProducts + sessionStorageManagerMock.state.processedProductSegmentations = processedProducts every { mockkInAppSegmentationRepository.getProductSegmentationFetched("website" to "successProduct") } returns ProductSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS every { mockkInAppSegmentationRepository.getProductSegmentationFetched("website" to "errorProduct") } returns ProductSegmentationFetchStatus.SEGMENTATION_FETCH_ERROR every { mockkInAppSegmentationRepository.getProductSegmentationFetched("website" to "newProduct") } returns ProductSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerTest.kt index 25890706b..e5141b0c4 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManagerTest.kt @@ -3,6 +3,7 @@ package cloud.mindbox.mobile_sdk.inapp.presentation import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.managers.ShowReservationOutcome import android.util.Log import cloud.mindbox.mobile_sdk.inapp.data.managers.SEND_INAPP_TAGS_FEATURE +import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionState import cloud.mindbox.mobile_sdk.inapp.data.managers.SessionStorageManager import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.InAppActionCallbacks import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.interactors.InAppInteractor @@ -35,6 +36,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.test.* import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule @@ -57,7 +59,8 @@ internal class InAppMessageManagerTest { @MockK private lateinit var monitoringRepository: MonitoringInteractor - private val sessionStorageManager = mockk(relaxUnitFun = true) + private val sessionState = SessionState() + private val sessionStorageManager = mockk(relaxUnitFun = true) { every { state } returns sessionState } private val userVisitManager = mockk() @@ -338,7 +341,7 @@ internal class InAppMessageManagerTest { }.throws(VolleyError(networkResponse)) inAppMessageManager.requestConfig() advanceUntilIdle() - verify(exactly = 1) { sessionStorageManager.configFetchingError = true } + assertTrue(sessionStorageManager.state.configFetchingError) verify(exactly = 1) { MindboxPreferences setProperty MindboxPreferences::inAppConfig.name value "test" } @@ -369,7 +372,7 @@ internal class InAppMessageManagerTest { }.throws(VolleyError(networkResponse)) inAppMessageManager.requestConfig() advanceUntilIdle() - verify(exactly = 0) { sessionStorageManager.configFetchingError = true } + assertFalse(sessionStorageManager.state.configFetchingError) verify(exactly = 1) { MindboxPreferences setProperty MindboxPreferences::inAppConfig.name value "" } diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorParamsTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorParamsTest.kt index 7ff561b54..20f3ef28f 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorParamsTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorParamsTest.kt @@ -161,7 +161,7 @@ class DataCollectorParamsTest { // The block and the requested show pass `null`, and the session's last trigger — which // belongs to somebody else's in-app — stays out of the payload. val session = SessionStorageManager(mockk(relaxed = true)).apply { - inAppTriggerEvent = InAppEventType.OrdinalEvent( + state.inAppTriggerEvent = InAppEventType.OrdinalEvent( eventType = EventType.AsyncOperation("SomebodyElsesOperation"), body = """{"not":"ours"}""", ) diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorTest.kt index 914bc6c39..9470d79d4 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/inapp/presentation/view/DataCollectorTest.kt @@ -77,7 +77,7 @@ class DataCollectorTest { requestUrl = "https://mindbox.cloud/path", sdkVersionNumeric = Constants.SDK_VERSION_NUMERIC, ) - sessionStorageManager.inAppTriggerEvent = InAppEventType.OrdinalEvent( + sessionStorageManager.state.inAppTriggerEvent = InAppEventType.OrdinalEvent( eventType = EventType.AsyncOperation("OpenScreen"), body = "{\"screen\":\"home\"}", ) @@ -90,7 +90,7 @@ class DataCollectorTest { inAppInsets = InAppInsets(left = 1, top = 2, right = 3, bottom = 4), gson = gson, inAppId = "inapp-id", - operation = sessionStorageManager.inAppTriggerEvent as? InAppEventType.OrdinalEvent, + operation = sessionStorageManager.state.inAppTriggerEvent as? InAppEventType.OrdinalEvent, ) val actualPayload: String = dataCollector.get() val actualJson: JsonObject = JsonParser.parseString(actualPayload).asJsonObject @@ -141,7 +141,7 @@ class DataCollectorTest { every { permissionManager.getMicrophonePermissionStatus() } returns PermissionStatus.GRANTED every { permissionManager.getNotificationPermissionStatus() } returns PermissionStatus.GRANTED every { permissionManager.getPhotoLibraryPermissionStatus() } returns PermissionStatus.GRANTED - sessionStorageManager.inAppTriggerEvent = InAppEventType.AppStartup + sessionStorageManager.state.inAppTriggerEvent = InAppEventType.AppStartup sessionStorageManager.lastTrackVisitData = TrackVisitData( ianaTimeZone = "Europe/Moscow", endpointId = "endpoint-id", @@ -196,7 +196,7 @@ class DataCollectorTest { every { permissionManager.getNotificationPermissionStatus() } returns PermissionStatus.DENIED every { permissionManager.getPhotoLibraryPermissionStatus() } returns PermissionStatus.DENIED sessionStorageManager.lastTrackVisitData = null - sessionStorageManager.inAppTriggerEvent = InAppEventType.AppStartup + sessionStorageManager.state.inAppTriggerEvent = InAppEventType.AppStartup val inAppInsets = InAppInsets(left = 5, top = 10, right = 15, bottom = 20) val dataCollector = DataCollector( appContext = appContext, diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerTest.kt index 4fbcfde9a..7c28a0470 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/managers/MobileConfigSettingsManagerTest.kt @@ -51,7 +51,7 @@ class MobileConfigSettingsManagerImplTest { mobileConfigSettingsManager.saveSessionTime(config) - assertEquals(100L, sessionStorageManager.sessionTime.inWholeMilliseconds) + assertEquals(100L, sessionStorageManager.state.sessionTime.inWholeMilliseconds) } @Test @@ -60,8 +60,7 @@ class MobileConfigSettingsManagerImplTest { mobileConfigSettingsManager.saveSessionTime(config) - verify(exactly = 0) { sessionStorageManager.sessionTime = any() } - assertEquals(0L, sessionStorageManager.sessionTime.inWholeMilliseconds) + assertEquals(0L, sessionStorageManager.state.sessionTime.inWholeMilliseconds) } @Test @@ -70,8 +69,7 @@ class MobileConfigSettingsManagerImplTest { mobileConfigSettingsManager.saveSessionTime(config) - verify(exactly = 0) { sessionStorageManager.sessionTime = any() } - assertEquals(0L, sessionStorageManager.sessionTime.inWholeMilliseconds) + assertEquals(0L, sessionStorageManager.state.sessionTime.inWholeMilliseconds) } @Test diff --git a/sdk/src/test/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequestTest.kt b/sdk/src/test/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequestTest.kt index f151b63e2..38952d3e1 100644 --- a/sdk/src/test/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequestTest.kt +++ b/sdk/src/test/java/cloud/mindbox/mobile_sdk/network/WebViewContentRequestTest.kt @@ -30,13 +30,19 @@ class WebViewContentRequestTest { } @Test - fun `a successful answer is logged at debug with status, time, size and cache headers`() { + fun `a successful answer is logged at debug with status, time, size and the CDN cache headers`() { val response = NetworkResponse( 200, "".toByteArray(), false, 143L, - listOf(Header("Age", "0"), Header("X-Cache", "HIT"), Header("ETag", "abc")), + listOf( + Header("Age", "0"), + Header("Cache-Status", "HIT"), + Header("Cache-Host", "cdn-msk-2"), + Header("ETag", "\"abc\""), + Header("Content-Type", "text/html"), + ), ) val parsed = request.parseNetworkResponse(response) @@ -44,7 +50,7 @@ class WebViewContentRequestTest { assertTrue(parsed.isSuccess) assertEquals("", parsed.result) verify(exactly = 1) { - MindboxLoggerImpl.d(any(), "<--- 200 $url in 143 ms, 6 bytes [Age: 0, X-Cache: HIT]") + MindboxLoggerImpl.d(any(), "<--- 200 $url in 143 ms, 6 bytes [Cache-Status: HIT, Cache-Host: cdn-msk-2, ETag: \"abc\"]") } }