mirror of
https://github.com/nasa/openmct.git
synced 2025-02-21 09:52:04 +00:00
[Search] Specs for GenericSearchProvider
Write specs for GenericSearchProvider and resolve some implementation bugs they uncovered.
This commit is contained in:
parent
98b5ff3c77
commit
1ddce48f7e
@ -31,9 +31,6 @@ define([
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_MAX_RESULTS = 100,
|
||||
MAX_CONCURRENT_REQUESTS = 100;
|
||||
|
||||
/**
|
||||
* A search service which searches through domain objects in
|
||||
* the filetree without using external search implementations.
|
||||
@ -60,12 +57,18 @@ define([
|
||||
this.pendingQueries = {};
|
||||
|
||||
this.worker = this.startWorker(workerService);
|
||||
this.indexOnMutation(topic);
|
||||
|
||||
ROOTS.forEach(function indexRoot(rootId) {
|
||||
provider.scheduleForIndexing(rootId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of concurrent index requests to allow.
|
||||
*/
|
||||
GenericSearchProvider.prototype.MAX_CONCURRENT_REQUESTS = 100;
|
||||
|
||||
/**
|
||||
* Query the search provider for results.
|
||||
*
|
||||
@ -77,9 +80,6 @@ define([
|
||||
input,
|
||||
maxResults
|
||||
) {
|
||||
if (!maxResults) {
|
||||
maxResults = DEFAULT_MAX_RESULTS;
|
||||
}
|
||||
|
||||
var queryId = this.dispatchSearch(input, maxResults),
|
||||
pendingQuery = this.$q.defer();
|
||||
@ -100,9 +100,9 @@ define([
|
||||
var worker = workerService.run('genericSearchWorker'),
|
||||
provider = this;
|
||||
|
||||
worker.onmessage = function (messageEvent) {
|
||||
worker.addEventListener('message', function (messageEvent) {
|
||||
provider.onWorkerMessage(messageEvent);
|
||||
};
|
||||
});
|
||||
|
||||
return worker;
|
||||
};
|
||||
@ -148,7 +148,7 @@ define([
|
||||
* @private
|
||||
*/
|
||||
GenericSearchProvider.prototype.keepIndexing = function () {
|
||||
if (this.pendingRequests < MAX_CONCURRENT_REQUESTS) {
|
||||
if (this.pendingRequests < this.MAX_CONCURRENT_REQUESTS) {
|
||||
this.beginIndexRequest();
|
||||
}
|
||||
};
|
||||
@ -206,7 +206,7 @@ define([
|
||||
.warn('Failed to index domain object ' + idToIndex);
|
||||
})
|
||||
.then(function () {
|
||||
provider.pendingRequests -=1;
|
||||
provider.pendingRequests -= 1;
|
||||
provider.keepIndexing();
|
||||
});
|
||||
};
|
||||
|
@ -26,27 +26,290 @@
|
||||
*/
|
||||
define([
|
||||
"../../src/services/GenericSearchProvider"
|
||||
], function (GenericSearchProvider) {
|
||||
], function (
|
||||
GenericSearchProvider
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
describe('GenericSearchProvider', function () {
|
||||
var $q,
|
||||
$log,
|
||||
modelService,
|
||||
models,
|
||||
workerService,
|
||||
worker,
|
||||
topic,
|
||||
ROOTS;
|
||||
mutationTopic,
|
||||
ROOTS,
|
||||
provider;
|
||||
|
||||
beforeEach(function () {
|
||||
$q = jasmine.createSpyObj(
|
||||
'$q',
|
||||
['defer']
|
||||
);
|
||||
// TODO: continue
|
||||
$log = jasmine.createSpyObj(
|
||||
'$log',
|
||||
['warn']
|
||||
);
|
||||
models = {};
|
||||
modelService = jasmine.createSpyObj(
|
||||
'modelService',
|
||||
['getModels']
|
||||
);
|
||||
modelService.getModels.andReturn(Promise.resolve(models));
|
||||
workerService = jasmine.createSpyObj(
|
||||
'workerService',
|
||||
['run']
|
||||
);
|
||||
worker = jasmine.createSpyObj(
|
||||
'worker',
|
||||
[
|
||||
'postMessage',
|
||||
'addEventListener'
|
||||
]
|
||||
);
|
||||
workerService.run.andReturn(worker);
|
||||
topic = jasmine.createSpy('topic');
|
||||
mutationTopic = jasmine.createSpyObj(
|
||||
'mutationTopic',
|
||||
['listen']
|
||||
);
|
||||
topic.andReturn(mutationTopic);
|
||||
ROOTS = [
|
||||
'mine'
|
||||
];
|
||||
|
||||
spyOn(GenericSearchProvider.prototype, 'scheduleForIndexing');
|
||||
|
||||
provider = new GenericSearchProvider(
|
||||
$q,
|
||||
$log,
|
||||
modelService,
|
||||
workerService,
|
||||
topic,
|
||||
ROOTS
|
||||
);
|
||||
});
|
||||
|
||||
it('listens for general mutation', function () {
|
||||
expect(topic).toHaveBeenCalledWith('mutation');
|
||||
expect(mutationTopic.listen)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it('starts indexing roots', function () {
|
||||
expect(provider.scheduleForIndexing).toHaveBeenCalledWith('mine');
|
||||
});
|
||||
|
||||
it('runs a worker', function () {
|
||||
expect(workerService.run)
|
||||
.toHaveBeenCalledWith('genericSearchWorker');
|
||||
});
|
||||
|
||||
it('listens for messages from worker', function () {
|
||||
expect(worker.addEventListener)
|
||||
.toHaveBeenCalledWith('message', jasmine.any(Function));
|
||||
spyOn(provider, 'onWorkerMessage');
|
||||
worker.addEventListener.mostRecentCall.args[1]('mymessage');
|
||||
expect(provider.onWorkerMessage).toHaveBeenCalledWith('mymessage');
|
||||
});
|
||||
|
||||
it('has a maximum number of concurrent requests', function () {
|
||||
expect(provider.MAX_CONCURRENT_REQUESTS).toBe(100);
|
||||
});
|
||||
|
||||
describe('scheduleForIndexing', function () {
|
||||
beforeEach(function () {
|
||||
provider.scheduleForIndexing.andCallThrough();
|
||||
spyOn(provider, 'keepIndexing');
|
||||
});
|
||||
|
||||
it('tracks ids to index', function () {
|
||||
expect(provider.indexedIds['a']).not.toBeDefined();
|
||||
expect(provider.pendingIndex['a']).not.toBeDefined();
|
||||
expect(provider.idsToIndex).not.toContain('a');
|
||||
provider.scheduleForIndexing('a');
|
||||
expect(provider.indexedIds['a']).toBeDefined();
|
||||
expect(provider.pendingIndex['a']).toBeDefined();
|
||||
expect(provider.idsToIndex).toContain('a');
|
||||
});
|
||||
|
||||
it('calls keep indexing', function () {
|
||||
provider.scheduleForIndexing('a');
|
||||
expect(provider.keepIndexing).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('keepIndexing', function () {
|
||||
it('kicks off an index request when not at maximum', function () {
|
||||
spyOn(provider, 'beginIndexRequest');
|
||||
provider.pendingRequests = 0;
|
||||
provider.MAX_CONCURRENT_REQUESTS = 10;
|
||||
provider.keepIndexing();
|
||||
expect(provider.beginIndexRequest).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not index when at capacity', function () {
|
||||
spyOn(provider, 'beginIndexRequest');
|
||||
provider.pendingRequests = 10;
|
||||
provider.MAX_CONCURRENT_REQUESTS = 10;
|
||||
provider.keepIndexing();
|
||||
expect(provider.beginIndexRequest).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('index', function () {
|
||||
it('sends index message to worker', function () {
|
||||
var id = 'anId',
|
||||
model = {};
|
||||
|
||||
provider.index(id, model);
|
||||
expect(worker.postMessage).toHaveBeenCalledWith({
|
||||
request: 'index',
|
||||
id: id,
|
||||
model: model
|
||||
});
|
||||
});
|
||||
|
||||
it('schedules composed ids for indexing', function () {
|
||||
var id = 'anId',
|
||||
model = {composition: ['abc', 'def']};
|
||||
|
||||
provider.index(id, model);
|
||||
expect(provider.scheduleForIndexing)
|
||||
.toHaveBeenCalledWith('abc');
|
||||
expect(provider.scheduleForIndexing)
|
||||
.toHaveBeenCalledWith('def');
|
||||
});
|
||||
});
|
||||
|
||||
describe('beginIndexRequest', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
provider.pendingRequests = 0;
|
||||
provider.pendingIds = {'abc': true};
|
||||
provider.idsToIndex = ['abc'];
|
||||
models.abc = {};
|
||||
spyOn(provider, 'index');
|
||||
});
|
||||
|
||||
it('removes items from queue', function () {
|
||||
provider.beginIndexRequest();
|
||||
expect(provider.idsToIndex.length).toBe(0);
|
||||
});
|
||||
|
||||
it('tracks number of pending requests', function () {
|
||||
provider.beginIndexRequest();
|
||||
expect(provider.pendingRequests).toBe(1);
|
||||
waitsFor(function () {
|
||||
return provider.pendingRequests === 0;
|
||||
});
|
||||
runs(function () {
|
||||
expect(provider.pendingRequests).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('indexes objects', function () {
|
||||
provider.beginIndexRequest();
|
||||
waitsFor(function () {
|
||||
return provider.pendingRequests === 0;
|
||||
})
|
||||
runs(function () {
|
||||
expect(provider.index)
|
||||
.toHaveBeenCalledWith('abc', models.abc);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not error if no objects queued', function () {
|
||||
provider.idsToIndex = [];
|
||||
expect(function () {
|
||||
provider.beginIndexRequest()
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('can dispatch searches to worker', function () {
|
||||
spyOn(provider, 'makeQueryId').andReturn(428);
|
||||
expect(provider.dispatchSearch('searchTerm', 100))
|
||||
.toBe(428);
|
||||
|
||||
expect(worker.postMessage).toHaveBeenCalledWith({
|
||||
request: 'search',
|
||||
input: 'searchTerm',
|
||||
maxResults: 100,
|
||||
queryId: 428
|
||||
});
|
||||
});
|
||||
|
||||
it('can generate queryIds', function () {
|
||||
expect(provider.makeQueryId()).toEqual(jasmine.any(Number));
|
||||
});
|
||||
|
||||
it('can query for terms', function () {
|
||||
var deferred = {promise: {}};
|
||||
spyOn(provider, 'dispatchSearch').andReturn(303);
|
||||
$q.defer.andReturn(deferred);
|
||||
|
||||
expect(provider.query('someTerm', 100)).toBe(deferred.promise);
|
||||
expect(provider.pendingQueries[303]).toBe(deferred);
|
||||
});
|
||||
|
||||
describe('onWorkerMessage', function () {
|
||||
var pendingQuery;
|
||||
beforeEach(function () {
|
||||
pendingQuery = jasmine.createSpyObj(
|
||||
'pendingQuery',
|
||||
['resolve']
|
||||
);
|
||||
provider.pendingQueries[143] = pendingQuery;
|
||||
});
|
||||
|
||||
it('resolves pending searches', function () {
|
||||
provider.onWorkerMessage({
|
||||
data: {
|
||||
request: 'search',
|
||||
total: 2,
|
||||
results: [
|
||||
{
|
||||
item: {
|
||||
id: 'abc',
|
||||
model: {id: 'abc'}
|
||||
},
|
||||
matchCount: 4
|
||||
},
|
||||
{
|
||||
item: {
|
||||
id: 'def',
|
||||
model: {id: 'def'}
|
||||
},
|
||||
matchCount: 2
|
||||
}
|
||||
],
|
||||
queryId: 143
|
||||
}
|
||||
});
|
||||
|
||||
expect(pendingQuery.resolve)
|
||||
.toHaveBeenCalledWith({
|
||||
total: 2,
|
||||
hits: [{
|
||||
id: 'abc',
|
||||
model: {id: 'abc'},
|
||||
score: 4
|
||||
}, {
|
||||
id: 'def',
|
||||
model: {id: 'def'},
|
||||
score: 2
|
||||
}]
|
||||
});
|
||||
|
||||
expect(provider.pendingQueries[143]).not.toBeDefined();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user