Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DIA-2654] Flush data if authId or propertyId changes #711

Merged
merged 41 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
dbae3bf
flush local data when needed for DIA-2654-flush data
bohdan-go-wombat Oct 9, 2023
ebdb3de
added test and logs for DIA-2654-flush-data
bohdan-go-wombat Oct 23, 2023
fe8c8a5
stored consent version change for DIA-2654-flush-data
bohdan-go-wombat Oct 23, 2023
c66e31e
added check of auth and property ids for DIA-2654-flush-data
bohdan-go-wombat Oct 24, 2023
ad5f0c7
reshuffle for DIA-265
bohdan-go-wombat Oct 24, 2023
6ec1595
test reshuffle for DIA-2654-flush-data
bohdan-go-wombat Oct 24, 2023
1fa0476
test check added for DIA-2654-flush-data
bohdan-go-wombat Oct 24, 2023
106c6d3
remove no property id config for DIA-2654-flush-data
bohdan-go-wombat Oct 24, 2023
c059f12
add needed and remove redundant config for DIA-2654-flush-data
bohdan-go-wombat Oct 24, 2023
45fb893
date created check for DIA-2654-flush-data
bohdan-go-wombat Oct 25, 2023
0779675
test deserializing triage for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
cba3669
deserialization shuffle for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
91fc2f1
more deserialize reshuffle for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
0d6fc2e
make test dependent on consent UUIDs for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
fb76941
polishing for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
1c259d2
comment property id test for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
c83986b
remove reconsent for tests for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
6ae3a78
change authId config for DIA-2654-flush-data
bohdan-go-wombat Oct 26, 2023
ddbf097
logs added for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
681e84f
cleanup after rebase for DIA-2654
bohdan-go-wombat Oct 27, 2023
a2f6861
addressing ktlint for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
1739fab
change config for main activity for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
4ccc230
remove redundant imports for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
851b316
test for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
5940d3f
test fix for DIA-2654-flush-data
bohdan-go-wombat Oct 27, 2023
81a61af
test for property id added for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
f69a25b
remove accept all for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
0be27ff
changed spclient for property id test for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
01da3f0
polishing for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
229e8d1
use bohdan test property for property id test for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
fd7cffe
test reshuffle for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
04535d4
remove authId from stored consent for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
569d20e
refining stored data for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
b817222
property id added to a stored consent for DIA-2654-flush-data
bohdan-go-wombat Oct 30, 2023
e7cee28
add property id as a backup for each stored consent for DIA-2654-flus…
bohdan-go-wombat Oct 30, 2023
0e58cf6
remove unused sp config for DIA-2654-flush-data
bohdan-go-wombat Oct 31, 2023
610bc09
revert consent migration test data change for DIA-2654-flush-data
bohdan-go-wombat Oct 31, 2023
6378189
fix the check to flush data for DIA-2654-flush-data
bohdan-go-wombat Oct 31, 2023
728153b
addressing ktlint for DIA-2654-flush-data
bohdan-go-wombat Oct 31, 2023
6499332
addressing comments for DIA-2654-flush-data
bohdan-go-wombat Oct 31, 2023
aedbb39
addressing comments by adding a logger back for DIA-2654-flush-data
bohdan-go-wombat Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ internal interface CampaignManager {
var choiceResp: ChoiceResp?
var dataRecordedConsent: Instant?
var authId: String?
var propertyId: Int

fun handleAuthIdOrPropertyIdChange(newAuthId: String?, newPropertyId: Int)
fun handleMetaDataResponse(response: MetaDataResp?)
fun handleOldLocalData()
fun getGdprPvDataBody(messageReq: MessagesParamReq): JsonObject
Expand Down Expand Up @@ -364,6 +366,12 @@ private class CampaignManagerImpl(
dataStorage.saveAuthId(value)
}

override var propertyId: Int
get() = dataStorage.propertyId
set(value) {
dataStorage.propertyId = value
}

// Optimized Implementation below

val isNewUser: Boolean
Expand Down Expand Up @@ -413,22 +421,23 @@ private class CampaignManagerImpl(
val hasNonEligibleLocalDataVersion =
dataStorage.localDataVersion != DataStorage.LOCAL_DATA_VERSION_HARDCODED_VALUE

val res = (isGdprOrCcpaUuidPresent && isLocalStateEmpty) ||
isV6LocalStatePresent ||
isV6LocalStatePresent2 ||
hasNonEligibleLocalDataVersion
val isEligibleForCallingConsentStatus =
(isGdprOrCcpaUuidPresent && isLocalStateEmpty) ||
isV6LocalStatePresent ||
isV6LocalStatePresent2 ||
hasNonEligibleLocalDataVersion

logger?.computation(
tag = "shouldCallConsentStatus",
msg = """
isGdprOrCcpaUuidPresent[$isGdprOrCcpaUuidPresent] - isLocalStateEmpty[$isLocalStateEmpty]
isV6LocalStatePresent[$isV6LocalStatePresent] - isV6LocalStatePresent2[$isV6LocalStatePresent2]
hasNonEligibleLocalDataVersion[$hasNonEligibleLocalDataVersion]
res[$res]
isEligibleForCallingConsentStatus[$isEligibleForCallingConsentStatus]
""".trimIndent()
)

return res
return isEligibleForCallingConsentStatus
}

override var gdprMessageMetaData: MessageMetaData?
Expand Down Expand Up @@ -523,6 +532,27 @@ private class CampaignManagerImpl(
override val hasLocalData: Boolean
get() = dataStorage.gdprConsentStatus != null || dataStorage.ccpaConsentStatus != null

/**
* The method that checks if the authId or propertyId was changed, if so it will flush all the
* data. At the end, it will update the authId and propertyId with the corresponding values.
*/
override fun handleAuthIdOrPropertyIdChange(
newAuthId: String?,
newPropertyId: Int,
) {
// flush local data if proper authId or propertyId change was detected
val isNewAuthId = newAuthId != null && newAuthId != authId
val isNewPropertyId = newPropertyId != propertyId
val hasPreviousPropertyId = propertyId != 0
if (isNewAuthId || isNewPropertyId && hasPreviousPropertyId) {
dataStorage.clearAll()
}

// update stored values of authId and propertyId
authId = newAuthId
propertyId = newPropertyId
}

override fun handleMetaDataResponse(response: MetaDataResp?) {
// update meta data response in the data storage
metaDataResp = response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,19 @@ private class ServiceImpl(
onFailure: (Throwable, Boolean) -> Unit,
) {
execManager.executeOnWorkerThread {
campaignManager.authId = messageReq.authId

if (connectionManager.isConnected.not()) {
val noInternetConnectionException = NoInternetConnectionException()
onFailure(noInternetConnectionException, true)
return@executeOnWorkerThread
}

// check whether the authId or propertyId changed, and handle the flow accordingly
campaignManager.handleAuthIdOrPropertyIdChange(
newAuthId = messageReq.authId,
newPropertyId = spConfig.propertyId,
)

val metadataResponse = this.getMetaData(messageReq.toMetaDataParamReq(campaigns4Config))
.executeOnLeft { metaDataError ->
onFailure(metaDataError, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal interface DataStorage : DataStorageGdpr, DataStorageCcpa {
const val CHOICE_RESP = "sp.key.choice"
const val DATA_RECORDED_CONSENT = "sp.key.data.recorded.consent"

const val KEY_PROPERTY_ID = "sp.key.config.propertyId"

const val CONSENT_STATUS_RESPONSE = "sp.key.consent.status.response"
const val GDPR_CONSENT_STATUS = "sp.gdpr.key.consent.status"
const val CCPA_CONSENT_STATUS = "sp.ccpa.key.consent.status"
Expand All @@ -41,6 +43,7 @@ internal interface DataStorage : DataStorageGdpr, DataStorageCcpa {
var ccpaConsentStatus: String?
var messagesOptimizedLocalState: String?
var nonKeyedLocalState: String?
var propertyId: Int

fun saveLocalState(value: String)
fun getLocalState(): String?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.CONSENT_STATU
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.CONSENT_STATUS_RESPONSE
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.DATA_RECORDED_CONSENT
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.GDPR_CONSENT_STATUS
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.KEY_PROPERTY_ID
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_DATA_VERSION_HARDCODED_VALUE
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_DATA_VERSION_KEY
import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_STATE
Expand Down Expand Up @@ -138,6 +139,12 @@ private class DataStorageImpl(
.putString(NON_KEYED_LOCAL_STATE, value)
.apply()
}
override var propertyId: Int
get() = preference.getInt(KEY_PROPERTY_ID, 0)
set(value) = preference
.edit()
.putInt(KEY_PROPERTY_ID, value)
.apply()

override var consentStatus: String?
get() = preference.getString(CONSENT_STATUS, null)
Expand Down Expand Up @@ -210,6 +217,7 @@ private class DataStorageImpl(
.remove(CCPA_CONSENT_STATUS)
.remove(MESSAGES_OPTIMIZED_LOCAL_STATE)
.remove(NON_KEYED_LOCAL_STATE)
.remove(KEY_PROPERTY_ID)
.apply()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class MainActivityKotlinOldConsentTest {
@Test
fun GIVEN_an_old_CCPA_GDPR_v6LocalState_VERIFY_that_the_migration_is_performed() = runBlocking<Unit> {

val v6LocalState = JSONObject(TestData.storedConsentGdprCcap)
val v6LocalState = JSONObject(TestData.storedConsentGdprCcpa)

val spClient = mockk<SpClient>(relaxed = true)

Expand Down Expand Up @@ -222,7 +222,7 @@ class MainActivityKotlinOldConsentTest {
@Test
fun GIVEN_an_old_CCPAv6LocalState_VERIFY_that_the_migration_is_performed() = runBlocking<Unit> {

val v6LocalState = JSONObject(TestData.storedConsentCcap)
val v6LocalState = JSONObject(TestData.storedConsentCcpa)

val spClient = mockk<SpClient>(relaxed = true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ import com.sourcepoint.app.v6.TestUseCase.Companion.clickOnRefreshBtnActivity
import com.sourcepoint.app.v6.TestUseCase.Companion.mockModule
import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptAllOnWebView
import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptCcpaOnWebView
import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnOk
import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnWebView
import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnWebViewDE
import com.sourcepoint.app.v6.TestUseCase.Companion.tapCancelOnWebView
import com.sourcepoint.app.v6.TestUseCase.Companion.tapFeaturesOnWebView
import com.sourcepoint.app.v6.TestUseCase.Companion.tapNetworkOnWebView
Expand Down Expand Up @@ -59,6 +57,7 @@ import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.koin.core.context.loadKoinModules
import java.util.UUID

@RunWith(AndroidJUnit4ClassRunner::class)
class MainActivityKotlinTest {
Expand Down Expand Up @@ -1076,6 +1075,86 @@ class MainActivityKotlinTest {
}
}

/**
* UI test that verifies that there was a clean up of local data after the user changed their
* auth ID. Due to the fact that the clean up happens, the message flow appears again, the user
* make their choice and the consent UUIDs of both campaigns changes.
*/
@Test
fun given_the_user_has_consent_and_the_auth_id_changes_then_should_flush_data() = runBlocking<Unit> {

val storedConsent = JSONObject(TestData.storedConsentWithAuthIdAndPropertyIdV741)
val spClient = mockk<SpClient>(relaxed = true)
val newAuthId = UUID.randomUUID().toString()

loadKoinModules(
mockModule(
spConfig = spConf,
gdprPmId = "488393",
ccpaPmId = "509688",
spClientObserver = listOf(spClient),
diagnostic = storedConsent.toList(),
pAuthId = newAuthId
)
)

scenario = launchActivity()

wr { tapAcceptAllOnWebView() }
wr { tapAcceptAllOnWebView() }

wr { verify(exactly = 0) { spClient.onError(any()) } }
wr { verify(exactly = 2) { spClient.onUIReady(any()) } }
wr { verify(exactly = 1) { spClient.onSpFinished(any()) } }

scenario.onActivity { activity ->
PreferenceManager.getDefaultSharedPreferences(activity).run {
getString("sp.gdpr.authId", null).assertEquals(newAuthId)
}
}
}

/**
* UI test that verifies that there was a clean up of local data after the user changed their
* property ID. Due to the fact that the clean up happens, the message flow appears again, the user
* make their choice and the consent UUIDs of both campaigns changes.
*/
@Test
fun given_the_user_has_consent_and_the_property_id_changes_then_should_flush_data() = runBlocking<Unit> {

val storedConsent = JSONObject(TestData.storedConsentWithAuthIdAndPropertyIdV741)
val spClient = mockk<SpClient>(relaxed = true)
val storedPropertyId = 31226
val newPropertyId = 16893

loadKoinModules(
mockModule(
spConfig = spConf,
gdprPmId = "488393",
ccpaPmId = "509688",
spClientObserver = listOf(spClient),
diagnostic = storedConsent.toList() + listOf(
Pair("sp.key.config.propertyId", storedPropertyId)
),
)
)

scenario = launchActivity()

wr { tapAcceptAllOnWebView() }
wr { tapAcceptAllOnWebView() }

wr { verify(exactly = 0) { spClient.onError(any()) } }
wr { verify(exactly = 2) { spClient.onUIReady(any()) } }
wr { verify(exactly = 1) { spClient.onSpFinished(any()) } }

scenario.onActivity { activity ->
PreferenceManager.getDefaultSharedPreferences(activity).run {
getInt("sp.key.config.propertyId", 0).assertEquals(newPropertyId)
}
}
}

private fun <E> check(block: () -> E): E? {
return try {
block.invoke()
Expand Down
Loading
Loading