Skip to content

Commit

Permalink
feat: allow to pass measurement id in the magic field
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-yarmosh committed Dec 7, 2023
1 parent 0ff18fc commit e649720
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/measurement/schema/location-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const schema = Joi.alternatives().try(
city: Joi.string().min(1).max(128).lowercase().custom(normalizeValue),
network: Joi.string().min(1).max(128).lowercase().custom(normalizeValue),
asn: Joi.number().integer().positive(),
magic: Joi.string().min(1).lowercase().custom(normalizeValue),
magic: Joi.string().min(1).custom(normalizeValue),
tags: Joi.array().items(Joi.string().min(1).max(128).lowercase().custom(normalizeValue)),
limit: Joi.number().min(1).max(measurementConfig.limits.location).when(Joi.ref('/limit'), {
is: Joi.exist(),
Expand Down
4 changes: 2 additions & 2 deletions src/probe/probes-location-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ export class ProbesLocationFilter {
}

static getExactIndexPosition (probe: Probe, value: string) {
return probe.index.findIndex(category => category.some(index => index === value.replaceAll('-', ' ').trim()));
return probe.index.findIndex(category => category.some(index => index === value.toLowerCase().replaceAll('-', ' ').trim()));
}

static getIndexPosition (probe: Probe, value: string) {
return probe.index.findIndex(category => category.some(index => index.includes(value.replaceAll('-', ' ').trim())));
return probe.index.findIndex(category => category.some(index => index.includes(value.toLowerCase().replaceAll('-', ' ').trim())));
}

static hasTag (probe: Probe, tag: string) {
Expand Down
36 changes: 22 additions & 14 deletions src/probe/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,34 @@ export class ProbeRouter {
globalLimit = 1,
) {
const connectedProbes = await this.fetchProbes();
let onlineProbesMap: Map<number, Probe>;
let allProbes: (Probe | OfflineProbe)[] = [];

if (typeof locations === 'string') {
({ onlineProbesMap, allProbes } = await this.findWithMeasurementId(connectedProbes, locations));
} else if (locations.some(l => l.limit)) {
return this.findWithMeasurementId(connectedProbes, locations);
}

if (locations.some(l => l.limit)) {
const filtered = this.findWithLocationLimit(connectedProbes, locations);
allProbes = filtered;
onlineProbesMap = new Map(filtered.entries());
} else if (locations.length > 0) {
return this.processFiltered(filtered, connectedProbes, locations);
}

if (locations.length > 0) {
const filtered = this.findWithGlobalLimit(connectedProbes, locations, globalLimit);
allProbes = filtered;
onlineProbesMap = new Map(filtered.entries());
} else {
const filtered = this.findGloballyDistributed(connectedProbes, globalLimit);
allProbes = filtered;
onlineProbesMap = new Map(filtered.entries());
return this.processFiltered(filtered, connectedProbes, locations);
}

return { onlineProbesMap, allProbes };
const filtered = this.findGloballyDistributed(connectedProbes, globalLimit);
return this.processFiltered(filtered, connectedProbes, locations);
}

private async processFiltered (filtered: Probe[], connectedProbes: Probe[], locations: LocationWithLimit[]) {
if (filtered.length === 0 && locations.length === 1 && locations[0]?.magic) {
return this.findWithMeasurementId(connectedProbes, locations[0].magic);
}

return {
allProbes: filtered,
onlineProbesMap: new Map(filtered.entries()),
};
}

private async fetchProbes (): Promise<Probe[]> {
Expand Down
37 changes: 37 additions & 0 deletions test/tests/integration/measurement/create-measurement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,43 @@ describe('Create measurement', () => {
});
});

it('should create measurement with another measurement id location passed in magic field', async () => {
let id;
await requestAgent.post('/v1/measurements')
.send({
type: 'ping',
target: 'example.com',
})
.expect(202)
.expect((response) => {
id = response.body.id;
});

let id2;
await requestAgent.post('/v1/measurements')
.send({
type: 'ping',
target: 'example.com',
locations: [{ magic: id }],
})
.expect(202)
.expect((response) => {
expect(response.body.id).to.exist;
expect(response.header.location).to.exist;
expect(response.body.probesCount).to.equal(1);
expect(response).to.matchApiSchema();
id2 = response.body.id;
});

await requestAgent.get(`/v1/measurements/${id2}`)
.expect(200)
.expect((response) => {
expect(response.body.limit).to.not.exist;
expect(response.body.locations).to.not.exist;
expect(response).to.matchApiSchema();
});
});

it('should respond with error if there is no requested measurement id', async () => {
await requestAgent.post('/v1/measurements')
.send({
Expand Down
2 changes: 1 addition & 1 deletion test/tests/unit/measurement/schema/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ describe('command schema', async () => {

const valid = locationSchema.validate(input);

expect(valid.value![0].magic).to.equal('petah tiqva');
expect(valid.value![0].magic).to.equal('Petah Tiqva');
});

it('should correct region value (lowercase)', () => {
Expand Down
53 changes: 46 additions & 7 deletions test/tests/unit/probe/router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('probe router', () => {
const geoLookupMock = sinon.stub();
const getRegionMock = sinon.stub();
const store = {
getMeasurementIps: sinon.stub(),
getMeasurementIps: sinon.stub().resolves([]),
getMeasurement: sinon.stub(),
};
const router = new ProbeRouter(fetchSocketsMock, store as unknown as MeasurementStore);
Expand Down Expand Up @@ -70,12 +70,9 @@ describe('probe router', () => {

beforeEach(() => {
sandbox.reset();
});

afterEach(() => {
geoLookupMock.reset();
fetchSocketsMock.reset();
getRegionMock.reset();
sinon.resetHistory();
sinon.resetBehavior();
store.getMeasurementIps.resolves([]);
});

after(() => {
Expand Down Expand Up @@ -920,6 +917,48 @@ describe('probe router', () => {
expect(onlineProbesMap.get(0)?.location.country).to.equal('PL');
});

it('should find probes by prev measurement id in magic field', async () => {
const sockets: Array<DeepPartial<RemoteProbeSocket>> = [
await buildSocket('socket-1', { continent: 'EU', country: 'PL' }),
];
fetchSocketsMock.resolves(sockets as never);
store.getMeasurementIps.resolves([ '1.2.3.4' ]);

store.getMeasurement.resolves({
results: [{
probe: {
continent: 'EU',
country: 'PL',
city: 'Warsaw',
network: 'Liberty Global B.V.',
tags: [],
},
}],
});

const { onlineProbesMap, allProbes } = await router.findMatchingProbes([{ magic: 'measurementid' }]);

expect(store.getMeasurementIps.args[0]).to.deep.equal([ 'measurementid' ]);
expect(store.getMeasurement.callCount).to.equal(0);
expect(allProbes[0]!.location.country).to.equal('PL');
expect(allProbes[0]!.status).to.equal('ready');
expect(onlineProbesMap.get(0)?.location.country).to.equal('PL');
});

it('should not find probes without errors by prev measurement id in magic field if no such measurement found', async () => {
const sockets: Array<DeepPartial<RemoteProbeSocket>> = [
await buildSocket('socket-1', { continent: 'EU', country: 'PL' }),
];
fetchSocketsMock.resolves(sockets as never);

const { onlineProbesMap, allProbes } = await router.findMatchingProbes([{ magic: 'measurementid' }]);

expect(store.getMeasurementIps.args[0]).to.deep.equal([ 'measurementid' ]);
expect(store.getMeasurement.callCount).to.equal(0);
expect(allProbes.length).to.equal(0);
expect(onlineProbesMap.size).to.equal(0);
});

it('should replace non-connected probes with offline probe data', async () => {
const sockets: Array<DeepPartial<RemoteProbeSocket>> = [
await buildSocket('socket-1', { continent: 'EU', country: 'PL' }),
Expand Down

0 comments on commit e649720

Please sign in to comment.