diff --git a/src/androidTest/assets/split_changes_legacy.json b/src/androidTest/assets/split_changes_legacy.json new file mode 100644 index 000000000..f52d7fa54 --- /dev/null +++ b/src/androidTest/assets/split_changes_legacy.json @@ -0,0 +1,121 @@ +{ + "splits": [ + { + "trafficTypeName": "account", + "name": "FACUNDO_TEST", + "trafficAllocation": 59, + "trafficAllocationSeed": -2108186082, + "seed": -1947050785, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "off", + "changeNumber": 1506703262916, + "algo": 2, + "conditions": [ + { + "conditionType": "WHITELIST", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": null, + "matcherType": "WHITELIST", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": { + "whitelist": [ + "nico_test", + "othertest" + ] + }, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + } + ], + "label": "whitelisted" + }, + { + "conditionType": "WHITELIST", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": null, + "matcherType": "WHITELIST", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": { + "whitelist": [ + "bla" + ] + }, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "off", + "size": 100 + } + ], + "label": "whitelisted" + }, + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "account", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 100 + }, + { + "treatment": "visa", + "size": 0 + } + ], + "label": "in segment all" + } + ] + } + ], + "since": -1, + "till": 1506703262916 +} \ No newline at end of file diff --git a/src/androidTest/java/helper/IntegrationHelper.java b/src/androidTest/java/helper/IntegrationHelper.java index 1e53c36ef..df13116fb 100644 --- a/src/androidTest/java/helper/IntegrationHelper.java +++ b/src/androidTest/java/helper/IntegrationHelper.java @@ -344,14 +344,22 @@ public static String rbsChange(String changeNumber, String previousChangeNumber, } public static String loadSplitChanges(Context context, String fileName) { - FileHelper fileHelper = new FileHelper(); - String change = fileHelper.loadFileContent(context, fileName); + String change = getFileContentsAsString(context, fileName); TargetingRulesChange targetingRulesChange = Json.fromJson(change, TargetingRulesChange.class); SplitChange parsedChange = targetingRulesChange.getFeatureFlagsChange(); parsedChange.since = parsedChange.till; return Json.toJson(TargetingRulesChange.create(parsedChange, targetingRulesChange.getRuleBasedSegmentsChange())); } + public static String loadLegacySplitChanges(Context context, String fileName) { + return getFileContentsAsString(context, fileName); + } + + private static String getFileContentsAsString(Context context, String fileName) { + FileHelper fileHelper = new FileHelper(); + return fileHelper.loadFileContent(context, fileName); + } + /** * Builds a dispatcher with the given responses. * @@ -442,6 +450,14 @@ public static String getRbSinceFromUri(URI uri) { } } + public static String getSpecFromUri(URI uri) { + try { + return parse(uri.getQuery()).get("s"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + static Map parse(String query) throws UnsupportedEncodingException { Map queryPairs = new HashMap<>(); String[] pairs = query.split("&"); diff --git a/src/androidTest/java/tests/integration/largesegments/LargeSegmentTestHelper.java b/src/androidTest/java/tests/integration/largesegments/LargeSegmentTestHelper.java index 3e30292f5..c19195a2b 100644 --- a/src/androidTest/java/tests/integration/largesegments/LargeSegmentTestHelper.java +++ b/src/androidTest/java/tests/integration/largesegments/LargeSegmentTestHelper.java @@ -65,8 +65,8 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio return new MockResponse().setResponseCode(500); } - if (request.getRequestUrl().encodedPathSegments().contains("splitChanges")) { - updateEndpointHit("splitChanges"); + if (request.getRequestUrl().encodedPathSegments().contains(IntegrationHelper.ServicePath.SPLIT_CHANGES)) { + updateEndpointHit(IntegrationHelper.ServicePath.SPLIT_CHANGES); return new MockResponse().setResponseCode(200).setBody(splitChangesLargeSegments(1602796638344L, 1602796638344L)); } else if (request.getRequestUrl().encodedPathSegments().contains(IntegrationHelper.ServicePath.MEMBERSHIPS)) { Thread.sleep(mMySegmentsDelay.get()); @@ -93,7 +93,7 @@ public void tearDown() throws IOException { private void initializeLatches() { mLatches = new ConcurrentHashMap<>(); - mLatches.put("splitChanges", new CountDownLatch(1)); + mLatches.put(IntegrationHelper.ServicePath.SPLIT_CHANGES, new CountDownLatch(1)); mLatches.put(IntegrationHelper.ServicePath.MEMBERSHIPS, new CountDownLatch(1)); } diff --git a/src/androidTest/java/tests/integration/rbs/OutdatedProxyIntegrationTest.java b/src/androidTest/java/tests/integration/rbs/OutdatedProxyIntegrationTest.java new file mode 100644 index 000000000..09bcab6c7 --- /dev/null +++ b/src/androidTest/java/tests/integration/rbs/OutdatedProxyIntegrationTest.java @@ -0,0 +1,194 @@ +package tests.integration.rbs; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static helper.IntegrationHelper.emptyTargetingRulesChanges; +import static helper.IntegrationHelper.getSinceFromUri; +import static helper.IntegrationHelper.getSpecFromUri; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import helper.DatabaseHelper; +import helper.IntegrationHelper; +import helper.TestableSplitConfigBuilder; +import io.split.android.client.ServiceEndpoints; +import io.split.android.client.SplitClient; +import io.split.android.client.SplitFactory; +import io.split.android.client.TestingConfig; +import io.split.android.client.events.SplitEvent; +import io.split.android.client.storage.db.GeneralInfoEntity; +import io.split.android.client.storage.db.SplitRoomDatabase; +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import tests.integration.shared.TestingHelper; + +public class OutdatedProxyIntegrationTest { + + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + + private MockWebServer mWebServer; + private Map mEndpointHits; + private Map mLatches; + private final AtomicBoolean mOutdatedProxy = new AtomicBoolean(false); + private final AtomicBoolean mSimulatedProxyError = new AtomicBoolean(false); + private final AtomicBoolean mRecoveryHit = new AtomicBoolean(false); + + @Before + public void setUp() throws IOException { + mEndpointHits = new ConcurrentHashMap<>(); + mOutdatedProxy.set(false); + initializeLatches(); + + mWebServer = new MockWebServer(); + mWebServer.setDispatcher(new Dispatcher() { + @NonNull + @Override + public MockResponse dispatch(@NonNull RecordedRequest request) { + if (request.getRequestUrl().encodedPathSegments().contains(IntegrationHelper.ServicePath.SPLIT_CHANGES)) { + updateEndpointHit(IntegrationHelper.ServicePath.SPLIT_CHANGES); + float specFromUri = Float.parseFloat(getSpecFromUri(request.getRequestUrl().uri())); + if (mOutdatedProxy.get() && specFromUri > 1.2f) { + mSimulatedProxyError.set(true); + return new MockResponse().setResponseCode(400); + } else if (mOutdatedProxy.get()) { + String body = (getSinceFromUri(request.getRequestUrl().uri()).equals("-1")) ? + IntegrationHelper.loadLegacySplitChanges(mContext, "split_changes_legacy.json") : + emptyTargetingRulesChanges(1506703262916L, -1L); + return new MockResponse().setResponseCode(200) + .setBody(body); + } + + if (!mOutdatedProxy.get()) { + if (request.getRequestUrl().uri().toString().contains("?s=1.3&since=-1&rbSince=-1")) { + mRecoveryHit.set(true); + } + } + + return new MockResponse().setResponseCode(200).setBody(IntegrationHelper.loadSplitChanges(mContext, "split_changes_rbs.json")); + } else if (request.getRequestUrl().encodedPathSegments().contains(IntegrationHelper.ServicePath.MEMBERSHIPS)) { + updateEndpointHit(IntegrationHelper.ServicePath.MEMBERSHIPS); + + return new MockResponse().setResponseCode(200).setBody(IntegrationHelper.emptyAllSegments()); + } else { + return new MockResponse().setResponseCode(404); + } + } + }); + mWebServer.start(); + } + + @After + public void tearDown() throws IOException { + mWebServer.shutdown(); + } + + @Test + public void clientIsReadyEvenWhenUsingOutdatedProxy() { + mOutdatedProxy.set(true); + SplitClient readyClient = getReadyClient(IntegrationHelper.dummyUserKey().matchingKey(), getFactory()); + + assertNotNull(readyClient); + assertFalse(mRecoveryHit.get()); + assertTrue(mSimulatedProxyError.get()); + } + + @Test + public void clientIsReadyWithLatestProxy() { + mOutdatedProxy.set(false); + SplitClient readyClient = getReadyClient(IntegrationHelper.dummyUserKey().matchingKey(), getFactory()); + + assertNotNull(readyClient); + assertFalse(mRecoveryHit.get() && mOutdatedProxy.get()); + assertFalse(mSimulatedProxyError.get()); + } + + @Test + public void clientRecoversFromOutdatedProxy() { + mOutdatedProxy.set(false); + SplitRoomDatabase database = DatabaseHelper.getTestDatabase(mContext); + database.generalInfoDao().update(new GeneralInfoEntity("lastProxyCheckTimestamp", System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(62))); + SplitClient readyClient = getReadyClient(IntegrationHelper.dummyUserKey().matchingKey(), getFactory(database)); + + assertNotNull(readyClient); + assertTrue(mRecoveryHit.get() && !mOutdatedProxy.get()); + assertFalse(mSimulatedProxyError.get()); + } + + private void initializeLatches() { + mLatches = new ConcurrentHashMap<>(); + mLatches.put(IntegrationHelper.ServicePath.SPLIT_CHANGES, new CountDownLatch(1)); + mLatches.put(IntegrationHelper.ServicePath.MEMBERSHIPS, new CountDownLatch(1)); + } + + private void updateEndpointHit(String splitChanges) { + if (mEndpointHits.containsKey(splitChanges)) { + mEndpointHits.get(splitChanges).getAndIncrement(); + } else { + mEndpointHits.put(splitChanges, new AtomicInteger(1)); + } + + if (mLatches.containsKey(splitChanges)) { + mLatches.get(splitChanges).countDown(); + } + } + + protected SplitFactory getFactory() { + return getFactory(null); + } + + protected SplitFactory getFactory(SplitRoomDatabase database) { + TestableSplitConfigBuilder configBuilder = new TestableSplitConfigBuilder() + .enableDebug() + .serviceEndpoints(ServiceEndpoints.builder() + .apiEndpoint("http://" + mWebServer.getHostName() + ":" + mWebServer.getPort()) + .build()); + + configBuilder.streamingEnabled(false); + configBuilder.ready(10000); + TestingConfig testingConfig = new TestingConfig(); + testingConfig.setFlagsSpec("1.3"); + return IntegrationHelper.buildFactory( + IntegrationHelper.dummyApiKey(), + IntegrationHelper.dummyUserKey(), + configBuilder.build(), + mContext, + null, database, null, testingConfig, null); + } + + protected SplitClient getReadyClient(String matchingKey, SplitFactory factory) { + CountDownLatch countDownLatch = new CountDownLatch(1); + + SplitClient client = factory.client(matchingKey); + boolean await; + client.on(SplitEvent.SDK_READY, TestingHelper.testTask(countDownLatch)); + try { + await = countDownLatch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (!await) { + fail("Client is not ready"); + } + + return client; + } +} diff --git a/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java b/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java index 164405fd4..25e663f86 100644 --- a/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java +++ b/src/androidTest/java/tests/integration/rbs/RuleBasedSegmentsIntegrationTest.java @@ -226,12 +226,11 @@ public void onPostExecutionView(SplitClient client) { private Map getStringResponseClosureMap(CountDownLatch authLatch) { Map responses = new HashMap<>(); responses.put(IntegrationHelper.ServicePath.SPLIT_CHANGES, (uri, httpMethod, body) -> { - int currentHit = mSplitChangesHits.incrementAndGet(); if (mCustomSplitChangesResponse.get() != null) { return new HttpResponseMock(200, mCustomSplitChangesResponse.get()); } - return new HttpResponseMock(200, IntegrationHelper.emptySplitChanges(1, 1)); + return new HttpResponseMock(200, IntegrationHelper.emptyTargetingRulesChanges(1, 1)); }); responses.put(IntegrationHelper.ServicePath.MEMBERSHIPS + "/" + "/CUSTOMER_ID", (uri, httpMethod, body) -> new HttpResponseMock(200, IntegrationHelper.emptyAllSegments())); responses.put("v2/auth", (uri, httpMethod, body) -> { @@ -241,11 +240,6 @@ private Map getStringResponseClosureM return responses; } - @NonNull - private static String missingSegmentFetch(long flagSince, long segmentSince) { - return "{\"ff\":{\"s\":" + flagSince + ",\"t\":" + flagSince + ",\"d\":[]},\"rbs\":{\"s\":" + segmentSince + ",\"t\":" + segmentSince + ",\"d\":[{\"name\":\"new_rbs_test\",\"status\":\"ACTIVE\",\"trafficTypeName\":\"user\",\"excluded\":{\"keys\":[],\"segments\":[]},\"conditions\":[{\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"user\"},\"matcherType\":\"WHITELIST\",\"negate\":false,\"whitelistMatcherData\":{\"whitelist\":[\"mdp\",\"tandil\",\"bsas\"]}},{\"keySelector\":{\"trafficType\":\"user\",\"attribute\":\"email\"},\"matcherType\":\"ENDS_WITH\",\"negate\":false,\"whitelistMatcherData\":{\"whitelist\":[\"@split.io\"]}}]}}]},{\"name\":\"rbs_test\",\"status\":\"ACTIVE\",\"trafficTypeName\":\"user\",\"excluded\":{\"keys\":[],\"segments\":[]},\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"user\"},\"matcherType\":\"IN_RULE_BASED_SEGMENT\",\"negate\":false,\"userDefinedSegmentMatcherData\":{\"segmentName\":\"new_rbs_test\"}}]}}]}]}}"; - } - private boolean processUpdate(SplitClient client, LinkedBlockingDeque streamingData, String change, String... expectedContents) throws InterruptedException { CountDownLatch updateLatch = new CountDownLatch(1); client.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(updateLatch)); diff --git a/src/main/java/io/split/android/client/SplitClientConfig.java b/src/main/java/io/split/android/client/SplitClientConfig.java index d9f55df7c..00af53115 100644 --- a/src/main/java/io/split/android/client/SplitClientConfig.java +++ b/src/main/java/io/split/android/client/SplitClientConfig.java @@ -1118,7 +1118,7 @@ public Builder impressionsDedupeTimeInterval(long impressionsDedupeTimeInterval) * @param rolloutCacheConfiguration Configuration object * @return This builder */ - Builder rolloutCacheConfiguration(@NonNull RolloutCacheConfiguration rolloutCacheConfiguration) { + public Builder rolloutCacheConfiguration(@NonNull RolloutCacheConfiguration rolloutCacheConfiguration) { if (rolloutCacheConfiguration == null) { Logger.w("Rollout cache configuration is null. Setting to default value."); mRolloutCacheConfiguration = RolloutCacheConfiguration.builder().build(); diff --git a/src/main/java/io/split/android/client/service/splits/LoadSplitsTask.java b/src/main/java/io/split/android/client/service/splits/LoadSplitsTask.java index f5546470e..49ca1d512 100644 --- a/src/main/java/io/split/android/client/service/splits/LoadSplitsTask.java +++ b/src/main/java/io/split/android/client/service/splits/LoadSplitsTask.java @@ -1,5 +1,7 @@ package io.split.android.client.service.splits; +import static io.split.android.client.utils.Utils.checkNotNull; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -9,8 +11,6 @@ import io.split.android.client.storage.splits.SplitsStorage; import io.split.android.client.utils.logger.Logger; -import static io.split.android.client.utils.Utils.checkNotNull; - /** * This task is responsible for loading the feature flags, saved filter & saved flags spec values * from the persistent storage into the in-memory storage. diff --git a/src/main/java/io/split/android/client/service/splits/OutdatedSplitProxyHandler.java b/src/main/java/io/split/android/client/service/splits/OutdatedSplitProxyHandler.java index 9e028254c..47b61c4dc 100644 --- a/src/main/java/io/split/android/client/service/splits/OutdatedSplitProxyHandler.java +++ b/src/main/java/io/split/android/client/service/splits/OutdatedSplitProxyHandler.java @@ -94,7 +94,6 @@ void performProxyCheck() { long lastProxyCheckTimestamp = getLastProxyCheckTimestamp(); if (lastProxyCheckTimestamp == 0L) { - Logger.v("Never checked proxy; continuing with latest spec"); updateHandlingType(ProxyHandlingType.NONE); } else if (System.currentTimeMillis() - lastProxyCheckTimestamp > mProxyCheckIntervalMillis) { Logger.i("Time since last check elapsed. Attempting recovery with latest spec: " + mLatestSpec); 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 3b04c44f5..8c756db7e 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 @@ -235,7 +235,7 @@ private void updateSplits(SplitRoomDatabase splitDatabase, GeneralInfoDao genera } GeneralInfoEntity trafficTypesEntity = generalInfoDao.getByName(GeneralInfoEntity.TRAFFIC_TYPES_MAP); - if (trafficTypesEntity != null) { + if (trafficTypesEntity != null && !trafficTypesEntity.getStringValue().isEmpty()) { String fromTrafficTypes = mFromCipher.decrypt(trafficTypesEntity.getStringValue()); String toTrafficTypes = mToCipher.encrypt(fromTrafficTypes); if (toTrafficTypes != null) { @@ -246,7 +246,7 @@ private void updateSplits(SplitRoomDatabase splitDatabase, GeneralInfoDao genera } GeneralInfoEntity flagSetsEntity = generalInfoDao.getByName(GeneralInfoEntity.FLAG_SETS_MAP); - if (flagSetsEntity != null) { + if (flagSetsEntity != null && !flagSetsEntity.getStringValue().isEmpty()) { String fromFlagSets = mFromCipher.decrypt(flagSetsEntity.getStringValue()); String toFlagSets = mToCipher.encrypt(fromFlagSets); if (toFlagSets != null) { 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 9f328e455..ecffa0670 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 @@ -161,6 +161,7 @@ public void run() { mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.CHANGE_NUMBER_INFO, -1)); mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.FLAG_SETS_MAP, "")); mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.TRAFFIC_TYPES_MAP, "")); + mDatabase.getSplitQueryDao().invalidate(); mDatabase.splitDao().deleteAll(); } }); @@ -258,14 +259,14 @@ public void run() { private synchronized void parseTrafficTypesAndSets(@Nullable GeneralInfoEntity trafficTypesEntity, @Nullable GeneralInfoEntity flagSetsEntity) { Logger.v("Parsing traffic types and sets"); - if (trafficTypesEntity != null) { + if (trafficTypesEntity != null && !trafficTypesEntity.getStringValue().isEmpty()) { Type mapType = new TypeToken>(){}.getType(); String encryptedTrafficTypes = trafficTypesEntity.getStringValue(); String decryptedTrafficTypes = mCipher.decrypt(encryptedTrafficTypes); mTrafficTypes = Json.fromJson(decryptedTrafficTypes, mapType); } - if (flagSetsEntity != null) { + if (flagSetsEntity != null && !flagSetsEntity.getStringValue().isEmpty()) { Type flagsMapType = new TypeToken>>(){}.getType(); String encryptedFlagSets = flagSetsEntity.getStringValue(); String decryptedFlagSets = mCipher.decrypt(encryptedFlagSets); @@ -290,15 +291,19 @@ private void migrateTrafficTypesAndSetsFromStoredData() { } // persist TTs - String decryptedTrafficTypes = Json.toJson(mTrafficTypes); - String encryptedTrafficTypes = mCipher.encrypt(decryptedTrafficTypes); + if (mTrafficTypes != null && !mTrafficTypes.isEmpty()) { + String decryptedTrafficTypes = Json.toJson(mTrafficTypes); + String encryptedTrafficTypes = mCipher.encrypt(decryptedTrafficTypes); + mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.TRAFFIC_TYPES_MAP, encryptedTrafficTypes)); + } - // persist flag sets - String decryptedFlagSets = Json.toJson(mFlagSets); - String encryptedFlagSets = mCipher.encrypt(decryptedFlagSets); + if (mFlagSets != null && !mFlagSets.isEmpty()) { + // persist flag sets + String decryptedFlagSets = Json.toJson(mFlagSets); + String encryptedFlagSets = mCipher.encrypt(decryptedFlagSets); - mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.TRAFFIC_TYPES_MAP, encryptedTrafficTypes)); - mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.FLAG_SETS_MAP, encryptedFlagSets)); + mDatabase.generalInfoDao().update(new GeneralInfoEntity(GeneralInfoEntity.FLAG_SETS_MAP, encryptedFlagSets)); + } } catch (Exception e) { Logger.e("Failed to migrate traffic types and flag sets", e); } diff --git a/src/test/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorageTest.java b/src/test/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorageTest.java index 38c07f3c0..7145fd775 100644 --- a/src/test/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorageTest.java +++ b/src/test/java/io/split/android/client/storage/splits/SqLitePersistentSplitsStorageTest.java @@ -45,6 +45,8 @@ public class SqLitePersistentSplitsStorageTest { @Mock private SplitDao mSplitDao; @Mock + private SplitQueryDao mSplitQueryDao; + @Mock private SplitCipher mCipher; private SqLitePersistentSplitsStorage mStorage; private AutoCloseable mAutoCloseable; @@ -56,6 +58,7 @@ public void setUp() { mAutoCloseable = MockitoAnnotations.openMocks(this); when(mDatabase.generalInfoDao()).thenReturn(mock(GeneralInfoDao.class)); when(mDatabase.splitDao()).thenReturn(mSplitDao); + when(mDatabase.getSplitQueryDao()).thenReturn(mSplitQueryDao); doAnswer((Answer) invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; @@ -201,6 +204,7 @@ public boolean matches(GeneralInfoEntity argument) { } })); verify(mDatabase.splitDao()).deleteAll(); + verify(mDatabase.getSplitQueryDao()).invalidate(); } @Test