Skip to content

Commit 724c681

Browse files
committed
Storage change & matcher implementation
1 parent 7519aca commit 724c681

5 files changed

Lines changed: 88 additions & 20 deletions

File tree

src/main/java/io/split/android/client/localhost/LocalhostRuleBasedSegmentsStorage.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77

88
import io.split.android.client.dtos.RuleBasedSegment;
99
import io.split.android.client.storage.rbs.RuleBasedSegmentStorage;
10+
import io.split.android.engine.experiments.ParsedRuleBasedSegment;
1011

1112
public class LocalhostRuleBasedSegmentsStorage implements RuleBasedSegmentStorage {
1213

1314
@Nullable
1415
@Override
15-
public RuleBasedSegment get(String segmentName) {
16+
public ParsedRuleBasedSegment get(String segmentName, String matchingKey) {
1617
return null;
1718
}
1819

src/main/java/io/split/android/client/storage/rbs/RuleBasedSegmentStorage.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
import io.split.android.client.dtos.RuleBasedSegment;
99
import io.split.android.client.storage.RolloutDefinitionsCache;
10+
import io.split.android.engine.experiments.ParsedRuleBasedSegment;
1011

1112
public interface RuleBasedSegmentStorage extends RolloutDefinitionsCache {
1213

1314
@Nullable
14-
RuleBasedSegment get(String segmentName);
15+
ParsedRuleBasedSegment get(String segmentName, String matchingKey);
1516

1617
boolean update(@NonNull Set<RuleBasedSegment> toAdd, @NonNull Set<RuleBasedSegment> toRemove, long changeNumber);
1718

src/main/java/io/split/android/client/storage/rbs/RuleBasedSegmentStorageImpl.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,31 @@
1111
import java.util.concurrent.ConcurrentHashMap;
1212

1313
import io.split.android.client.dtos.RuleBasedSegment;
14+
import io.split.android.engine.experiments.ParsedRuleBasedSegment;
15+
import io.split.android.engine.experiments.RuleBasedSegmentParser;
1416

1517
public class RuleBasedSegmentStorageImpl implements RuleBasedSegmentStorage {
1618

1719
private final ConcurrentHashMap<String, RuleBasedSegment> mInMemorySegments;
20+
private final RuleBasedSegmentParser mParser;
1821
private final PersistentRuleBasedSegmentStorage mPersistentStorage;
1922
private volatile long mChangeNumber;
2023

21-
public RuleBasedSegmentStorageImpl(@NonNull PersistentRuleBasedSegmentStorage persistentStorage) {
24+
public RuleBasedSegmentStorageImpl(@NonNull PersistentRuleBasedSegmentStorage persistentStorage, @NonNull RuleBasedSegmentParser parser) {
2225
mInMemorySegments = new ConcurrentHashMap<>();
26+
mParser = checkNotNull(parser);
2327
mPersistentStorage = checkNotNull(persistentStorage);
2428
mChangeNumber = -1;
2529
}
2630

27-
@Nullable
2831
@Override
29-
public RuleBasedSegment get(String segmentName) {
30-
return mInMemorySegments.get(segmentName);
32+
public @Nullable ParsedRuleBasedSegment get(String segmentName, String matchingKey) {
33+
RuleBasedSegment ruleBasedSegment = mInMemorySegments.get(segmentName);
34+
if (ruleBasedSegment == null) {
35+
return null;
36+
}
37+
38+
return mParser.parse(ruleBasedSegment, matchingKey);
3139
}
3240

3341
@Override
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.split.android.engine.matchers;
2+
3+
import static io.split.android.client.utils.Utils.checkNotNull;
4+
5+
import java.util.Map;
6+
7+
import io.split.android.client.Evaluator;
8+
import io.split.android.client.storage.mysegments.MySegmentsStorage;
9+
import io.split.android.client.storage.rbs.RuleBasedSegmentStorage;
10+
import io.split.android.engine.experiments.ParsedCondition;
11+
import io.split.android.engine.experiments.ParsedRuleBasedSegment;
12+
13+
public class InRuleBasedSegmentMatcher implements Matcher {
14+
15+
private final RuleBasedSegmentStorage mRuleBasedSegmentStorage;
16+
private final MySegmentsStorage mMySegmentsStorage;
17+
private final String mSegmentName;
18+
19+
public InRuleBasedSegmentMatcher(RuleBasedSegmentStorage ruleBasedSegmentStorage, MySegmentsStorage mySegmentsStorage, String segmentName) {
20+
mRuleBasedSegmentStorage = checkNotNull(ruleBasedSegmentStorage);
21+
mMySegmentsStorage = checkNotNull(mySegmentsStorage);
22+
mSegmentName = checkNotNull(segmentName);
23+
}
24+
25+
@Override
26+
public boolean match(Object matchValue, String bucketingKey, Map<String, Object> attributes, Evaluator evaluator) {
27+
if (!(matchValue instanceof String)) {
28+
return false;
29+
}
30+
31+
final String matchingKey = (String) matchValue;
32+
final ParsedRuleBasedSegment parsedRuleBasedSegment = mRuleBasedSegmentStorage.get(mSegmentName, matchingKey);
33+
34+
if (parsedRuleBasedSegment.getExcludedKeys().contains(matchingKey)) {
35+
return false;
36+
}
37+
38+
for (String segmentName : parsedRuleBasedSegment.getExcludedSegments()) {
39+
if (mMySegmentsStorage.getAll().contains(segmentName)) {
40+
return false;
41+
}
42+
}
43+
44+
for (ParsedCondition condition : parsedRuleBasedSegment.getParsedConditions()) {
45+
if (condition.matcher().match(matchingKey, bucketingKey, attributes, evaluator)) {
46+
return true;
47+
}
48+
}
49+
50+
return false;
51+
}
52+
}

src/test/java/io/split/android/client/storage/rbs/RuleBasedSegmentStorageImplTest.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,29 @@
2222
import io.split.android.client.dtos.Excluded;
2323
import io.split.android.client.dtos.RuleBasedSegment;
2424
import io.split.android.client.dtos.Status;
25+
import io.split.android.client.storage.mysegments.MySegmentsStorageContainer;
26+
import io.split.android.engine.experiments.ParsedRuleBasedSegment;
27+
import io.split.android.engine.experiments.ParserCommons;
28+
import io.split.android.engine.experiments.RuleBasedSegmentParser;
2529

2630
public class RuleBasedSegmentStorageImplTest {
2731

2832
private RuleBasedSegmentStorageImpl storage;
2933
private PersistentRuleBasedSegmentStorage mPersistentStorage;
34+
private RuleBasedSegmentParser mParser;
3035

3136
@Before
3237
public void setUp() {
3338
mPersistentStorage = mock(PersistentRuleBasedSegmentStorage.class);
34-
storage = new RuleBasedSegmentStorageImpl(mPersistentStorage);
39+
mParser = new RuleBasedSegmentParser(new ParserCommons(mock(MySegmentsStorageContainer.class), mock(MySegmentsStorageContainer.class), mock(RuleBasedSegmentStorageProvider.class)));
40+
storage = new RuleBasedSegmentStorageImpl(mPersistentStorage, mParser);
3541
}
3642

3743
@Test
3844
public void get() {
3945
RuleBasedSegment segment = createRuleBasedSegment("segment1");
4046
storage.update(Set.of(segment), null, 1);
41-
assertNotNull(storage.get("segment1"));
47+
assertNotNull(storage.get("segment1", "matchingKey"));
4248
}
4349

4450
@Test
@@ -51,15 +57,15 @@ public void sequentialUpdate() {
5157
toAdd.add(segment2);
5258

5359
storage.update(toAdd, null, 2);
54-
assertNotNull(storage.get("segment1"));
55-
assertNotNull(storage.get("segment2"));
60+
assertNotNull(storage.get("segment1", "matchingKey"));
61+
assertNotNull(storage.get("segment2", "matchingKey"));
5662
assertEquals(2, storage.getChangeNumber());
5763

5864
Set<RuleBasedSegment> toRemove = new HashSet<>();
5965
toRemove.add(segment1);
6066
storage.update(null, toRemove, 3);
61-
assertNull(storage.get("segment1"));
62-
assertNotNull(storage.get("segment2"));
67+
assertNull(storage.get("segment1", "matchingKey"));
68+
assertNotNull(storage.get("segment2", "matchingKey"));
6369
assertEquals(3, storage.getChangeNumber());
6470
}
6571

@@ -93,7 +99,7 @@ public void clearRemovesAllSegments() {
9399
RuleBasedSegment segment = createRuleBasedSegment("segment1");
94100
storage.update(Set.of(segment), null, 1);
95101
storage.clear();
96-
assertNull(storage.get("segment1"));
102+
assertNull(storage.get("segment1", "matchingKey"));
97103
}
98104

99105
@Test
@@ -126,15 +132,15 @@ public void segmentRemoval() {
126132
toAdd.add(segment2);
127133
storage.update(toAdd, null, 1);
128134

129-
assertNotNull(storage.get("segment1"));
130-
assertNotNull(storage.get("segment2"));
135+
assertNotNull(storage.get("segment1", "matchingKey"));
136+
assertNotNull(storage.get("segment2", "matchingKey"));
131137

132138
Set<RuleBasedSegment> toRemove = new HashSet<>();
133139
toRemove.add(createRuleBasedSegment("segment1"));
134140
storage.update(null, toRemove, 2);
135141

136-
assertNull(storage.get("segment1"));
137-
assertNotNull(storage.get("segment2"));
142+
assertNull(storage.get("segment1", "matchingKey"));
143+
assertNotNull(storage.get("segment2", "matchingKey"));
138144
}
139145

140146
@Test
@@ -143,7 +149,7 @@ public void segmentRemovalOfSameSegment() {
143149
Set<RuleBasedSegment> segments = Collections.singleton(segment1);
144150

145151
storage.update(segments, segments, 1);
146-
assertNull(storage.get("segment1"));
152+
assertNull(storage.get("segment1", "matchingKey"));
147153
assertEquals(1, storage.getChangeNumber());
148154
}
149155

@@ -173,12 +179,12 @@ public void loadLocalPopulatesValues() {
173179
when(mPersistentStorage.getSnapshot()).thenReturn(snapshot);
174180

175181
long initialCn = storage.getChangeNumber();
176-
RuleBasedSegment initialSegment1 = storage.get("segment1");
182+
ParsedRuleBasedSegment initialSegment1 = storage.get("segment1", "matchingKey");
177183

178184
storage.loadLocal();
179185

180186
long finalCn = storage.getChangeNumber();
181-
RuleBasedSegment finalSegment1 = storage.get("segment1");
187+
ParsedRuleBasedSegment finalSegment1 = storage.get("segment1", "matchingKey");
182188

183189
assertEquals(-1, initialCn);
184190
assertEquals(1, finalCn);

0 commit comments

Comments
 (0)