-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: update message handling (#614)
- Loading branch information
1 parent
4e29af6
commit bee1440
Showing
12 changed files
with
162 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import config from 'config'; | ||
import TTLCache from '@isaacs/ttlcache'; | ||
import { type RedisCluster, getMeasurementRedisClient } from './redis/measurement-client.js'; | ||
|
||
export class ProbeValidator { | ||
private readonly measurementIdToTests = new TTLCache<string, Map<string, string>>({ | ||
ttl: (config.get<number>('measurement.timeout') + 30) * 1000, | ||
}); | ||
|
||
constructor (private readonly redis: RedisCluster) {} | ||
|
||
addValidIds (measurementId: string, testId: string, probeUuid: string): void { | ||
const measurement = this.measurementIdToTests.get(measurementId); | ||
|
||
if (!measurement) { | ||
this.measurementIdToTests.set(measurementId, new Map([ [ testId, probeUuid ] ])); | ||
} else { | ||
measurement.set(testId, probeUuid); | ||
} | ||
} | ||
|
||
async validateProbe (measurementId: string, testId: string, probeUuid: string): Promise<void> { | ||
const measurement = this.measurementIdToTests.get(measurementId); | ||
let probeId = measurement && measurement.get(testId); | ||
|
||
if (!probeId) { | ||
probeId = await this.getProbeIdFromRedis(measurementId, testId); | ||
} | ||
|
||
if (!probeId) { | ||
throw new Error(`Probe ID not found for measurement ID: ${measurementId}, test ID: ${testId}`); | ||
} else if (probeId !== probeUuid) { | ||
throw new Error(`Probe ID is wrong for measurement ID: ${measurementId}, test ID: ${testId}. Expected: ${probeId}, actual: ${probeUuid}`); | ||
} | ||
} | ||
|
||
async getProbeIdFromRedis (measurementId: string, testId: string) { | ||
return this.redis.hGet('gp:test-to-probe', `${measurementId}_${testId}`); | ||
} | ||
} | ||
|
||
let probeValidator: ProbeValidator; | ||
|
||
export const getProbeValidator = () => { | ||
if (!probeValidator) { | ||
probeValidator = new ProbeValidator(getMeasurementRedisClient()); | ||
} | ||
|
||
return probeValidator; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
import type { Probe } from '../../probe/types.js'; | ||
import type { MeasurementAckMessage } from '../types.js'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export const handleMeasurementAck = (_probe: Probe) => async (_data: MeasurementAckMessage, ack: () => void): Promise<void> => { | ||
export const handleMeasurementAck = (_probe: Probe) => async (_data: null, ack: () => void): Promise<void> => { | ||
ack(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
import { getMeasurementRunner } from '../runner.js'; | ||
import type { Probe } from '../../probe/types.js'; | ||
import type { MeasurementProgressMessage } from '../types.js'; | ||
import { getMeasurementRunner } from '../runner.js'; | ||
import { getProbeValidator } from '../../lib/probe-validator.js'; | ||
|
||
const runner = getMeasurementRunner(); | ||
|
||
export const handleMeasurementProgress = async (data: MeasurementProgressMessage): Promise<void> => { | ||
export const handleMeasurementProgress = (probe: Probe) => async (data: MeasurementProgressMessage): Promise<void> => { | ||
await getProbeValidator().validateProbe(data.measurementId, data.testId, probe.uuid); | ||
await runner.recordProgress(data); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import type { Probe } from '../../probe/types.js'; | ||
import { getProbeValidator } from '../../lib/probe-validator.js'; | ||
import { MeasurementRequestMessage } from '../types.js'; | ||
|
||
export const listenMeasurementRequest = (probe: Probe) => (event: string, data: unknown) => { | ||
if (event !== 'probe:measurement:request') { | ||
return; | ||
} | ||
|
||
const message = data as MeasurementRequestMessage; | ||
getProbeValidator().addValidIds(message.measurementId, message.testId, probe.uuid); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
import type { Probe } from '../../probe/types.js'; | ||
import type { MeasurementResultMessage } from '../types.js'; | ||
import { getMeasurementRunner } from '../runner.js'; | ||
import { getProbeValidator } from '../../lib/probe-validator.js'; | ||
|
||
const runner = getMeasurementRunner(); | ||
|
||
export const handleMeasurementResult = async (data: MeasurementResultMessage): Promise<void> => { | ||
export const handleMeasurementResult = (probe: Probe) => async (data: MeasurementResultMessage): Promise<void> => { | ||
await getProbeValidator().validateProbe(data.measurementId, data.testId, probe.uuid); | ||
await runner.recordResult(data); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { expect } from 'chai'; | ||
import * as sinon from 'sinon'; | ||
import { ProbeValidator } from '../../../src/lib/probe-validator.js'; | ||
import { RedisCluster } from '../../../src/lib/redis/shared.js'; | ||
|
||
describe('ProbeValidator', () => { | ||
const sandbox = sinon.createSandbox(); | ||
const redis = { hGet: sandbox.stub() }; | ||
const probeValidator = new ProbeValidator(redis as unknown as RedisCluster); | ||
|
||
beforeEach(() => { | ||
redis.hGet.resolves(undefined); | ||
}); | ||
|
||
it('should pass through valid probe id', async () => { | ||
probeValidator.addValidIds('measurement-id', 'test-id-0', 'probe-uuid-0'); | ||
probeValidator.addValidIds('measurement-id', 'test-id-1', 'probe-uuid-1'); | ||
await probeValidator.validateProbe('measurement-id', 'test-id-0', 'probe-uuid-0'); | ||
await probeValidator.validateProbe('measurement-id', 'test-id-1', 'probe-uuid-1'); | ||
}); | ||
|
||
it('should throw for invalid probe id', async () => { | ||
probeValidator.addValidIds('measurement-id', 'test-id', 'probe-uuid'); | ||
const error = await probeValidator.validateProbe('measurement-id', 'test-id', 'invalid-probe-uuid').catch(err => err); | ||
expect(error.message).to.equal('Probe ID is wrong for measurement ID: measurement-id, test ID: test-id. Expected: probe-uuid, actual: invalid-probe-uuid'); | ||
}); | ||
|
||
it('should throw for missing key', async () => { | ||
const error = await probeValidator.validateProbe('missing-measurement-id', 'test-id', 'probe-uuid').catch(err => err); | ||
expect(error.message).to.equal('Probe ID not found for measurement ID: missing-measurement-id, test ID: test-id'); | ||
}); | ||
|
||
it('should search key in redis if not found locally', async () => { | ||
redis.hGet.resolves('probe-uuid'); | ||
await probeValidator.validateProbe('only-redis-measurement-id', 'test-id', 'probe-uuid'); | ||
}); | ||
|
||
it('should throw if redis probe id is different', async () => { | ||
redis.hGet.resolves('different-probe-uuid'); | ||
const error = await probeValidator.validateProbe('only-redis-measurement-id', 'test-id', 'probe-uuid').catch(err => err); | ||
expect(error.message).to.equal('Probe ID is wrong for measurement ID: only-redis-measurement-id, test ID: test-id. Expected: different-probe-uuid, actual: probe-uuid'); | ||
}); | ||
}); |