Skip to content

Commit 688a8ff

Browse files
Add support for large and rule-based segments in exclusion rules
1 parent b59b098 commit 688a8ff

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

src/dtos/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export interface ISplitCondition {
200200
}
201201

202202
export interface IExcludedSegments {
203-
type: string,
203+
type: 'standard' | 'large' | 'rule-based',
204204
name: string,
205205
}
206206

src/evaluator/matchers/__tests__/rbsegment.spec.ts

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ const STORED_SPLITS: Record<string, ISplit> = {
1313
};
1414

1515
const STORED_SEGMENTS: Record<string, Set<string>> = {
16-
'segment_test': new Set(['emi@split.io']),
16+
'excluded_standard_segment': new Set(['emi@split.io']),
1717
'regular_segment': new Set(['nadia@split.io'])
1818
};
1919

20+
const STORED_LARGE_SEGMENTS: Record<string, Set<string>> = {
21+
'excluded_large_segment': new Set(['emi-large@split.io'])
22+
};
23+
2024
const STORED_RBSEGMENTS: Record<string, IRBSegment> = {
2125
'mauro_rule_based_segment': {
2226
changeNumber: 5,
@@ -25,7 +29,9 @@ const STORED_RBSEGMENTS: Record<string, IRBSegment> = {
2529
excluded: {
2630
keys: ['mauro@split.io', 'gaston@split.io'],
2731
segments: [
28-
{ type: 'regular', name: 'segment_test' }
32+
{ type: 'standard', name: 'excluded_standard_segment' },
33+
{ type: 'large', name: 'excluded_large_segment' },
34+
{ type: 'rule-based', name: 'excluded_rule_based_segment' }
2935
]
3036
},
3137
conditions: [
@@ -137,6 +143,31 @@ const STORED_RBSEGMENTS: Record<string, IRBSegment> = {
137143
}
138144
}]
139145
},
146+
'excluded_rule_based_segment': {
147+
name: 'excluded_rule_based_segment',
148+
changeNumber: 123,
149+
status: 'ACTIVE',
150+
conditions: [
151+
{
152+
matcherGroup: {
153+
combiner: 'AND',
154+
matchers: [
155+
{
156+
keySelector: null,
157+
matcherType: 'WHITELIST',
158+
negate: false,
159+
userDefinedSegmentMatcherData: null,
160+
whitelistMatcherData: {
161+
whitelist: ['emi-rule-based@split.io']
162+
},
163+
unaryNumericMatcherData: null,
164+
betweenMatcherData: null
165+
}
166+
]
167+
}
168+
}
169+
],
170+
}
140171
};
141172

142173
const mockStorageSync = {
@@ -151,6 +182,11 @@ const mockStorageSync = {
151182
return STORED_SEGMENTS[segmentName] ? STORED_SEGMENTS[segmentName].has(matchingKey) : false;
152183
}
153184
},
185+
largeSegments: {
186+
isInSegment(segmentName: string, matchingKey: string) {
187+
return STORED_LARGE_SEGMENTS[segmentName] ? STORED_LARGE_SEGMENTS[segmentName].has(matchingKey) : false;
188+
}
189+
},
154190
rbSegments: {
155191
get(rbsegmentName: string) {
156192
return STORED_RBSEGMENTS[rbsegmentName];
@@ -170,6 +206,11 @@ const mockStorageAsync = {
170206
return Promise.resolve(STORED_SEGMENTS[segmentName] ? STORED_SEGMENTS[segmentName].has(matchingKey) : false);
171207
}
172208
},
209+
largeSegments: {
210+
isInSegment(segmentName: string, matchingKey: string) {
211+
return Promise.resolve(STORED_LARGE_SEGMENTS[segmentName] ? STORED_LARGE_SEGMENTS[segmentName].has(matchingKey) : false);
212+
}
213+
},
173214
rbSegments: {
174215
get(rbsegmentName: string) {
175216
return Promise.resolve(STORED_RBSEGMENTS[rbsegmentName]);
@@ -192,18 +233,28 @@ describe.each([
192233
value: 'depend_on_mauro_rule_based_segment'
193234
} as IMatcherDto, mockStorage)!;
194235

195-
[matcher, dependentMatcher].forEach(async matcher => {
236+
[matcher, dependentMatcher].forEach(async (matcher) => {
196237

197238
// should return false if the provided key is excluded (even if some condition is met)
198239
let match = matcher({ key: 'mauro@split.io', attributes: { location: 'mdp' } }, evaluateFeature);
199240
expect(thenable(match)).toBe(isAsync);
200241
expect(await match).toBe(false);
201242

202-
// should return false if the provided key is in some excluded segment (even if some condition is met)
243+
// should return false if the provided key is in some excluded standard segment (even if some condition is met)
203244
match = matcher({ key: 'emi@split.io', attributes: { location: 'tandil' } }, evaluateFeature);
204245
expect(thenable(match)).toBe(isAsync);
205246
expect(await match).toBe(false);
206247

248+
// should return false if the provided key is in some excluded large segment (even if some condition is met)
249+
match = matcher({ key: 'emi-large@split.io', attributes: { location: 'tandil' } }, evaluateFeature);
250+
expect(thenable(match)).toBe(isAsync);
251+
expect(await match).toBe(false);
252+
253+
// should return false if the provided key is in some excluded rule-based segment (even if some condition is met)
254+
match = matcher({ key: 'emi-rule-based@split.io', attributes: { location: 'tandil' } }, evaluateFeature);
255+
expect(thenable(match)).toBe(isAsync);
256+
expect(await match).toBe(false);
257+
207258
// should return false if doesn't match any condition
208259
match = matcher({ key: 'zeta@split.io' }, evaluateFeature);
209260
expect(thenable(match)).toBe(isAsync);

src/evaluator/matchers/rbsegment.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@ export function ruleBasedSegmentMatcherContext(segmentName: string, storage: ISt
3535

3636
if (excluded.keys && excluded.keys.indexOf(matchingKey) !== -1) return true;
3737

38-
const isInSegment = (excluded.segments || []).map(segment => {
39-
return storage.segments.isInSegment(segment.name, matchingKey);
38+
const isInSegment = (excluded.segments || []).map(({ type, name }) => {
39+
return type === 'standard' ?
40+
storage.segments.isInSegment(name, matchingKey) :
41+
type === 'rule-based' ?
42+
ruleBasedSegmentMatcherContext(name, storage, log)({ key, attributes }, splitEvaluator) :
43+
type === 'large' && (storage as IStorageSync).largeSegments ?
44+
(storage as IStorageSync).largeSegments!.isInSegment(name, matchingKey) :
45+
false;
4046
});
4147

4248
return isInSegment.length && thenable(isInSegment[0]) ?

0 commit comments

Comments
 (0)