From 823a49775d0a6e90f4512401edafeeec118357ed Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 22 May 2025 16:17:02 -0300 Subject: [PATCH 1/2] Prerequisites in splitChanges DTO --- .../android/client/dtos/Prerequisite.java | 31 +++ .../io/split/android/client/dtos/Split.java | 9 + .../TargetingRulesResponseParserTest.java | 34 +++ .../split_changes_prerequisites.json | 253 ++++++++++++++++++ 4 files changed, 327 insertions(+) create mode 100644 src/main/java/io/split/android/client/dtos/Prerequisite.java create mode 100644 src/test/resources/split_changes_prerequisites.json diff --git a/src/main/java/io/split/android/client/dtos/Prerequisite.java b/src/main/java/io/split/android/client/dtos/Prerequisite.java new file mode 100644 index 000000000..153704e69 --- /dev/null +++ b/src/main/java/io/split/android/client/dtos/Prerequisite.java @@ -0,0 +1,31 @@ +package io.split.android.client.dtos; + +import com.google.gson.annotations.SerializedName; + +import java.util.HashSet; +import java.util.Set; + +public class Prerequisite { + + @SerializedName("n") + private String name; + + @SerializedName("ts") + private Set treatments; + + public Prerequisite() { + } + + Prerequisite(String name, Set treatments) { + this.name = name; + this.treatments = treatments; + } + + public String getName() { + return name; + } + + public Set getTreatments() { + return treatments == null ? new HashSet<>() : treatments; + } +} diff --git a/src/main/java/io/split/android/client/dtos/Split.java b/src/main/java/io/split/android/client/dtos/Split.java index e22838048..22869d3f7 100644 --- a/src/main/java/io/split/android/client/dtos/Split.java +++ b/src/main/java/io/split/android/client/dtos/Split.java @@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +54,10 @@ public class Split { @SerializedName("impressionsDisabled") public boolean impressionsDisabled = false; + @Nullable + @SerializedName("prerequisites") + private List prerequisites; + public String json = null; public Split() { @@ -63,4 +68,8 @@ public Split(String name, String json) { this.name = name; this.json = json; } + + public List getPrerequisites() { + return prerequisites == null ? new ArrayList<>() : prerequisites; + } } 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 2ce2ded65..19540d879 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 @@ -8,10 +8,13 @@ import org.junit.Before; import org.junit.Test; +import java.util.List; import java.util.Set; import io.split.android.client.dtos.Excluded; import io.split.android.client.dtos.ExcludedSegment; +import io.split.android.client.dtos.Prerequisite; +import io.split.android.client.dtos.Split; import io.split.android.client.dtos.TargetingRulesChange; import io.split.android.client.service.http.HttpResponseParserException; import io.split.android.helpers.FileHelper; @@ -63,6 +66,37 @@ public void parsesLegacySplitChangeJson() throws Exception { assertTrue(result.getRuleBasedSegmentsChange().getSegments().isEmpty()); } + @Test + public void parsesPrerequisites() throws HttpResponseParserException { + String json = fileHelper.loadFileContent("split_changes_prerequisites.json"); + TargetingRulesChange result = parser.parse(json); + + assertNotNull(result); + assertNotNull(result.getFeatureFlagsChange()); + Split firstSplit = result.getFeatureFlagsChange().splits.get(0); + assertEquals("FACUNDO_TEST", firstSplit.name); + List preReqs = firstSplit.getPrerequisites(); + assertEquals(2, preReqs.size()); + assertEquals("flag1", preReqs.get(0).getName()); + assertEquals("flag2", preReqs.get(1).getName()); + assertEquals(2, preReqs.get(0).getTreatments().size()); + assertEquals(1, preReqs.get(1).getTreatments().size()); + assertTrue(preReqs.get(0).getTreatments().contains("on")); + assertTrue(preReqs.get(0).getTreatments().contains("v1")); + assertTrue(preReqs.get(1).getTreatments().contains("off")); + } + + @Test + public void nonExistingPrerequisitesDefaultsToEmpty() throws HttpResponseParserException { + String json = fileHelper.loadFileContent("split_changes_prerequisites.json"); + TargetingRulesChange result = parser.parse(json); + assertNotNull(result); + Split split = result.getFeatureFlagsChange().splits.get(1); + assertEquals("FACUNDO_TEST_2", split.name); + List preReqs = split.getPrerequisites(); + assertEquals(0, preReqs.size()); + } + @Test public void parseNullReturnsNull() throws HttpResponseParserException { TargetingRulesChange result = parser.parse(null); diff --git a/src/test/resources/split_changes_prerequisites.json b/src/test/resources/split_changes_prerequisites.json new file mode 100644 index 000000000..1b9467bc3 --- /dev/null +++ b/src/test/resources/split_changes_prerequisites.json @@ -0,0 +1,253 @@ +{ + "ff": { + "splits": [ + { + "trafficTypeName": "account", + "name": "FACUNDO_TEST", + "trafficAllocation": 59, + "trafficAllocationSeed": -2108186082, + "seed": -1947050785, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "off", + "changeNumber": 1506703262916, + "prerequisites": [ + { + "n": "flag1", + "ts": ["on","v1"] + }, + { + "n": "flag2", + "ts": ["off"] + } + ], + "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" + } + ] + }, + { + "trafficTypeName": "account", + "name": "FACUNDO_TEST_2", + "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" + } + ] + } + ], + "s": -1, + "t": 1506703262916 + }, + "rbs": { + "d": [], + "s": 1506703262920, + "t": 1506703263000 + } +} \ No newline at end of file From 4bfcb35e56d62049b53aca707595367e51083507 Mon Sep 17 00:00:00 2001 From: gthea Date: Fri, 23 May 2025 14:30:25 -0300 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Emiliano Sanchez --- src/test/resources/split_changes_prerequisites.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/split_changes_prerequisites.json b/src/test/resources/split_changes_prerequisites.json index 1b9467bc3..e456d4cb2 100644 --- a/src/test/resources/split_changes_prerequisites.json +++ b/src/test/resources/split_changes_prerequisites.json @@ -1,6 +1,6 @@ { "ff": { - "splits": [ + "d": [ { "trafficTypeName": "account", "name": "FACUNDO_TEST",