Skip to content

Commit c289e63

Browse files
committed
Update insertToFlagBuffer and unit test it
1 parent 548858d commit c289e63

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed

packages/utils/src/flags.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,32 @@ import type { FeatureFlag } from '@sentry/types';
66
* from oldest to newest.
77
*/
88

9-
export const FLAG_BUFFER_SIZE = 100;
9+
export const DEFAULT_MAX_SIZE = 100;
1010

1111
/**
12-
* Insert into a FeatureFlag array while maintaining ordered LRU properties.
13-
* After inserting:
14-
* - The flag is guaranteed to be at the end of `flags`.
12+
* Insert into a FeatureFlag array while maintaining ordered LRU properties. Not
13+
* thread-safe. After inserting:
14+
* - `flags` is sorted in order of recency, with the newest flag at the end.
1515
* - No other flags with the same name exist in `flags`.
16-
* - The length of `flags` does not exceed FLAG_BUFFER_SIZE. If needed, the
17-
* oldest inserted flag is evicted.
16+
* - The length of `flags` does not exceed `maxSize`. The oldest flag is evicted
17+
* as needed.
18+
*
19+
* @param flags The array to insert into.
20+
* @param name Name of the feature flag to insert.
21+
* @param value Value of the feature flag.
22+
* @param maxSize Max number of flags the buffer should store. It's recommended
23+
* to keep this consistent across insertions. Default is DEFAULT_MAX_SIZE
1824
*/
19-
export function insertToFlagBuffer(flags: FeatureFlag[], name: string, value: boolean): void {
25+
export function insertToFlagBuffer(
26+
flags: FeatureFlag[],
27+
name: string,
28+
value: boolean,
29+
maxSize: number = DEFAULT_MAX_SIZE,
30+
): void {
31+
if (flags.length > maxSize) {
32+
throw Error(`insertToFlagBuffer called on a buffer larger than the given maxSize=${maxSize}`);
33+
}
34+
2035
// Check if the flag is already in the buffer - O(n)
2136
const index = flags.findIndex(f => f.flag === name);
2237

@@ -25,7 +40,7 @@ export function insertToFlagBuffer(flags: FeatureFlag[], name: string, value: bo
2540
flags.splice(index, 1);
2641
}
2742

28-
if (flags.length === FLAG_BUFFER_SIZE) {
43+
if (flags.length === maxSize) {
2944
// If at capacity, pop the earliest flag - O(n)
3045
flags.shift();
3146
}

packages/utils/test/flags.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
import { insertToFlagBuffer } from '../src';
3+
import type { FeatureFlag } from '@sentry/types';
4+
5+
describe('flags', () => {
6+
describe('insertToFlagBuffer()', () => {
7+
it('maintains ordering and evicts the oldest entry', () => {
8+
const buffer: FeatureFlag[] = [];
9+
const maxSize = 3;
10+
insertToFlagBuffer(buffer, 'feat1', true, maxSize);
11+
insertToFlagBuffer(buffer, 'feat2', true, maxSize);
12+
insertToFlagBuffer(buffer, 'feat3', true, maxSize);
13+
insertToFlagBuffer(buffer, 'feat4', true, maxSize);
14+
15+
expect(buffer).toEqual([
16+
{ flag: 'feat2', result: true },
17+
{ flag: 'feat3', result: true },
18+
{ flag: 'feat4', result: true },
19+
]);
20+
});
21+
22+
it('does not duplicate same-name flags and updates order and values', () => {
23+
const buffer: FeatureFlag[] = [];
24+
const maxSize = 3;
25+
insertToFlagBuffer(buffer, 'feat1', true, maxSize);
26+
insertToFlagBuffer(buffer, 'feat2', true, maxSize);
27+
insertToFlagBuffer(buffer, 'feat3', true, maxSize);
28+
insertToFlagBuffer(buffer, 'feat3', false, maxSize);
29+
insertToFlagBuffer(buffer, 'feat1', false, maxSize);
30+
31+
expect(buffer).toEqual([
32+
{ flag: 'feat2', result: true },
33+
{ flag: 'feat3', result: false },
34+
{ flag: 'feat1', result: false },
35+
]);
36+
});
37+
38+
it('does not allocate unnecessary space', () => {
39+
const buffer: FeatureFlag[] = [];
40+
const maxSize = 1000;
41+
insertToFlagBuffer(buffer, 'feat1', true, maxSize);
42+
insertToFlagBuffer(buffer, 'feat2', true, maxSize);
43+
44+
expect(buffer).toEqual([
45+
{ flag: 'feat1', result: true },
46+
{ flag: 'feat2', result: true },
47+
]);
48+
});
49+
50+
it('errors when maxSize is less than current buffer size', () => {
51+
const buffer: FeatureFlag[] = [
52+
{ flag: 'feat1', result: true },
53+
{ flag: 'feat2', result: true },
54+
];
55+
56+
expect(() => insertToFlagBuffer(buffer, 'feat1', true, 1)).toThrowError();
57+
expect(() => insertToFlagBuffer(buffer, 'feat1', true, -2)).toThrowError();
58+
});
59+
})
60+
})

0 commit comments

Comments
 (0)