mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
merging in latest changes from master
This commit is contained in:
commit
86a4d92fe7
26 changed files with 12363 additions and 82 deletions
|
@ -9,6 +9,7 @@ module.exports = function (grunt) {
|
|||
src: __dirname + '/src',
|
||||
app: __dirname + '/src/kibana',
|
||||
unitTestDir: __dirname + '/test/unit',
|
||||
testUtilsDir: __dirname + '/test/utils',
|
||||
meta: {
|
||||
banner: '/*! <%= package.name %> - v<%= package.version %> - ' +
|
||||
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||
|
|
|
@ -26,5 +26,6 @@
|
|||
"lodash": "~2.4.1",
|
||||
"d3": "~3.4.1",
|
||||
"angular-route": "~1.2.12"
|
||||
}
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
|
32
src/config.js
Normal file
32
src/config.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
define(function () {
|
||||
/** @scratch /configuration/config.js/1
|
||||
* == Configuration
|
||||
* config.js is where you will find the core Kibana configuration. This file contains parameter that
|
||||
* must be set before kibana is run for the first time.
|
||||
*/
|
||||
|
||||
/** @scratch /configuration/config.js/2
|
||||
* === Parameters
|
||||
*/
|
||||
return {
|
||||
|
||||
/** @scratch /configuration/config.js/5
|
||||
* ==== elasticsearch
|
||||
*
|
||||
* The URL to your elasticsearch server. You almost certainly don't
|
||||
* want +http://localhost:9200+ here. Even if Kibana and Elasticsearch are on
|
||||
* the same host. By default this will attempt to reach ES at the same host you have
|
||||
* kibana installed on. You probably want to set it to the FQDN of your
|
||||
* elasticsearch host
|
||||
*/
|
||||
elasticsearch: 'http://' + window.location.hostname + ':9200',
|
||||
|
||||
/** @scratch /configuration/config.js/5
|
||||
* ==== kibana-int
|
||||
*
|
||||
* The default ES index to use for storing Kibana specific object
|
||||
* such as stored dashboards
|
||||
*/
|
||||
kibanaIndex: 'kibana-int'
|
||||
};
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
define(function (require) {
|
||||
|
||||
var DataSource = require('courier/data_source');
|
||||
var Docs = require('courier/docs');
|
||||
var EventEmitter = require('utils/event_emitter');
|
||||
var inherits = require('utils/inherits');
|
||||
var errors = require('courier/errors');
|
||||
|
@ -14,9 +15,18 @@ define(function (require) {
|
|||
};
|
||||
}
|
||||
|
||||
function emitError(source, courier, error) {
|
||||
if (EventEmitter.listenerCount(source, 'error')) {
|
||||
source.emit('error', error);
|
||||
} else {
|
||||
courier.emit('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
function mergeProp(state, filters, val, key) {
|
||||
switch (key) {
|
||||
case 'inherits':
|
||||
case '_type':
|
||||
// ignore
|
||||
return;
|
||||
case 'filter':
|
||||
|
@ -45,7 +55,6 @@ define(function (require) {
|
|||
|
||||
// all of the filters from the source chain
|
||||
var filters = [];
|
||||
|
||||
var collectProp = _.partial(mergeProp, state, filters);
|
||||
|
||||
// walk the chain and merge each property
|
||||
|
@ -81,7 +90,7 @@ define(function (require) {
|
|||
return state;
|
||||
}
|
||||
|
||||
function fetch(client, sources, cb) {
|
||||
function fetchSearchResults(courier, client, sources, cb) {
|
||||
if (!client) {
|
||||
this.emit('error', new Error('Courier does not have a client yet, unable to fetch queries.'));
|
||||
return;
|
||||
|
@ -90,6 +99,9 @@ define(function (require) {
|
|||
var all = [];
|
||||
var body = '';
|
||||
_.each(sources, function (source) {
|
||||
if (source.getType() !== 'search') {
|
||||
return;
|
||||
}
|
||||
all.push(source);
|
||||
|
||||
var state = flattenDataSource(source);
|
||||
|
@ -106,13 +118,58 @@ define(function (require) {
|
|||
if (err) return cb(err);
|
||||
|
||||
_.each(resp.responses, function (resp, i) {
|
||||
sources[i].emit('results', resp);
|
||||
var source = sources[i];
|
||||
if (resp.error) return emitError(source, courier, resp);
|
||||
source.emit('results', resp);
|
||||
});
|
||||
|
||||
cb(err, resp);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchDocs(courier, client, sources, cb) {
|
||||
if (!client) {
|
||||
this.emit('error', new Error('Courier does not have a client yet, unable to fetch queries.'));
|
||||
return;
|
||||
}
|
||||
|
||||
var all = [];
|
||||
var body = {
|
||||
docs: []
|
||||
};
|
||||
|
||||
_.each(sources, function (source) {
|
||||
if (source.getType() !== 'get') {
|
||||
return;
|
||||
}
|
||||
|
||||
all.push(source);
|
||||
|
||||
var state = flattenDataSource(source);
|
||||
body.docs.push({
|
||||
index: state.index,
|
||||
type: state.type,
|
||||
id: state.id
|
||||
});
|
||||
});
|
||||
|
||||
return client.mget({ body: body }, function (err, resp) {
|
||||
if (err) return cb(err);
|
||||
|
||||
_.each(resp.responses, function (resp, i) {
|
||||
var source = sources[i];
|
||||
if (resp.error) return emitError(source, courier, resp);
|
||||
source.emit('results', resp);
|
||||
});
|
||||
|
||||
cb(err, resp);
|
||||
});
|
||||
}
|
||||
|
||||
function saveUpdate(source, fields) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Federated query service, supports data sources that inherit properties
|
||||
* from one another and automatically emit results.
|
||||
|
@ -127,10 +184,13 @@ define(function (require) {
|
|||
};
|
||||
var fetchTimer;
|
||||
var activeRequest;
|
||||
var courier = this;
|
||||
var sources = {
|
||||
search: [],
|
||||
get: []
|
||||
};
|
||||
|
||||
var sources = [];
|
||||
|
||||
function doFetch() {
|
||||
function doSearch() {
|
||||
if (!opts.client) {
|
||||
this.emit('error', new Error('Courier does not have a client, pass it ' +
|
||||
'in to the constructor or set it with the .client() method'));
|
||||
|
@ -144,7 +204,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
// we need to catch the original promise in order to keep it's abort method
|
||||
activeRequest = fetch(opts.client, sources, function (err, resp) {
|
||||
activeRequest = fetchSearchResults(courier, opts.client, sources.search, function (err, resp) {
|
||||
activeRequest = null;
|
||||
setFetchTimeout();
|
||||
|
||||
|
@ -157,61 +217,59 @@ define(function (require) {
|
|||
function setFetchTimeout() {
|
||||
clearTimeout(fetchTimer);
|
||||
if (opts.fetchInterval) {
|
||||
fetchTimer = setTimeout(doFetch, opts.fetchInterval);
|
||||
fetchTimer = setTimeout(doSearch, opts.fetchInterval);
|
||||
} else {
|
||||
fetchTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function stopFetching() {
|
||||
function stopFetching(type) {
|
||||
clearTimeout(fetchTimer);
|
||||
}
|
||||
|
||||
function startFetchingSource(source) {
|
||||
var existing = _.find(sources, { source: source });
|
||||
if (existing) return false;
|
||||
|
||||
sources.push(source);
|
||||
// start using a DataSource in fetches/updates
|
||||
function openDataSource(source) {
|
||||
var type = source.getType();
|
||||
if (~sources[type].indexOf(source)) return false;
|
||||
sources[type].push(source);
|
||||
}
|
||||
|
||||
function stopFetchingSource(source) {
|
||||
var i = sources.indexOf(source);
|
||||
if (i !== -1) {
|
||||
sources.slice(i, 1);
|
||||
}
|
||||
if (sources.length === 0) stopFetching();
|
||||
// stop using a DataSource in fetches/updates
|
||||
function closeDataSource(source) {
|
||||
var type = source.getType();
|
||||
var i = sources[type].indexOf(source);
|
||||
if (i === -1) return;
|
||||
sources[type].slice(i, 1);
|
||||
// only search DataSources get fetched automatically
|
||||
if (type === 'search' && sources.search.length === 0) stopFetching();
|
||||
}
|
||||
|
||||
// is there a scheduled request?
|
||||
function isStarted() {
|
||||
// has the courier been started?
|
||||
function isRunning() {
|
||||
return !!fetchTimer;
|
||||
}
|
||||
|
||||
// chainable public api
|
||||
this.isStarted = chain(this, isStarted);
|
||||
this.start = chain(this, doFetch);
|
||||
this.startFetchingSource = chain(this, startFetchingSource);
|
||||
this.start = chain(this, doSearch);
|
||||
this.running = chain(this, isRunning);
|
||||
this.stop = chain(this, stopFetching);
|
||||
this.stopFetchingSource = chain(this, stopFetchingSource);
|
||||
this.close = chain(this, function stopFetchingAllSources() {
|
||||
_.each(sources, stopFetchingSource);
|
||||
});
|
||||
this.close = chain(this, function () { _(sources.search).each(closeDataSource); });
|
||||
this.openDataSource = chain(this, openDataSource);
|
||||
this.closeDataSource = chain(this, closeDataSource);
|
||||
|
||||
// setter
|
||||
// setters
|
||||
this.client = chain(this, function (client) {
|
||||
opts.client = client;
|
||||
});
|
||||
|
||||
// setter/getter
|
||||
this.fetchInterval = function (val) {
|
||||
opts.fetchInterval = val;
|
||||
if (isStarted()) setFetchTimeout();
|
||||
if (isRunning()) setFetchTimeout();
|
||||
return this;
|
||||
};
|
||||
|
||||
// factory
|
||||
this.createSource = function (state) {
|
||||
return new DataSource(this, state);
|
||||
this.createSource = function (type, initialState) {
|
||||
return new DataSource(this, type, initialState);
|
||||
};
|
||||
|
||||
// apply the passed in config
|
||||
|
@ -220,10 +278,10 @@ define(function (require) {
|
|||
this[key](val);
|
||||
}, this);
|
||||
}
|
||||
inherits(Courier, EventEmitter);
|
||||
|
||||
// private api, exposed for testing
|
||||
Courier._flattenDataSource = flattenDataSource;
|
||||
inherits(Courier, EventEmitter);
|
||||
|
||||
return Courier;
|
||||
});
|
|
@ -14,21 +14,30 @@ define(function (require) {
|
|||
}
|
||||
}
|
||||
|
||||
var optionNames = [
|
||||
'index',
|
||||
'type',
|
||||
'query',
|
||||
'filter',
|
||||
'sort',
|
||||
'highlight',
|
||||
'aggs',
|
||||
'from',
|
||||
'size',
|
||||
'source',
|
||||
'inherits'
|
||||
];
|
||||
var apiMethods = {
|
||||
search: [
|
||||
'index',
|
||||
'type',
|
||||
'query',
|
||||
'filter',
|
||||
'sort',
|
||||
'highlight',
|
||||
'aggs',
|
||||
'from',
|
||||
'size',
|
||||
'source',
|
||||
'inherits'
|
||||
],
|
||||
get: [
|
||||
'index',
|
||||
'type',
|
||||
'id',
|
||||
'sourceInclude',
|
||||
'sourceExclude'
|
||||
]
|
||||
};
|
||||
|
||||
function DataSource(courier, initialState) {
|
||||
function DataSource(courier, type, initialState) {
|
||||
var state;
|
||||
|
||||
if (initialState) {
|
||||
|
@ -38,23 +47,36 @@ define(function (require) {
|
|||
} else {
|
||||
state = _.cloneDeep(initialState);
|
||||
}
|
||||
if (state._type) {
|
||||
if (type && type !== state._type) {
|
||||
throw new Error('Initial state is not of the type specified for this DataSource');
|
||||
} else {
|
||||
type = state._type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state = {};
|
||||
}
|
||||
|
||||
type = type || 'search';
|
||||
if (!_.has(apiMethods, type)) {
|
||||
throw new TypeError('Invalid DataSource type ' + type);
|
||||
}
|
||||
state._type = type;
|
||||
|
||||
var mapper = new Mapper();
|
||||
|
||||
var onNewListener = _.bind(function (name) {
|
||||
// new newListener is emitted before it is added, count will be 0
|
||||
if (name !== 'results' || listenerCount(this, 'results') !== 0) return;
|
||||
courier.startFetchingSource(this);
|
||||
courier.openDataSource(this);
|
||||
this.removeListener('newListener', onNewListener);
|
||||
this.on('removeListener', onRemoveListener);
|
||||
}, this);
|
||||
|
||||
var onRemoveListener = _.bind(function () {
|
||||
if (listenerCount(this, 'results') > 0) return;
|
||||
courier.stopFetchingSource(this);
|
||||
courier.closeDataSource(this);
|
||||
this.removeListener('removeListener', onRemoveListener);
|
||||
this.on('newListener', onNewListener);
|
||||
}, this);
|
||||
|
@ -82,12 +104,15 @@ define(function (require) {
|
|||
return _.keys(mapping);
|
||||
});
|
||||
};
|
||||
this.getType = function () {
|
||||
return state._type;
|
||||
};
|
||||
this.extend = function () {
|
||||
return courier.createSource().inherits(this);
|
||||
return courier.createSource(type).inherits(this);
|
||||
};
|
||||
|
||||
// get/set internal state values
|
||||
optionNames.forEach(function (name) {
|
||||
apiMethods[type].forEach(function (name) {
|
||||
this[name] = function (val) {
|
||||
state[name] = val;
|
||||
if (name === 'index' && arguments[1]) {
|
||||
|
|
135
src/courier/docs.js
Normal file
135
src/courier/docs.js
Normal file
|
@ -0,0 +1,135 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
function Docs(courier) {
|
||||
// docs that we have let loose, and want to track
|
||||
var tracking = {};
|
||||
var watchers = {};
|
||||
|
||||
function respId(getResp) {
|
||||
return [
|
||||
encodeURIComponent(getResp._index),
|
||||
encodeURIComponent(getResp._type),
|
||||
encodeURIComponent(getResp._id)
|
||||
].join('/');
|
||||
}
|
||||
|
||||
function change(id, updated) {
|
||||
if (watchers[id]) {
|
||||
var notify = function () {
|
||||
var oldVal = tracking[id]._source;
|
||||
tracking[id] = _.cloneDeep(update);
|
||||
watchers[id].forEach(function (watcher) {
|
||||
try {
|
||||
watcher(updated, oldVal);
|
||||
} catch (e) { console.error(e); }
|
||||
});
|
||||
};
|
||||
|
||||
if (updated) {
|
||||
notify();
|
||||
} else {
|
||||
courier.get('client').get({
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function track(resp) {
|
||||
var id = respId(resp);
|
||||
var tracker = _.pick(resp, '_id', '_type', '_index', '_source');
|
||||
if (tracking[id] && equal(tracking[id]._source, resp)) return false;
|
||||
change(id, resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a function to be called when objects matching
|
||||
* this resp are changed
|
||||
* @param {object} resp - Response like object, should contain _id, _type, and _index keys
|
||||
* @param {[type]} onChange - Function to be called when changes are noticed
|
||||
*/
|
||||
function watch(resp, onChange) {
|
||||
var id = respId(resp);
|
||||
if (!watchers[id]) watchers[id] = [];
|
||||
watchers[id].push(onChange);
|
||||
}
|
||||
|
||||
function get(args, cb, onChange) {
|
||||
var client = courier.get('client');
|
||||
client.get(args, function (err, getResp) {
|
||||
if (err) return cb(err);
|
||||
watch(getResp, onChange);
|
||||
return cb(void 0, getResp);
|
||||
});
|
||||
}
|
||||
|
||||
function index(args, cb) {
|
||||
var client = courier.get('client');
|
||||
|
||||
client.index(args, function (err, indexResp) {
|
||||
if (err) return cb(err);
|
||||
delete indexResp.created;
|
||||
indexResp._source = args.body;
|
||||
track(indexResp);
|
||||
return cb(void 0, indexResp);
|
||||
});
|
||||
}
|
||||
|
||||
function update(args, cb) {
|
||||
var client = courier.get('client');
|
||||
client.update(args, function (err, updateResp) {
|
||||
if (err) return cb(err);
|
||||
return cb(void 0, updateResp);
|
||||
});
|
||||
}
|
||||
|
||||
this.watch = watch;
|
||||
this.get = get;
|
||||
this.index = index;
|
||||
this.set = index;
|
||||
this.update = update;
|
||||
}
|
||||
|
||||
function equal(o1, o2) {
|
||||
/* jshint eqeqeq:false, forin:false */
|
||||
if (o1 === o2) return true;
|
||||
if (o1 === null || o2 === null) return false;
|
||||
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
|
||||
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
|
||||
if (t1 == t2) {
|
||||
if (t1 == 'object') {
|
||||
if (_.isArray(o1)) {
|
||||
if (!_.isArray(o2)) return false;
|
||||
if ((length = o1.length) == o2.length) {
|
||||
for (key = 0; key < length; key++) {
|
||||
if (!equal(o1[key], o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (_.isDate(o1)) {
|
||||
return _.isDate(o2) && o1.getTime() == o2.getTime();
|
||||
} else if (_.isRegExp(o1) && _.isRegExp(o2)) {
|
||||
return o1.toString() == o2.toString();
|
||||
} else {
|
||||
if (_.isArray(o2)) return false;
|
||||
keySet = {};
|
||||
for (key in o1) {
|
||||
if (_.isFunction(o1[key])) continue;
|
||||
if (!equal(o1[key], o2[key])) return false;
|
||||
keySet[key] = true;
|
||||
}
|
||||
for (key in o2) {
|
||||
if (!keySet.hasOwnProperty(key) &&
|
||||
o2[key] !== undefined &&
|
||||
!_.isFunction(o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return Docs;
|
||||
});
|
|
@ -8,14 +8,16 @@ define(function (require) {
|
|||
*/
|
||||
function Mapper(index, type) {
|
||||
this.indices = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
this.getFields = function () {
|
||||
|
||||
};
|
||||
|
||||
this.getFieldType = function (field, type) {
|
||||
return field, type;
|
||||
};
|
||||
}
|
||||
|
||||
return Mapper;
|
||||
|
|
16
src/courier/scratch.js
Normal file
16
src/courier/scratch.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
var elasticsearch = require('elasticsearch');
|
||||
var es = elasticsearch.Client();
|
||||
|
||||
es.msearch({
|
||||
body: [
|
||||
{
|
||||
index: 'logstash-2014.02.1111'
|
||||
},
|
||||
{
|
||||
query: { 'match_all': {} }
|
||||
}
|
||||
]
|
||||
}, function (err, resp) {
|
||||
console.log(resp);
|
||||
es.close();
|
||||
});
|
|
@ -1,2 +1,3 @@
|
|||
<courier-test type="apache" fields="extension,response,request"></courier-test>
|
||||
<courier-test type="nginx" fields=""></courier-test>
|
||||
<courier-test type="nginx" fields=""></courier-test>
|
||||
<courier-doc-test index="" ></courier-doc-test>
|
|
@ -3,8 +3,8 @@ define(function (require) {
|
|||
|
||||
angular.module('kibana/controllers')
|
||||
.controller('Kibana', function (courier, $scope, $rootScope) {
|
||||
$rootScope.dataSource = courier.createSource()
|
||||
.index('logstash-2014.02.13', 'daily')
|
||||
$rootScope.dataSource = courier.createSource('search')
|
||||
.index('_all')
|
||||
.size(5);
|
||||
|
||||
// this should be triggered from within the controlling application
|
||||
|
|
|
@ -77,6 +77,7 @@ define(function (require) {
|
|||
require([
|
||||
'services/courier',
|
||||
'services/es',
|
||||
'services/config',
|
||||
'controllers/kibana'
|
||||
], function () {
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
};
|
||||
|
||||
var bowerComponents = [
|
||||
'd3',
|
||||
['lodash', 'dist/lodash'],
|
||||
'jquery',
|
||||
'angular',
|
||||
'angular-route',
|
||||
['elasticsearch', 'elasticsearch.angular']
|
||||
'd3',
|
||||
['elasticsearch', 'elasticsearch.angular'],
|
||||
'jquery',
|
||||
['lodash', 'dist/lodash']
|
||||
];
|
||||
|
||||
bowerComponents.forEach(function (name) {
|
||||
|
|
89
src/kibana/services/config.js
Normal file
89
src/kibana/services/config.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var configFile = require('../../config');
|
||||
var _ = require('lodash');
|
||||
|
||||
var module = angular.module('kibana/services');
|
||||
module.service('config', function ($q, es, courier) {
|
||||
|
||||
var app = angular.module('kibana');
|
||||
var config = {};
|
||||
var watchers = {};
|
||||
|
||||
function watch(key, onChange) {
|
||||
// probably a horrible idea
|
||||
if (!watchers[key]) watchers[key] = [];
|
||||
watchers[key].push(onChange);
|
||||
}
|
||||
|
||||
function change(key, val) {
|
||||
if (config[key] !== val) {
|
||||
var oldVal = config[key];
|
||||
config[key] = val;
|
||||
if (watchers[key]) {
|
||||
watchers[key].forEach(function (watcher) {
|
||||
watcher(val, oldVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDoc() {
|
||||
var defer = $q.promise();
|
||||
|
||||
courier.get({
|
||||
index: config.kibanaIndex,
|
||||
type: 'config',
|
||||
id: app.constant('kbnVersion')
|
||||
}, function fetchDoc(err, doc) {
|
||||
_.assign(config, doc);
|
||||
defer.resolve();
|
||||
}, function onDocUpdate(doc) {
|
||||
_.forOwn(doc, function (val, key) {
|
||||
change(key, val);
|
||||
});
|
||||
});
|
||||
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
return {
|
||||
get: function (key) {
|
||||
return config[key];
|
||||
},
|
||||
set: function (key, val) {
|
||||
// sets a value in the config
|
||||
// the es doc must be updated successfully for the update to reflect in the get api.
|
||||
|
||||
if (key === 'elasticsearch' || key === 'kibanaIndex') {
|
||||
return $q.reject(new Error('These values must be updated in the config.js file.'));
|
||||
}
|
||||
|
||||
var defer = $q.defer();
|
||||
|
||||
if (config[key] === val) {
|
||||
defer.resolve();
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
var body = {};
|
||||
body[key] = val;
|
||||
courier.update({
|
||||
index: config.kibanaIndex,
|
||||
type: 'config',
|
||||
id: app.constant('kbnVersion'),
|
||||
body: body
|
||||
}, function (err) {
|
||||
if (err) return defer.reject(err);
|
||||
|
||||
change(key, val);
|
||||
defer.resolve();
|
||||
});
|
||||
|
||||
return defer.promise;
|
||||
},
|
||||
$watch: watch,
|
||||
init: getDoc
|
||||
};
|
||||
});
|
||||
});
|
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
options: {
|
||||
base: [
|
||||
'<%= unitTestDir %>',
|
||||
'<%= testUtilsDir %>',
|
||||
'<%= src %>',
|
||||
'<%= root %>/node_modules/mocha',
|
||||
'<%= root %>/node_modules/expect.js'
|
||||
|
|
19
tasks/config/jshint.js
Normal file
19
tasks/config/jshint.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
module.exports = function(config) {
|
||||
return {
|
||||
// just lint the source dir
|
||||
source: {
|
||||
files: {
|
||||
src: ['Gruntfile.js', '<%= root %>/src/**/*.js']
|
||||
}
|
||||
},
|
||||
options: {
|
||||
jshintrc: '<%= root %>/.jshintrc',
|
||||
ignores: [
|
||||
'node_modules/*',
|
||||
'dist/*',
|
||||
'sample/*',
|
||||
'<%= root %>/src/bower_components/**/*'
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
4
tasks/default.js
Normal file
4
tasks/default.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Lint and build CSS
|
||||
module.exports = function(grunt) {
|
||||
grunt.registerTask('default', ['jshint:source']);
|
||||
};
|
|
@ -22,6 +22,19 @@
|
|||
|
||||
<!-- tests -->
|
||||
<script>
|
||||
require.config({
|
||||
paths: {
|
||||
sinon: '../sinon'
|
||||
},
|
||||
shim: {
|
||||
'sinon/sinon': {
|
||||
deps: [
|
||||
'sinon/sinon-timers-1.8.2'
|
||||
],
|
||||
exports: 'sinon'
|
||||
}
|
||||
}
|
||||
})
|
||||
require([
|
||||
'/specs/courier.js',
|
||||
'/specs/data_source.js'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
define(function (require) {
|
||||
var Courier = require('courier/courier');
|
||||
var _ = require('lodash');
|
||||
var sinon = require('sinon/sinon');
|
||||
|
||||
describe('Courier Module', function () {
|
||||
|
||||
|
@ -22,37 +23,51 @@ define(function (require) {
|
|||
|
||||
describe('sync API', function () {
|
||||
var courier;
|
||||
beforeEach(function () {
|
||||
courier = new Courier();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
courier.close();
|
||||
if (courier) {
|
||||
courier.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe('#fetchInterval', function () {
|
||||
it('sets the interval in milliseconds that queries will be fetched', function () {
|
||||
courier.fetchInterval(1000);
|
||||
expect(courier.fetchInterval()).to.eql(1000);
|
||||
});
|
||||
it('sets the interval in milliseconds that queries will be fetched');
|
||||
it('resets the timer if the courier has been started');
|
||||
});
|
||||
|
||||
describe('#define', function () {
|
||||
it('creates an empty (match all) DataSource object', function () {
|
||||
var source = courier.define();
|
||||
expect(source._state()).to.eql({});
|
||||
describe('#createSource', function () {
|
||||
it('creates an empty search DataSource object', function () {
|
||||
courier = new Courier();
|
||||
var source = courier.createSource();
|
||||
expect(source._state()).to.eql({ _type: 'search' });
|
||||
});
|
||||
it('optionally accepts a type for the DataSource', function () {
|
||||
var courier = new Courier();
|
||||
expect(courier.createSource()._state()._type).to.eql('search');
|
||||
expect(courier.createSource('search')._state()._type).to.eql('search');
|
||||
expect(courier.createSource('get')._state()._type).to.eql('get');
|
||||
expect(function () {
|
||||
courier.createSource('invalid type');
|
||||
}).to.throwError(TypeError);
|
||||
});
|
||||
it('optionally accepts a json object/string that will populate the DataSource object with settings', function () {
|
||||
courier = new Courier();
|
||||
var savedState = JSON.stringify({
|
||||
index: 'logstash-[YYYY-MM-DD]'
|
||||
_type: 'get',
|
||||
index: 'logstash-[YYYY-MM-DD]',
|
||||
type: 'nginx',
|
||||
id: '1'
|
||||
});
|
||||
var source = courier.define(savedState);
|
||||
var source = courier.createSource('get', savedState);
|
||||
expect(source + '').to.eql(savedState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#start', function () {
|
||||
it('triggers a fetch and begins the fetch cycle');
|
||||
it('triggers a fetch and begins the fetch cycle', function () {
|
||||
courier = new Courier();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('#stop', function () {
|
||||
|
@ -63,7 +78,7 @@ define(function (require) {
|
|||
describe('source req tracking', function () {
|
||||
it('updates the stored query when the data source is updated', function () {
|
||||
var courier = new Courier();
|
||||
var source = courier.define();
|
||||
var source = courier.createSource('search');
|
||||
|
||||
source.on('results', _.noop);
|
||||
source.index('the index name');
|
||||
|
@ -77,7 +92,7 @@ define(function (require) {
|
|||
it('merges the state of one data source with it\'s parents', function () {
|
||||
var courier = new Courier();
|
||||
|
||||
var root = courier.define()
|
||||
var root = courier.createSource('search')
|
||||
.index('people')
|
||||
.type('students')
|
||||
.filter({
|
||||
|
@ -86,7 +101,7 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
var math = courier.define()
|
||||
var math = courier.createSource('search')
|
||||
.inherits(root)
|
||||
.filter({
|
||||
terms: {
|
||||
|
|
|
@ -1,5 +1,34 @@
|
|||
define(function (require) {
|
||||
var Courier = require('courier/courier');
|
||||
var DataSource = require('courier/data_source');
|
||||
|
||||
describe('DataSource class', function () {
|
||||
var courier = new Courier();
|
||||
describe('::new', function () {
|
||||
it('accepts and validates a type', function () {
|
||||
var source = new DataSource(courier, 'get');
|
||||
expect(source._state()._type).to.eql('get');
|
||||
|
||||
source = new DataSource(courier, 'search');
|
||||
expect(source._state()._type).to.eql('search');
|
||||
|
||||
expect(function () {
|
||||
source = new DataSource(courier, 'invalid Type');
|
||||
}).to.throwError(TypeError);
|
||||
});
|
||||
|
||||
it('optionally accepts a json object/string that will populate the DataSource object with settings', function () {
|
||||
var savedState = JSON.stringify({
|
||||
_type: 'get',
|
||||
index: 'logstash-[YYYY-MM-DD]',
|
||||
type: 'nginx',
|
||||
id: '1'
|
||||
});
|
||||
var source = new DataSource(courier, 'get', savedState);
|
||||
expect(source + '').to.eql(savedState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', function () {
|
||||
describe('results', function () {
|
||||
it('emits when a new result is available');
|
||||
|
|
4728
test/utils/sinon/sinon-1.8.2.js
Normal file
4728
test/utils/sinon/sinon-1.8.2.js
Normal file
File diff suppressed because it is too large
Load diff
86
test/utils/sinon/sinon-ie-1.8.2.js
Normal file
86
test/utils/sinon/sinon-ie-1.8.2.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Sinon.JS 1.8.2, 2014/02/13
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
|
||||
*
|
||||
* (The BSD License)
|
||||
*
|
||||
* Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Christian Johansen nor the names of his contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
|
||||
/**
|
||||
* Helps IE run the fake timers. By defining global functions, IE allows
|
||||
* them to be overwritten at a later point. If these are not defined like
|
||||
* this, overwriting them will result in anything from an exception to browser
|
||||
* crash.
|
||||
*
|
||||
* If you don't require fake timers to work in IE, don't include this file.
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
function setTimeout() {}
|
||||
function clearTimeout() {}
|
||||
function setImmediate() {}
|
||||
function clearImmediate() {}
|
||||
function setInterval() {}
|
||||
function clearInterval() {}
|
||||
function Date() {}
|
||||
|
||||
// Reassign the original functions. Now their writable attribute
|
||||
// should be true. Hackish, I know, but it works.
|
||||
setTimeout = sinon.timers.setTimeout;
|
||||
clearTimeout = sinon.timers.clearTimeout;
|
||||
setImmediate = sinon.timers.setImmediate;
|
||||
clearImmediate = sinon.timers.clearImmediate;
|
||||
setInterval = sinon.timers.setInterval;
|
||||
clearInterval = sinon.timers.clearInterval;
|
||||
Date = sinon.timers.Date;
|
||||
|
||||
/*global sinon*/
|
||||
/**
|
||||
* Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
|
||||
* them to be overwritten at a later point. If these are not defined like
|
||||
* this, overwriting them will result in anything from an exception to browser
|
||||
* crash.
|
||||
*
|
||||
* If you don't require fake XHR to work in IE, don't include this file.
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
function XMLHttpRequest() {}
|
||||
|
||||
// Reassign the original function. Now its writable attribute
|
||||
// should be true. Hackish, I know, but it works.
|
||||
XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
|
86
test/utils/sinon/sinon-ie.js
Normal file
86
test/utils/sinon/sinon-ie.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Sinon.JS 1.8.2, 2014/02/13
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
|
||||
*
|
||||
* (The BSD License)
|
||||
*
|
||||
* Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Christian Johansen nor the names of his contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
|
||||
/**
|
||||
* Helps IE run the fake timers. By defining global functions, IE allows
|
||||
* them to be overwritten at a later point. If these are not defined like
|
||||
* this, overwriting them will result in anything from an exception to browser
|
||||
* crash.
|
||||
*
|
||||
* If you don't require fake timers to work in IE, don't include this file.
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
function setTimeout() {}
|
||||
function clearTimeout() {}
|
||||
function setImmediate() {}
|
||||
function clearImmediate() {}
|
||||
function setInterval() {}
|
||||
function clearInterval() {}
|
||||
function Date() {}
|
||||
|
||||
// Reassign the original functions. Now their writable attribute
|
||||
// should be true. Hackish, I know, but it works.
|
||||
setTimeout = sinon.timers.setTimeout;
|
||||
clearTimeout = sinon.timers.clearTimeout;
|
||||
setImmediate = sinon.timers.setImmediate;
|
||||
clearImmediate = sinon.timers.clearImmediate;
|
||||
setInterval = sinon.timers.setInterval;
|
||||
clearInterval = sinon.timers.clearInterval;
|
||||
Date = sinon.timers.Date;
|
||||
|
||||
/*global sinon*/
|
||||
/**
|
||||
* Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
|
||||
* them to be overwritten at a later point. If these are not defined like
|
||||
* this, overwriting them will result in anything from an exception to browser
|
||||
* crash.
|
||||
*
|
||||
* If you don't require fake XHR to work in IE, don't include this file.
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
function XMLHttpRequest() {}
|
||||
|
||||
// Reassign the original function. Now its writable attribute
|
||||
// should be true. Hackish, I know, but it works.
|
||||
XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
|
1726
test/utils/sinon/sinon-server-1.8.2.js
Normal file
1726
test/utils/sinon/sinon-server-1.8.2.js
Normal file
File diff suppressed because it is too large
Load diff
419
test/utils/sinon/sinon-timers-1.8.2.js
Normal file
419
test/utils/sinon/sinon-timers-1.8.2.js
Normal file
|
@ -0,0 +1,419 @@
|
|||
/**
|
||||
* Sinon.JS 1.8.2, 2014/02/13
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
|
||||
*
|
||||
* (The BSD License)
|
||||
*
|
||||
* Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Christian Johansen nor the names of his contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
|
||||
/*global module, require, window*/
|
||||
/**
|
||||
* Fake timer API
|
||||
* setTimeout
|
||||
* setInterval
|
||||
* clearTimeout
|
||||
* clearInterval
|
||||
* tick
|
||||
* reset
|
||||
* Date
|
||||
*
|
||||
* Inspired by jsUnitMockTimeOut from JsUnit
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
|
||||
if (typeof sinon == "undefined") {
|
||||
var sinon = {};
|
||||
}
|
||||
|
||||
(function (global) {
|
||||
var id = 1;
|
||||
|
||||
function addTimer(args, recurring) {
|
||||
if (args.length === 0) {
|
||||
throw new Error("Function requires at least 1 parameter");
|
||||
}
|
||||
|
||||
if (typeof args[0] === "undefined") {
|
||||
throw new Error("Callback must be provided to timer calls");
|
||||
}
|
||||
|
||||
var toId = id++;
|
||||
var delay = args[1] || 0;
|
||||
|
||||
if (!this.timeouts) {
|
||||
this.timeouts = {};
|
||||
}
|
||||
|
||||
this.timeouts[toId] = {
|
||||
id: toId,
|
||||
func: args[0],
|
||||
callAt: this.now + delay,
|
||||
invokeArgs: Array.prototype.slice.call(args, 2)
|
||||
};
|
||||
|
||||
if (recurring === true) {
|
||||
this.timeouts[toId].interval = delay;
|
||||
}
|
||||
|
||||
return toId;
|
||||
}
|
||||
|
||||
function parseTime(str) {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var strings = str.split(":");
|
||||
var l = strings.length, i = l;
|
||||
var ms = 0, parsed;
|
||||
|
||||
if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
|
||||
throw new Error("tick only understands numbers and 'h:m:s'");
|
||||
}
|
||||
|
||||
while (i--) {
|
||||
parsed = parseInt(strings[i], 10);
|
||||
|
||||
if (parsed >= 60) {
|
||||
throw new Error("Invalid time " + str);
|
||||
}
|
||||
|
||||
ms += parsed * Math.pow(60, (l - i - 1));
|
||||
}
|
||||
|
||||
return ms * 1000;
|
||||
}
|
||||
|
||||
function createObject(object) {
|
||||
var newObject;
|
||||
|
||||
if (Object.create) {
|
||||
newObject = Object.create(object);
|
||||
} else {
|
||||
var F = function () {};
|
||||
F.prototype = object;
|
||||
newObject = new F();
|
||||
}
|
||||
|
||||
newObject.Date.clock = newObject;
|
||||
return newObject;
|
||||
}
|
||||
|
||||
sinon.clock = {
|
||||
now: 0,
|
||||
|
||||
create: function create(now) {
|
||||
var clock = createObject(this);
|
||||
|
||||
if (typeof now == "number") {
|
||||
clock.now = now;
|
||||
}
|
||||
|
||||
if (!!now && typeof now == "object") {
|
||||
throw new TypeError("now should be milliseconds since UNIX epoch");
|
||||
}
|
||||
|
||||
return clock;
|
||||
},
|
||||
|
||||
setTimeout: function setTimeout(callback, timeout) {
|
||||
return addTimer.call(this, arguments, false);
|
||||
},
|
||||
|
||||
clearTimeout: function clearTimeout(timerId) {
|
||||
if (!this.timeouts) {
|
||||
this.timeouts = [];
|
||||
}
|
||||
|
||||
if (timerId in this.timeouts) {
|
||||
delete this.timeouts[timerId];
|
||||
}
|
||||
},
|
||||
|
||||
setInterval: function setInterval(callback, timeout) {
|
||||
return addTimer.call(this, arguments, true);
|
||||
},
|
||||
|
||||
clearInterval: function clearInterval(timerId) {
|
||||
this.clearTimeout(timerId);
|
||||
},
|
||||
|
||||
setImmediate: function setImmediate(callback) {
|
||||
var passThruArgs = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
|
||||
},
|
||||
|
||||
clearImmediate: function clearImmediate(timerId) {
|
||||
this.clearTimeout(timerId);
|
||||
},
|
||||
|
||||
tick: function tick(ms) {
|
||||
ms = typeof ms == "number" ? ms : parseTime(ms);
|
||||
var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
|
||||
var timer = this.firstTimerInRange(tickFrom, tickTo);
|
||||
|
||||
var firstException;
|
||||
while (timer && tickFrom <= tickTo) {
|
||||
if (this.timeouts[timer.id]) {
|
||||
tickFrom = this.now = timer.callAt;
|
||||
try {
|
||||
this.callTimer(timer);
|
||||
} catch (e) {
|
||||
firstException = firstException || e;
|
||||
}
|
||||
}
|
||||
|
||||
timer = this.firstTimerInRange(previous, tickTo);
|
||||
previous = tickFrom;
|
||||
}
|
||||
|
||||
this.now = tickTo;
|
||||
|
||||
if (firstException) {
|
||||
throw firstException;
|
||||
}
|
||||
|
||||
return this.now;
|
||||
},
|
||||
|
||||
firstTimerInRange: function (from, to) {
|
||||
var timer, smallest = null, originalTimer;
|
||||
|
||||
for (var id in this.timeouts) {
|
||||
if (this.timeouts.hasOwnProperty(id)) {
|
||||
if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (smallest === null || this.timeouts[id].callAt < smallest) {
|
||||
originalTimer = this.timeouts[id];
|
||||
smallest = this.timeouts[id].callAt;
|
||||
|
||||
timer = {
|
||||
func: this.timeouts[id].func,
|
||||
callAt: this.timeouts[id].callAt,
|
||||
interval: this.timeouts[id].interval,
|
||||
id: this.timeouts[id].id,
|
||||
invokeArgs: this.timeouts[id].invokeArgs
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return timer || null;
|
||||
},
|
||||
|
||||
callTimer: function (timer) {
|
||||
if (typeof timer.interval == "number") {
|
||||
this.timeouts[timer.id].callAt += timer.interval;
|
||||
} else {
|
||||
delete this.timeouts[timer.id];
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof timer.func == "function") {
|
||||
timer.func.apply(null, timer.invokeArgs);
|
||||
} else {
|
||||
eval(timer.func);
|
||||
}
|
||||
} catch (e) {
|
||||
var exception = e;
|
||||
}
|
||||
|
||||
if (!this.timeouts[timer.id]) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
},
|
||||
|
||||
reset: function reset() {
|
||||
this.timeouts = {};
|
||||
},
|
||||
|
||||
Date: (function () {
|
||||
var NativeDate = Date;
|
||||
|
||||
function ClockDate(year, month, date, hour, minute, second, ms) {
|
||||
// Defensive and verbose to avoid potential harm in passing
|
||||
// explicit undefined when user does not pass argument
|
||||
switch (arguments.length) {
|
||||
case 0:
|
||||
return new NativeDate(ClockDate.clock.now);
|
||||
case 1:
|
||||
return new NativeDate(year);
|
||||
case 2:
|
||||
return new NativeDate(year, month);
|
||||
case 3:
|
||||
return new NativeDate(year, month, date);
|
||||
case 4:
|
||||
return new NativeDate(year, month, date, hour);
|
||||
case 5:
|
||||
return new NativeDate(year, month, date, hour, minute);
|
||||
case 6:
|
||||
return new NativeDate(year, month, date, hour, minute, second);
|
||||
default:
|
||||
return new NativeDate(year, month, date, hour, minute, second, ms);
|
||||
}
|
||||
}
|
||||
|
||||
return mirrorDateProperties(ClockDate, NativeDate);
|
||||
}())
|
||||
};
|
||||
|
||||
function mirrorDateProperties(target, source) {
|
||||
if (source.now) {
|
||||
target.now = function now() {
|
||||
return target.clock.now;
|
||||
};
|
||||
} else {
|
||||
delete target.now;
|
||||
}
|
||||
|
||||
if (source.toSource) {
|
||||
target.toSource = function toSource() {
|
||||
return source.toSource();
|
||||
};
|
||||
} else {
|
||||
delete target.toSource;
|
||||
}
|
||||
|
||||
target.toString = function toString() {
|
||||
return source.toString();
|
||||
};
|
||||
|
||||
target.prototype = source.prototype;
|
||||
target.parse = source.parse;
|
||||
target.UTC = source.UTC;
|
||||
target.prototype.toUTCString = source.prototype.toUTCString;
|
||||
|
||||
for (var prop in source) {
|
||||
if (source.hasOwnProperty(prop)) {
|
||||
target[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
var methods = ["Date", "setTimeout", "setInterval",
|
||||
"clearTimeout", "clearInterval"];
|
||||
|
||||
if (typeof global.setImmediate !== "undefined") {
|
||||
methods.push("setImmediate");
|
||||
}
|
||||
|
||||
if (typeof global.clearImmediate !== "undefined") {
|
||||
methods.push("clearImmediate");
|
||||
}
|
||||
|
||||
function restore() {
|
||||
var method;
|
||||
|
||||
for (var i = 0, l = this.methods.length; i < l; i++) {
|
||||
method = this.methods[i];
|
||||
|
||||
if (global[method].hadOwnProperty) {
|
||||
global[method] = this["_" + method];
|
||||
} else {
|
||||
try {
|
||||
delete global[method];
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent multiple executions which will completely remove these props
|
||||
this.methods = [];
|
||||
}
|
||||
|
||||
function stubGlobal(method, clock) {
|
||||
clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
|
||||
clock["_" + method] = global[method];
|
||||
|
||||
if (method == "Date") {
|
||||
var date = mirrorDateProperties(clock[method], global[method]);
|
||||
global[method] = date;
|
||||
} else {
|
||||
global[method] = function () {
|
||||
return clock[method].apply(clock, arguments);
|
||||
};
|
||||
|
||||
for (var prop in clock[method]) {
|
||||
if (clock[method].hasOwnProperty(prop)) {
|
||||
global[method][prop] = clock[method][prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global[method].clock = clock;
|
||||
}
|
||||
|
||||
sinon.useFakeTimers = function useFakeTimers(now) {
|
||||
var clock = sinon.clock.create(now);
|
||||
clock.restore = restore;
|
||||
clock.methods = Array.prototype.slice.call(arguments,
|
||||
typeof now == "number" ? 1 : 0);
|
||||
|
||||
if (clock.methods.length === 0) {
|
||||
clock.methods = methods;
|
||||
}
|
||||
|
||||
for (var i = 0, l = clock.methods.length; i < l; i++) {
|
||||
stubGlobal(clock.methods[i], clock);
|
||||
}
|
||||
|
||||
return clock;
|
||||
};
|
||||
}(typeof global != "undefined" && typeof global !== "function" ? global : this));
|
||||
|
||||
sinon.timers = {
|
||||
setTimeout: setTimeout,
|
||||
clearTimeout: clearTimeout,
|
||||
setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
|
||||
clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
|
||||
setInterval: setInterval,
|
||||
clearInterval: clearInterval,
|
||||
Date: Date
|
||||
};
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = sinon;
|
||||
}
|
66
test/utils/sinon/sinon-timers-ie-1.8.2.js
Normal file
66
test/utils/sinon/sinon-timers-ie-1.8.2.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Sinon.JS 1.8.2, 2014/02/13
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
|
||||
*
|
||||
* (The BSD License)
|
||||
*
|
||||
* Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Christian Johansen nor the names of his contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
|
||||
/**
|
||||
* Helps IE run the fake timers. By defining global functions, IE allows
|
||||
* them to be overwritten at a later point. If these are not defined like
|
||||
* this, overwriting them will result in anything from an exception to browser
|
||||
* crash.
|
||||
*
|
||||
* If you don't require fake timers to work in IE, don't include this file.
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
* @license BSD
|
||||
*
|
||||
* Copyright (c) 2010-2013 Christian Johansen
|
||||
*/
|
||||
function setTimeout() {}
|
||||
function clearTimeout() {}
|
||||
function setImmediate() {}
|
||||
function clearImmediate() {}
|
||||
function setInterval() {}
|
||||
function clearInterval() {}
|
||||
function Date() {}
|
||||
|
||||
// Reassign the original functions. Now their writable attribute
|
||||
// should be true. Hackish, I know, but it works.
|
||||
setTimeout = sinon.timers.setTimeout;
|
||||
clearTimeout = sinon.timers.clearTimeout;
|
||||
setImmediate = sinon.timers.setImmediate;
|
||||
clearImmediate = sinon.timers.clearImmediate;
|
||||
setInterval = sinon.timers.setInterval;
|
||||
clearInterval = sinon.timers.clearInterval;
|
||||
Date = sinon.timers.Date;
|
4728
test/utils/sinon/sinon.js
Normal file
4728
test/utils/sinon/sinon.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue