mirror of
https://github.com/nasa/openmct.git
synced 2024-12-29 17:38:53 +00:00
Merge remote-tracking branch 'origin/open-master' into open1482c
Merge latest into topic branch for WTD-1482
This commit is contained in:
commit
bf417a14e0
@ -67,7 +67,7 @@ as described above.
|
||||
An example of this is expressed in `platform/framework`, which follows
|
||||
bundle conventions.
|
||||
|
||||
### Regression Testing
|
||||
### Functional Testing
|
||||
|
||||
The tests described above are all at the unit-level; an additional
|
||||
test suite using [Protractor](https://angular.github.io/protractor/)
|
||||
@ -76,9 +76,9 @@ us under development, in the `protractor` folder.
|
||||
To run:
|
||||
|
||||
* Install protractor following the instructions above.
|
||||
* `webdriver-manager start`
|
||||
* `node app.js -p 1984 -x platform/persistence/elastic -i example/persistence
|
||||
* `protractor protractor/conf.js`
|
||||
* `cd protractor`
|
||||
* `npm install`
|
||||
* `npm run all`
|
||||
|
||||
## Build
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
"platform/persistence/queue",
|
||||
"platform/policy",
|
||||
"platform/entanglement",
|
||||
"platform/search",
|
||||
|
||||
"example/imagery",
|
||||
"example/persistence",
|
||||
|
@ -4,3 +4,7 @@ deployment:
|
||||
commands:
|
||||
- ./build-docs.sh
|
||||
- git push git@heroku.com:openmctweb-demo.git $CIRCLE_SHA1:refs/heads/master
|
||||
openmctweb-staging-un:
|
||||
branch: search
|
||||
heroku:
|
||||
appname: openmctweb-staging-un
|
||||
|
@ -92,7 +92,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
@ -113,38 +113,38 @@ time, mark, audio, video {
|
||||
font-size: 100%;
|
||||
vertical-align: baseline; }
|
||||
|
||||
/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
html {
|
||||
line-height: 1; }
|
||||
|
||||
/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
ol, ul {
|
||||
list-style: none; }
|
||||
|
||||
/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0; }
|
||||
|
||||
/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
caption, th, td {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
vertical-align: middle; }
|
||||
|
||||
/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q, blockquote {
|
||||
quotes: none; }
|
||||
/* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
q:before, q:after, blockquote:before, blockquote:after {
|
||||
content: "";
|
||||
content: none; }
|
||||
|
||||
/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
a img {
|
||||
border: none; }
|
||||
|
||||
/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
|
||||
display: block; }
|
||||
|
||||
|
213
platform/persistence/elastic/src/ElasticsearchSearchProvider.js
Normal file
213
platform/persistence/elastic/src/ElasticsearchSearchProvider.js
Normal file
@ -0,0 +1,213 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Module defining ElasticsearchSearchProvider. Created by shale on 07/16/2015.
|
||||
* This is not currently included in the bundle definition.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
// 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 ElasticsearchSearchProvider($http, objectService, ROOT) {
|
||||
|
||||
// Add the fuzziness operator to the search term
|
||||
function addFuzziness(searchTerm, editDistance) {
|
||||
if (!editDistance) {
|
||||
editDistance = '';
|
||||
}
|
||||
|
||||
return searchTerm.split(' ').map(function (s) {
|
||||
// Don't add fuzziness for quoted strings
|
||||
if (s.indexOf('"') !== -1) {
|
||||
return s;
|
||||
} else {
|
||||
return s + '~' + editDistance;
|
||||
}
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// For documentation, see query below.
|
||||
function query(searchTerm, timestamp, maxResults, timeout) {
|
||||
var esQuery;
|
||||
|
||||
// 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 $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 {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
query: query
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return ElasticsearchSearchProvider;
|
||||
}
|
||||
);
|
@ -0,0 +1,115 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* SearchSpec. Created by shale on 07/31/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/ElasticsearchSearchProvider"],
|
||||
function (ElasticsearchSearchProvider) {
|
||||
"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;
|
||||
|
||||
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 ElasticsearchSearchProvider(mockHttp, mockObjectService, "");
|
||||
provider.query(' test "query" ', 0, undefined, 1000);
|
||||
});
|
||||
|
||||
it("sends a query to ElasticSearch", function () {
|
||||
expect(mockHttp).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("gets data from ElasticSearch", function () {
|
||||
var data = {
|
||||
hits: {
|
||||
hits: [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
total: 0
|
||||
},
|
||||
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);
|
||||
});
|
||||
|
||||
it("returns nothing for an empty string query", function () {
|
||||
expect(provider.query("").hits).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns something when there is an ElasticSearch error", function () {
|
||||
mockProviderResults = mockHttpPromise.then.mostRecentCall.args[1]();
|
||||
expect(mockProviderResults).toBeDefined();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -1,4 +1,5 @@
|
||||
[
|
||||
"ElasticIndicator",
|
||||
"ElasticPersistenceProvider"
|
||||
"ElasticPersistenceProvider",
|
||||
"ElasticsearchSearchProvider"
|
||||
]
|
||||
|
33
platform/search/bundle.json
Normal file
33
platform/search/bundle.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Search",
|
||||
"description": "Allows the user to search through the file tree.",
|
||||
"extensions": {
|
||||
"constants": [
|
||||
{
|
||||
"key": "GENERIC_SEARCH_ROOTS",
|
||||
"value": [ "ROOT" ],
|
||||
"priority": "fallback"
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"provides": "searchService",
|
||||
"type": "provider",
|
||||
"implementation": "GenericSearchProvider.js",
|
||||
"depends": [ "$q", "$timeout", "objectService", "workerService", "GENERIC_SEARCH_ROOTS" ]
|
||||
},
|
||||
{
|
||||
"provides": "searchService",
|
||||
"type": "aggregator",
|
||||
"implementation": "SearchAggregator.js",
|
||||
"depends": [ "$q" ]
|
||||
}
|
||||
],
|
||||
"workers": [
|
||||
{
|
||||
"key": "genericSearchWorker",
|
||||
"scriptUrl": "GenericSearchWorker.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
268
platform/search/src/GenericSearchProvider.js
Normal file
268
platform/search/src/GenericSearchProvider.js
Normal file
@ -0,0 +1,268 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Module defining GenericSearchProvider. Created by shale on 07/16/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_MAX_RESULTS = 100,
|
||||
DEFAULT_TIMEOUT = 1000,
|
||||
stopTime;
|
||||
|
||||
/**
|
||||
* A search service which searches through domain objects in
|
||||
* the filetree without using external search implementations.
|
||||
*
|
||||
* @constructor
|
||||
* @param $q Angular's $q, for promise consolidation.
|
||||
* @param $timeout Angular's $timeout, for delayed function execution.
|
||||
* @param {ObjectService} objectService The service from which
|
||||
* domain objects can be gotten.
|
||||
* @param {WorkerService} workerService The service which allows
|
||||
* more easy creation of web workers.
|
||||
* @param {GENERIC_SEARCH_ROOTS} ROOTS An array of the root
|
||||
* domain objects' IDs.
|
||||
*/
|
||||
function GenericSearchProvider($q, $timeout, objectService, workerService, ROOTS) {
|
||||
var worker = workerService.run('genericSearchWorker'),
|
||||
indexed = {},
|
||||
pendingQueries = {};
|
||||
// pendingQueries is a dictionary with the key value pairs st
|
||||
// the key is the timestamp and the value is the promise
|
||||
|
||||
// Tell the web worker to add a domain object's model to its list of items.
|
||||
function indexItem(domainObject) {
|
||||
var message;
|
||||
|
||||
// undefined check
|
||||
if (domainObject && domainObject.getModel) {
|
||||
// Using model instead of whole domain object because
|
||||
// it's a JSON object.
|
||||
message = {
|
||||
request: 'index',
|
||||
model: domainObject.getModel(),
|
||||
id: domainObject.getId()
|
||||
};
|
||||
worker.postMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the worker to search for items it has that match this searchInput.
|
||||
// Takes the searchInput, as well as a max number of results (will return
|
||||
// less than that if there are fewer matches).
|
||||
function workerSearch(searchInput, maxResults, timestamp, timeout) {
|
||||
var message = {
|
||||
request: 'search',
|
||||
input: searchInput,
|
||||
maxNumber: maxResults,
|
||||
timestamp: timestamp,
|
||||
timeout: timeout
|
||||
};
|
||||
worker.postMessage(message);
|
||||
}
|
||||
|
||||
// Handles responses from the web worker. Namely, the results of
|
||||
// a search request.
|
||||
function handleResponse(event) {
|
||||
var ids = [],
|
||||
id;
|
||||
|
||||
// If we have the results from a search
|
||||
if (event.data.request === 'search') {
|
||||
// Convert the ids given from the web worker into domain objects
|
||||
for (id in event.data.results) {
|
||||
ids.push(id);
|
||||
}
|
||||
objectService.getObjects(ids).then(function (objects) {
|
||||
var searchResults = [],
|
||||
id;
|
||||
|
||||
// Create searchResult objects
|
||||
for (id in objects) {
|
||||
searchResults.push({
|
||||
object: objects[id],
|
||||
id: id,
|
||||
score: event.data.results[id]
|
||||
});
|
||||
}
|
||||
|
||||
// Resove the promise corresponding to this
|
||||
pendingQueries[event.data.timestamp].resolve({
|
||||
hits: searchResults,
|
||||
total: event.data.total,
|
||||
timedOut: event.data.timedOut
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
worker.onmessage = handleResponse;
|
||||
|
||||
// Helper function for getItems(). Indexes the tree.
|
||||
function indexItems(nodes) {
|
||||
nodes.forEach(function (node) {
|
||||
var id = node && node.getId && node.getId();
|
||||
|
||||
// If we have already indexed this item, stop here
|
||||
if (indexed[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Index each item with the web worker
|
||||
indexItem(node);
|
||||
indexed[id] = true;
|
||||
|
||||
|
||||
// If this node has children, index those
|
||||
if (node && node.hasCapability && node.hasCapability('composition')) {
|
||||
// Make sure that this is async, so doesn't block up page
|
||||
$timeout(function () {
|
||||
// Get the children...
|
||||
node.useCapability('composition').then(function (children) {
|
||||
$timeout(function () {
|
||||
// ... then index the children
|
||||
if (children.constructor === Array) {
|
||||
indexItems(children);
|
||||
} else {
|
||||
indexItems([children]);
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Watch for changes to this item, in case it gets new children
|
||||
if (node && node.hasCapability && node.hasCapability('mutation')) {
|
||||
node.getCapability('mutation').listen(function (listener) {
|
||||
if (listener && listener.composition) {
|
||||
// If the node was mutated to have children, get the child domain objects
|
||||
objectService.getObjects(listener.composition).then(function (objectsById) {
|
||||
var objects = [],
|
||||
id;
|
||||
|
||||
// Get each of the domain objects in objectsById
|
||||
for (id in objectsById) {
|
||||
objects.push(objectsById[id]);
|
||||
}
|
||||
|
||||
indexItems(objects);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Converts the filetree into a list
|
||||
function getItems() {
|
||||
// Aquire root objects
|
||||
objectService.getObjects(ROOTS).then(function (objectsById) {
|
||||
var objects = [],
|
||||
id;
|
||||
|
||||
// Get each of the domain objects in objectsById
|
||||
for (id in objectsById) {
|
||||
objects.push(objectsById[id]);
|
||||
}
|
||||
|
||||
// Index all of the roots' descendents
|
||||
indexItems(objects);
|
||||
});
|
||||
}
|
||||
|
||||
// For documentation, see query below
|
||||
function query(input, timestamp, maxResults, timeout) {
|
||||
var terms = [],
|
||||
searchResults = [],
|
||||
defer = $q.defer();
|
||||
|
||||
// If the input is nonempty, do a search
|
||||
if (input !== '' && input !== undefined) {
|
||||
|
||||
// Allow us to access this promise later to resolve it later
|
||||
pendingQueries[timestamp] = defer;
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Similarly, check if timeout was provided
|
||||
if (!timeout) {
|
||||
timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
// Send the query to the worker
|
||||
workerSearch(input, maxResults, timestamp, timeout);
|
||||
|
||||
return defer.promise;
|
||||
} else {
|
||||
// Otherwise return an empty result
|
||||
return {hits: [], total: 0};
|
||||
}
|
||||
}
|
||||
|
||||
// Index the tree's contents once at the beginning
|
||||
getItems();
|
||||
|
||||
return {
|
||||
/**
|
||||
* Searches through the filetree for domain objects which match
|
||||
* the search term. This function is to be used as a fallback
|
||||
* in the case where other search services are not avaliable.
|
||||
* 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 not guarenteed.
|
||||
* * A domain object qualifies as a match for a search input if
|
||||
* the object's name property contains any of the search terms
|
||||
* (which are generated by splitting the input at spaces).
|
||||
* * Scores are higher for matches that have more of the terms
|
||||
* as substrings.
|
||||
*
|
||||
* @param input 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.
|
||||
*/
|
||||
query: query
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return GenericSearchProvider;
|
||||
}
|
||||
);
|
185
platform/search/src/GenericSearchWorker.js
Normal file
185
platform/search/src/GenericSearchWorker.js
Normal file
@ -0,0 +1,185 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global self*/
|
||||
|
||||
/**
|
||||
* Module defining GenericSearchWorker. Created by shale on 07/21/2015.
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// An array of objects composed of domain object IDs and models
|
||||
// {id: domainObject's ID, model: domainObject's model}
|
||||
var indexedItems = [];
|
||||
|
||||
// Helper function for index()
|
||||
// Checks whether an item with this ID is already indexed
|
||||
function conainsItem(id) {
|
||||
var i;
|
||||
for (i = 0; i < indexedItems.length; i += 1) {
|
||||
if (indexedItems[i].id === id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes an item to indexedItems.
|
||||
*
|
||||
* @param data An object which contains:
|
||||
* * model: The model of the domain object
|
||||
* * id: The ID of the domain object
|
||||
*/
|
||||
function index(data) {
|
||||
var message;
|
||||
|
||||
if (!conainsItem(data.id)) {
|
||||
indexedItems.push({
|
||||
id: data.id,
|
||||
model: data.model
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for serach()
|
||||
function convertToTerms(input) {
|
||||
var terms = input;
|
||||
// Shave any spaces off of the ends of the input
|
||||
while (terms.substr(0, 1) === ' ') {
|
||||
terms = terms.substring(1, terms.length);
|
||||
}
|
||||
while (terms.substr(terms.length - 1, 1) === ' ') {
|
||||
terms = terms.substring(0, terms.length - 1);
|
||||
}
|
||||
|
||||
// Then split it at spaces and asterisks
|
||||
terms = terms.split(/ |\*/);
|
||||
|
||||
// Remove any empty strings from the terms
|
||||
while (terms.indexOf('') !== -1) {
|
||||
terms.splice(terms.indexOf(''), 1);
|
||||
}
|
||||
|
||||
return terms;
|
||||
}
|
||||
|
||||
// Helper function for search()
|
||||
function scoreItem(item, input, terms) {
|
||||
var name = item.model.name.toLocaleLowerCase(),
|
||||
weight = 0.65,
|
||||
score = 0.0,
|
||||
i;
|
||||
|
||||
// Make the score really big if the item name and
|
||||
// the original search input are the same
|
||||
if (name === input) {
|
||||
score = 42;
|
||||
}
|
||||
|
||||
for (i = 0; i < terms.length; i += 1) {
|
||||
// Increase the score if the term is in the item name
|
||||
if (name.indexOf(terms[i]) !== -1) {
|
||||
score += 1;
|
||||
|
||||
// Add extra to the score if the search term exists
|
||||
// as its own term within the items
|
||||
if (name.split(' ').indexOf(terms[i]) !== -1) {
|
||||
score += 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return score * weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets search results from the indexedItems based on provided search
|
||||
* input. Returns matching results from indexedItems, as well as the
|
||||
* timestamp that was passed to it.
|
||||
*
|
||||
* @param data An object which contains:
|
||||
* * input: The original string which we are searching with
|
||||
* * maxNumber: The maximum number of search results desired
|
||||
* * timestamp: The time identifier from when the query was made
|
||||
*/
|
||||
function search(data) {
|
||||
// This results dictionary will have domain object ID keys which
|
||||
// point to the value the domain object's score.
|
||||
var results = {},
|
||||
input = data.input.toLocaleLowerCase(),
|
||||
terms = convertToTerms(input),
|
||||
message = {
|
||||
request: 'search',
|
||||
results: {},
|
||||
total: 0,
|
||||
timestamp: data.timestamp,
|
||||
timedOut: false
|
||||
},
|
||||
score,
|
||||
i,
|
||||
id;
|
||||
|
||||
// If the user input is empty, we want to have no search results.
|
||||
if (input !== '') {
|
||||
for (i = 0; i < indexedItems.length; i += 1) {
|
||||
// If this is taking too long, then stop
|
||||
if (Date.now() > data.timestamp + data.timeout) {
|
||||
message.timedOut = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Score and add items
|
||||
score = scoreItem(indexedItems[i], input, terms);
|
||||
if (score > 0) {
|
||||
results[indexedItems[i].id] = score;
|
||||
message.total += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate results if there are more than maxResults
|
||||
if (message.total > data.maxResults) {
|
||||
i = 0;
|
||||
for (id in results) {
|
||||
message.results[id] = results[id];
|
||||
i += 1;
|
||||
if (i >= data.maxResults) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: This seems inefficient.
|
||||
} else {
|
||||
message.results = results;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
self.onmessage = function (event) {
|
||||
if (event.data.request === 'index') {
|
||||
index(event.data);
|
||||
} else if (event.data.request === 'search') {
|
||||
self.postMessage(search(event.data));
|
||||
}
|
||||
};
|
||||
}());
|
146
platform/search/src/SearchAggregator.js
Normal file
146
platform/search/src/SearchAggregator.js
Normal file
@ -0,0 +1,146 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Module defining SearchAggregator. Created by shale on 07/16/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
var DEFUALT_TIMEOUT = 1000,
|
||||
DEFAULT_MAX_RESULTS = 100;
|
||||
|
||||
/**
|
||||
* Allows multiple services which provide search functionality
|
||||
* to be treated as one.
|
||||
*
|
||||
* @constructor
|
||||
* @param $q Angular's $q, for promise consolidation.
|
||||
* @param {SearchProvider[]} providers The search providers to be
|
||||
* aggregated.
|
||||
*/
|
||||
function SearchAggregator($q, providers) {
|
||||
|
||||
// Remove duplicate objects that have the same ID. Modifies the passed
|
||||
// array, and returns the number that were removed.
|
||||
function filterDuplicates(results, total) {
|
||||
var ids = {},
|
||||
numRemoved = 0,
|
||||
i;
|
||||
|
||||
for (i = 0; i < results.length; i += 1) {
|
||||
if (ids[results[i].id]) {
|
||||
// If this result's ID is already there, remove the object
|
||||
results.splice(i, 1);
|
||||
numRemoved += 1;
|
||||
|
||||
// Reduce loop index because we shortened the array
|
||||
i -= 1;
|
||||
} else {
|
||||
// Otherwise add the ID to the list of the ones we have seen
|
||||
ids[results[i].id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return numRemoved;
|
||||
}
|
||||
|
||||
// Order the objects from highest to lowest score in the array.
|
||||
// Modifies the passed array, as well as returns the modified array.
|
||||
function orderByScore(results) {
|
||||
results.sort(function (a, b) {
|
||||
if (a.score > b.score) {
|
||||
return -1;
|
||||
} else if (b.score > a.score) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
// For documentation, see query below.
|
||||
function queryAll(inputText, maxResults) {
|
||||
var i,
|
||||
timestamp = Date.now(),
|
||||
resultPromises = [];
|
||||
|
||||
if (!maxResults) {
|
||||
maxResults = DEFAULT_MAX_RESULTS;
|
||||
}
|
||||
|
||||
// Send the query to all the providers
|
||||
for (i = 0; i < providers.length; i += 1) {
|
||||
resultPromises.push(
|
||||
providers[i].query(inputText, timestamp, maxResults, DEFUALT_TIMEOUT)
|
||||
);
|
||||
}
|
||||
|
||||
// Get promises for results arrays
|
||||
return $q.all(resultPromises).then(function (resultObjects) {
|
||||
var results = [],
|
||||
totalSum = 0,
|
||||
i;
|
||||
|
||||
// Merge results
|
||||
for (i = 0; i < resultObjects.length; i += 1) {
|
||||
results = results.concat(resultObjects[i].hits);
|
||||
totalSum += resultObjects[i].total;
|
||||
}
|
||||
// Order by score first, so that when removing repeats we keep the higher scored ones
|
||||
orderByScore(results);
|
||||
totalSum -= filterDuplicates(results, totalSum);
|
||||
|
||||
return {
|
||||
hits: results,
|
||||
total: totalSum,
|
||||
timedOut: resultObjects.some(function (obj) {
|
||||
return obj.timedOut;
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Sends a query to each of the providers. 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}
|
||||
*
|
||||
* @param inputText The text input that is the query.
|
||||
* @param maxResults (optional) The maximum number of results
|
||||
* that this function should return. If not provided, a
|
||||
* default of 100 will be used.
|
||||
*/
|
||||
query: queryAll
|
||||
};
|
||||
}
|
||||
|
||||
return SearchAggregator;
|
||||
}
|
||||
);
|
157
platform/search/test/GenericSearchProviderSpec.js
Normal file
157
platform/search/test/GenericSearchProviderSpec.js
Normal file
@ -0,0 +1,157 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* SearchSpec. Created by shale on 07/31/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/GenericSearchProvider"],
|
||||
function (GenericSearchProvider) {
|
||||
"use strict";
|
||||
|
||||
describe("The generic search provider ", function () {
|
||||
var mockQ,
|
||||
mockTimeout,
|
||||
mockDeferred,
|
||||
mockObjectService,
|
||||
mockObjectPromise,
|
||||
mockDomainObjects,
|
||||
mockCapability,
|
||||
mockCapabilityPromise,
|
||||
mockWorkerService,
|
||||
mockWorker,
|
||||
mockRoots = ['root1', 'root2'],
|
||||
provider,
|
||||
mockProviderResults;
|
||||
|
||||
beforeEach(function () {
|
||||
var i;
|
||||
|
||||
mockQ = jasmine.createSpyObj(
|
||||
"$q",
|
||||
[ "defer" ]
|
||||
);
|
||||
mockDeferred = jasmine.createSpyObj(
|
||||
"deferred",
|
||||
[ "resolve", "reject"]
|
||||
);
|
||||
mockDeferred.promise = "mock promise";
|
||||
mockQ.defer.andReturn(mockDeferred);
|
||||
|
||||
mockTimeout = jasmine.createSpy("$timeout");
|
||||
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
[ "getObjects" ]
|
||||
);
|
||||
mockObjectPromise = jasmine.createSpyObj(
|
||||
"promise",
|
||||
[ "then", "catch" ]
|
||||
);
|
||||
mockObjectService.getObjects.andReturn(mockObjectPromise);
|
||||
|
||||
|
||||
mockWorkerService = jasmine.createSpyObj(
|
||||
"workerService",
|
||||
[ "run" ]
|
||||
);
|
||||
mockWorker = jasmine.createSpyObj(
|
||||
"worker",
|
||||
[ "postMessage" ]
|
||||
);
|
||||
mockWorkerService.run.andReturn(mockWorker);
|
||||
|
||||
mockDomainObjects = {};
|
||||
for (i = 0; i < 4; i += 1) {
|
||||
mockDomainObjects[i] = (
|
||||
jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getId", "getModel", "hasCapability", "getCapability", "useCapability" ]
|
||||
)
|
||||
);
|
||||
mockDomainObjects[i].getId.andReturn(i);
|
||||
mockDomainObjects[i].getCapability.andReturn(mockCapability);
|
||||
}
|
||||
// Give the first object children
|
||||
mockDomainObjects[0].hasCapability.andReturn(true);
|
||||
mockCapability = jasmine.createSpyObj(
|
||||
"capability",
|
||||
[ "invoke", "listen" ]
|
||||
);
|
||||
mockCapabilityPromise = jasmine.createSpyObj(
|
||||
"promise",
|
||||
[ "then", "catch" ]
|
||||
);
|
||||
mockCapability.invoke.andReturn(mockCapabilityPromise);
|
||||
mockDomainObjects[0].getCapability.andReturn(mockCapability);
|
||||
|
||||
provider = new GenericSearchProvider(mockQ, mockTimeout, mockObjectService, mockWorkerService, mockRoots);
|
||||
});
|
||||
|
||||
it("indexes tree on initialization", function () {
|
||||
expect(mockObjectService.getObjects).toHaveBeenCalled();
|
||||
expect(mockObjectPromise.then).toHaveBeenCalled();
|
||||
|
||||
mockObjectPromise.then.mostRecentCall.args[0](mockDomainObjects);
|
||||
|
||||
//mockCapabilityPromise.then.mostRecentCall.args[0](mockDomainObjects[1]);
|
||||
|
||||
expect(mockWorker.postMessage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sends search queries to the worker", function () {
|
||||
var timestamp = Date.now();
|
||||
provider.query(' test "query" ', timestamp, 1, 2);
|
||||
expect(mockWorker.postMessage).toHaveBeenCalledWith({
|
||||
request: "search",
|
||||
input: ' test "query" ',
|
||||
timestamp: timestamp,
|
||||
maxNumber: 1,
|
||||
timeout: 2
|
||||
});
|
||||
});
|
||||
|
||||
it("handles responses from the worker", function () {
|
||||
var timestamp = Date.now(),
|
||||
event = {
|
||||
data: {
|
||||
request: "search",
|
||||
results: {
|
||||
1: 1,
|
||||
2: 2
|
||||
},
|
||||
total: 2,
|
||||
timedOut: false,
|
||||
timestamp: timestamp
|
||||
}
|
||||
};
|
||||
|
||||
provider.query(' test "query" ', timestamp);
|
||||
mockWorker.onmessage(event);
|
||||
mockObjectPromise.then.mostRecentCall.args[0](mockDomainObjects);
|
||||
expect(mockDeferred.resolve).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
132
platform/search/test/GenericSearchWorkerSpec.js
Normal file
132
platform/search/test/GenericSearchWorkerSpec.js
Normal file
@ -0,0 +1,132 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,describe,it,expect,runs,waitsFor,beforeEach,jasmine,Worker,require*/
|
||||
|
||||
/**
|
||||
* SearchSpec. Created by shale on 07/31/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
describe("The generic search worker ", function () {
|
||||
// If this test fails, make sure this path is correct
|
||||
var worker = new Worker(require.toUrl('platform/search/src/GenericSearchWorker.js')),
|
||||
numObjects = 5;
|
||||
|
||||
beforeEach(function () {
|
||||
var i;
|
||||
for (i = 0; i < numObjects; i += 1) {
|
||||
worker.postMessage(
|
||||
{
|
||||
request: "index",
|
||||
id: i,
|
||||
model: {
|
||||
name: "object " + i,
|
||||
id: i,
|
||||
type: "something"
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("searches can reach all objects", function () {
|
||||
var flag = false,
|
||||
workerOutput,
|
||||
resultsLength = 0;
|
||||
|
||||
// Search something that should return all objects
|
||||
runs(function () {
|
||||
worker.postMessage(
|
||||
{
|
||||
request: "search",
|
||||
input: "object",
|
||||
maxNumber: 100,
|
||||
timestamp: Date.now(),
|
||||
timeout: 1000
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
worker.onmessage = function (event) {
|
||||
var id;
|
||||
|
||||
workerOutput = event.data;
|
||||
for (id in workerOutput.results) {
|
||||
resultsLength += 1;
|
||||
}
|
||||
flag = true;
|
||||
};
|
||||
|
||||
waitsFor(function () {
|
||||
return flag;
|
||||
}, "The worker should be searching", 1000);
|
||||
|
||||
runs(function () {
|
||||
expect(workerOutput).toBeDefined();
|
||||
expect(resultsLength).toEqual(numObjects);
|
||||
});
|
||||
});
|
||||
|
||||
it("searches return only matches", function () {
|
||||
var flag = false,
|
||||
workerOutput,
|
||||
resultsLength = 0;
|
||||
|
||||
// Search something that should return 1 object
|
||||
runs(function () {
|
||||
worker.postMessage(
|
||||
{
|
||||
request: "search",
|
||||
input: "2",
|
||||
maxNumber: 100,
|
||||
timestamp: Date.now(),
|
||||
timeout: 1000
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
worker.onmessage = function (event) {
|
||||
var id;
|
||||
|
||||
workerOutput = event.data;
|
||||
for (id in workerOutput.results) {
|
||||
resultsLength += 1;
|
||||
}
|
||||
flag = true;
|
||||
};
|
||||
|
||||
waitsFor(function () {
|
||||
return flag;
|
||||
}, "The worker should be searching", 1000);
|
||||
|
||||
runs(function () {
|
||||
expect(workerOutput).toBeDefined();
|
||||
expect(resultsLength).toEqual(1);
|
||||
expect(workerOutput.results[2]).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
101
platform/search/test/SearchAggregatorSpec.js
Normal file
101
platform/search/test/SearchAggregatorSpec.js
Normal file
@ -0,0 +1,101 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* 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*/
|
||||
|
||||
/**
|
||||
* SearchSpec. Created by shale on 07/31/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/SearchAggregator"],
|
||||
function (SearchAggregator) {
|
||||
"use strict";
|
||||
|
||||
describe("The search aggregator ", function () {
|
||||
var mockQ,
|
||||
mockPromise,
|
||||
mockProviders = [],
|
||||
aggregator,
|
||||
mockProviderResults = [],
|
||||
mockAggregatorResults,
|
||||
i;
|
||||
|
||||
beforeEach(function () {
|
||||
mockQ = jasmine.createSpyObj(
|
||||
"$q",
|
||||
[ "all" ]
|
||||
);
|
||||
mockPromise = jasmine.createSpyObj(
|
||||
"promise",
|
||||
[ "then" ]
|
||||
);
|
||||
for (i = 0; i < 3; i += 1) {
|
||||
mockProviders.push(
|
||||
jasmine.createSpyObj(
|
||||
"mockProvider" + i,
|
||||
[ "query" ]
|
||||
)
|
||||
);
|
||||
mockProviders[i].query.andReturn(mockPromise);
|
||||
}
|
||||
mockQ.all.andReturn(mockPromise);
|
||||
|
||||
aggregator = new SearchAggregator(mockQ, mockProviders);
|
||||
aggregator.query();
|
||||
|
||||
for (i = 0; i < mockProviders.length; i += 1) {
|
||||
mockProviderResults.push({
|
||||
hits: [
|
||||
{
|
||||
id: i,
|
||||
score: 42 - i
|
||||
},
|
||||
{
|
||||
id: i + 1,
|
||||
score: 42 - (2 * i)
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
mockAggregatorResults = mockPromise.then.mostRecentCall.args[0](mockProviderResults);
|
||||
});
|
||||
|
||||
it("sends queries to all providers", function () {
|
||||
for (i = 0; i < mockProviders.length; i += 1) {
|
||||
expect(mockProviders[i].query).toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
|
||||
it("filters out duplicate objects", function () {
|
||||
expect(mockAggregatorResults.hits.length).toEqual(mockProviders.length + 1);
|
||||
expect(mockAggregatorResults.total).not.toBeLessThan(mockAggregatorResults.hits.length);
|
||||
});
|
||||
|
||||
it("orders results by score", function () {
|
||||
for (i = 1; i < mockAggregatorResults.hits.length; i += 1) {
|
||||
expect(mockAggregatorResults.hits[i].score)
|
||||
.not.toBeGreaterThan(mockAggregatorResults.hits[i - 1].score);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
5
platform/search/test/suite.json
Normal file
5
platform/search/test/suite.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
"SearchAggregator",
|
||||
"GenericSearchProvider",
|
||||
"GenericSearchWorker"
|
||||
]
|
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
<groupId>gov.nasa.arc.wtd</groupId>
|
||||
<artifactId>open-mct-web</artifactId>
|
||||
<name>Open MCT Web</name>
|
||||
<version>0.8.0-SNAPSHOT</version>
|
||||
<version>0.8.1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
|
69
protractor/README
Normal file
69
protractor/README
Normal file
@ -0,0 +1,69 @@
|
||||
E2e Protractor Tests.
|
||||
|
||||
1. Instructions:
|
||||
|
||||
1. 3 Control Scripts located in bin/.
|
||||
run.js : node script used to start tests
|
||||
start.js: node script used to setup test(starts node,localstorage and webdriver)
|
||||
stop.js : node script, kills the 3 process started in start.js.
|
||||
clean.js: node script used to remove the node_module directory.(clean up directory).
|
||||
|
||||
2. Use npm(Node Package Mangager) to Run Scripts.
|
||||
a. cd protractor;
|
||||
b. npm install;
|
||||
c. To Run:
|
||||
-npm start : will start processes need by protractor
|
||||
-npm stop : will stop the processes need by protractor
|
||||
-npm run-script run : will execute Protractor Script
|
||||
-npm run-script all : will execute "start", "run", and "stop" script
|
||||
|
||||
2. Directory Hierachy:
|
||||
|
||||
-protractor: base directory
|
||||
-common: contains prototype javascript functions that all other tests use.
|
||||
-Buttons: common prototype functions related to enter fullscreen
|
||||
-CreateItem: common prototype functions related to creating an item
|
||||
-drag: common functions to test drag and drop.
|
||||
-editItem: common functions used to test edit functionality.
|
||||
-Launch: common script used to navigate the specified website.
|
||||
-RightMenu: common functions for right click menu(remove).
|
||||
-create
|
||||
-e2e tests that creates the specified object.
|
||||
-delete
|
||||
-e2e tests that removes the specified object
|
||||
-logs
|
||||
-ctrl.sh redirects console output of MMAP, webdriver and elastic search and pipes them to log files.
|
||||
-UI
|
||||
-Contains tests that test the UI(drag drop, fullscreen, info bubble)
|
||||
-conf.js:
|
||||
-protractor config file. Explained below
|
||||
-stressTest:
|
||||
Tests that are used to test for memory leaks. You can use the new tab option on WARP and then open the
|
||||
timeline in the new tab during the browser.sleep(). Once the test is do the browser will pause and you
|
||||
can look a the timeline results in the new tab.
|
||||
|
||||
NOTE: Cannot open chrome dev tools on same tab as the test are run on. Protractor uses the dev tools to
|
||||
exectute the tests.
|
||||
|
||||
-StressTest will create and delete folders.
|
||||
-StressTestBubble.js: creates manny bubbles.
|
||||
(Delay variable in InfoGesture.js was changed to 0)
|
||||
3. Conf.js
|
||||
Conf.js is used by protractor to setup and execute the tests.
|
||||
-allScriptsTimeout: gives more time for protractor to synchronize with the page.
|
||||
-jasmineNodeOpts: Protractor uses jasmine for the tests and jasmine has a default time out 30 seconds
|
||||
per "it" test. Changed to maximume allowed time 360000 ms
|
||||
-seleniumAddress: Protractor uses a Selenium server as a "proxy" between the test scripts and the browser
|
||||
driver. A stand a lone version comes with protractor and to run use "webdriver-manager"
|
||||
default address is: http://localhost:4444/wd/hub.
|
||||
-specs[]: Is an array of files. Each File should have a "describe, it" test to be executed by protractor.
|
||||
-capabilities: Tells protractor what browser to use and any browser arguments.
|
||||
|
||||
4. bundle.json
|
||||
bundle.json is used by npm to determine dependencies and location of script files.
|
||||
-Dependencies:
|
||||
"protractor": Contains protractor and webdriver package.
|
||||
"psnode": Window/Unix Command, used for list/kill process.(ps aux)
|
||||
"shelljs": Window/Unix Common JS Commands. eg rm,ls,exec
|
||||
"sleep": Window/Unix Commands used to sleep the script
|
||||
"string": Window/Unix Commands for string manipulation.
|
@ -22,7 +22,7 @@
|
||||
//TODO Add filter for duplications/
|
||||
var fullScreenFile = require("../common/Buttons");
|
||||
|
||||
describe('Test Fullscreen', function() {
|
||||
describe('Enable Fullscreen', function() {
|
||||
var fullScreenClass = new fullScreenFile();
|
||||
|
||||
beforeEach(require('../common/Launch'));
|
||||
|
@ -25,7 +25,7 @@ var itemEdit = require("../common/EditItem");
|
||||
var rightMenu = require("../common/RightMenu");
|
||||
var Drag = require("../common/drag");
|
||||
|
||||
describe('Test Info Bubble', function() {
|
||||
describe('Info Bubble', function() {
|
||||
var fullScreenClass = new fullScreenFile();
|
||||
var createClass = new createItem();
|
||||
var editItemClass = new itemEdit();
|
||||
|
@ -24,7 +24,7 @@ var createClassFile = require("../common/CreateItem")
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var rightMenu = require("../common/RightMenu.js");
|
||||
|
||||
describe('Test New Window', function() {
|
||||
describe('New Window', function() {
|
||||
var fullScreenClass = new fullScreenFile();
|
||||
var createClass = new createClassFile();
|
||||
var editItemClass = new itemEdit();
|
||||
|
@ -21,28 +21,64 @@
|
||||
*****************************************************************************/
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
var Create = require("../common/CreateItem")
|
||||
describe('Right Click Interations', function() {
|
||||
var itemEdit = require("../common/EditItem");
|
||||
|
||||
describe('The Right Menu', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new Create();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
|
||||
beforeEach(require('../common/Launch'));
|
||||
|
||||
it('should delete the specified object', function(){
|
||||
it('should Dissapear After Delete', function(){
|
||||
browser.wait(function() {
|
||||
createClass.createButton().click();
|
||||
return true;
|
||||
}).then(function (){
|
||||
var folder = createClass.selectNewItem(ITEM_TYPE);
|
||||
expect(folder.getText()).toEqual([ ITEM_MENU_GLYPH ]);
|
||||
browser.sleep(1000);
|
||||
folder.click()
|
||||
browser.sleep(1000);
|
||||
}).then(function() {
|
||||
browser.wait(function () {
|
||||
return element.all(by.model('ngModel[field]')).isDisplayed();
|
||||
})
|
||||
createClass.fillFolderForum(ITEM_NAME, ITEM_TYPE).click();
|
||||
clickClass.delete(ITEM_NAME);
|
||||
browser.sleep(1000);
|
||||
}).then(function (){
|
||||
var item = editItemClass.SelectItem(ITEM_GRID_SELECT);
|
||||
expect(item.count()).toBe(1);
|
||||
browser.sleep(1000);
|
||||
}).then(function () {
|
||||
var MyItem = ">\nF\nMy Items"
|
||||
element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
return text === MyItem;
|
||||
});
|
||||
}).all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
return text === ">\nF\nFolder";
|
||||
});
|
||||
});
|
||||
browser.sleep(1000)
|
||||
browser.actions().mouseMove(object.get(0)).perform();
|
||||
browser.actions().click(protractor.Button.RIGHT).perform();
|
||||
browser.sleep(1000)
|
||||
var menu = element.all(by.css('.ng-binding')).filter(function (ele){
|
||||
return ele.getText().then(function (text) {
|
||||
return text == "Z\nRemove";
|
||||
})
|
||||
})
|
||||
menu.click();
|
||||
browser.sleep(1000)
|
||||
|
||||
expect(menu.isDisplayed()).toBe(false);
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
15
protractor/bin/clean.js
Executable file
15
protractor/bin/clean.js
Executable file
@ -0,0 +1,15 @@
|
||||
#! /usr/bin/env node
|
||||
var shell = require("shelljs/global");
|
||||
|
||||
var startdir = process.cwd();
|
||||
var command = "npm unlink";
|
||||
|
||||
console.log("Cleaning Directory")
|
||||
exec(command, function(code, output) {
|
||||
if(code != 0){
|
||||
console.log('Exit code:', code);
|
||||
console.log('Program output:', output);
|
||||
}
|
||||
});
|
||||
console.log("rm -rf node_modules")
|
||||
rm('-rf', __dirname + "/../node_modules")
|
90
protractor/bin/ctrl.sh
Executable file
90
protractor/bin/ctrl.sh
Executable file
@ -0,0 +1,90 @@
|
||||
#! /bin/bash
|
||||
ARGUMENT=$1;
|
||||
|
||||
if [ $# != 1 ]; then
|
||||
echo "Expected 1 Aurgument. Received " $# 1>&2;
|
||||
exit 1
|
||||
fi
|
||||
#Start webdrive and http-server
|
||||
if [ $ARGUMENT == start ]; then
|
||||
echo "Creating Log Directory ..."
|
||||
mkdir logs;
|
||||
|
||||
cd ..
|
||||
node app.js -p 1984 -x platform/persistence/elastic -i example/persistence > protractor/logs/nodeApp.log 2>&1 &
|
||||
sleep 3;
|
||||
if grep -iq "Error" protractor/logs/nodeApp.log; then
|
||||
if grep -iq "minimist" protractor/logs/nodeApp.log; then
|
||||
echo " Node Failed Because Minimist is not installed"
|
||||
echo " Installng Minimist ..."
|
||||
npm install minimist express > protractor/logs/minimist.log 2>&1 &
|
||||
wait $!
|
||||
if [ $? != 0 ]; then
|
||||
echo " Error: minimist"
|
||||
echo " Check Log file"
|
||||
echo
|
||||
else
|
||||
echo " Started: Minimist"
|
||||
echo
|
||||
node app.js -p 1984 -x platform/persistence/elastic -i example/persistence > protractor/logs/nodeApp.log 2>&1 &
|
||||
if grep -iq "Error" protractor/logs/nodeApp.log; then
|
||||
echo " Error: node app failed"
|
||||
echo " Check Log file"
|
||||
echo
|
||||
else
|
||||
echo " Started: node app.js"
|
||||
echo
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " Error: node app failed"
|
||||
echo " Check Log file"
|
||||
echo
|
||||
fi
|
||||
else
|
||||
echo " Started: node app.js"
|
||||
echo
|
||||
fi
|
||||
echo "Starting webdriver ..."
|
||||
|
||||
cd protractor;
|
||||
webdriver-manager start > logs/webdriver.log 2>&1 &
|
||||
sleep 3;
|
||||
if grep -iq "Exception" logs/webdriver.log; then
|
||||
echo " Error: webdriver-manager"
|
||||
echo " Check Log file"
|
||||
echo
|
||||
else
|
||||
echo " Started: webdriver-manager"
|
||||
fi
|
||||
echo "Starting Elastic Search..."
|
||||
|
||||
elasticsearch > logs/elasticSearch.log 2>&1 &
|
||||
sleep 3;
|
||||
if grep -iq "Exception" logs/elasticSearch.log; then
|
||||
echo " Error: ElasticSearch"
|
||||
echo " Check Log file"
|
||||
echo
|
||||
else
|
||||
echo " Started: ElasticSearch"
|
||||
fi
|
||||
#Runs Protractor tests
|
||||
elif [ $ARGUMENT == run ]; then
|
||||
protractor ./conf.js
|
||||
#Kill Process
|
||||
elif [ $ARGUMENT == stop ]; then
|
||||
echo "Removing logs"
|
||||
rm -rf logs
|
||||
echo "Stopping Node"
|
||||
kill $(ps aux | grep "[n]ode app.js"| awk '{print $2}');
|
||||
|
||||
echo "Stopping webdriver ..."
|
||||
kill $(ps aux | grep "[p]rotractor" | awk '{print $2}');
|
||||
kill $(ps aux | grep "[w]ebdriver-manager" | awk '{print $2}');
|
||||
sleep 1;
|
||||
echo "Stopping Elastic..."
|
||||
kill $(ps aux | grep "[e]lastic" | awk '{print $2}');
|
||||
sleep 1;
|
||||
else
|
||||
echo "Unkown: Command" $1;
|
||||
fi
|
12
protractor/bin/run.js
Executable file
12
protractor/bin/run.js
Executable file
@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env node
|
||||
var shell = require("shelljs/global");
|
||||
var sleep = require('sleep');
|
||||
|
||||
var command = __dirname + "/../node_modules/protractor/bin/protractor " +__dirname + "/../conf.js";
|
||||
console.log("Executing Protractor Test")
|
||||
exec(command, function(code, output) {
|
||||
if(code != 0){
|
||||
console.log('Exit code:', code);
|
||||
console.log('Program output:', output);
|
||||
}
|
||||
});
|
40
protractor/bin/start.js
Executable file
40
protractor/bin/start.js
Executable file
@ -0,0 +1,40 @@
|
||||
#! /usr/bin/env node
|
||||
var shell,sleep;
|
||||
try {
|
||||
shell = require("shelljs/global");
|
||||
sleep = require('sleep');
|
||||
}catch (e){
|
||||
console.log("Dependencies Error");
|
||||
console.log("Run npm install");
|
||||
throw (e);
|
||||
}
|
||||
///Users/jsanderf/git/elastic/wtd/protractor/bin
|
||||
var startdir = process.cwd();
|
||||
var command;
|
||||
mkdir(__dirname + '/../logs');
|
||||
|
||||
command = __dirname + "/../node_modules/protractor/bin/webdriver-manager update";
|
||||
console.log("Installing Webdriver");
|
||||
exec(command,{async:false});
|
||||
sleep.sleep(1);
|
||||
|
||||
console.log();
|
||||
cd(__dirname + '/../../');
|
||||
console.log('Installing Dependencies');
|
||||
exec("npm install minimist express", {async:false});
|
||||
console.log('Starting Node');
|
||||
sleep.sleep(1);
|
||||
exec("node app.js -p 1984 -x example/persistence -x platform/persistence/elastic -i example/localstorage > protractor/logs/nodeApp.log 2>&1 &", {async:false});
|
||||
console.log(' Started Node');
|
||||
|
||||
console.log();
|
||||
console.log('Starting Webdriver');
|
||||
sleep.sleep(1);
|
||||
exec("protractor/node_modules/protractor/bin/webdriver-manager start --standalone> protractor/logs/webdriver.log 2>&1 &",{async:false});
|
||||
if(error() == null){
|
||||
console.log(" Webdriver Started");
|
||||
}else{
|
||||
console.log(" Error : ", error());
|
||||
}
|
||||
sleep.sleep(1);
|
||||
cd(startdir);
|
44
protractor/bin/stop.js
Executable file
44
protractor/bin/stop.js
Executable file
@ -0,0 +1,44 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
var shell = require("shelljs/global");
|
||||
var ps = require('psnode');
|
||||
var S = require('string');
|
||||
var sleep = require('sleep');
|
||||
|
||||
// A simple pid lookup
|
||||
ps.list(function(err, results) {
|
||||
|
||||
results.forEach(function( process ){
|
||||
//Killing Node
|
||||
if(S(process.command).contains("node app.js")) {
|
||||
console.log();
|
||||
console.log( 'Killing Node: %s', process.command);
|
||||
ps.kill(process.pid, function(err, stdout) {
|
||||
if (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
console.log(stdout);
|
||||
});
|
||||
}else if(S(process.command).contains("webdriver")) {
|
||||
console.log();
|
||||
console.log( 'Killing WebDriver: %s', process.command);
|
||||
ps.kill(process.pid, function(err, stdout) {
|
||||
if (err){
|
||||
throw new Error(err);
|
||||
}
|
||||
console.log(stdout);
|
||||
});
|
||||
}else if(S(process.command).contains("protractor")) {
|
||||
console.log();
|
||||
console.log( 'Killing Chrome Drive: %s', process.command);
|
||||
ps.kill(process.pid, function(err, stdout) {
|
||||
if (err){
|
||||
throw new Error(err);
|
||||
}
|
||||
console.log(stdout);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -24,6 +24,6 @@
|
||||
module.exports = function launch() {
|
||||
'use strict';
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
browser.get('http://localhost:1984');
|
||||
browser.sleep(2000); // 2 seconds
|
||||
};
|
||||
|
@ -24,18 +24,25 @@ var RightMenu = (function () {
|
||||
|
||||
function RightMenu() {
|
||||
}
|
||||
function carrotMyItem(){
|
||||
var MyItem = ">\nF\nMy Items"
|
||||
element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
return text === MyItem;
|
||||
});
|
||||
}).all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
}
|
||||
//RightMenu Click on Object
|
||||
RightMenu.prototype.delete = function (name, flag) {
|
||||
if(typeof flag === 'undefined'){
|
||||
flag = true;
|
||||
}
|
||||
if(flag === true){
|
||||
var carrot = element.all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).get(0).click();
|
||||
carrotMyItem();
|
||||
}
|
||||
browser.sleep(1000)
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
//expect(text).toEqual("3");
|
||||
return text === name;
|
||||
});
|
||||
});
|
||||
@ -43,7 +50,7 @@ var RightMenu = (function () {
|
||||
browser.actions().mouseMove(object.get(0)).perform();
|
||||
browser.actions().click(protractor.Button.RIGHT).perform();
|
||||
browser.sleep(1000)
|
||||
var remove = element.all(by.css('.ng-binding')).filter(function (ele){
|
||||
element.all(by.css('.ng-binding')).filter(function (ele){
|
||||
return ele.getText().then(function (text) {
|
||||
return text == "Z\nRemove";
|
||||
})
|
||||
@ -58,11 +65,10 @@ var RightMenu = (function () {
|
||||
});
|
||||
};
|
||||
RightMenu.prototype.reset = function (name) {
|
||||
var carrot = element.all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
carrotMyItem();
|
||||
browser.sleep(1000)
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
//expect(text).toEqual("3");
|
||||
return text === name;
|
||||
});
|
||||
}).click();
|
||||
@ -75,19 +81,19 @@ var RightMenu = (function () {
|
||||
return text == "r\nRestart at 0";
|
||||
})
|
||||
}).click();
|
||||
browser.sleep(1000)
|
||||
};
|
||||
//click '<', true==yes false==no
|
||||
RightMenu.prototype.select = function(name, flag){
|
||||
if(typeof flag == "undefined"){
|
||||
flag = true;
|
||||
}
|
||||
//click '<', true==yes false==no
|
||||
if(flag == true){
|
||||
var carrot = element.all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
carrotMyItem();
|
||||
}
|
||||
browser.sleep(1000)
|
||||
return element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
// expect(text).toEqual("3");
|
||||
return text === name;
|
||||
});
|
||||
});
|
||||
@ -96,7 +102,6 @@ var RightMenu = (function () {
|
||||
RightMenu.prototype.dragDrop = function(name){
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
//expect(text).toEqual("3");
|
||||
return text === name;
|
||||
});
|
||||
});
|
||||
|
@ -24,34 +24,34 @@
|
||||
// conf.js
|
||||
exports.config = {
|
||||
allScriptsTimeout: 500000,
|
||||
defaultTimeoutInterval: 60000,
|
||||
jasmineNodeOpts: {defaultTimeoutInterval: 360000},
|
||||
seleniumAddress: 'http://localhost:4444/wd/hub',
|
||||
//specs: ['StressTest.js'],
|
||||
//specs: ['StressTestCarrot.js'],
|
||||
specs: [
|
||||
// 'create/CreateActivity.js',
|
||||
// 'delete/DeleteActivity.js',
|
||||
// 'create/CreateActivityMode.js',
|
||||
// 'delete/DeleteActivityMode.js',
|
||||
//'create/CreateActivityMode.js',
|
||||
// 'create/CreateClock.js',
|
||||
// 'delete/DeleteClock.js',
|
||||
'create/CreateDisplay.js',
|
||||
//'delete/DeleteDisplay.js',
|
||||
'delete/DeleteDisplay.js',
|
||||
'create/CreateFolder.js',
|
||||
//'delete/DeleteFolder.js',
|
||||
'create/CreateTelemetry.js',
|
||||
'delete/DeleteFolder.js',
|
||||
// 'create/CreateTelemetry.js',
|
||||
// 'delete/DeleteTelemetry.js',
|
||||
// 'create/CreateTimeline.js',
|
||||
// 'delete/DeleteTimeline.js',
|
||||
// 'create/CreateTimer.js',
|
||||
// 'delete/DeleteTimer.js',
|
||||
'create/CreateWebPage.js',
|
||||
//'delete/DeleteWebPage.js',
|
||||
'delete/DeleteWebPage.js',
|
||||
'UI/Fullscreen.js',
|
||||
'create/CreateButton.js',
|
||||
//"UI/DragDrop.js",
|
||||
//"UI/NewWindow.js",
|
||||
'UI/InfoBubble.js'
|
||||
"UI/NewWindow.js"
|
||||
//'UI/InfoBubble.js',
|
||||
//'UI/RightClick.js'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome', // or 'safari'
|
||||
@ -61,7 +61,7 @@ exports.config = {
|
||||
|
||||
// Allow specifying binary location as an environment variable,
|
||||
// for cases where Chrome is not installed in a usual location.
|
||||
if (process.env.PROTRACTOR_CHROME_BINARY) {
|
||||
if (process.env.CHROME_BIN) {
|
||||
exports.config.capabilities.chromeOptions.binary =
|
||||
process.env.PROTRACTOR_CHROME_BINARY;
|
||||
process.env.CHROME_BIN;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
|
||||
describe('Create Web Page', function() {
|
||||
describe('Create Activity Mode', function() {
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Activity Mode";
|
||||
|
@ -57,7 +57,7 @@ describe('Create Clock', function() {
|
||||
});
|
||||
it('should check clock', function () {
|
||||
|
||||
function getTime() {
|
||||
function getTime(flag) {
|
||||
function addZero(time){
|
||||
if(time < 10){
|
||||
return '0' + time;
|
||||
@ -66,7 +66,6 @@ describe('Create Clock', function() {
|
||||
}
|
||||
var currentdate = new Date();
|
||||
|
||||
|
||||
var month = currentdate.getMonth() + 1;
|
||||
month = addZero(month);
|
||||
|
||||
@ -77,6 +76,9 @@ describe('Create Clock', function() {
|
||||
hour = addZero(hour);
|
||||
|
||||
var second = currentdate.getSeconds();
|
||||
if(flag == true) {
|
||||
second = second + 1;
|
||||
}
|
||||
second = addZero(second);
|
||||
|
||||
var minute = currentdate.getMinutes();
|
||||
@ -85,17 +87,23 @@ describe('Create Clock', function() {
|
||||
return ("UTC " + currentdate.getFullYear() + "/" + (month) + "/" +
|
||||
day + " " + (hour) + ":" + minute + ":" + second + " PM");
|
||||
}
|
||||
|
||||
var current,clock;
|
||||
this.addMatchers({
|
||||
toBeIn: function(expected){
|
||||
var posibilities = Array.isArray(this.actual) ? this.actual : [this.actual];
|
||||
return posibilities.indexOf(expected) > -1;
|
||||
}
|
||||
})
|
||||
rightClickClass.select(ITEM_MENU_GLYPH, true).click().then(function () {
|
||||
browser.sleep(1000);
|
||||
current = browser.executeScript(getTime);
|
||||
}).then(function () {
|
||||
clock = element(by.css('.l-time-display.l-digital.l-clock.s-clock.ng-scope'));
|
||||
clock.getText().then(function (time) {
|
||||
expect(current).toEqual(time);
|
||||
})
|
||||
browser.executeScript(getTime, false).then(function(current){
|
||||
browser.executeScript(getTime, true).then(function(current1) {
|
||||
var clock = element(by.css('.l-time-display.l-digital.l-clock.s-clock.ng-scope'));
|
||||
clock.getText().then(function (ele) {
|
||||
expect([current,current1]).toBeIn(ele);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@ -63,7 +63,11 @@ describe('Create Timer', function() {
|
||||
browser.sleep(1000)
|
||||
var timer = element(by.css('.value.ng-binding.active'))
|
||||
timer.getText().then(function (time) {
|
||||
expect(time).toEqual("0D 00:00:01")
|
||||
var timerChecker = false;
|
||||
if(time == "0D 00:00:01" || time == "0D 00:00:02"){
|
||||
timerChecker = true;
|
||||
}
|
||||
expect(timerChecker).toEqual(true)
|
||||
})
|
||||
});
|
||||
|
||||
|
20
protractor/package.json
Normal file
20
protractor/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "ProtractorLauncher",
|
||||
"version": "1.0.0",
|
||||
"scripts" : {
|
||||
"start" : "bin/start.js",
|
||||
"protractor" : "bin/run.js",
|
||||
"stop" : "bin/stop.js",
|
||||
"all" : "bin/start.js; bin/run.js; bin/stop.js;",
|
||||
"clean" : "bin/clean.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"protractor": "^2.1.0",
|
||||
"psnode": "0.0.1",
|
||||
"shelljs": "^0.5.2",
|
||||
"sleep": "^3.0.0",
|
||||
"string": "^3.3.1"
|
||||
},
|
||||
"description": "E2e Protractor Tests.",
|
||||
"license": "ISC"
|
||||
}
|
@ -19,10 +19,9 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
//TODO Add filter for duplications/
|
||||
var itemCreate = require("./common/CreateItem");
|
||||
var itemEdit = require("./common/EditItem");
|
||||
var right_click = require("./common/RightMenu.js");
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
@ -41,31 +40,35 @@ describe('Create Folder', function() {
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(5000);
|
||||
for(var i=0; i < 50; i++){
|
||||
for(var i=0; i < 25; i++){
|
||||
browser.wait(function() {
|
||||
createClass.createButton().click();
|
||||
return true;
|
||||
}).then(function (){
|
||||
var folder = createClass.selectNewItem(ITEM_TYPE);
|
||||
expect(folder.getText()).toEqual([ ITEM_MENU_GLYPH ]);
|
||||
browser.sleep(1000);
|
||||
browser.sleep(500);
|
||||
folder.click()
|
||||
}).then(function() {
|
||||
browser.wait(function () {
|
||||
return element.all(by.model('ngModel[field]')).isDisplayed();
|
||||
})
|
||||
createClass.fillFolderForum(ITEM_NAME, ITEM_TYPE).click();
|
||||
browser.sleep(1000);
|
||||
browser.sleep(500);
|
||||
}).then(function (){
|
||||
browser.sleep(1000);
|
||||
// if(i === 1){
|
||||
browser.sleep(500);
|
||||
clickClass.delete(ITEM_SIDE_SELECT, true);
|
||||
element.all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
// }else{
|
||||
browser.sleep(1000);
|
||||
//element.all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
|
||||
|
||||
var MyItem = ">\nF\nMy Items"
|
||||
element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
//expect(text).toEqual(MyItem);
|
||||
return text === MyItem;
|
||||
});
|
||||
}).all(by.css('.ui-symbol.view-control.ng-binding.ng-scope')).click();
|
||||
// clickClass.delete(ITEM_SIDE_SELECT, false);
|
||||
// }
|
||||
});
|
||||
}
|
||||
browser.pause();
|
59
protractor/stressTest/StressTestBubble.js
Normal file
59
protractor/stressTest/StressTestBubble.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/StressTestBubble.jsStressTestBubble.js
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
var ITEM_SIDE_SELECT = ">\nF\nFolder"
|
||||
|
||||
beforeEach(function() {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/warp/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(10000);
|
||||
for(var i=0; i < 1000; i++){
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
return text === ">\nF\nMy Items";
|
||||
});
|
||||
});
|
||||
//browser.sleep(1000)
|
||||
browser.actions().mouseMove(object.get(0)).perform();
|
||||
//browser.actions().click(protractor.Button.RIGHT).perform();
|
||||
|
||||
element.all(by.css('.items-holder.grid.abs.ng-scope')).click();
|
||||
}
|
||||
browser.pause();
|
||||
|
||||
});
|
||||
|
||||
});
|
56
protractor/stressTest/StressTestCreateButton.js
Normal file
56
protractor/stressTest/StressTestCreateButton.js
Normal file
@ -0,0 +1,56 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
var ITEM_SIDE_SELECT = ">\nF\nFolder"
|
||||
|
||||
beforeEach(function() {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/warp/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(10000);
|
||||
for(var i=0; i < 1000; i++){
|
||||
createClass.createButton().click();
|
||||
|
||||
//browser.sleep(1000)
|
||||
//browser.actions().mouseMove(object.get(0)).perform();
|
||||
//browser.actions().click(protractor.Button.RIGHT).perform();
|
||||
|
||||
element.all(by.css('.items-holder.grid.abs.ng-scope')).click();
|
||||
}
|
||||
browser.pause();
|
||||
|
||||
});
|
||||
|
||||
});
|
55
protractor/stressTest/StressTestMenu.js
Normal file
55
protractor/stressTest/StressTestMenu.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
var ITEM_SIDE_SELECT = ">\nF\nFolder"
|
||||
|
||||
beforeEach(function() {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/warp/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(10000);
|
||||
for(var i=0; i < 1000; i++){
|
||||
browser.wait(function() {
|
||||
createClass.createButton().click();
|
||||
return true;
|
||||
}).then(function (){
|
||||
element.all(by.css('.items-holder.grid.abs.ng-scope')).click();
|
||||
})
|
||||
}
|
||||
browser.pause();
|
||||
|
||||
});
|
||||
|
||||
});
|
61
protractor/stressTest/StressTestNewPage.js
Normal file
61
protractor/stressTest/StressTestNewPage.js
Normal file
@ -0,0 +1,61 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
var fullScreenFile = require("../common/FullScreen");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var fullScreenClass = new fullScreenFile();
|
||||
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
var ITEM_SIDE_SELECT = ">\nF\nFolder"
|
||||
|
||||
beforeEach(function() {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/warp/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(15000);
|
||||
for(var i=0; i < 1000; i++){
|
||||
fullScreenClass.newWidnow().click();
|
||||
|
||||
browser.getAllWindowHandles().then(function (handles) {
|
||||
//browser.driver.switchTo().window(handles[1]);
|
||||
browser.sleep(1000);
|
||||
browser.driver.close();
|
||||
browser.sleep(1000);
|
||||
// browser.driver.switchTo().window(handles[0]);
|
||||
});
|
||||
}
|
||||
browser.pause();
|
||||
|
||||
});
|
||||
|
||||
});
|
59
protractor/stressTest/StressTestRightClick.js
Normal file
59
protractor/stressTest/StressTestRightClick.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
var itemCreate = require("../common/CreateItem");
|
||||
var itemEdit = require("../common/EditItem");
|
||||
var right_click = require("../common/RightMenu.js");
|
||||
|
||||
describe('Create Folder', function() {
|
||||
var clickClass = new right_click();
|
||||
var createClass = new itemCreate();
|
||||
var editItemClass = new itemEdit();
|
||||
var ITEM_NAME = "Folder";
|
||||
var ITEM_TYPE = "folder";
|
||||
var ITEM_MENU_GLYPH = 'F\nFolder';
|
||||
var ITEM_GRID_SELECT = 'P\nF\nFolder\n0 Items';
|
||||
var ITEM_SIDE_SELECT = ">\nF\nFolder"
|
||||
|
||||
beforeEach(function() {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('http://localhost:1984/warp/');
|
||||
browser.sleep(2000); // 20 seconds
|
||||
});
|
||||
it('should Create new Folder', function(){
|
||||
browser.sleep(8000);
|
||||
for(var i=0; i < 1000; i++){
|
||||
var object = element.all(by.repeater('child in composition')).filter(function (ele){
|
||||
return ele.getText().then(function(text) {
|
||||
return text === ">\nF\nMy Items";
|
||||
});
|
||||
});
|
||||
//browser.sleep(1000)
|
||||
browser.actions().mouseMove(object.get(0)).perform();
|
||||
browser.actions().click(protractor.Button.RIGHT).perform();
|
||||
|
||||
element.all(by.css('.items-holder.grid.abs.ng-scope')).click();
|
||||
}
|
||||
browser.pause();
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user