|
@@ -4,11 +4,30 @@ describe('StackdriverQueryCtrl', () => {
|
|
|
let ctrl;
|
|
let ctrl;
|
|
|
let result;
|
|
let result;
|
|
|
|
|
|
|
|
- beforeEach(() => {
|
|
|
|
|
- ctrl = createCtrlWithFakes();
|
|
|
|
|
|
|
+ describe('when initializing query editor', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingFilters = ['key1', '=', 'val1', 'AND', 'key2', '=', 'val2'];
|
|
|
|
|
+ ctrl = createCtrlWithFakes(existingFilters);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should initialize filter segments using the target filter values', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(8);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[3].type).toBe('condition');
|
|
|
|
|
+ expect(ctrl.filterSegments[4].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[5].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[6].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[7].type).toBe('plus-button');
|
|
|
|
|
+ });
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
describe('group bys', () => {
|
|
describe('group bys', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ ctrl = createCtrlWithFakes();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
describe('when labels are fetched', () => {
|
|
describe('when labels are fetched', () => {
|
|
|
beforeEach(async () => {
|
|
beforeEach(async () => {
|
|
|
ctrl.metricLabels = { 'metric-key-1': ['metric-value-1'] };
|
|
ctrl.metricLabels = { 'metric-key-1': ['metric-value-1'] };
|
|
@@ -76,6 +95,10 @@ describe('StackdriverQueryCtrl', () => {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
describe('filters', () => {
|
|
describe('filters', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ ctrl = createCtrlWithFakes();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
describe('when values for a condition filter part are fetched', () => {
|
|
describe('when values for a condition filter part are fetched', () => {
|
|
|
beforeEach(async () => {
|
|
beforeEach(async () => {
|
|
|
const segment = { type: 'condition' };
|
|
const segment = { type: 'condition' };
|
|
@@ -139,7 +162,7 @@ describe('StackdriverQueryCtrl', () => {
|
|
|
'resource-key-2': ['resource-value-2'],
|
|
'resource-key-2': ['resource-value-2'],
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- ctrl.filterSegments = [{ type: 'key', value: 'metric-key-1' }, { type: 'operator', value: '=' }];
|
|
|
|
|
|
|
+ ctrl.filterSegments = [{ type: 'key', value: 'metric.label.metric-key-1' }, { type: 'operator', value: '=' }];
|
|
|
|
|
|
|
|
const segment = { type: 'value' };
|
|
const segment = { type: 'value' };
|
|
|
result = await ctrl.getFilters(segment, 2);
|
|
result = await ctrl.getFilters(segment, 2);
|
|
@@ -150,16 +173,186 @@ describe('StackdriverQueryCtrl', () => {
|
|
|
expect(result[0].value).toBe('metric-value-1');
|
|
expect(result[0].value).toBe('metric-value-1');
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ describe('when a filter is created by clicking on plus button', () => {
|
|
|
|
|
+ describe('and there are no other filters', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const segment = { value: 'filterkey1', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [segment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(segment, 0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should transform the plus button segment to a key segment', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should add an operator, value segment and plus button segment', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(3);
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ describe('when has one existing filter', () => {
|
|
|
|
|
+ describe('and user clicks on key segment', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment = { value: 'filterkey1', type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ const plusSegment = { value: '', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [existingKeySegment, existingOperatorSegment, existingValueSegment, plusSegment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingKeySegment, 0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should not add any new segments', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(4);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ describe('and user clicks on value segment and value not equal to fake value', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment = { value: 'filterkey1', type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ ctrl.filterSegments = [existingKeySegment, existingOperatorSegment, existingValueSegment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingValueSegment, 2);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should ensure that plus segment exists', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(4);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[3].type).toBe('plus-button');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('and user clicks on value segment and value is equal to fake value', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment = { value: 'filterkey1', type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: ctrl.defaultFilterValue, type: 'value' };
|
|
|
|
|
+ ctrl.filterSegments = [existingKeySegment, existingOperatorSegment, existingValueSegment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingValueSegment, 2);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should not add plus segment', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(3);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ describe('and user removes key segment', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment = { value: ctrl.defaultRemoveFilterValue, type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ const plusSegment = { value: '', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [existingKeySegment, existingOperatorSegment, existingValueSegment, plusSegment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingKeySegment, 0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should remove filter segments', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(1);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('plus-button');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('and user removes key segment and there is a previous filter', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment1 = { value: ctrl.defaultRemoveFilterValue, type: 'key' };
|
|
|
|
|
+ const existingKeySegment2 = { value: ctrl.defaultRemoveFilterValue, type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ const conditionSegment = { value: 'AND', type: 'condition' };
|
|
|
|
|
+ const plusSegment = { value: '', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [
|
|
|
|
|
+ existingKeySegment1,
|
|
|
|
|
+ existingOperatorSegment,
|
|
|
|
|
+ existingValueSegment,
|
|
|
|
|
+ conditionSegment,
|
|
|
|
|
+ existingKeySegment2,
|
|
|
|
|
+ Object.assign({}, existingOperatorSegment),
|
|
|
|
|
+ Object.assign({}, existingValueSegment),
|
|
|
|
|
+ plusSegment,
|
|
|
|
|
+ ];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingKeySegment2, 4);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should remove filter segments and the condition segment', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(4);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[3].type).toBe('plus-button');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('and user removes key segment and there is a filter after it', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment1 = { value: ctrl.defaultRemoveFilterValue, type: 'key' };
|
|
|
|
|
+ const existingKeySegment2 = { value: ctrl.defaultRemoveFilterValue, type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ const conditionSegment = { value: 'AND', type: 'condition' };
|
|
|
|
|
+ const plusSegment = { value: '', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [
|
|
|
|
|
+ existingKeySegment1,
|
|
|
|
|
+ existingOperatorSegment,
|
|
|
|
|
+ existingValueSegment,
|
|
|
|
|
+ conditionSegment,
|
|
|
|
|
+ existingKeySegment2,
|
|
|
|
|
+ Object.assign({}, existingOperatorSegment),
|
|
|
|
|
+ Object.assign({}, existingValueSegment),
|
|
|
|
|
+ plusSegment,
|
|
|
|
|
+ ];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(existingKeySegment1, 0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should remove filter segments and the condition segment', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(4);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[3].type).toBe('plus-button');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('and user clicks on plus button', () => {
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ const existingKeySegment = { value: 'filterkey1', type: 'key' };
|
|
|
|
|
+ const existingOperatorSegment = { value: '=', type: 'operator' };
|
|
|
|
|
+ const existingValueSegment = { value: 'filtervalue', type: 'value' };
|
|
|
|
|
+ const plusSegment = { value: 'filterkey2', type: 'plus-button' };
|
|
|
|
|
+ ctrl.filterSegments = [existingKeySegment, existingOperatorSegment, existingValueSegment, plusSegment];
|
|
|
|
|
+ ctrl.filterSegmentUpdated(plusSegment, 3);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should condition segment and new filter segments', () => {
|
|
|
|
|
+ expect(ctrl.filterSegments.length).toBe(7);
|
|
|
|
|
+ expect(ctrl.filterSegments[0].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[1].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[2].type).toBe('value');
|
|
|
|
|
+ expect(ctrl.filterSegments[3].type).toBe('condition');
|
|
|
|
|
+ expect(ctrl.filterSegments[4].type).toBe('key');
|
|
|
|
|
+ expect(ctrl.filterSegments[5].type).toBe('operator');
|
|
|
|
|
+ expect(ctrl.filterSegments[6].type).toBe('value');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-function createCtrlWithFakes() {
|
|
|
|
|
|
|
+function createCtrlWithFakes(existingFilters?: string[]) {
|
|
|
StackdriverQueryCtrl.prototype.panelCtrl = {
|
|
StackdriverQueryCtrl.prototype.panelCtrl = {
|
|
|
events: { on: () => {} },
|
|
events: { on: () => {} },
|
|
|
panel: { scopedVars: [], targets: [] },
|
|
panel: { scopedVars: [], targets: [] },
|
|
|
refresh: () => {},
|
|
refresh: () => {},
|
|
|
};
|
|
};
|
|
|
- StackdriverQueryCtrl.prototype.target = createTarget();
|
|
|
|
|
|
|
+ StackdriverQueryCtrl.prototype.target = createTarget(existingFilters);
|
|
|
StackdriverQueryCtrl.prototype.getMetricTypes = () => {
|
|
StackdriverQueryCtrl.prototype.getMetricTypes = () => {
|
|
|
return Promise.resolve();
|
|
return Promise.resolve();
|
|
|
};
|
|
};
|
|
@@ -168,20 +361,37 @@ function createCtrlWithFakes() {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const fakeSegmentServer = {
|
|
const fakeSegmentServer = {
|
|
|
|
|
+ newKey: val => {
|
|
|
|
|
+ return { value: val, type: 'key' };
|
|
|
|
|
+ },
|
|
|
|
|
+ newKeyValue: val => {
|
|
|
|
|
+ return { value: val, type: 'value' };
|
|
|
|
|
+ },
|
|
|
newSegment: obj => {
|
|
newSegment: obj => {
|
|
|
return { value: obj.value ? obj.value : obj };
|
|
return { value: obj.value ? obj.value : obj };
|
|
|
},
|
|
},
|
|
|
newOperators: ops => {
|
|
newOperators: ops => {
|
|
|
return ops.map(o => {
|
|
return ops.map(o => {
|
|
|
- return { type: 'operator', value: o, text: o };
|
|
|
|
|
|
|
+ return { type: 'operator', value: o };
|
|
|
});
|
|
});
|
|
|
},
|
|
},
|
|
|
- newPlusButton: () => {},
|
|
|
|
|
|
|
+ newFake: (value, type, cssClass) => {
|
|
|
|
|
+ return { value, type, cssClass };
|
|
|
|
|
+ },
|
|
|
|
|
+ newOperator: op => {
|
|
|
|
|
+ return { value: op, type: 'operator' };
|
|
|
|
|
+ },
|
|
|
|
|
+ newPlusButton: () => {
|
|
|
|
|
+ return { type: 'plus-button' };
|
|
|
|
|
+ },
|
|
|
|
|
+ newCondition: val => {
|
|
|
|
|
+ return { type: 'condition', value: val };
|
|
|
|
|
+ },
|
|
|
};
|
|
};
|
|
|
return new StackdriverQueryCtrl(null, null, fakeSegmentServer, null);
|
|
return new StackdriverQueryCtrl(null, null, fakeSegmentServer, null);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function createTarget() {
|
|
|
|
|
|
|
+function createTarget(existingFilters?: string[]) {
|
|
|
return {
|
|
return {
|
|
|
project: {
|
|
project: {
|
|
|
id: '',
|
|
id: '',
|
|
@@ -195,6 +405,6 @@ function createTarget() {
|
|
|
perSeriesAligner: '',
|
|
perSeriesAligner: '',
|
|
|
groupBys: [],
|
|
groupBys: [],
|
|
|
},
|
|
},
|
|
|
- filters: [],
|
|
|
|
|
|
|
+ filters: existingFilters || [],
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|