mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
feat(slo): Add internal slo data (#143888)
* Add duration format method * Add internal slo fields * Update test
This commit is contained in:
parent
3150520ac4
commit
2d7f5c904a
12 changed files with 359 additions and 132 deletions
|
@ -20,6 +20,9 @@ export const getSLOMappingsTemplate = (name: string) => ({
|
|||
type: 'keyword',
|
||||
ignore_above: 256,
|
||||
},
|
||||
revision: {
|
||||
type: 'long',
|
||||
},
|
||||
numerator: {
|
||||
type: 'long',
|
||||
},
|
||||
|
@ -29,6 +32,25 @@ export const getSLOMappingsTemplate = (name: string) => ({
|
|||
context: {
|
||||
type: 'flattened',
|
||||
},
|
||||
_internal: {
|
||||
properties: {
|
||||
name: { type: 'keyword', ignore_above: 256 },
|
||||
budgeting_method: { type: 'keyword' },
|
||||
objective: {
|
||||
properties: {
|
||||
target: { type: 'double' },
|
||||
timeslice_target: { type: 'double' },
|
||||
timeslice_window: { type: 'keyword' },
|
||||
},
|
||||
},
|
||||
time_window: {
|
||||
properties: {
|
||||
duration: { type: 'keyword' },
|
||||
is_rolling: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -57,6 +57,31 @@ Object {
|
|||
"field": "@timestamp",
|
||||
},
|
||||
},
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.budgeting_method",
|
||||
},
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.name",
|
||||
},
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.objective.target",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.duration",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.is_rolling",
|
||||
},
|
||||
},
|
||||
"slo.id": Object {
|
||||
"terms": Object {
|
||||
"field": "slo.id",
|
||||
|
@ -106,6 +131,36 @@ Object {
|
|||
},
|
||||
},
|
||||
"runtime_mappings": Object {
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"script": Object {
|
||||
"source": "emit('occurrences')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"script": Object {
|
||||
"source": "emit('irrelevant')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"script": Object {
|
||||
"source": "emit(0.999)",
|
||||
},
|
||||
"type": "double",
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"script": Object {
|
||||
"source": "emit('7d')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"script": Object {
|
||||
"source": "emit(true)",
|
||||
},
|
||||
"type": "boolean",
|
||||
},
|
||||
"slo.id": Object {
|
||||
"script": Object {
|
||||
"source": Any<String>,
|
||||
|
|
|
@ -62,6 +62,31 @@ Object {
|
|||
"field": "@timestamp",
|
||||
},
|
||||
},
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.budgeting_method",
|
||||
},
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.name",
|
||||
},
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.objective.target",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.duration",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.is_rolling",
|
||||
},
|
||||
},
|
||||
"slo.id": Object {
|
||||
"terms": Object {
|
||||
"field": "slo.id",
|
||||
|
@ -111,6 +136,36 @@ Object {
|
|||
},
|
||||
},
|
||||
"runtime_mappings": Object {
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"script": Object {
|
||||
"source": "emit('occurrences')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"script": Object {
|
||||
"source": "emit('irrelevant')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"script": Object {
|
||||
"source": "emit(0.999)",
|
||||
},
|
||||
"type": "double",
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"script": Object {
|
||||
"source": "emit('7d')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"script": Object {
|
||||
"source": "emit(true)",
|
||||
},
|
||||
"type": "boolean",
|
||||
},
|
||||
"slo.id": Object {
|
||||
"script": Object {
|
||||
"source": Any<String>,
|
||||
|
|
|
@ -141,6 +141,31 @@ Object {
|
|||
"field": "@timestamp",
|
||||
},
|
||||
},
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.budgeting_method",
|
||||
},
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.name",
|
||||
},
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.objective.target",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.duration",
|
||||
},
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"terms": Object {
|
||||
"field": "slo._internal.time_window.is_rolling",
|
||||
},
|
||||
},
|
||||
"slo.id": Object {
|
||||
"terms": Object {
|
||||
"field": "slo.id",
|
||||
|
@ -171,6 +196,36 @@ Object {
|
|||
},
|
||||
},
|
||||
"runtime_mappings": Object {
|
||||
"slo._internal.budgeting_method": Object {
|
||||
"script": Object {
|
||||
"source": "emit('occurrences')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.name": Object {
|
||||
"script": Object {
|
||||
"source": "emit('irrelevant')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.objective.target": Object {
|
||||
"script": Object {
|
||||
"source": "emit(0.999)",
|
||||
},
|
||||
"type": "double",
|
||||
},
|
||||
"slo._internal.time_window.duration": Object {
|
||||
"script": Object {
|
||||
"source": "emit('7d')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
"slo._internal.time_window.is_rolling": Object {
|
||||
"script": Object {
|
||||
"source": "emit(true)",
|
||||
},
|
||||
"type": "boolean",
|
||||
},
|
||||
"slo.id": Object {
|
||||
"script": Object {
|
||||
"source": Any<String>,
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
AggregationsCalendarInterval,
|
||||
MappingRuntimeFieldType,
|
||||
TransformPutTransformRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { InvalidTransformError } from '../../../errors';
|
||||
import { ALL_VALUE, apmTransactionDurationIndicatorSchema } from '../../../types/schema';
|
||||
import {
|
||||
|
@ -23,7 +19,7 @@ import { TransformGenerator } from '.';
|
|||
|
||||
const APM_SOURCE_INDEX = 'metrics-apm*';
|
||||
|
||||
export class ApmTransactionDurationTransformGenerator implements TransformGenerator {
|
||||
export class ApmTransactionDurationTransformGenerator extends TransformGenerator {
|
||||
public getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
if (!apmTransactionDurationIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
|
@ -33,7 +29,7 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera
|
|||
this.buildTransformId(slo),
|
||||
this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(),
|
||||
this.buildGroupBy(),
|
||||
this.buildCommonGroupBy(slo),
|
||||
this.buildAggregations(slo.indicator)
|
||||
);
|
||||
}
|
||||
|
@ -78,20 +74,7 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera
|
|||
|
||||
return {
|
||||
index: APM_SOURCE_INDEX,
|
||||
runtime_mappings: {
|
||||
'slo.id': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.id}')`,
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
type: 'long' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.revision})`,
|
||||
},
|
||||
},
|
||||
},
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
@ -114,27 +97,6 @@ export class ApmTransactionDurationTransformGenerator implements TransformGenera
|
|||
};
|
||||
}
|
||||
|
||||
private buildGroupBy() {
|
||||
return {
|
||||
'slo.id': {
|
||||
terms: {
|
||||
field: 'slo.id',
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
terms: {
|
||||
field: 'slo.revision',
|
||||
},
|
||||
},
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
calendar_interval: '1m' as AggregationsCalendarInterval,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildAggregations(indicator: APMTransactionDurationIndicator) {
|
||||
const truncatedThreshold = Math.trunc(indicator.params['threshold.us']);
|
||||
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
AggregationsCalendarInterval,
|
||||
MappingRuntimeFieldType,
|
||||
TransformPutTransformRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { InvalidTransformError } from '../../../errors';
|
||||
import { ALL_VALUE, apmTransactionErrorRateIndicatorSchema } from '../../../types/schema';
|
||||
import { getSLOTransformTemplate } from '../../../assets/transform_templates/slo_transform_template';
|
||||
|
@ -25,7 +21,7 @@ const APM_SOURCE_INDEX = 'metrics-apm*';
|
|||
const ALLOWED_STATUS_CODES = ['2xx', '3xx', '4xx', '5xx'];
|
||||
const DEFAULT_GOOD_STATUS_CODES = ['2xx', '3xx', '4xx'];
|
||||
|
||||
export class ApmTransactionErrorRateTransformGenerator implements TransformGenerator {
|
||||
export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator {
|
||||
public getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
if (!apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
|
@ -35,7 +31,7 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener
|
|||
this.buildTransformId(slo),
|
||||
this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(),
|
||||
this.buildGroupBy(),
|
||||
this.buildCommonGroupBy(slo),
|
||||
this.buildAggregations(slo, slo.indicator)
|
||||
);
|
||||
}
|
||||
|
@ -80,20 +76,7 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener
|
|||
|
||||
return {
|
||||
index: APM_SOURCE_INDEX,
|
||||
runtime_mappings: {
|
||||
'slo.id': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.id}')`,
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
type: 'long' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.revision})`,
|
||||
},
|
||||
},
|
||||
},
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
@ -116,27 +99,6 @@ export class ApmTransactionErrorRateTransformGenerator implements TransformGener
|
|||
};
|
||||
}
|
||||
|
||||
private buildGroupBy() {
|
||||
return {
|
||||
'slo.id': {
|
||||
terms: {
|
||||
field: 'slo.id',
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
terms: {
|
||||
field: 'slo.revision',
|
||||
},
|
||||
},
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
calendar_interval: '1m' as AggregationsCalendarInterval,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildAggregations(slo: SLO, indicator: APMTransactionErrorRateIndicator) {
|
||||
const goodStatusCodesFilter = this.getGoodStatusCodesFilter(indicator.params.good_status_codes);
|
||||
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
AggregationsCalendarInterval,
|
||||
MappingRuntimeFieldType,
|
||||
TransformPutTransformRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
|
||||
|
||||
import { InvalidTransformError } from '../../../errors';
|
||||
|
@ -23,7 +19,7 @@ import {
|
|||
} from '../../../assets/constants';
|
||||
import { KQLCustomIndicator, SLO } from '../../../types/models';
|
||||
|
||||
export class KQLCustomTransformGenerator implements TransformGenerator {
|
||||
export class KQLCustomTransformGenerator extends TransformGenerator {
|
||||
public getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
if (!kqlCustomIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
|
@ -33,7 +29,7 @@ export class KQLCustomTransformGenerator implements TransformGenerator {
|
|||
this.buildTransformId(slo),
|
||||
this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(),
|
||||
this.buildGroupBy(),
|
||||
this.buildCommonGroupBy(slo),
|
||||
this.buildAggregations(slo, slo.indicator)
|
||||
);
|
||||
}
|
||||
|
@ -46,20 +42,7 @@ export class KQLCustomTransformGenerator implements TransformGenerator {
|
|||
const filter = getElastichsearchQueryOrThrow(indicator.params.query_filter);
|
||||
return {
|
||||
index: indicator.params.index,
|
||||
runtime_mappings: {
|
||||
'slo.id': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.id}')`,
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
type: 'long' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.revision})`,
|
||||
},
|
||||
},
|
||||
},
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo),
|
||||
query: filter,
|
||||
};
|
||||
}
|
||||
|
@ -71,27 +54,6 @@ export class KQLCustomTransformGenerator implements TransformGenerator {
|
|||
};
|
||||
}
|
||||
|
||||
private buildGroupBy() {
|
||||
return {
|
||||
'slo.id': {
|
||||
terms: {
|
||||
field: 'slo.id',
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
terms: {
|
||||
field: 'slo.revision',
|
||||
},
|
||||
},
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
calendar_interval: '1m' as AggregationsCalendarInterval,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildAggregations(slo: SLO, indicator: KQLCustomIndicator) {
|
||||
const numerator = getElastichsearchQueryOrThrow(indicator.params.numerator);
|
||||
const denominator = getElastichsearchQueryOrThrow(indicator.params.denominator);
|
||||
|
|
|
@ -5,9 +5,147 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { MappingRuntimeFieldType } from '@elastic/elasticsearch/lib/api/types';
|
||||
import {
|
||||
AggregationsCalendarInterval,
|
||||
TransformPutTransformRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import {
|
||||
calendarAlignedTimeWindowSchema,
|
||||
rollingTimeWindowSchema,
|
||||
timeslicesBudgetingMethodSchema,
|
||||
} from '../../../types/schema';
|
||||
import { SLO } from '../../../types/models';
|
||||
|
||||
export interface TransformGenerator {
|
||||
getTransformParams(slo: SLO): TransformPutTransformRequest;
|
||||
export abstract class TransformGenerator {
|
||||
public abstract getTransformParams(slo: SLO): TransformPutTransformRequest;
|
||||
|
||||
public buildCommonRuntimeMappings(slo: SLO) {
|
||||
return {
|
||||
'slo.id': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.id}')`,
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
type: 'long' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.revision})`,
|
||||
},
|
||||
},
|
||||
'slo._internal.name': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.name}')`,
|
||||
},
|
||||
},
|
||||
'slo._internal.budgeting_method': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.budgeting_method}')`,
|
||||
},
|
||||
},
|
||||
'slo._internal.objective.target': {
|
||||
type: 'double' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.objective.target})`,
|
||||
},
|
||||
},
|
||||
...(timeslicesBudgetingMethodSchema.is(slo.budgeting_method) && {
|
||||
'slo._internal.objective.timeslice_target': {
|
||||
type: 'double' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(${slo.objective.timeslice_target})`,
|
||||
},
|
||||
},
|
||||
'slo._internal.objective.timeslice_window': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.objective.timeslice_window?.format()}')`,
|
||||
},
|
||||
},
|
||||
}),
|
||||
'slo._internal.time_window.duration': {
|
||||
type: 'keyword' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit('${slo.time_window.duration.format()}')`,
|
||||
},
|
||||
},
|
||||
...(calendarAlignedTimeWindowSchema.is(slo.time_window) && {
|
||||
'slo._internal.time_window.is_rolling': {
|
||||
type: 'boolean' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(false)`,
|
||||
},
|
||||
},
|
||||
}),
|
||||
...(rollingTimeWindowSchema.is(slo.time_window) && {
|
||||
'slo._internal.time_window.is_rolling': {
|
||||
type: 'boolean' as MappingRuntimeFieldType,
|
||||
script: {
|
||||
source: `emit(true)`,
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
public buildCommonGroupBy(slo: SLO) {
|
||||
return {
|
||||
'slo.id': {
|
||||
terms: {
|
||||
field: 'slo.id',
|
||||
},
|
||||
},
|
||||
'slo.revision': {
|
||||
terms: {
|
||||
field: 'slo.revision',
|
||||
},
|
||||
},
|
||||
'slo._internal.name': {
|
||||
terms: {
|
||||
field: 'slo._internal.name',
|
||||
},
|
||||
},
|
||||
'slo._internal.budgeting_method': {
|
||||
terms: {
|
||||
field: 'slo._internal.budgeting_method',
|
||||
},
|
||||
},
|
||||
'slo._internal.objective.target': {
|
||||
terms: {
|
||||
field: 'slo._internal.objective.target',
|
||||
},
|
||||
},
|
||||
'slo._internal.time_window.duration': {
|
||||
terms: {
|
||||
field: 'slo._internal.time_window.duration',
|
||||
},
|
||||
},
|
||||
'slo._internal.time_window.is_rolling': {
|
||||
terms: {
|
||||
field: 'slo._internal.time_window.is_rolling',
|
||||
},
|
||||
},
|
||||
...(timeslicesBudgetingMethodSchema.is(slo.budgeting_method) && {
|
||||
'slo._internal.objective.timeslice_target': {
|
||||
terms: {
|
||||
field: 'slo._internal.objective.timeslice_target',
|
||||
},
|
||||
},
|
||||
'slo._internal.objective.timeslice_window': {
|
||||
terms: {
|
||||
field: 'slo._internal.objective.timeslice_window',
|
||||
},
|
||||
},
|
||||
}),
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
calendar_interval: '1m' as AggregationsCalendarInterval,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,13 +138,13 @@ describe('TransformManager', () => {
|
|||
});
|
||||
});
|
||||
|
||||
class DummyTransformGenerator implements TransformGenerator {
|
||||
class DummyTransformGenerator extends TransformGenerator {
|
||||
getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
return {} as TransformPutTransformRequest;
|
||||
}
|
||||
}
|
||||
|
||||
class FailTransformGenerator implements TransformGenerator {
|
||||
class FailTransformGenerator extends TransformGenerator {
|
||||
getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
throw new Error('Some error');
|
||||
}
|
||||
|
|
|
@ -20,6 +20,18 @@ describe('Duration', () => {
|
|||
expect(() => new Duration(1, 'z' as DurationUnit)).toThrow('invalid duration unit');
|
||||
});
|
||||
|
||||
describe('format', () => {
|
||||
it('formats the duration correctly', () => {
|
||||
expect(new Duration(1, DurationUnit.m).format()).toBe('1m');
|
||||
expect(new Duration(1, DurationUnit.h).format()).toBe('1h');
|
||||
expect(new Duration(1, DurationUnit.d).format()).toBe('1d');
|
||||
expect(new Duration(1, DurationUnit.w).format()).toBe('1w');
|
||||
expect(new Duration(1, DurationUnit.M).format()).toBe('1M');
|
||||
expect(new Duration(1, DurationUnit.Q).format()).toBe('1Q');
|
||||
expect(new Duration(1, DurationUnit.Y).format()).toBe('1Y');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isShorterThan', () => {
|
||||
it('returns true when the current duration is shorter than the other duration', () => {
|
||||
const short = new Duration(1, DurationUnit.m);
|
||||
|
|
|
@ -33,6 +33,10 @@ class Duration {
|
|||
const currentDurationMoment = moment.duration(this.value, toMomentUnitOfTime(this.unit));
|
||||
return currentDurationMoment.asSeconds() < otherDurationMoment.asSeconds();
|
||||
}
|
||||
|
||||
format(): string {
|
||||
return `${this.value}${this.unit}`;
|
||||
}
|
||||
}
|
||||
|
||||
const toMomentUnitOfTime = (unit: DurationUnit): moment.unitOfTime.Diff => {
|
||||
|
|
|
@ -24,7 +24,7 @@ const durationType = new t.Type<Duration, string, unknown>(
|
|||
return t.failure(input, context);
|
||||
}
|
||||
}),
|
||||
(duration: Duration): string => `${duration.value}${duration.unit}`
|
||||
(duration: Duration): string => duration.format()
|
||||
);
|
||||
|
||||
export { durationType };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue