diff --git a/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java b/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java index 85154d0d9..164405fd4 100644 --- a/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java +++ b/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java @@ -163,7 +163,7 @@ private void referencedRbsTest(String notification) throws IOException, Interrup List names = entities.stream().map(RuleBasedSegmentEntity::getName).collect(Collectors.toList()); assertEquals(2, names.size()); assertTrue(names.contains("rbs_test") && names.contains("new_rbs_test")); - assertEquals(3, mSplitChangesHits.get()); + assertEquals(2, mSplitChangesHits.get()); } private void successfulInstantUpdateTest(String rbsChange0, String expectedContents) throws IOException, InterruptedException { diff --git a/src/main/java/io/split/android/client/storage/cipher/ApplyCipherTask.java b/src/main/java/io/split/android/client/storage/cipher/ApplyCipherTask.java index 0325cc861..8cb17df13 100644 --- a/src/main/java/io/split/android/client/storage/cipher/ApplyCipherTask.java +++ b/src/main/java/io/split/android/client/storage/cipher/ApplyCipherTask.java @@ -54,7 +54,7 @@ public SplitTaskExecutionInfo execute() { @Override public void run() { updateAttributes(mSplitDatabase.attributesDao()); - updateSplits(mSplitDatabase.splitDao(), mSplitDatabase.generalInfoDao()); + updateSplits(mSplitDatabase, mSplitDatabase.generalInfoDao()); updateSegments(mSplitDatabase.mySegmentDao()); updateLargeSegments(mSplitDatabase.myLargeSegmentDao()); updateImpressions(mSplitDatabase.impressionDao()); @@ -88,6 +88,8 @@ private void updateRuleBasedSegment(RuleBasedSegmentDao ruleBasedSegmentDao) { if (toName != null && toBody != null) { ruleBasedSegmentDao.update(name, toName, toBody); + } else{ + Logger.e("Error applying cipher to rule based segment storage"); } } } @@ -120,7 +122,7 @@ private void updateUniqueKeys(UniqueKeysDao uniqueKeysDao) { String toUserKey = mToCipher.encrypt(fromUserKey); String toFeatureList = mToCipher.encrypt(fromFeatureList); - if (toFeatureList != null) { + if (toUserKey != null && toFeatureList != null) { item.setUserKey(toUserKey); item.setFeatureList(toFeatureList); uniqueKeysDao.insert(item); @@ -213,9 +215,10 @@ private void updateEvents(EventDao eventDao) { } } - private void updateSplits(SplitDao dao, GeneralInfoDao generalInfoDao) { + private void updateSplits(SplitRoomDatabase splitDatabase, GeneralInfoDao generalInfoDao) { + SplitDao dao = splitDatabase.splitDao(); List items = dao.getAll(); - + splitDatabase.getSplitQueryDao().invalidate(); for (SplitEntity item : items) { String name = item.getName(); String fromName = mFromCipher.decrypt(name); diff --git a/src/main/java/io/split/android/client/storage/cipher/CBCCipher.java b/src/main/java/io/split/android/client/storage/cipher/CBCCipher.java index ca4f1d7b5..d296a1045 100644 --- a/src/main/java/io/split/android/client/storage/cipher/CBCCipher.java +++ b/src/main/java/io/split/android/client/storage/cipher/CBCCipher.java @@ -60,7 +60,7 @@ public String decrypt(String data) { return new String(bytes, CHARSET); } catch (Exception e) { - Logger.e("Error decrypting data: " + e.getMessage()); + Logger.e("Error decrypting data for source: " + data + " - " + e.getMessage()); return null; } finally { mCipherProvider.release(cipher); diff --git a/src/main/java/io/split/android/client/storage/db/SplitQueryDao.java b/src/main/java/io/split/android/client/storage/db/SplitQueryDao.java index 784e6f863..82ddcc086 100644 --- a/src/main/java/io/split/android/client/storage/db/SplitQueryDao.java +++ b/src/main/java/io/split/android/client/storage/db/SplitQueryDao.java @@ -4,4 +4,6 @@ public interface SplitQueryDao { Map getAllAsMap(); + + void invalidate(); } \ No newline at end of file diff --git a/src/main/java/io/split/android/client/storage/db/SplitQueryDaoImpl.java b/src/main/java/io/split/android/client/storage/db/SplitQueryDaoImpl.java index 42458f16e..2c126feb2 100644 --- a/src/main/java/io/split/android/client/storage/db/SplitQueryDaoImpl.java +++ b/src/main/java/io/split/android/client/storage/db/SplitQueryDaoImpl.java @@ -15,8 +15,9 @@ public class SplitQueryDaoImpl implements SplitQueryDao { private final SplitRoomDatabase mDatabase; private volatile Map mCachedSplitsMap; private final Object mLock = new Object(); - private boolean mIsInitialized = false; private final Thread mInitializationThread; + private boolean mIsInitialized = false; + private boolean mIsInvalidated = false; public SplitQueryDaoImpl(SplitRoomDatabase mDatabase) { this.mDatabase = mDatabase; @@ -27,7 +28,6 @@ public SplitQueryDaoImpl(SplitRoomDatabase mDatabase) { } catch (Exception ignore) { // Ignore } - long startTime = System.currentTimeMillis(); Map result = loadSplitsMap(); @@ -51,13 +51,13 @@ int getColumnIndexOrThrow(@NonNull Cursor c, @NonNull String name) { public Map getAllAsMap() { // Fast path - if the map is already initialized, return it immediately - if (mIsInitialized && !mCachedSplitsMap.isEmpty()) { + if (isValid() && !mCachedSplitsMap.isEmpty()) { return new HashMap<>(mCachedSplitsMap); } // Wait for initialization to complete if it's in progress synchronized (mLock) { - if (mIsInitialized && !mCachedSplitsMap.isEmpty()) { + if (isValid() && !mCachedSplitsMap.isEmpty()) { return new HashMap<>(mCachedSplitsMap); } @@ -66,7 +66,7 @@ public Map getAllAsMap() { try { mLock.wait(5000); // Wait up to 5 seconds - if (mIsInitialized) { + if (isValid()) { return new HashMap<>(mCachedSplitsMap); } } catch (InterruptedException e) { @@ -85,6 +85,20 @@ public Map getAllAsMap() { return new HashMap<>(result); } } + + private boolean isValid() { + return mIsInitialized && !mIsInvalidated; + } + + @Override + public void invalidate() { + synchronized (mLock) { + mCachedSplitsMap.clear(); + mIsInvalidated = true; + mLock.notifyAll(); + Logger.i("Invalidated preloaded flags"); + } + } /** * Internal method to load the splits map from the database. diff --git a/src/main/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorage.java b/src/main/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorage.java index 8de3f2325..9f328e455 100644 --- a/src/main/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorage.java +++ b/src/main/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorage.java @@ -85,12 +85,14 @@ public void run() { mDatabase.splitDao().delete(removedSplits); } if (!mTrafficTypes.isEmpty()) { + String encryptedTrafficTypes = mCipher.encrypt(Json.toJson(mTrafficTypes)); mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.TRAFFIC_TYPES_MAP, - Json.toJson(mTrafficTypes))); + encryptedTrafficTypes)); } if (!mFlagSets.isEmpty()) { + String encryptedFlagSets = mCipher.encrypt(Json.toJson(mFlagSets)); mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.FLAG_SETS_MAP, - Json.toJson(mFlagSets))); + encryptedFlagSets)); } mDatabase.generalInfoDao().update( new GeneralInfoEntity(GeneralInfoEntity.SPLITS_UPDATE_TIMESTAMP, splitChange.getUpdateTimestamp())); @@ -178,10 +180,8 @@ public String getFilterQueryString() { private List loadSplits() { Map allNamesAndBodies = mDatabase.getSplitQueryDao().getAllAsMap(); - long transformStartTime = System.currentTimeMillis(); - List splits = mEntityToSplitTransformer.transform(allNamesAndBodies); - return splits; + return mEntityToSplitTransformer.transform(allNamesAndBodies); } private List convertSplitListToEntities(List splits) { @@ -278,12 +278,14 @@ private void migrateTrafficTypesAndSetsFromStoredData() { try { for (Split split : mSplits) { Split parsedSplit = Json.fromJson(split.json, Split.class); - if (parsedSplit != null && parsedSplit.status == Status.ACTIVE) { - increaseTrafficTypeCount(parsedSplit.trafficTypeName, mTrafficTypes); - addOrUpdateFlagSets(parsedSplit, mFlagSets); - } else { - decreaseTrafficTypeCount(parsedSplit.trafficTypeName, mTrafficTypes); - deleteFromFlagSetsIfNecessary(parsedSplit, mFlagSets); + if (parsedSplit != null) { + if (parsedSplit.status == Status.ACTIVE) { + increaseTrafficTypeCount(parsedSplit.trafficTypeName, mTrafficTypes); + addOrUpdateFlagSets(parsedSplit, mFlagSets); + } else { + decreaseTrafficTypeCount(parsedSplit.trafficTypeName, mTrafficTypes); + deleteFromFlagSetsIfNecessary(parsedSplit, mFlagSets); + } } } diff --git a/src/test/java/io/split/android/client/service/rules/TargetingRulesResponseParserTest.java b/src/test/java/io/split/android/client/service/rules/TargetingRulesResponseParserTest.java index 117e6f7e2..2ce2ded65 100644 --- a/src/test/java/io/split/android/client/service/rules/TargetingRulesResponseParserTest.java +++ b/src/test/java/io/split/android/client/service/rules/TargetingRulesResponseParserTest.java @@ -12,7 +12,6 @@ import io.split.android.client.dtos.Excluded; import io.split.android.client.dtos.ExcludedSegment; - import io.split.android.client.dtos.TargetingRulesChange; import io.split.android.client.service.http.HttpResponseParserException; import io.split.android.helpers.FileHelper; @@ -40,7 +39,6 @@ public void parsesNewTargetingRulesChangeJson() throws Exception { assertEquals(1506703262920L, result.getRuleBasedSegmentsChange().getSince()); assertEquals(1506703263000L, result.getRuleBasedSegmentsChange().getTill()); assertEquals("mauro_rule_based_segment", result.getRuleBasedSegmentsChange().getSegments().get(0).getName()); - Excluded excluded = result.getRuleBasedSegmentsChange().getSegments().get(0).getExcluded(); assertEquals(1, excluded.getKeys().size()); Set excludedSegments = excluded.getSegments(); diff --git a/src/test/java/io/split/android/client/storage/cipher/ApplyCipherTaskTest.kt b/src/test/java/io/split/android/client/storage/cipher/ApplyCipherTaskTest.kt index e68b61c4d..0c5b4ae45 100644 --- a/src/test/java/io/split/android/client/storage/cipher/ApplyCipherTaskTest.kt +++ b/src/test/java/io/split/android/client/storage/cipher/ApplyCipherTaskTest.kt @@ -16,6 +16,7 @@ import io.split.android.client.storage.db.MySegmentDao import io.split.android.client.storage.db.MySegmentEntity import io.split.android.client.storage.db.SplitDao import io.split.android.client.storage.db.SplitEntity +import io.split.android.client.storage.db.SplitQueryDao import io.split.android.client.storage.db.SplitRoomDatabase import io.split.android.client.storage.db.attributes.AttributesDao import io.split.android.client.storage.db.attributes.AttributesEntity @@ -50,6 +51,9 @@ class ApplyCipherTaskTest { @Mock private lateinit var splitDao: SplitDao + @Mock + private lateinit var splitQueryDao: SplitQueryDao + @Mock private lateinit var mySegmentDao: MySegmentDao @@ -83,6 +87,7 @@ class ApplyCipherTaskTest { fun setup() { MockitoAnnotations.openMocks(this) `when`(splitDatabase.splitDao()).thenReturn(splitDao) + `when`(splitDatabase.splitQueryDao).thenReturn(splitQueryDao) `when`(splitDatabase.mySegmentDao()).thenReturn(mySegmentDao) `when`(splitDatabase.myLargeSegmentDao()).thenReturn(myLargeSegmentDao) `when`(splitDatabase.impressionDao()).thenReturn(impressionDao) @@ -131,6 +136,8 @@ class ApplyCipherTaskTest { verify(toCipher).encrypt("decrypted_name2") verify(toCipher).encrypt("decrypted_body2") verify(splitDao).update("name2", "encrypted_decrypted_name2", "encrypted_decrypted_body2") + + verify(splitQueryDao).invalidate() } @Test