Merging in latest github/master
open #90 Squashed commit of the following: commita2d06583caMerge:74f289c5d5425dAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 27 14:04:49 2015 -0700 Merge pull request #216 from nasa/open-vista54a Review and integrate open-vista54a into master commit5d5425db04Author: Charles Hacskaylo <charlesh88@gmail.com> Date: Tue Oct 27 11:50:16 2015 -0700 [Frontend] Finessing and verifying CSS vista#54 Verified against fixed position and scrolling views using SineWave generator; font-size of glyph tweaked; commita8856c0612Author: Charles Hacskaylo <charlesh88@gmail.com> Date: Tue Oct 27 11:40:35 2015 -0700 [Frontend] Platform-specific mods to limits vista#54 Refactor limits into multiple classes, separating upr/lwr from red/yellow; Modded SineWaveLimitCapability accordingly; Normalized upr/lwr glyphs; (cherry picked from commit a26d71b) commit74f289cb34Merge:4ec243c29bdc9dAuthor: akhenry <akhenry@gmail.com> Date: Tue Oct 27 10:48:33 2015 -0700 Merge pull request #206 from nasa/open150b [Plot] Ignore empty lines commit4ec243c6fbMerge:407d9883d996acAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Sat Oct 24 07:48:45 2015 -0700 Merge pull request #212 from nasa/open211 [RequireJS] Specify path for uuid commit407d9881ffMerge:6ee622b21739ffAuthor: akhenry <akhenry@gmail.com> Date: Fri Oct 23 19:16:51 2015 -0700 Merge pull request #200 from nasa/open-toc [Documentation] Add table of contents commit6ee622b3f5Merge:099d70b87e317aAuthor: akhenry <akhenry@gmail.com> Date: Fri Oct 23 17:04:04 2015 -0700 Merge pull request #192 from nasa/open153 [CI] Remove non-existent bundle from procfile commit099d70b8d9Merge:90828ef8e2a2eeAuthor: akhenry <akhenry@gmail.com> Date: Fri Oct 23 17:00:46 2015 -0700 Merge pull request #175 from nasa/open147 [Entanglement] Add "Go To Original" action commit3d996ac466Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 23 16:32:05 2015 -0700 [RequireJS] Specify path for uuid Specify path for uuid, making it available for any code that would require it, without that code needing to know the path to it. Fixes https://github.com/nasa/openmctweb/issues/211. commit90828ef63dMerge:bf24ac7dbebf08Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 23 16:23:29 2015 -0700 Merge remote-tracking branch 'github-open/open181' into open-master commit29bdc9d574Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Fri Oct 23 13:04:06 2015 -0700 [Plot] Ignore empty lines Ignore empty lines (plot lines with no data) when determining domain extrema; avoids failure to draw multiple plot lines in a telemetry panel, nasa/openmctweb#150. commitbf24ac7c93Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Fri Oct 23 12:14:46 2015 -0700 [Search] Update field name Update field name in GenericSearchProvider to reflect changes from nasa/openmctweb#193. Avoids exceptions on mutation. Additionally, add test case exercising relevant code and verifying that reindexing is scheduled upon mutation as expected. commit59f094763bMerge:3080861496cf85Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Thu Oct 22 16:58:02 2015 -0700 Merge pull request #193 from nasa/search-performance Search performance commitdbebf08500Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 15:38:58 2015 -0700 [Time Controller] Add test cases ...to verify behavior on text entry of dates. commit847c356063Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 15:26:42 2015 -0700 [Time Controller] Change color when input is invalid nasa/openmctweb#181 commit06bcd28558Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 15:22:00 2015 -0700 [Time Controller] Keep inputs in sync Keep inputs in sync with displayed data in time controller, without overwriting user-entered text. nasa/openmctweb#181 commitf88e8ebb51Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 15:08:44 2015 -0700 [Time Controller] Update model state for text entry commit6d2b2fd81eAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 14:46:12 2015 -0700 [Time Controller] Parse user-entered timestamps nasa/openmctweb#181. commit608800ae63Merge:07818b0fb0ce1eAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 14:40:42 2015 -0700 Merge remote-tracking branch 'github/master' into open181 Conflicts: platform/commonUI/general/res/templates/controls/time-controller.html commit07818b0a6dAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Wed Oct 21 14:35:18 2015 -0700 [Time Controller] Show bounds in a text field Show bounds in a text field to allow user editing; supports manual editing of time controller bounds, nasa/openmctweb#181. commit496cf85b7eAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Wed Oct 21 09:46:32 2015 -0700 [JSDoc] Correct mistake commit833f57e284Author: Pete Richards <peter.l.richards@nasa.gov> Date: Wed Oct 21 07:39:59 2015 -0700 [Search] Don't block UI between requests Timeout subsequent calls to keepIndexing at the end of a indexRequest, so that UI operations are not blocked. commit9a63e99710Author: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 16:01:42 2015 -0700 [Search] Add spec for ElasticSearchProvider Add spec coverage for ElasticSearchProvider. Also remove unneeded guards for max number of results, as the aggregator will always provide a max number of results. commit21739fffd9Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 20 15:52:49 2015 -0700 [Documentation] Add table of contents Add table of contents to generated documents, without modifying document sources; nasa/openmctweb#189. commit77d81f899bAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 15:31:33 2015 -0700 [Style] JSLint compliance commitfe3263fdfeAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 15:27:46 2015 -0700 [Search] Remove invalid specs commitce42429fbdAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 15:14:43 2015 -0700 [Search] expose constants, add fudge factor The SearchAggregator exposes it's constants to add stability to tests. It also has a fudge factor which increaases the number of results it requests from providers to better support pagination when using client side filtering. commit76151d09a0Author: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 15:13:37 2015 -0700 [Search] use service for filters, add spec Add a spec for the SearchController, and use the SearchService to execute filters by supplying a filterPredicate. commitec7e6cc5b4Author: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 13:55:46 2015 -0700 [Search] Update spec for Generic Search Worker commit1ddce48f7eAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Tue Oct 20 13:12:04 2015 -0700 [Search] Specs for GenericSearchProvider Write specs for GenericSearchProvider and resolve some implementation bugs they uncovered. commit98b5ff3c77Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 18:14:33 2015 -0700 [Search] Decrement number of pending requests commit14094a48fcAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 17:33:23 2015 -0700 [Search] Remove old specs in prep for rewrite Remove old specs in prep for rewrite. commit8e2a2eeba5Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Mon Oct 19 12:08:49 2015 -0700 [Entanglement] Add license headers ...per code review feedback from nasa/openmctweb#175 commit0f63e4dde9Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 17:06:23 2015 -0700 [Tests] Rewrite search aggregator specs commit12efb47be7Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 16:09:51 2015 -0700 [Search] Remove timeouts and timestamps Remove timeouts and timestamps which were not effectively doing anything. commita2fce8e56cAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 16:05:31 2015 -0700 [Search] Rewrite elasticsearch provider with prototype Rewrite the elasticsearch provider to use prototypes and clean up the implementation. Now returns a modelResults object to keep it in line with the general search provider. commit78e5c0143bAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 15:26:46 2015 -0700 [Search] Overhaul generic search provider Rewrite the generic search provider to use prototypes. Increase performance by utilizing the model service instead of the object service, and use a simplified method of request queueing. commit099591ad2eAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 15:26:04 2015 -0700 [Search] Aggregator returns objects, providers return models Search providers return search results as models for domain objects, as the actual number of max results is enforced by the aggregator, and because the individual providers store and return the models for their objects already. This lowers the amount of resources consumed instantiating domain objects, and also allows the individual search providers to implement function-based filtering on domain object models, which is beneficial as it allows the search filtering in the search controller to be done before paginating of results. commitb5505f372fAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 12:39:41 2015 -0700 [Search] Generic Worker Performance Tweaks The generic search worker now does indexing work during the index operation, ensuring that queries do not have to do extraneous or repeat calculations. Change the return format slightly and fixed a bug in the GenericSearchProvider which caused more objects than intended to be returned from the provider. commit9ad860babdAuthor: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 12:34:47 2015 -0700 [Search] Rewrite search controller, tidy Rewrite the search controller, making numerous changes and using prototypical style. First, the search controller immediately hides previous results when a new search is started. Secondly, the search controller ensures that search results displayed match the currently entered query, preventing race conditions. Finally, the search controller uses a poor filtering option that means it may not display all results. commit87e317a6f5Author: Pete Richards <peter.l.richards@nasa.gov> Date: Fri Oct 16 11:33:42 2015 -0700 [CI] Remove non-existent bundle from procfile Remove the example/localstorage bundle from the procfile. Fixes #153. commitbf41d82a78Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 6 16:50:35 2015 -0700 [Entanglement] Restore missing specs Restore specs which had been omitted from suite.json (but currently succeed for the relevant scripts); done in the context of nasa/openmctweb#147 commita4944717a1Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 6 16:47:37 2015 -0700 [Location] Test getOriginal method commit70bbd3cf97Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 6 16:37:37 2015 -0700 [Entanglement] Add test cases for Go To Original commite3afaf0842Author: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 6 16:22:16 2015 -0700 [Entanglement] Add Go To Original nasa/openmctweb#147 commit60f2f9fb6cAuthor: Victor Woeltjen <victor.woeltjen@nasa.gov> Date: Tue Oct 6 16:08:48 2015 -0700 [Location] Add getOriginal method Add a getOriginal method to the location capability, to simplify loading of original versions of objects. nasa/openmctweb#147
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
"provides": "searchService",
|
||||
"type": "provider",
|
||||
"implementation": "ElasticSearchProvider.js",
|
||||
"depends": [ "$http", "objectService", "ELASTIC_ROOT" ]
|
||||
"depends": [ "$http", "ELASTIC_ROOT" ]
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
|
||||
@@ -24,190 +24,122 @@
|
||||
/**
|
||||
* Module defining ElasticSearchProvider. Created by shale on 07/16/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
define([
|
||||
|
||||
// JSLint doesn't like underscore-prefixed properties,
|
||||
// so hide them here.
|
||||
var ID = "_id",
|
||||
SCORE = "_score",
|
||||
DEFAULT_MAX_RESULTS = 100;
|
||||
|
||||
/**
|
||||
* A search service which searches through domain objects in
|
||||
* the filetree using ElasticSearch.
|
||||
*
|
||||
* @constructor
|
||||
* @param $http Angular's $http service, for working with urls.
|
||||
* @param {ObjectService} objectService the service from which
|
||||
* domain objects can be gotten.
|
||||
* @param ROOT the constant `ELASTIC_ROOT` which allows us to
|
||||
* interact with ElasticSearch.
|
||||
*/
|
||||
function ElasticSearchProvider($http, objectService, ROOT) {
|
||||
this.$http = $http;
|
||||
this.objectService = objectService;
|
||||
this.root = ROOT;
|
||||
}
|
||||
], function (
|
||||
|
||||
/**
|
||||
* Searches through the filetree for domain objects using a search
|
||||
* term. This is done through querying elasticsearch. Returns a
|
||||
* promise for a result object that has the format
|
||||
* {hits: searchResult[], total: number, timedOut: boolean}
|
||||
* where a searchResult has the format
|
||||
* {id: string, object: domainObject, score: number}
|
||||
*
|
||||
* Notes:
|
||||
* * The order of the results is from highest to lowest score,
|
||||
* as elsaticsearch determines them to be.
|
||||
* * Uses the fuzziness operator to get more results.
|
||||
* * More about this search's behavior at
|
||||
* https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
|
||||
*
|
||||
* @param searchTerm The text input that is the query.
|
||||
* @param timestamp The time at which this function was called.
|
||||
* This timestamp is used as a unique identifier for this
|
||||
* query and the corresponding results.
|
||||
* @param maxResults (optional) The maximum number of results
|
||||
* that this function should return.
|
||||
* @param timeout (optional) The time after which the search should
|
||||
* stop calculations and return partial results. Elasticsearch
|
||||
* does not guarentee that this timeout will be strictly followed.
|
||||
*/
|
||||
ElasticSearchProvider.prototype.query = function query(searchTerm, timestamp, maxResults, timeout) {
|
||||
var $http = this.$http,
|
||||
objectService = this.objectService,
|
||||
root = this.root,
|
||||
esQuery;
|
||||
|
||||
function addFuzziness(searchTerm, editDistance) {
|
||||
if (!editDistance) {
|
||||
editDistance = '';
|
||||
}
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
return searchTerm.split(' ').map(function (s) {
|
||||
// Don't add fuzziness for quoted strings
|
||||
if (s.indexOf('"') !== -1) {
|
||||
return s;
|
||||
} else {
|
||||
return s + '~' + editDistance;
|
||||
}
|
||||
}).join(' ');
|
||||
}
|
||||
var ID_PROPERTY = '_id',
|
||||
SOURCE_PROPERTY = '_source',
|
||||
SCORE_PROPERTY = '_score';
|
||||
|
||||
// Currently specific to elasticsearch
|
||||
function processSearchTerm(searchTerm) {
|
||||
var spaceIndex;
|
||||
|
||||
// Cut out any extra spaces
|
||||
while (searchTerm.substr(0, 1) === ' ') {
|
||||
searchTerm = searchTerm.substring(1, searchTerm.length);
|
||||
}
|
||||
while (searchTerm.substr(searchTerm.length - 1, 1) === ' ') {
|
||||
searchTerm = searchTerm.substring(0, searchTerm.length - 1);
|
||||
}
|
||||
spaceIndex = searchTerm.indexOf(' ');
|
||||
while (spaceIndex !== -1) {
|
||||
searchTerm = searchTerm.substring(0, spaceIndex) +
|
||||
searchTerm.substring(spaceIndex + 1, searchTerm.length);
|
||||
spaceIndex = searchTerm.indexOf(' ');
|
||||
}
|
||||
|
||||
// Add fuzziness for completeness
|
||||
searchTerm = addFuzziness(searchTerm);
|
||||
|
||||
return searchTerm;
|
||||
}
|
||||
|
||||
// Processes results from the format that elasticsearch returns to
|
||||
// a list of searchResult objects, then returns a result object
|
||||
// (See documentation for query for object descriptions)
|
||||
function processResults(rawResults, timestamp) {
|
||||
var results = rawResults.data.hits.hits,
|
||||
resultsLength = results.length,
|
||||
ids = [],
|
||||
scores = {},
|
||||
searchResults = [],
|
||||
i;
|
||||
|
||||
// Get the result objects' IDs
|
||||
for (i = 0; i < resultsLength; i += 1) {
|
||||
ids.push(results[i][ID]);
|
||||
}
|
||||
|
||||
// Get the result objects' scores
|
||||
for (i = 0; i < resultsLength; i += 1) {
|
||||
scores[ids[i]] = results[i][SCORE];
|
||||
}
|
||||
|
||||
// Get the domain objects from their IDs
|
||||
return objectService.getObjects(ids).then(function (objects) {
|
||||
var j,
|
||||
id;
|
||||
|
||||
for (j = 0; j < resultsLength; j += 1) {
|
||||
id = ids[j];
|
||||
|
||||
// Include items we can get models for
|
||||
if (objects[id].getModel) {
|
||||
// Format the results as searchResult objects
|
||||
searchResults.push({
|
||||
id: id,
|
||||
object: objects[id],
|
||||
score: scores[id]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hits: searchResults,
|
||||
total: rawResults.data.hits.total,
|
||||
timedOut: rawResults.data.timed_out
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Check to see if the user provided a maximum
|
||||
// number of results to display
|
||||
if (!maxResults) {
|
||||
// Else, we provide a default value.
|
||||
maxResults = DEFAULT_MAX_RESULTS;
|
||||
}
|
||||
|
||||
// If the user input is empty, we want to have no search results.
|
||||
if (searchTerm !== '' && searchTerm !== undefined) {
|
||||
// Process the search term
|
||||
searchTerm = processSearchTerm(searchTerm);
|
||||
|
||||
// Create the query to elasticsearch
|
||||
esQuery = root + "/_search/?q=" + searchTerm +
|
||||
"&size=" + maxResults;
|
||||
if (timeout) {
|
||||
esQuery += "&timeout=" + timeout;
|
||||
}
|
||||
|
||||
// Get the data...
|
||||
return this.$http({
|
||||
method: "GET",
|
||||
url: esQuery
|
||||
}).then(function (rawResults) {
|
||||
// ...then process the data
|
||||
return processResults(rawResults, timestamp);
|
||||
}, function (err) {
|
||||
// In case of error, return nothing. (To prevent
|
||||
// infinite loading time.)
|
||||
return {hits: [], total: 0};
|
||||
});
|
||||
} else {
|
||||
return {hits: [], total: 0};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return ElasticSearchProvider;
|
||||
/**
|
||||
* A search service which searches through domain objects in
|
||||
* the filetree using ElasticSearch.
|
||||
*
|
||||
* @constructor
|
||||
* @param $http Angular's $http service, for working with urls.
|
||||
* @param ROOT the constant `ELASTIC_ROOT` which allows us to
|
||||
* interact with ElasticSearch.
|
||||
*/
|
||||
function ElasticSearchProvider($http, ROOT) {
|
||||
this.$http = $http;
|
||||
this.root = ROOT;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Search for domain objects using elasticsearch as a search provider.
|
||||
*
|
||||
* @param {String} searchTerm the term to search by.
|
||||
* @param {Number} [maxResults] the max numer of results to return.
|
||||
* @returns {Promise} promise for a modelResults object.
|
||||
*/
|
||||
ElasticSearchProvider.prototype.query = function (searchTerm, maxResults) {
|
||||
var searchUrl = this.root + '/_search/',
|
||||
params = {},
|
||||
provider = this;
|
||||
|
||||
searchTerm = this.cleanTerm(searchTerm);
|
||||
searchTerm = this.fuzzyMatchUnquotedTerms(searchTerm);
|
||||
|
||||
params.q = searchTerm;
|
||||
params.size = maxResults;
|
||||
|
||||
return this
|
||||
.$http({
|
||||
method: "GET",
|
||||
url: searchUrl,
|
||||
params: params
|
||||
})
|
||||
.then(function success(succesResponse) {
|
||||
return provider.parseResponse(succesResponse);
|
||||
}, function error(errorResponse) {
|
||||
// Gracefully fail.
|
||||
return {
|
||||
hits: [],
|
||||
total: 0
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clean excess whitespace from a search term and return the cleaned
|
||||
* version.
|
||||
*
|
||||
* @private
|
||||
* @param {string} the search term to clean.
|
||||
* @returns {string} search terms cleaned of excess whitespace.
|
||||
*/
|
||||
ElasticSearchProvider.prototype.cleanTerm = function (term) {
|
||||
return term.trim().replace(/ +/g, ' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Add fuzzy matching markup to search terms that are not quoted.
|
||||
*
|
||||
* The following:
|
||||
* hello welcome "to quoted village" have fun
|
||||
* will become
|
||||
* hello~ welcome~ "to quoted village" have~ fun~
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ElasticSearchProvider.prototype.fuzzyMatchUnquotedTerms = function (query) {
|
||||
var matchUnquotedSpaces = '\\s+(?=([^"]*"[^"]*")*[^"]*$)',
|
||||
matcher = new RegExp(matchUnquotedSpaces, 'g');
|
||||
|
||||
return query
|
||||
.replace(matcher, '~ ')
|
||||
.replace(/$/, '~')
|
||||
.replace(/"~+/, '"');
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the response from ElasticSearch and convert it to a
|
||||
* modelResults object.
|
||||
*
|
||||
* @private
|
||||
* @param response a ES response object from $http
|
||||
* @returns modelResults
|
||||
*/
|
||||
ElasticSearchProvider.prototype.parseResponse = function (response) {
|
||||
var results = response.data.hits.hits,
|
||||
searchResults = results.map(function (result) {
|
||||
return {
|
||||
id: result[ID_PROPERTY],
|
||||
model: result[SOURCE_PROPERTY],
|
||||
score: result[SCORE_PROPERTY]
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
hits: searchResults,
|
||||
total: response.data.hits.total
|
||||
};
|
||||
};
|
||||
|
||||
return ElasticSearchProvider;
|
||||
});
|
||||
|
||||
@@ -19,97 +19,151 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine,spyOn,Promise,waitsFor*/
|
||||
|
||||
/**
|
||||
* SearchSpec. Created by shale on 07/31/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/ElasticSearchProvider"],
|
||||
function (ElasticSearchProvider) {
|
||||
"use strict";
|
||||
define([
|
||||
'../src/ElasticSearchProvider'
|
||||
], function (
|
||||
ElasticSearchProvider
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
// JSLint doesn't like underscore-prefixed properties,
|
||||
// so hide them here.
|
||||
var ID = "_id",
|
||||
SCORE = "_score";
|
||||
|
||||
describe("The ElasticSearch search provider ", function () {
|
||||
var mockHttp,
|
||||
mockHttpPromise,
|
||||
mockObjectPromise,
|
||||
mockObjectService,
|
||||
mockDomainObject,
|
||||
provider,
|
||||
mockProviderResults;
|
||||
describe('ElasticSearchProvider', function () {
|
||||
var $http,
|
||||
ROOT,
|
||||
provider;
|
||||
|
||||
beforeEach(function () {
|
||||
$http = jasmine.createSpy('$http');
|
||||
ROOT = 'http://localhost:9200';
|
||||
|
||||
provider = new ElasticSearchProvider($http, ROOT);
|
||||
});
|
||||
|
||||
describe('query', function () {
|
||||
beforeEach(function () {
|
||||
mockHttp = jasmine.createSpy("$http");
|
||||
mockHttpPromise = jasmine.createSpyObj(
|
||||
"promise",
|
||||
[ "then" ]
|
||||
);
|
||||
mockHttp.andReturn(mockHttpPromise);
|
||||
// allow chaining of promise.then().catch();
|
||||
mockHttpPromise.then.andReturn(mockHttpPromise);
|
||||
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
[ "getObjects" ]
|
||||
);
|
||||
mockObjectPromise = jasmine.createSpyObj(
|
||||
"promise",
|
||||
[ "then" ]
|
||||
);
|
||||
mockObjectService.getObjects.andReturn(mockObjectPromise);
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getId", "getModel" ]
|
||||
);
|
||||
|
||||
provider = new ElasticSearchProvider(mockHttp, mockObjectService, "");
|
||||
provider.query(' test "query" ', 0, undefined, 1000);
|
||||
spyOn(provider, 'cleanTerm').andReturn('cleanedTerm');
|
||||
spyOn(provider, 'fuzzyMatchUnquotedTerms').andReturn('fuzzy');
|
||||
spyOn(provider, 'parseResponse').andReturn('parsedResponse');
|
||||
$http.andReturn(Promise.resolve({}));
|
||||
});
|
||||
|
||||
it("sends a query to ElasticSearch", function () {
|
||||
expect(mockHttp).toHaveBeenCalled();
|
||||
|
||||
it('cleans terms and adds fuzzyness', function () {
|
||||
provider.query('hello', 10);
|
||||
expect(provider.cleanTerm).toHaveBeenCalledWith('hello');
|
||||
expect(provider.fuzzyMatchUnquotedTerms)
|
||||
.toHaveBeenCalledWith('cleanedTerm');
|
||||
});
|
||||
|
||||
it("gets data from ElasticSearch", function () {
|
||||
var data = {
|
||||
hits: {
|
||||
hits: [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
total: 0
|
||||
|
||||
it('calls through to $http', function () {
|
||||
provider.query('hello', 10);
|
||||
expect($http).toHaveBeenCalledWith({
|
||||
method: 'GET',
|
||||
params: {
|
||||
q: 'fuzzy',
|
||||
size: 10
|
||||
},
|
||||
timed_out: false
|
||||
};
|
||||
data.hits.hits[0][ID] = 1;
|
||||
data.hits.hits[0][SCORE] = 1;
|
||||
data.hits.hits[1][ID] = 2;
|
||||
data.hits.hits[1][SCORE] = 2;
|
||||
|
||||
mockProviderResults = mockHttpPromise.then.mostRecentCall.args[0]({data: data});
|
||||
|
||||
expect(
|
||||
mockObjectPromise.then.mostRecentCall.args[0]({
|
||||
1: mockDomainObject,
|
||||
2: mockDomainObject
|
||||
}).hits.length
|
||||
).toEqual(2);
|
||||
url: 'http://localhost:9200/_search/'
|
||||
});
|
||||
});
|
||||
|
||||
it("returns nothing for an empty string query", function () {
|
||||
expect(provider.query("").hits).toEqual([]);
|
||||
|
||||
it('gracefully fails when http fails', function () {
|
||||
var promiseChainResolved = false;
|
||||
$http.andReturn(Promise.reject());
|
||||
|
||||
provider
|
||||
.query('hello', 10)
|
||||
.then(function (results) {
|
||||
expect(results).toEqual({
|
||||
hits: [],
|
||||
total: 0
|
||||
});
|
||||
promiseChainResolved = true;
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return promiseChainResolved;
|
||||
});
|
||||
});
|
||||
|
||||
it("returns something when there is an ElasticSearch error", function () {
|
||||
mockProviderResults = mockHttpPromise.then.mostRecentCall.args[1]();
|
||||
expect(mockProviderResults).toBeDefined();
|
||||
|
||||
it('parses and returns when http succeeds', function () {
|
||||
var promiseChainResolved = false;
|
||||
$http.andReturn(Promise.resolve('successResponse'));
|
||||
|
||||
provider
|
||||
.query('hello', 10)
|
||||
.then(function (results) {
|
||||
expect(provider.parseResponse)
|
||||
.toHaveBeenCalledWith('successResponse');
|
||||
expect(results).toBe('parsedResponse');
|
||||
promiseChainResolved = true;
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return promiseChainResolved;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('can clean terms', function () {
|
||||
expect(provider.cleanTerm(' asdhs ')).toBe('asdhs');
|
||||
expect(provider.cleanTerm(' and some words'))
|
||||
.toBe('and some words');
|
||||
expect(provider.cleanTerm('Nice input')).toBe('Nice input');
|
||||
});
|
||||
|
||||
it('can create fuzzy term matchers', function () {
|
||||
expect(provider.fuzzyMatchUnquotedTerms('pwr dvc 43'))
|
||||
.toBe('pwr~ dvc~ 43~');
|
||||
|
||||
expect(provider.fuzzyMatchUnquotedTerms(
|
||||
'hello welcome "to quoted village" have fun'
|
||||
)).toBe(
|
||||
'hello~ welcome~ "to quoted village" have~ fun~'
|
||||
);
|
||||
});
|
||||
|
||||
it('can parse responses', function () {
|
||||
var elasticSearchResponse = {
|
||||
data: {
|
||||
hits: {
|
||||
total: 2,
|
||||
hits: [
|
||||
{
|
||||
'_id': 'hit1Id',
|
||||
'_source': 'hit1Model',
|
||||
'_score': 0.56
|
||||
},
|
||||
{
|
||||
'_id': 'hit2Id',
|
||||
'_source': 'hit2Model',
|
||||
'_score': 0.34
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expect(provider.parseResponse(elasticSearchResponse))
|
||||
.toEqual({
|
||||
hits: [
|
||||
{
|
||||
id: 'hit1Id',
|
||||
model: 'hit1Model',
|
||||
score: 0.56
|
||||
},
|
||||
{
|
||||
id: 'hit2Id',
|
||||
model: 'hit2Model',
|
||||
score: 0.34
|
||||
}
|
||||
],
|
||||
total: 2
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user