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. 64
      server/spec/models/detection_model.jest.ts
  2. 46
      server/src/models/detection_model.ts

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

@ -5,29 +5,48 @@ import * as Detection from '../../src/models/detection_model';
import * as _ from 'lodash'; 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); afterEach(clearSpansDB);
describe('insertSpan', () => { describe('insertSpan', () => {
it('should merge spans with the same status', async () => { it('should merge spans with the same status', async () => {
await insertSpans([ /*
{ from: 3, 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 expectedSpans = [ */
{ from: 1, to: 5, status: Detection.DetectionStatus.READY } 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 }
]
},
]; ];
const spansInDB = await Detection.findMany(TEST_ANALYTIC_UNIT_ID, { });
const spansOptions = convertSpansToOptions(spansInDB); for(let step of insertSteps) {
expect(spansOptions).toEqual(expectedSpans); await insertSpans(step.insert);
const spansInDB = await Detection.findMany(TEST_ANALYTIC_UNIT_ID, {});
const spansOptions = convertSpansToOptions(spansInDB);
expect(spansOptions).toEqual(step.expectedAfterInsertion);
}
}); });
@ -47,15 +66,20 @@ describe('insertSpan', () => {
describe('getIntersectedSpans', () => { describe('getIntersectedSpans', () => {
it('should find all intersections with the inserted span', async () => { 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 = [ const testCases = [
{ {
from: 1, to: 5, from: 1, to: 5,
expected: [ expected: [
{ from: 1, to: 3, status: Detection.DetectionStatus.READY }, { 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: [] } { from: 6, to: 7, expected: [] }
] ]

46
server/src/models/detection_model.ts

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

Loading…
Cancel
Save