Browse Source

Detection model fixes (#752)

pull/1/head
rozetko 5 years ago committed by GitHub
parent
commit
d20a3b964a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 60
      server/spec/models/detection_model.jest.ts
  2. 44
      server/src/models/detection_model.ts

60
server/spec/models/detection_model.jest.ts

@ -5,29 +5,48 @@ import * as Detection from '../../src/models/detection_model';
import * as _ from 'lodash';
const INITIAL_SPANS_CONFIGS = [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }
];
beforeEach(async () => {
await insertSpans(INITIAL_SPANS_CONFIGS);
});
afterEach(clearSpansDB);
describe('insertSpan', () => {
it('should merge spans with the same status', async () => {
await insertSpans([
{ from: 3, to: 5, status: Detection.DetectionStatus.READY }
]);
const expectedSpans = [
{ from: 1, to: 5, status: Detection.DetectionStatus.READY }
/*
* Config for test
* insert -- what we want to insert in our test database
* expectedAfterInsertion -- expected database state after insertion
*/
const insertSteps = [
{
insert: [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }
],
expectedAfterInsertion: [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }
]
},
{
insert: [ { from: 5, to: 9, status: Detection.DetectionStatus.RUNNING } ],
expectedAfterInsertion: [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 4, to: 9, status: Detection.DetectionStatus.RUNNING }
]
},
{
insert: [ { from: 2, to: 5, status: Detection.DetectionStatus.READY } ],
expectedAfterInsertion: [
{ from: 1, to: 5, status: Detection.DetectionStatus.READY },
{ from: 4, to: 9, status: Detection.DetectionStatus.RUNNING }
]
},
];
for(let step of insertSteps) {
await insertSpans(step.insert);
const spansInDB = await Detection.findMany(TEST_ANALYTIC_UNIT_ID, {});
const spansOptions = convertSpansToOptions(spansInDB);
expect(spansOptions).toEqual(expectedSpans);
expect(spansOptions).toEqual(step.expectedAfterInsertion);
}
});
@ -47,15 +66,20 @@ describe('insertSpan', () => {
describe('getIntersectedSpans', () => {
it('should find all intersections with the inserted span', async () => {
await insertSpans([
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }
]);
const testCases = [
{
from: 1, to: 5,
expected: [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY },
{ from: 3, to: 4, status: Detection.DetectionStatus.RUNNING }
{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }
]
},
{ from: 4, to: 5, expected: [{ from: 3, to: 4, status: Detection.DetectionStatus.RUNNING }] },
{ from: 4, to: 5, expected: [{ from: 4, to: 5, status: Detection.DetectionStatus.RUNNING }] },
{ from: 6, to: 7, expected: [] }
]

44
server/src/models/detection_model.ts

@ -11,7 +11,7 @@ export enum DetectionStatus {
FAILED = 'FAILED'
}
export type DetectionId = string;
export type SpanId = string;
/**
* Detection-span represents the state of dataset segment:
@ -25,7 +25,7 @@ export class DetectionSpan {
public from: number,
public to: number,
public status: DetectionStatus,
public id?: DetectionId,
public id?: SpanId,
) {
if(analyticUnitId === undefined) {
throw new Error('AnalyticUnitId is undefined');
@ -115,24 +115,40 @@ export async function getIntersectedSpans(
return findMany(analyticUnitId, { status, timeFromLTE: to, timeToGTE: from });
}
export async function insertSpan(span: DetectionSpan) {
export async function insertSpan(span: DetectionSpan): Promise<SpanId> {
let spanToInsert = span.toObject();
const intersections = await getIntersectedSpans(span.analyticUnitId, span.from, span.to, span.status);
if(!_.isEmpty(intersections) && span.status === DetectionStatus.READY) {
let minFrom: number = _.minBy(intersections, 'from').from;
minFrom = Math.min(span.from, minFrom);
let maxTo: number = _.maxBy(intersections, 'to').to;
maxTo = Math.max(span.to, maxTo);
const intersections = await getIntersectedSpans(span.analyticUnitId, span.from, span.to);
if(_.isEmpty(intersections)) {
return db.insertOne(spanToInsert);
}
const spansWithSameStatus = intersections.filter(
intersectedSpan => intersectedSpan.status === span.status
);
const spansInside = await findMany(span.analyticUnitId, { timeFromGTE: minFrom, timeToLTE: maxTo });
const toRemove = _.concat(intersections.map(span => span.id), spansInside.map(span => span.id));
let from = span.from;
let to = span.to;
await db.removeMany(toRemove);
if(!_.isEmpty(spansWithSameStatus)) {
let minFrom = _.minBy(spansWithSameStatus, s => s.from).from;
from = Math.min(from, minFrom);
spanToInsert = new DetectionSpan(span.analyticUnitId, minFrom, maxTo, span.status).toObject();
let maxTo = _.maxBy(spansWithSameStatus, s => s.to).to;
to = Math.max(to, maxTo);
}
const spansInside = intersections.filter(
intersectedSpan => intersectedSpan.from >= span.from && intersectedSpan.to <= span.to
);
const spanIdsToRemove = _.concat(
spansWithSameStatus.map(s => s.id),
spansInside.map(s => s.id)
);
await db.removeMany(spanIdsToRemove);
spanToInsert = new DetectionSpan(span.analyticUnitId, from, to, span.status).toObject();
return db.insertOne(spanToInsert);
}

Loading…
Cancel
Save