From 6e998126213d41d5e8757beb43310e0235e4d7f6 Mon Sep 17 00:00:00 2001 From: Arif Burak Demiray <57103426+arifBurakDemiray@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:25:38 +0300 Subject: [PATCH] [Java] Module RC init and refactor for preparations (#140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: rc init * Update CHANGELOG.md --------- Co-authored-by: Artūrs Kadiķis --- CHANGELOG.md | 7 + .../main/java/ly/count/sdk/java/Config.java | 74 ++++- .../main/java/ly/count/sdk/java/Countly.java | 16 + .../sdk/java/internal/InternalConfig.java | 16 +- .../sdk/java/internal/ModuleRemoteConfig.java | 278 +----------------- .../sdk/java/internal/ModuleRequests.java | 33 --- .../ly/count/sdk/java/internal/RCData.java | 11 + .../sdk/java/internal/RCDownloadCallback.java | 15 + .../sdk/java/internal/RequestResult.java | 3 + .../ly/count/sdk/java/internal/SDKCore.java | 14 +- .../count/sdk/java/internal/SDKStorage.java | 10 + .../sdk/java/internal/StorageProvider.java | 14 + .../internal/ModuleRemoteConfigTests.java | 150 ---------- .../ly/count/sdk/java/internal/TestUtils.java | 4 + 14 files changed, 168 insertions(+), 477 deletions(-) create mode 100644 sdk-java/src/main/java/ly/count/sdk/java/internal/RCData.java create mode 100644 sdk-java/src/main/java/ly/count/sdk/java/internal/RCDownloadCallback.java create mode 100644 sdk-java/src/main/java/ly/count/sdk/java/internal/RequestResult.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 79fc3fc40..0b2f150fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ * Session update time duration increased to 60 seconds from 30 seconds. * Adding remaining request queue size information to every request. * Adding application version information to every request. +* Added the remote config feature. +* Remote Config module is accessible through "Countly::instance()::remoteConfig()" call. +* Added configuration functions to configure Remote Config module on init: + * 'enableRemoteConfigValueCaching' to enable caching of remote config values + * 'enrollABOnRCDownload' to enroll A/B tests when remote config values downloaded + * 'enableRemoteConfigAutomaticTriggers' to automatically download remote config values on init + * 'remoteConfigRegisterGlobalCallback(RCDownloadCallback callback)' to register a remote config callback * Added the ability to set the user profile picture with an URL * Fixed a bug where it was not possible to send a profile picture with binary data diff --git a/sdk-java/src/main/java/ly/count/sdk/java/Config.java b/sdk-java/src/main/java/ly/count/sdk/java/Config.java index a0ba9030a..2ee61ca1e 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/Config.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/Config.java @@ -8,8 +8,10 @@ import java.io.ObjectOutputStream; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import ly.count.sdk.java.internal.Byteable; @@ -17,6 +19,7 @@ import ly.count.sdk.java.internal.Log; import ly.count.sdk.java.internal.LogCallback; import ly.count.sdk.java.internal.ModuleBase; +import ly.count.sdk.java.internal.RCDownloadCallback; import ly.count.sdk.java.internal.Utils; /** @@ -81,9 +84,9 @@ public enum Feature { CrashReporting(CoreFeature.CrashReporting.getIndex()), Location(CoreFeature.Location.getIndex()), UserProfiles(CoreFeature.UserProfiles.getIndex()), - Feedback(CoreFeature.Feedback.getIndex()); + Feedback(CoreFeature.Feedback.getIndex()), + RemoteConfig(CoreFeature.RemoteConfig.getIndex()); // StarRating(1 << 12), - // RemoteConfig(1 << 13), // PerformanceMonitoring(1 << 14); private final int index; @@ -109,12 +112,8 @@ public static Config.Feature byIndex(int index) { return Location; } else if (index == UserProfiles.index) { return UserProfiles; - // } else if (index == StarRating.index) { - // return StarRating; - // } else if (index == RemoteConfig.index) { - // return RemoteConfig; - // } else if (index == PerformanceMonitoring.index) { - // return PerformanceMonitoring; + } else if (index == RemoteConfig.index) { + return RemoteConfig; } else if (index == Feedback.index) { return Feedback; } else { @@ -447,17 +446,26 @@ public boolean restore(byte[] data, Log L) { //endregion - //region Remote Config Module fields + //Begin Remote Config Module Fields /** * If remote config automatic fetching should be enabled */ - protected Boolean enableAutomaticRemoteConfig = null; + protected boolean enableRemoteConfigAutomaticDownloadTriggers = false; /** - * After how much time the request is canceled and timeout error returned + * If remote config value caching should be enabled */ - protected Long remoteConfigUpdateRequestTimeout = null; + protected boolean enableRemoteConfigValueCaching = false; + + /** + * If automatic remote config enrollment should be enabled + */ + protected boolean enableAutoEnrollFlag = false; + + protected List remoteConfigGlobalCallbacks = new ArrayList<>(); + + //End Remote Config Module Fields /** * Maximum in memory request queue size. @@ -1563,5 +1571,45 @@ public Config setSdkPlatform(String platform) { public String getSdkPlatform() { return sdkPlatform; } -} + /** + * Enable automatic download of remote config values + * + * @return {@code this} instance for method chaining + */ + public Config enableRemoteConfigAutomaticTriggers() { + this.enableRemoteConfigAutomaticDownloadTriggers = true; + return this; + } + + /** + * Enable caching of remote config values + * + * @return {@code this} instance for method chaining + */ + public Config enableRemoteConfigValueCaching() { + this.enableRemoteConfigValueCaching = true; + return this; + } + + /** + * Enable automatic enroll for AB + * + * @return {@code this} instance for method chaining + */ + public Config enrollABOnRCDownload() { + this.enableAutoEnrollFlag = true; + return this; + } + + /** + * Register a callback to be called when remote config is downloaded + * + * @param callback to be called see {@link RCDownloadCallback} + * @return {@code this} instance for method chaining + */ + public Config remoteConfigRegisterGlobalCallback(RCDownloadCallback callback) { + remoteConfigGlobalCallbacks.add(callback); + return this; + } +} \ No newline at end of file diff --git a/sdk-java/src/main/java/ly/count/sdk/java/Countly.java b/sdk-java/src/main/java/ly/count/sdk/java/Countly.java index cd4f995da..bd1166958 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/Countly.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/Countly.java @@ -8,6 +8,7 @@ import ly.count.sdk.java.internal.ModuleBackendMode; import ly.count.sdk.java.internal.ModuleEvents; import ly.count.sdk.java.internal.ModuleFeedback; +import ly.count.sdk.java.internal.ModuleRemoteConfig; import ly.count.sdk.java.internal.SDKCore; /** @@ -345,6 +346,21 @@ public ModuleFeedback.Feedback feedback() { return sdk.feedback(); } + /** + * RemoteConfig interface to use remote config feature. + * + * @return {@link ModuleRemoteConfig.RemoteConfig} instance. + */ + public ModuleRemoteConfig.RemoteConfig remoteConfig() { + if (!isInitialized()) { + if (L != null) { + L.e("[Countly] remoteConfig, SDK is not initialized yet."); + } + return null; + } + return sdk.remoteConfig(); + } + /** * Record event with provided key. * diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/InternalConfig.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/InternalConfig.java index 3c0a4e551..fc8d77212 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/InternalConfig.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/InternalConfig.java @@ -407,12 +407,20 @@ public Boolean getStarRatingDisabledForNewVersion() { //endregion //region remote config - public Boolean getRemoteConfigAutomaticUpdateEnabled() { - return enableAutomaticRemoteConfig; + public boolean isRemoteConfigAutomaticDownloadTriggersEnabled() { + return enableRemoteConfigAutomaticDownloadTriggers; } - public Long getRemoteConfigUpdateTimeoutLength() { - return remoteConfigUpdateRequestTimeout; + public boolean isRemoteConfigValueCachingEnabled() { + return enableRemoteConfigValueCaching; + } + + public boolean isAutoEnrollFlagEnabled() { + return enableAutoEnrollFlag; + } + + public List getRemoteConfigGlobalCallbackList() { + return remoteConfigGlobalCallbacks; } //endregion diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRemoteConfig.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRemoteConfig.java index 84142b5fe..c4e6f4be2 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRemoteConfig.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRemoteConfig.java @@ -1,286 +1,12 @@ package ly.count.sdk.java.internal; -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - public class ModuleRemoteConfig extends ModuleBase { - //after how much time the timeout error is returned - Long rcRequestTimeout = 5000L; - - //if set to true, it will automatically download remote configs on module startup - boolean automaticUpdateEnabled = false; - - public final static Long storableStorageId = 456L; - public final static String storableStoragePrefix = "remote_config"; - - protected InternalConfig internalConfig = null; - - protected Map requestCallbacks; - - //disabled is set when a empty module is created - //in instances when the rating feature was not enabled - //when a module is disabled, developer facing functions do nothing - protected boolean disabledModule = false; - - public interface RemoteConfigCallback { - /** - * Called after receiving remote config update result - * - * @param error if is null, it means that no errors were encountered - */ - void callback(String error); - } - - @Override - public void init(InternalConfig config) { - super.init(config); - requestCallbacks = new HashMap<>(); - } - - @Override - public void initFinished(InternalConfig config) { - Long timeoutVal = config.getRemoteConfigUpdateTimeoutLength(); - if (timeoutVal != null) { - this.rcRequestTimeout = timeoutVal; - } - - Boolean automEnabled = config.getRemoteConfigAutomaticUpdateEnabled(); - if (automEnabled != null) { - automaticUpdateEnabled = automEnabled; - } - - if (automaticUpdateEnabled) { - updateRemoteConfigValues(null, null, null); - } - } - - @Override - public Boolean onRequest(Request request) { - //check if it's a old request or from this session - if (requestCallbacks.containsKey(request.storageId())) { - //indicate that this module is the owner - request.own(ModuleRemoteConfig.class); - //returned to indicate that the request is ready - return true; - } else { - //no reference in callback map - //assume that it probably is from a old session and therefore throw - //this request away - return false; - } - } - - public void disableModule() { - disabledModule = true; - } - - @Override - public void onRequestCompleted(Request request, String response, int responseCode) { - //check if we have a callback - long receivedRequestId = request.storageId(); - boolean requestExists = requestCallbacks.containsKey(receivedRequestId); - RemoteConfigCallback callback = requestCallbacks.get(receivedRequestId); - String error = null; - - if (responseCode == 200) { - //continue only if good response - - try { - //interpret received changes - JSONObject jobj = new JSONObject(response); - - //merge them into current values and save them - RemoteConfigValueStore stored = getStoredValues(); - stored.mergeValues(jobj, L); - saveStoredValues(stored); - } catch (Exception e) { - L.e("Failed merging new values into old ones" + e); - error = "Error merging results"; - } - } else { - //assume error - L.w("onRequestCompleted, server returned failure code, response: [" + response + "]"); - error = "Server side error, [" + response + "]"; - } - - if (callback != null) { - callback.callback(error); - } - } - - /** - * Internal call for updating remote config keys - * - * @param keysOnly set if these are the only keys to update - * @param keysExcept set if these keys should be ignored from the update - * @param callback called after the update is done - */ - protected void updateRemoteConfigValues(String[] keysOnly, String[] keysExcept, RemoteConfigCallback callback) { - String sKOnly = null; - String sKExcept = null; - - if (keysOnly != null && keysOnly.length > 0) { - //include list takes precedence - //if there is at least one item, use it - JSONArray includeArray = new JSONArray(); - for (String key : keysOnly) { - includeArray.put(key); - } - sKOnly = includeArray.toString(); - } else if (keysExcept != null && keysExcept.length > 0) { - //include list was not used, use the exclude list - JSONArray excludeArray = new JSONArray(); - for (String key : keysExcept) { - excludeArray.put(key); - } - sKExcept = excludeArray.toString(); - } - - Request req = ModuleRequests.remoteConfigUpdate(internalConfig, sKOnly, sKExcept, ModuleRemoteConfig.class); - requestCallbacks.put(req.storageId(), callback); - ModuleRequests.pushAsync(internalConfig, req); - } - - protected Object getRemoteConfigValue(String key) { - RemoteConfigValueStore values = getStoredValues(); - return values.getValue(key); - } - - public RemoteConfigValueStore getStoredValues() { - RemoteConfigValueStore rcvs = new RemoteConfigValueStore(); - Storage.read(internalConfig, rcvs); - return rcvs; - } - - public void saveStoredValues(RemoteConfigValueStore values) { - Storage.push(internalConfig, values); - } - - public static class RemoteConfigValueStore implements Storable { - public JSONObject values = new JSONObject(); - - //add new values to the current storage - public void mergeValues(JSONObject newValues, Log L) { - if (newValues == null) { - return; - } + RemoteConfig remoteConfigInterface = null; - Iterator iter = newValues.keys(); - while (iter.hasNext()) { - String key = iter.next(); - try { - Object value = newValues.get(key); - values.put(key, value); - } catch (Exception e) { - if (L != null) { - L.e("[ModuleRemoteConfig] Failed merging new remote config values " + e); - } - } - } - } - - public Object getValue(String key) { - return values.opt(key); - } - - @Override - public Long storageId() { - return storableStorageId; - } - - @Override - public String storagePrefix() { - return storableStoragePrefix; - } - - @Override - public void setId(Long id) { - //do nothing - } - - @Override - public byte[] store(Log L) { - try { - return values.toString().getBytes(Utils.UTF8); - } catch (UnsupportedEncodingException e) { - if (L != null) { - L.e("[ModuleRemoteConfig] UTF is not supported for RemoteConfigValueStore " + e); - } - return null; - } - } - - @Override - public boolean restore(byte[] data, Log L) { - try { - String json = new String(data, Utils.UTF8); - try { - values = new JSONObject(json); - } catch (JSONException e) { - if (L != null) { - L.e("[ModuleRemoteConfig] Couldn't decode RemoteConfigValueStore successfully " + e); - } - } - return true; - } catch (UnsupportedEncodingException e) { - if (L != null) { - L.e("[ModuleRemoteConfig] Cannot deserialize RemoteConfigValueStore " + e); - } - } - - return false; - } - - @Override - public String toString() { - return values.toString(); - } + ModuleRemoteConfig() { } public class RemoteConfig { - public void updateRemoteConfig(RemoteConfigCallback callback) { - L.d("Manually calling to updateRemoteConfig"); - if (disabledModule) { - return; - } - ModuleRemoteConfig.this.updateRemoteConfigValues(null, null, callback); - } - - public void updateRemoteConfigForKeysOnly(String[] keysOnly, RemoteConfigCallback callback) { - L.d("Manually calling to updateRemoteConfig with include keys"); - if (disabledModule) { - return; - } - if (keysOnly == null) { - L.w("updateRemoteConfigExceptKeys passed 'keys to include' array is null"); - } - ModuleRemoteConfig.this.updateRemoteConfigValues(keysOnly, null, callback); - } - - public void updateRemoteConfigExceptKeys(String[] keysExclude, RemoteConfigCallback callback) { - L.d("Manually calling to updateRemoteConfig with exclude keys"); - if (disabledModule) { - return; - } - if (keysExclude == null) { - L.w("updateRemoteConfigExceptKeys passed 'keys to ignore' array is null"); - } - ModuleRemoteConfig.this.updateRemoteConfigValues(null, keysExclude, callback); - } - - public Object remoteConfigValueForKey(String key) { - L.d("Manually calling to remoteConfigValueForKey"); - if (disabledModule) { - return null; - } - - return ModuleRemoteConfig.this.getRemoteConfigValue(key); - } } } diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRequests.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRequests.java index d3ec2aba5..2900f16a8 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRequests.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/ModuleRequests.java @@ -151,40 +151,7 @@ static void addRequiredTimeParametersToParams(Params params) { .add("dow", instant.dow); } - /** - * Request to see if rating widget is available - * Expected format - * https://the.server.com/o/feedback/widget?app_key=d899c0f6adb2e9&widget_id=5c48ehdgee96c - * - * @param config {@link InternalConfig} instannce - * @param widgetId widget id - * @return request instance - */ - public static Request ratingWidgetAvailabilityCheck(InternalConfig config, String widgetId, Class module) { - Request req = Request.build("widget_id", widgetId, "app_key", config.getServerAppKey()); - req.own(module); - req.endpoint("/o/feedback/widget?"); - - return req; - } - - public static Request remoteConfigUpdate(InternalConfig config, String keysInclude, String keysExclude, Class module) { - Request req = Request.build("method", "fetch_remote_config", "app_key", config.getServerAppKey()); - - if (keysInclude != null) { - req.params.add("keys", keysInclude); - } else if (keysExclude != null) { - req.params.add("omit_keys", keysExclude); - } - - req.own(module); - req.endpoint("/o/sdk?"); - - return req; - } - static void addRequiredParametersToParams(InternalConfig config, Params params) { - Map map = params.map(); if (map.isEmpty() || (map.size() == 1 && map.containsKey(Params.PARAM_DEVICE_ID))) { //if nothing was in the request, no need to add these mandatory fields diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/RCData.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/RCData.java new file mode 100644 index 000000000..998c51717 --- /dev/null +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/RCData.java @@ -0,0 +1,11 @@ +package ly.count.sdk.java.internal; + +public class RCData { + public Object value; + public boolean isCurrentUsersData; + + public RCData(Object givenValue, boolean givenUserState) { + this.value = givenValue; + this.isCurrentUsersData = givenUserState; + } +} diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/RCDownloadCallback.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/RCDownloadCallback.java new file mode 100644 index 000000000..57dc285b6 --- /dev/null +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/RCDownloadCallback.java @@ -0,0 +1,15 @@ +package ly.count.sdk.java.internal; + +import java.util.Map; + +public interface RCDownloadCallback { + /** + * Called when RC values are downloaded + * + * @param rResult see {@link RequestResult} + * @param error null if there is no error + * @param fullValueUpdate "true" - all values updated, "false" - a subset of values updated + * @param downloadedValues the whole downloaded RC set, the delta + */ + void callback(RequestResult rResult, String error, boolean fullValueUpdate, Map downloadedValues); +} diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/RequestResult.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/RequestResult.java new file mode 100644 index 000000000..39a6c2971 --- /dev/null +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/RequestResult.java @@ -0,0 +1,3 @@ +package ly.count.sdk.java.internal; + +public enum RequestResult {Error, Success, NetworkIssue} diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKCore.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKCore.java index 36f2f9a1c..4122325eb 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKCore.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKCore.java @@ -60,6 +60,7 @@ protected static void registerDefaultModuleMappings() { moduleMappings.put(CoreFeature.BackendMode.getIndex(), ModuleBackendMode.class); moduleMappings.put(CoreFeature.Feedback.getIndex(), ModuleFeedback.class); moduleMappings.put(CoreFeature.Events.getIndex(), ModuleEvents.class); + moduleMappings.put(CoreFeature.RemoteConfig.getIndex(), ModuleRemoteConfig.class); } /** @@ -377,13 +378,23 @@ public SessionImpl getSession() { public ModuleFeedback.Feedback feedback() { if (!hasConsentForFeature(CoreFeature.Feedback)) { - L.v("[SDKCore] feedback: Feedback feature has no consent, returning null"); + L.v("[SDKCore] feedback, Feedback feature has no consent, returning null"); return null; } return module(ModuleFeedback.class).feedbackInterface; } + public ModuleRemoteConfig.RemoteConfig remoteConfig() { + + if (!hasConsentForFeature(CoreFeature.RemoteConfig)) { + L.v("[SDKCore] remoteConfig, RemoteConfig feature has no consent, returning null"); + return null; + } + + return module(ModuleRemoteConfig.class).remoteConfigInterface; + } + /** * Get current {@link SessionImpl} or create new one if current is {@code null}. * @@ -728,6 +739,7 @@ private boolean processCrash(InternalConfig config, Long id) { Request request = ModuleRequests.nonSessionRequest(config); ModuleCrash.putCrashIntoParams(crash, request.params); + ModuleRequests.addRequiredParametersToParams(config, request.params); ModuleRequests.addRequiredTimeParametersToParams(request.params); diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKStorage.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKStorage.java index 7af4db81b..6a2691dcc 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKStorage.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/SDKStorage.java @@ -30,6 +30,7 @@ public class SDKStorage implements StorageProvider { //key names protected static final String key_device_id = "did"; protected static final String key_device_id_type = "did_t"; + protected static final String key_remote_config = "rc"; protected static final String key_migration_version = "dv"; private JsonFileStorage jsonFileStorage; @@ -358,6 +359,15 @@ public void setDeviceIdType(String deviceIdTypeString) { } @Override + public void setRemoteConfigValues(Object s) { + jsonFileStorage.addAndSave(key_remote_config, s); + } + + @Override + public Object getRemoteConfigValues() { + return jsonFileStorage.get(key_remote_config); + } + public Integer getMigrationVersion() { return jsonFileStorage.getInt(key_migration_version, -1); } diff --git a/sdk-java/src/main/java/ly/count/sdk/java/internal/StorageProvider.java b/sdk-java/src/main/java/ly/count/sdk/java/internal/StorageProvider.java index be74a0e1a..9fb5b1588 100644 --- a/sdk-java/src/main/java/ly/count/sdk/java/internal/StorageProvider.java +++ b/sdk-java/src/main/java/ly/count/sdk/java/internal/StorageProvider.java @@ -33,6 +33,20 @@ public interface StorageProvider { */ void setDeviceIdType(String deviceIdTypeString); + /** + * Set remote config values + * + * @param remoteConfigValues set of remote config values + */ + void setRemoteConfigValues(Object remoteConfigValues); + + /** + * Get remote config values + * + * @return set of remote config values + */ + Object getRemoteConfigValues(); + /** * Get migration version * diff --git a/sdk-java/src/test/java/ly/count/sdk/java/internal/ModuleRemoteConfigTests.java b/sdk-java/src/test/java/ly/count/sdk/java/internal/ModuleRemoteConfigTests.java index f61520a03..26590732a 100644 --- a/sdk-java/src/test/java/ly/count/sdk/java/internal/ModuleRemoteConfigTests.java +++ b/sdk-java/src/test/java/ly/count/sdk/java/internal/ModuleRemoteConfigTests.java @@ -1,155 +1,5 @@ package ly.count.sdk.java.internal; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Map; -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) public class ModuleRemoteConfigTests { - final String[] keys = new String[] { "qwe", "123", "asd", "zxc", "wer", "sdf", "xcv" }; - final JSONArray jsonArray = new JSONArray(); - - @Before - public void setupEveryTest() { - jsonArray.put(12); - jsonArray.put(23.4); - jsonArray.put("asd"); - jsonArray.put("765"); - } - - @Test - public void remoteConfigValueStoreAddRemoveValues() { - ModuleRemoteConfig.RemoteConfigValueStore rcvs = createValueStore(); - - Assert.assertEquals(123345567789645L, rcvs.getValue(keys[0])); - Assert.assertEquals(23, rcvs.getValue(keys[1])); - Assert.assertEquals("asas", rcvs.getValue(keys[2])); - Assert.assertEquals(123.3, rcvs.getValue(keys[3])); - Assert.assertEquals(true, rcvs.getValue(keys[4])); - Assert.assertEquals(jsonArray.toString(), rcvs.getValue(keys[5]).toString()); - } - - @Test - public void remoteConfigValueStoreStoreRestore() { - ModuleRemoteConfig.RemoteConfigValueStore rcvs = createValueStore(); - ModuleRemoteConfig.RemoteConfigValueStore rcvs2 = new ModuleRemoteConfig.RemoteConfigValueStore(); - - byte[] byteVal = rcvs.store(null); - rcvs2.restore(byteVal, null); - - Assert.assertTrue(compareValueStores(rcvs, rcvs2)); - } - - @Test - public void remoteConfigValueStoreMergeValues() { - String[] keys = new String[] { "dsd", "123", "xcv", "ty", "aa", "nn", "zx", "io" }; - int[] valsI = new int[] { 2, 3, 56, 8, 7, 345, 76, 98 }; - ModuleRemoteConfig.RemoteConfigValueStore rcvs = new ModuleRemoteConfig.RemoteConfigValueStore(); - - //add values #1 - JSONObject jobj = new JSONObject(); - jobj.put(keys[0], valsI[0]); - jobj.put(keys[1], valsI[1]); - jobj.put(keys[2], keys[0]); - rcvs.mergeValues(jobj, null); - - Assert.assertEquals(rcvs.getValue(keys[0]), valsI[0]); - Assert.assertEquals(rcvs.getValue(keys[1]), valsI[1]); - Assert.assertEquals(rcvs.getValue(keys[2]), keys[0]); - - //add values #2 - jobj = new JSONObject(); - JSONArray jarr = new JSONArray(); - jarr.put(valsI[0]); - jarr.put(valsI[1]); - jarr.put(valsI[2]); - - jobj.put(keys[3], jarr); - jobj.put(keys[1], valsI[3]); - jobj.put(keys[2], keys[5]); - rcvs.mergeValues(jobj, null); - jarr = new JSONArray(); - jarr.put(valsI[0]); - jarr.put(valsI[1]); - jarr.put(valsI[2]); - - Assert.assertEquals(rcvs.getValue(keys[0]), valsI[0]); - Assert.assertEquals(rcvs.getValue(keys[1]), valsI[3]); - Assert.assertEquals(rcvs.getValue(keys[2]), keys[5]); - JSONArray jarr2 = (JSONArray) rcvs.getValue(keys[3]); - - for (int a = 0; a < jarr.length(); a++) { - Assert.assertEquals(jarr.get(a), jarr2.get(a)); - } - } - - boolean compareValueStores(ModuleRemoteConfig.RemoteConfigValueStore v1, ModuleRemoteConfig.RemoteConfigValueStore v2) { - Map map1 = v1.values.toMap(); - Map map2 = v2.values.toMap(); - - if (map1.size() != map2.size()) { - return false; - } - - for (Map.Entry entry : map1.entrySet()) { - for (Map.Entry entry2 : map2.entrySet()) { - if (entry.getKey().equals(entry2.getKey())) { - Object vv1 = entry.getValue(); - Object vv2 = entry2.getValue(); - - if (vv2 instanceof BigDecimal) { - vv1 = BigDecimal.valueOf((double) vv1); - } - - //todo simplify this - if (vv2 instanceof ArrayList) { - ArrayList alVV1 = (ArrayList) vv1; - ArrayList alVV2 = (ArrayList) vv2; - Assert.assertEquals(alVV1.size(), alVV2.size()); - - for (int a = 0; a < alVV1.size(); a++) { - Object vvv1 = alVV1.get(a); - Object vvv2 = alVV2.get(a); - - if (vvv2 instanceof BigDecimal) { - vvv1 = BigDecimal.valueOf((double) vvv1); - } - - boolean resInternal = vvv1.equals(vvv2); - if (!resInternal) { - return false; - } - } - } else { - boolean res = vv1.equals(vv2); - if (!res) { - return false; - } - } - } - } - } - - return true; - } - - ModuleRemoteConfig.RemoteConfigValueStore createValueStore() { - ModuleRemoteConfig.RemoteConfigValueStore rcvs = new ModuleRemoteConfig.RemoteConfigValueStore(); - rcvs.values.put(keys[0], 123345567789645L); - rcvs.values.put(keys[1], 23); - rcvs.values.put(keys[2], "asas"); - rcvs.values.put(keys[3], 123.3); - rcvs.values.put(keys[4], true); - rcvs.values.put(keys[5], jsonArray); - return rcvs; - } } diff --git a/sdk-java/src/test/java/ly/count/sdk/java/internal/TestUtils.java b/sdk-java/src/test/java/ly/count/sdk/java/internal/TestUtils.java index d32d91da3..0de6c72d4 100644 --- a/sdk-java/src/test/java/ly/count/sdk/java/internal/TestUtils.java +++ b/sdk-java/src/test/java/ly/count/sdk/java/internal/TestUtils.java @@ -64,6 +64,10 @@ static Config getBaseConfig(String deviceID) { return config; } + static Config getConfigRemoteConfigs() { + return getBaseConfig().enableFeatures(Config.Feature.RemoteConfig); + } + static Config getConfigSessions(Config.Feature... features) { Config config = getBaseConfig(); config.setEventQueueSizeToSend(2);