|
|
|
|
@ -4,11 +4,30 @@ describe('StackdriverQueryCtrl', () => { |
|
|
|
|
let ctrl; |
|
|
|
|
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', () => { |
|
|
|
|
beforeEach(() => { |
|
|
|
|
ctrl = createCtrlWithFakes(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('when labels are fetched', () => { |
|
|
|
|
beforeEach(async () => { |
|
|
|
|
ctrl.metricLabels = { 'metric-key-1': ['metric-value-1'] }; |
|
|
|
|
@ -76,6 +95,10 @@ describe('StackdriverQueryCtrl', () => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('filters', () => { |
|
|
|
|
beforeEach(() => { |
|
|
|
|
ctrl = createCtrlWithFakes(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
describe('when values for a condition filter part are fetched', () => { |
|
|
|
|
beforeEach(async () => { |
|
|
|
|
const segment = { type: 'condition' }; |
|
|
|
|
@ -139,7 +162,7 @@ describe('StackdriverQueryCtrl', () => { |
|
|
|
|
'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' }; |
|
|
|
|
result = await ctrl.getFilters(segment, 2); |
|
|
|
|
@ -150,16 +173,186 @@ describe('StackdriverQueryCtrl', () => { |
|
|
|
|
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 = { |
|
|
|
|
events: { on: () => {} }, |
|
|
|
|
panel: { scopedVars: [], targets: [] }, |
|
|
|
|
refresh: () => {}, |
|
|
|
|
}; |
|
|
|
|
StackdriverQueryCtrl.prototype.target = createTarget(); |
|
|
|
|
StackdriverQueryCtrl.prototype.target = createTarget(existingFilters); |
|
|
|
|
StackdriverQueryCtrl.prototype.getMetricTypes = () => { |
|
|
|
|
return Promise.resolve(); |
|
|
|
|
}; |
|
|
|
|
@ -168,20 +361,37 @@ function createCtrlWithFakes() { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const fakeSegmentServer = { |
|
|
|
|
newKey: val => { |
|
|
|
|
return { value: val, type: 'key' }; |
|
|
|
|
}, |
|
|
|
|
newKeyValue: val => { |
|
|
|
|
return { value: val, type: 'value' }; |
|
|
|
|
}, |
|
|
|
|
newSegment: obj => { |
|
|
|
|
return { value: obj.value ? obj.value : obj }; |
|
|
|
|
}, |
|
|
|
|
newOperators: ops => { |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function createTarget() { |
|
|
|
|
function createTarget(existingFilters?: string[]) { |
|
|
|
|
return { |
|
|
|
|
project: { |
|
|
|
|
id: '', |
|
|
|
|
@ -195,6 +405,6 @@ function createTarget() { |
|
|
|
|
perSeriesAligner: '', |
|
|
|
|
groupBys: [], |
|
|
|
|
}, |
|
|
|
|
filters: [], |
|
|
|
|
filters: existingFilters || [], |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|