Skip to content

Commit 6114533

Browse files
Junaed/fssdk 1119 test js to ts (#1002)
1 parent 49c6b8a commit 6114533

File tree

11 files changed

+2039
-43
lines changed

11 files changed

+2039
-43
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { expect, describe, it } from 'vitest';
17+
import { sprintf } from '../../utils/fns';
18+
import { generateBucketValue } from './bucket_value_generator';
19+
import { OptimizelyError } from '../../error/optimizly_error';
20+
import { INVALID_BUCKETING_ID } from 'error_message';
21+
22+
describe('generateBucketValue', () => {
23+
it('should return a bucket value for different inputs', () => {
24+
const experimentId = 1886780721;
25+
const bucketingKey1 = sprintf('%s%s', 'ppid1', experimentId);
26+
const bucketingKey2 = sprintf('%s%s', 'ppid2', experimentId);
27+
const bucketingKey3 = sprintf('%s%s', 'ppid2', 1886780722);
28+
const bucketingKey4 = sprintf('%s%s', 'ppid3', experimentId);
29+
30+
expect(generateBucketValue(bucketingKey1)).toBe(5254);
31+
expect(generateBucketValue(bucketingKey2)).toBe(4299);
32+
expect(generateBucketValue(bucketingKey3)).toBe(2434);
33+
expect(generateBucketValue(bucketingKey4)).toBe(5439);
34+
});
35+
36+
it('should return an error if it cannot generate the hash value', () => {
37+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
38+
// @ts-ignore
39+
expect(() => generateBucketValue(null)).toThrowError(
40+
new OptimizelyError(INVALID_BUCKETING_ID)
41+
);
42+
});
43+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import murmurhash from 'murmurhash';
17+
import { INVALID_BUCKETING_ID } from 'error_message';
18+
import { OptimizelyError } from '../../error/optimizly_error';
19+
20+
const HASH_SEED = 1;
21+
const MAX_HASH_VALUE = Math.pow(2, 32);
22+
const MAX_TRAFFIC_VALUE = 10000;
23+
24+
/**
25+
* Helper function to generate bucket value in half-closed interval [0, MAX_TRAFFIC_VALUE)
26+
* @param {string} bucketingKey String value for bucketing
27+
* @return {number} The generated bucket value
28+
* @throws If bucketing value is not a valid string
29+
*/
30+
export const generateBucketValue = function(bucketingKey: string): number {
31+
try {
32+
// NOTE: the mmh library already does cast the hash value as an unsigned 32bit int
33+
// https://github.com/perezd/node-murmurhash/blob/master/murmurhash.js#L115
34+
const hashValue = murmurhash.v3(bucketingKey, HASH_SEED);
35+
const ratio = hashValue / MAX_HASH_VALUE;
36+
return Math.floor(ratio * MAX_TRAFFIC_VALUE);
37+
} catch (ex) {
38+
throw new OptimizelyError(INVALID_BUCKETING_ID, bucketingKey, ex.message);
39+
}
40+
};

0 commit comments

Comments
 (0)