mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Merge pull request #30232 from overleaf/ar/convert-clsi-to-es-modules
[clsi] convert to ES modules GitOrigin-RevId: fb7fa52cc8f678ee31be352e62a5dff95e88008b
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
import { expect, describe, it, vi } from 'vitest'
|
||||
import StatsManager from '../../../app/js/StatsManager.js'
|
||||
|
||||
const { sampleByHash, sampleRequest } = StatsManager
|
||||
|
||||
// Mocks allow us to import Metrics.js twice without getting errors.
|
||||
vi.mock('@overleaf/metrics', () => ({
|
||||
prom: {
|
||||
Gauge: vi.fn(),
|
||||
Counter: vi.fn(),
|
||||
Histogram: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
describe('StatsManager', function () {
|
||||
describe('sampleByHash', function () {
|
||||
it('should always return false for a sample percentage of 0', function () {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const key = `test-key-${i}`
|
||||
expect(sampleByHash(key, 0), `key ${key} should be false`).to.be.false
|
||||
}
|
||||
})
|
||||
|
||||
it('should always return false for a negative sample percentage', function () {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const key = `test-key-${i}`
|
||||
expect(sampleByHash(key, -10), `key ${key} should be false`).to.be.false
|
||||
}
|
||||
})
|
||||
|
||||
it('should always return true for a sample percentage of 100', function () {
|
||||
// This isn't strictly true, if the hash is exactly 0xffffffff, then the percentile is 100
|
||||
// and 100 < 100 is false. But the chances of that are 1 in 4 billion.
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const key = `test-key-${i}`
|
||||
expect(sampleByHash(key, 100), `key ${key} should be true`).to.be.true
|
||||
}
|
||||
})
|
||||
|
||||
it('should return the expected number of results for a sample percentage of 75', function () {
|
||||
// This isn't strictly true, if the hash is exactly 0xffffffff, then the percentile is 100
|
||||
// and 100 < 100 is false. But the chances of that are 1 in 4 billion.
|
||||
let count = 0
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const key = `test-key-${i}`
|
||||
count += sampleByHash(key, 75) ? 1 : 0
|
||||
}
|
||||
// Actual result is 74, it's deterministic but the test allows the algorithm to change
|
||||
expect(count).to.be.within(70, 80)
|
||||
})
|
||||
|
||||
it('should return true when the hash is within the sample percentage', function () {
|
||||
// The MD5 hash of 'test-key-in' gives a percentile of 13
|
||||
const key = 'test-key-in'
|
||||
const percentage = 40
|
||||
expect(sampleByHash(key, percentage)).to.be.true
|
||||
})
|
||||
|
||||
it('should return false when the hash is outside the sample percentage', function () {
|
||||
// The MD5 hash of 'test-key-outer' gives a percentile of 47
|
||||
const key = 'test-key-outer'
|
||||
const percentage = 40
|
||||
expect(sampleByHash(key, percentage)).to.be.false
|
||||
})
|
||||
|
||||
it('should produce consistent results for the same key', function () {
|
||||
const key = 'consistent-key'
|
||||
const percentage = 50
|
||||
const result1 = sampleByHash(key, percentage)
|
||||
const result2 = sampleByHash(key, percentage)
|
||||
expect(result1).to.equal(result2)
|
||||
})
|
||||
|
||||
it('should handle different keys correctly', function () {
|
||||
// MD5('key1') => percentile 76
|
||||
// MD5('key2') => percentile 47
|
||||
expect(sampleByHash('key1', 80)).to.be.true
|
||||
expect(sampleByHash('key1', 70)).to.be.false
|
||||
expect(sampleByHash('key2', 50)).to.be.true
|
||||
expect(sampleByHash('key2', 40)).to.be.false
|
||||
})
|
||||
|
||||
it('should be monotonic with respect to percentage', function () {
|
||||
const key = 'test-key'
|
||||
const percentile = 32
|
||||
for (let i = 0; i <= 100; i++) {
|
||||
const result = sampleByHash(key, i)
|
||||
if (i <= percentile) {
|
||||
expect(result, `percentage ${i} should be false`).to.be.false
|
||||
} else {
|
||||
expect(result, `percentage ${i} should be true`).to.be.true
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('sampleRequest', function () {
|
||||
it('should return undefined if there is no user_id', function () {
|
||||
const request = { metricsOpts: {} }
|
||||
const percentage = 50
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined if the path is health-check', function () {
|
||||
const request = {
|
||||
user_id: 'some-user',
|
||||
metricsOpts: { path: 'health-check' },
|
||||
}
|
||||
const percentage = 100
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined if the path is clsi-perf', function () {
|
||||
const request = {
|
||||
user_id: 'some-user',
|
||||
metricsOpts: { path: 'clsi-perf' },
|
||||
}
|
||||
const percentage = 100
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined for a health-check even if the user would be sampled', function () {
|
||||
const request = {
|
||||
user_id: 'test-key-in', // percentile 13
|
||||
metricsOpts: { path: 'health-check' },
|
||||
}
|
||||
const percentage = 40
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined for clsi-perf even if the user would be sampled', function () {
|
||||
const request = {
|
||||
user_id: 'test-key-in', // percentile 13
|
||||
metricsOpts: { path: 'clsi-perf' },
|
||||
}
|
||||
const percentage = 40
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined if the sampling percentage is 0', function () {
|
||||
const request = { user_id: 'some-user', metricsOpts: {} }
|
||||
const percentage = 0
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should return undefined if the sampling percentage is negative', function () {
|
||||
const request = { user_id: 'some-user', metricsOpts: {} }
|
||||
const percentage = -10
|
||||
expect(sampleRequest(request, percentage)).to.be.undefined
|
||||
})
|
||||
|
||||
it('should sample if metricsOpts has no path', function () {
|
||||
const request = { user_id: 'test-key-in', metricsOpts: {} } // percentile 13
|
||||
const percentage = 40
|
||||
expect(sampleRequest(request, percentage)).to.be.true
|
||||
})
|
||||
|
||||
it('should return true for a request that should be sampled', function () {
|
||||
const request = { user_id: 'test-key-in', metricsOpts: {} } // percentile 13
|
||||
const percentage = 40
|
||||
expect(sampleRequest(request, percentage)).to.be.true
|
||||
})
|
||||
|
||||
it('should return false for a request that should not be sampled', function () {
|
||||
const request = { user_id: 'test-key-outer', metricsOpts: {} } // percentile 47
|
||||
const percentage = 40
|
||||
expect(sampleRequest(request, percentage)).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user