Merge pull request #2228 from w33ble/index-pattern-tests

Add _index_pattern tests
This commit is contained in:
Rashid Khan 2014-12-12 11:23:22 -07:00
commit 0c926e6ea7
9 changed files with 331 additions and 36 deletions

View file

@ -14,12 +14,11 @@ define(function (require) {
_(DocSource).inherits(SourceAbstract);
function DocSource(initialState) {
DocSource.Super.call(this, initialState);
// move onResults over to onUpdate, because that makes more sense
this.onUpdate = this.onResults;
this.onResults = void 0;
}
DocSource.prototype.onUpdate = SourceAbstract.prototype.onResults;
DocSource.prototype.onResults = void 0;
/*****
* PUBLIC API
*****/

View file

@ -5,7 +5,6 @@ define(function (require) {
var errors = require('errors');
var SourceAbstract = Private(require('components/courier/data_source/_abstract'));
var FetchFailure = errors.FetchFailure;
var RequestFailure = errors.RequestFailure;

View file

@ -72,13 +72,7 @@ define(function (require) {
// Give obj all of the values in _source.fields
_.assign(self, resp._source);
if (self.id) {
if (!self.fields) {
return self.refreshFields();
} else {
setIndexedValue('fields');
}
}
self._indexFields();
// Any time obj is updated, re-call applyESResp
docSource.onUpdate().then(applyESResp, notify.fatal);
@ -130,6 +124,16 @@ define(function (require) {
});
}
self._indexFields = function () {
if (self.id) {
if (!self.fields) {
return self.refreshFields();
} else {
setIndexedValue('fields');
}
}
};
self.addScriptedField = function (name, script, type) {
type = type || 'string';
@ -145,6 +149,7 @@ define(function (require) {
type: type,
scripted: true,
});
self.save();
};
@ -153,18 +158,19 @@ define(function (require) {
name: name,
scripted: true
});
self.fields.splice(fieldIndex, 1);
self.save();
};
self.popularizeField = function (fieldName, unit) {
if (_.isUndefined(unit)) unit = 1;
if (unit == null) unit = 1;
if (!(self.fields.byName && self.fields.byName[fieldName])) return;
var field = self.fields.byName[fieldName];
if (!field.count && unit < 1) return;
if (!field.count) field.count = 1;
else field.count = field.count + (unit);
field.count = field.count + (unit);
self.save();
};

View file

@ -0,0 +1,31 @@
define(function (require) {
function stubbedLogstashFields() {
var sourceData = [
{ name: 'bytes', type: 'number', indexed: true, analyzed: true, count: 10 },
{ name: 'ssl', type: 'boolean', indexed: true, analyzed: true, count: 20 },
{ name: '@timestamp', type: 'date', indexed: true, analyzed: true, count: 30 },
{ name: 'utc_time', type: 'date', indexed: true, analyzed: true },
{ name: 'phpmemory', type: 'number', indexed: true, analyzed: true },
{ name: 'ip', type: 'ip', indexed: true, analyzed: true },
{ name: 'request_body', type: 'attachment', indexed: true, analyzed: true },
{ name: 'extension', type: 'string', indexed: true, analyzed: true },
{ name: 'point', type: 'geo_point', indexed: true, analyzed: true },
{ name: 'area', type: 'geo_shape', indexed: true, analyzed: true },
{ name: 'extension', type: 'string', indexed: true, analyzed: true },
{ name: 'machine.os', type: 'string', indexed: true, analyzed: true },
{ name: 'geo.src', type: 'string', indexed: true, analyzed: true },
{ name: '_type', type: 'string', indexed: true, analyzed: true },
{ name: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false },
{ name: 'scritped string', type: 'string', scripted: true, script: '\'i am a string\''},
{ name: 'scritped number', type: 'number', scripted: true, script: '1234'},
].map(function (field) {
field.count = field.count || 0;
field.scripted = field.scripted || false;
return field;
});
return sourceData;
}
return stubbedLogstashFields;
});

View file

@ -0,0 +1,22 @@
define(function (require) {
function stubbedDocSourceResponse(Private) {
var mockLogstashFields = Private(require('fixtures/logstash_fields'));
return function (id, index) {
index = index || '.kibana';
return {
_id: id,
_index: index,
_type: 'index-pattern',
_version: 2,
found: true,
_source: {
customFormats: '{}',
fields: JSON.stringify(mockLogstashFields)
}
};
};
}
return stubbedDocSourceResponse;
});

View file

@ -1,37 +1,24 @@
define(function (require) {
return function stubbedLogstashIndexPatternService(Private) {
var StubIndexPattern = Private(require('test_utils/stub_index_pattern'));
var fieldTypes = Private(require('components/index_patterns/_field_types'));
var mockLogstashFields = Private(require('fixtures/logstash_fields'));
var flattenSearchResponse = require('components/index_patterns/_flatten_search_response');
var flattenHit = require('components/index_patterns/_flatten_hit');
var fieldTypes = Private(require('components/index_patterns/_field_types'));
var getComputedFields = require('components/index_patterns/_get_computed_fields');
var _ = require('lodash');
var indexPattern = new StubIndexPattern('logstash-*', 'time', [
{ name: 'bytes', type: 'number', indexed: true, analyzed: true, count: 10 },
{ name: 'ssl', type: 'boolean', indexed: true, analyzed: true, count: 20 },
{ name: '@timestamp', type: 'date', indexed: true, analyzed: true, count: 30 },
{ name: 'utc_time', type: 'date', indexed: true, analyzed: true, count: 0 },
{ name: 'phpmemory', type: 'number', indexed: true, analyzed: true, count: 0 },
{ name: 'ip', type: 'ip', indexed: true, analyzed: true, count: 0 },
{ name: 'request_body', type: 'attachment', indexed: true, analyzed: true, count: 0 },
{ name: 'extension', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: 'point', type: 'geo_point', indexed: true, analyzed: true, count: 0 },
{ name: 'area', type: 'geo_shape', indexed: true, analyzed: true, count: 0 },
{ name: 'extension', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: 'machine.os', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: 'geo.src', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: '_type', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false, count: 0 }
].map(function (field) {
var fields = mockLogstashFields.map(function (field) {
field.displayName = field.name;
var type = fieldTypes.byName[field.type];
if (!type) throw new TypeError('unknown type ' + field.type);
if (!_.has(field, 'sortable')) field.sortable = type.sortable;
if (!_.has(field, 'filterable')) field.filterable = type.filterable;
return field;
}));
});
var indexPattern = new StubIndexPattern('logstash-*', 'time', fields);
indexPattern.getComputedFields = _.bind(getComputedFields, indexPattern);
indexPattern.flattenSearchResponse = _.bind(flattenSearchResponse, indexPattern);

View file

@ -124,7 +124,7 @@ define(function (require) {
done();
});
it('setting field.display should move the field into selected', function (done) {
it('should move the field into selected when setting field.display', function (done) {
var section = getSections($elem);
indexPattern.fields.byName.bytes.display = true;
$scope.$digest();

View file

@ -0,0 +1,250 @@
define(function (require) {
return ['index pattern', function () {
var _ = require('lodash');
var sinon = require('test_utils/auto_release_sinon');
var Promise = require('bluebird');
var errors = require('errors');
var IndexedArray = require('utils/indexed_array/index');
var IndexPattern;
var mapper;
var mappingSetup;
var mockLogstashFields;
var DocSource;
var config;
var docSourceResponse;
var indexPatternId = 'test-pattern';
var indexPattern;
beforeEach(module('kibana'));
beforeEach(inject(function (Private, $injector, _config_) {
config = _config_;
mockLogstashFields = Private(require('fixtures/logstash_fields'));
docSourceResponse = Private(require('fixtures/stubbed_doc_source_response'));
DocSource = Private(require('components/courier/data_source/doc_source'));
sinon.stub(DocSource.prototype, 'doIndex');
sinon.stub(DocSource.prototype, 'fetch');
// stub mapper
mapper = Private(require('components/index_patterns/_mapper'));
sinon.stub(mapper, 'getFieldsForIndexPattern', function () {
return Promise.resolve(_.filter(mockLogstashFields, { scripted: false }));
});
// stub mappingSetup
mappingSetup = Private(require('utils/mapping_setup'));
sinon.stub(mappingSetup, 'isDefined', function () {
return Promise.resolve(true);
});
IndexPattern = Private(require('components/index_patterns/_index_pattern'));
}));
// create an indexPattern instance for each test
beforeEach(function () {
return create(indexPatternId).then(function (pattern) {
indexPattern = pattern;
});
});
// helper function to create index patterns
function create(id, payload) {
var indexPattern = new IndexPattern(id);
DocSource.prototype.doIndex.returns(Promise.resolve(id));
payload = _.defaults(payload || {}, docSourceResponse(id));
setDocsourcePayload(payload);
return indexPattern.init();
}
function setDocsourcePayload(payload) {
DocSource.prototype.fetch.returns(Promise.resolve(payload));
}
describe('api', function () {
it('should have expected properties', function () {
return create('test-pattern').then(function (indexPattern) {
// methods
expect(indexPattern).to.have.property('refreshFields');
expect(indexPattern).to.have.property('popularizeField');
expect(indexPattern).to.have.property('getFields');
expect(indexPattern).to.have.property('getInterval');
expect(indexPattern).to.have.property('addScriptedField');
expect(indexPattern).to.have.property('removeScriptedField');
expect(indexPattern).to.have.property('toString');
expect(indexPattern).to.have.property('toJSON');
expect(indexPattern).to.have.property('save');
// properties
expect(indexPattern).to.have.property('fields');
});
});
});
describe('init', function () {
it('should append the found fields', function () {
expect(DocSource.prototype.fetch.callCount).to.be(1);
expect(indexPattern.fields).to.have.length(mockLogstashFields.length);
expect(indexPattern.fields).to.be.an(IndexedArray);
});
});
describe('getFields', function () {
it('should return all non-scripted fields', function () {
var indexed = _.where(mockLogstashFields, { scripted: false });
expect(indexPattern.getFields()).to.eql(indexed);
});
it('should return all scripted fields', function () {
var scripted = _.where(mockLogstashFields, { scripted: true });
expect(indexPattern.getFields('scripted')).to.eql(scripted);
});
});
describe('refresh fields', function () {
// override the default indexPattern, with a truncated field list
require('test_utils/no_digest_promises').activateForSuite();
var indexPatternId = 'test-pattern';
var indexPattern;
var fieldLength;
var truncatedFields;
beforeEach(function () {
fieldLength = mockLogstashFields.length;
truncatedFields = mockLogstashFields.slice(3);
return create(indexPatternId, {
_source: {
customFormats: '{}',
fields: JSON.stringify(truncatedFields)
}
}).then(function (pattern) {
indexPattern = pattern;
});
});
it('should fetch fields from the doc source', function () {
// ensure that we don't have all the fields
expect(truncatedFields.length).to.not.equal(mockLogstashFields.length);
expect(indexPattern.fields).to.have.length(truncatedFields.length);
// ensure that all fields will be included in the returned docSource
setDocsourcePayload(docSourceResponse(indexPatternId));
// refresh fields, which will fetch
return indexPattern.refreshFields().then(function () {
// compare non-scripted fields to the mapper.getFieldsForIndexPattern fields
return mapper.getFieldsForIndexPattern().then(function (fields) {
expect(indexPattern.getFields()).to.eql(fields);
});
});
});
it('should preserve the scripted fields', function () {
// ensure that all fields will be included in the returned docSource
setDocsourcePayload(docSourceResponse(indexPatternId));
// add spy to indexPattern.getFields
var getFieldsSpy = sinon.spy(indexPattern, 'getFields');
// refresh fields, which will fetch
return indexPattern.refreshFields().then(function () {
// called to append scripted fields to the response from mapper.getFieldsForIndexPattern
expect(getFieldsSpy.callCount).to.equal(1);
var scripted = _.where(mockLogstashFields, { scripted: true });
expect(_.filter(indexPattern.fields, { scripted: true })).to.eql(scripted);
});
});
});
describe('add and remove scripted fields', function () {
it('should append the scripted field', function () {
// keep a copy of the current scripted field count
var saveSpy = sinon.spy(indexPattern, 'save');
var oldCount = indexPattern.getFields('scripted').length;
// add a new scripted field
var scriptedField = {
name: 'new scripted field',
script: 'false',
type: 'boolean'
};
indexPattern.addScriptedField(scriptedField.name, scriptedField.script, scriptedField.type);
indexPattern._indexFields(); // normally triggered by docSource.onUpdate()
var scriptedFields = indexPattern.getFields('scripted');
expect(saveSpy.callCount).to.equal(1);
expect(scriptedFields).to.have.length(oldCount + 1);
expect(indexPattern.fields.byName[scriptedField.name].displayName).to.equal(scriptedField.name);
});
it('should remove scripted field, by name', function () {
var saveSpy = sinon.spy(indexPattern, 'save');
var scriptedFields = indexPattern.getFields('scripted');
var oldCount = scriptedFields.length;
var scriptedField = _.last(scriptedFields);
indexPattern.removeScriptedField(scriptedField.name);
expect(saveSpy.callCount).to.equal(1);
expect(indexPattern.getFields('scripted').length).to.equal(oldCount - 1);
expect(indexPattern.fields.byName[scriptedField.name]).to.equal(undefined);
});
it('should not allow duplicate names', function () {
var scriptedFields = indexPattern.getFields('scripted');
var scriptedField = _.last(scriptedFields);
expect(function () {
indexPattern.addScriptedField(scriptedField.name, '\'new script\'', 'string');
}).to.throwError(function (e) {
expect(e).to.be.a(errors.DuplicateField);
});
});
});
describe('popularizeField', function () {
it('should increment the poplarity count by default', function () {
var saveSpy = sinon.spy(indexPattern, 'save');
var field = _.sample(indexPattern.fields);
var oldCount = field.count;
indexPattern.popularizeField(field.name);
expect(saveSpy.callCount).to.equal(1);
expect(field.count).to.equal(oldCount + 1);
});
it('should increment the poplarity count', function () {
var saveSpy = sinon.spy(indexPattern, 'save');
var field = _.sample(indexPattern.fields);
var oldCount = field.count;
var incrementAmount = 4;
indexPattern.popularizeField(field.name, incrementAmount);
expect(saveSpy.callCount).to.equal(1);
expect(field.count).to.equal(oldCount + incrementAmount);
});
it('should decrement the poplarity count', function () {
var saveSpy = sinon.spy(indexPattern, 'save');
var field = _.sample(indexPattern.fields);
var oldCount = field.count;
var incrementAmount = 4;
var decrementAmount = -2;
indexPattern.popularizeField(field.name, incrementAmount);
indexPattern.popularizeField(field.name, decrementAmount);
expect(saveSpy.callCount).to.equal(2);
expect(field.count).to.equal(oldCount + incrementAmount + decrementAmount);
});
it('should not go below 0', function () {
var field = _.sample(indexPattern.fields);
var decrementAmount = -20000000;
indexPattern.popularizeField(field.name, decrementAmount);
expect(field.count).to.equal(0);
});
});
}];
});

View file

@ -1,5 +1,6 @@
define(function (require) {
describe('Index Patterns', function () {
run(require('specs/components/index_pattern/_index_pattern'));
run(require('specs/components/index_pattern/_cast_mapping_type'));
run(require('specs/components/index_pattern/_map_field'));
run(require('specs/components/index_pattern/_pattern_to_wildcard'));
@ -8,4 +9,4 @@ define(function (require) {
function run(mod) { describe(mod[0], mod[1]); }
});
});
});