Angular API Unit Tests

Contains tests for API services.  There are currently few of these, so
these are meant to establish a good baseline.  Since many services are
cookie-cutter, the tests often establish a similar structured pattern.

Change-Id: Ice0dd49e61b0c828b502ec7632534732f934ae76
Partial-Bug: 1435869
Closes-Bug: 1449648
This commit is contained in:
Matt Borland 2015-04-28 08:58:02 -06:00
parent dbaab2f124
commit 64347bb15b
15 changed files with 1403 additions and 28 deletions

View File

@ -44,7 +44,7 @@ limitations under the License.
var config = (params) ? {'params': params} : {};
return apiService.get('/api/cinder/volumes/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve volumes.'));
toastService.add('error', gettext('Unable to retrieve the volumes.'));
});
};
@ -71,7 +71,7 @@ limitations under the License.
return apiService.get('/api/cinder/volumesnapshots/', config)
.error(function () {
toastService.add('error',
gettext('Unable to retrieve volume snapshots.'));
gettext('Unable to retrieve the volume snapshots.'));
});
};
}

View File

@ -0,0 +1,75 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Cinder API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.cinder', function(cinderAPI) {
service = cinderAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{ func: 'getVolumes',
method: 'get',
path: '/api/cinder/volumes/',
data: { params: 'config' },
error: 'Unable to retrieve the volumes.',
testInput: [ 'config' ] },
{ func: 'getVolumes',
method: 'get',
path: '/api/cinder/volumes/',
data: {},
error: 'Unable to retrieve the volumes.' },
{ func: 'getVolumeSnapshots',
method: 'get',
path: '/api/cinder/volumesnapshots/',
data: {},
error: 'Unable to retrieve the volume snapshots.' },
{ func: 'getVolumeSnapshots',
method: 'get',
path: '/api/cinder/volumesnapshots/',
data: { params: 'config' },
error: 'Unable to retrieve the volume snapshots.',
testInput: [ 'config' ] } ] ;
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.name + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
});
})();

View File

@ -0,0 +1,83 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
/* This function tests the 'typical' way that apiService calls are made.
Look at this typical approach:
this.getVolumes = function(params) {
var config = (params) ? {'params': params} : {};
return apiService.get('/api/cinder/volumes/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the volumes.'));
});
In this case there is an apiService call that is made with one or two
arguments, and on error a function is called that invokes the
toastService's add method.
The function below takes in the set of variables, both input and output,
that are required to test the above code. It spies on the apiService
method that is called, and also spies on its returned simulated promise
'error' method.
Having established those spies, the code then inspects the parameters
passed to the apiService, as well as the results of those methods.
Then the code invokes of function passed to the error handler, and
ensures that the toastService is called with the appropriate parameters.
*/
function testCall(apiService, service, toastService, config) {
// 'promise' simulates a promise, including a self-referential success
// handler.
var promise = {error: angular.noop, success: function() { return this; }};
spyOn(apiService, config.method).and.returnValue(promise);
spyOn(promise, 'error');
service[config.func].apply(null, config.testInput);
// Checks to ensure we call the api service with the appropriate
// parameters.
if (angular.isDefined(config.data)) {
expect(apiService[config.method]).toHaveBeenCalledWith(config.path, config.data);
} else {
expect(apiService[config.method]).toHaveBeenCalledWith(config.path);
}
// The following retrieves the first argument of the first call to the
// error spy. This exposes the inner function that, when invoked,
// allows us to inspect the error call and the message given.
var innerFunc = promise.error.calls.argsFor(0)[0];
expect(innerFunc).toBeDefined();
spyOn(toastService, 'add');
innerFunc();
expect(toastService.add).toHaveBeenCalledWith(config.messageType || 'error', config.error);
}
function initServices ($provide, apiService, toastService) {
angular.extend(apiService, { get: angular.noop,
post: angular.noop,
put: angular.noop,
patch: angular.noop,
delete: angular.noop });
angular.extend(toastService, { add: angular.noop });
$provide.value('hz.api.common.service', apiService);
$provide.value('horizon.framework.widgets.toast.service', toastService);
}
window.apiTest = { testCall: testCall, initServices: initServices };
})();

View File

@ -35,7 +35,7 @@ limitations under the License.
this.getImage = function(id) {
return apiService.get('/api/glance/images/' + id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve image.'));
toastService.add('error', gettext('Unable to retrieve the image.'));
});
};
@ -78,7 +78,7 @@ limitations under the License.
var config = (params) ? { 'params' : params} : {};
return apiService.get('/api/glance/images/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve images.'));
toastService.add('error', gettext('Unable to retrieve the images.'));
});
};
@ -141,7 +141,7 @@ limitations under the License.
var promise = apiService.get('/api/glance/metadefs/namespaces/', config);
return suppressError ? promise : promise.error(function() {
toastService.add('error', gettext('Unable to retrieve namespaces.'));
toastService.add('error', gettext('Unable to retrieve the namespaces.'));
});
};

View File

@ -0,0 +1,110 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Glance API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.glance', function(glanceAPI) {
service = glanceAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "getImage",
"method": "get",
"path": "/api/glance/images/42",
"error": "Unable to retrieve the image.",
"testInput": [
42
]
},
{
"func": "getImages",
"method": "get",
"path": "/api/glance/images/",
"data": {
"params": "config"
},
"error": "Unable to retrieve the images.",
"testInput": [
"config"
]
},
{
"func": "getImages",
"method": "get",
"path": "/api/glance/images/",
"data": {},
"error": "Unable to retrieve the images."
},
{
"func": "getNamespaces",
"method": "get",
"path": "/api/glance/metadefs/namespaces/",
"data": {
"params": {
"orig": true
},
"cache": true
},
"error": "Unable to retrieve the namespaces.",
"testInput": [
{
"orig": true
}
]
},
{
"func": "getNamespaces",
"method": "get",
"path": "/api/glance/metadefs/namespaces/",
"data": {
"cache": true
},
"error": "Unable to retrieve the namespaces."
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
it('supresses the error if instructed for getNamespaces', function() {
spyOn(apiService, 'get').and.returnValue("promise");
expect(service.getNamespaces("whatever", true)).toBe("promise");
});
});
})();

View File

@ -21,7 +21,7 @@ limitations under the License.
var config = (params) ? {'params': params} : {};
return apiService.get('/api/keystone/users/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve users'));
toastService.add('error', gettext('Unable to retrieve users.'));
});
};
@ -77,7 +77,7 @@ limitations under the License.
this.getUser = function(user_id) {
return apiService.get('/api/keystone/users/' + user_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the user'));
toastService.add('error', gettext('Unable to retrieve the user.'));
});
};
@ -100,7 +100,7 @@ limitations under the License.
this.getRoles = function() {
return apiService.get('/api/keystone/roles/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve role'));
toastService.add('error', gettext('Unable to retrieve the roles.'));
});
};
@ -121,7 +121,7 @@ limitations under the License.
this.getRole = function(role_id) {
return apiService.get('/api/keystone/roles/' + role_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the role'));
toastService.add('error', gettext('Unable to retrieve the role.'));
});
};
@ -144,7 +144,7 @@ limitations under the License.
this.getDomains = function() {
return apiService.get('/api/keystone/domains/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve domains'));
toastService.add('error', gettext('Unable to retrieve the domains.'));
});
};
@ -165,7 +165,7 @@ limitations under the License.
this.getDomain = function(domain_id) {
return apiService.get('/api/keystone/domains/' + domain_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the domain'));
toastService.add('error', gettext('Unable to retrieve the domain.'));
});
};
@ -189,7 +189,7 @@ limitations under the License.
var config = (params) ? {'params': params} : {};
return apiService.get('/api/keystone/projects/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve projects'));
toastService.add('error', gettext('Unable to retrieve the projects.'));
});
};
@ -210,7 +210,7 @@ limitations under the License.
this.getProject = function(project_id) {
return apiService.get('/api/keystone/projects/' + project_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the project'));
toastService.add('error', gettext('Unable to retrieve the project.'));
});
};
@ -230,7 +230,7 @@ limitations under the License.
};
this.grantRole = function(project_id, role_id, user_id) {
return apiService.delete('/api/keystone/projects/' + project_id + '/' +
return apiService.put('/api/keystone/projects/' + project_id + '/' +
role_id + '/' + user_id)
.error(function () {
toastService.add('error', gettext('Unable to grant the role.'));

View File

@ -0,0 +1,557 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Keystone API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.keystone', function(keystoneAPI) {
service = keystoneAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "getUsers",
"method": "get",
"path": "/api/keystone/users/",
"data": {},
"error": "Unable to retrieve users."
},
{
"func": "getUsers",
"method": "get",
"path": "/api/keystone/users/",
"data": {
"params": {
"info": true
}
},
"error": "Unable to retrieve users.",
"testInput": [
{
"info": true
}
]
},
{
"func": "createUser",
"method": "post",
"path": "/api/keystone/users/",
"data": {
"name": "Matt"
},
"error": "Unable to create the user.",
"testInput": [
{
"name": "Matt"
}
]
},
{
"func": "deleteUsers",
"method": "delete",
"path": "/api/keystone/users/",
"data": [
1,
2,
3
],
"error": "Unable to delete the users.",
"testInput": [
[
1,
2,
3
]
]
},
{
"func": "getCurrentUserSession",
"method": "get",
"path": "/api/keystone/user-session/",
"data": "config",
"error": "Unable to retrieve the current user session.",
"testInput": [
"config"
]
},
{
"func": "getUser",
"method": "get",
"path": "/api/keystone/users/42",
"error": "Unable to retrieve the user.",
"testInput": [
42
]
},
{
"func": "editUser",
"method": "patch",
"path": "/api/keystone/users/42",
"data": {
"id": 42
},
"error": "Unable to edit the user.",
"testInput": [
{
"id": 42
}
]
},
{
"func": "deleteUser",
"method": "delete",
"path": "/api/keystone/users/42",
"error": "Unable to delete the user.",
"testInput": [
42
]
},
{
"func": "getRoles",
"method": "get",
"path": "/api/keystone/roles/",
"error": "Unable to retrieve the roles."
},
{
"func": "createRole",
"method": "post",
"path": "/api/keystone/roles/",
"data": "new role",
"error": "Unable to create the role.",
"testInput": [
"new role"
]
},
{
"func": "deleteRoles",
"method": "delete",
"path": "/api/keystone/roles/",
"data": [
1,
2,
3
],
"error": "Unable to delete the roles.",
"testInput": [
[
1,
2,
3
]
]
},
{
"func": "getRole",
"method": "get",
"path": "/api/keystone/roles/42",
"error": "Unable to retrieve the role.",
"testInput": [
42
]
},
{
"func": "editRole",
"method": "patch",
"path": "/api/keystone/roles/42",
"data": {
"id": 42
},
"error": "Unable to edit the role.",
"testInput": [
{
"id": 42
}
]
},
{
"func": "deleteRole",
"method": "delete",
"path": "/api/keystone/roles/42",
"error": "Unable to delete the role.",
"testInput": [
42
]
},
{
"func": "getDomains",
"method": "get",
"path": "/api/keystone/domains/",
"error": "Unable to retrieve the domains."
},
{
"func": "createDomain",
"method": "post",
"path": "/api/keystone/domains/",
"data": "new domain",
"error": "Unable to create the domain.",
"testInput": [
"new domain"
]
},
{
"func": "deleteDomains",
"method": "delete",
"path": "/api/keystone/domains/",
"data": [
1,
2,
3
],
"error": "Unable to delete the domains.",
"testInput": [
[
1,
2,
3
]
]
},
{
"func": "getDomain",
"method": "get",
"path": "/api/keystone/domains/42",
"error": "Unable to retrieve the domain.",
"testInput": [
42
]
},
{
"func": "editDomain",
"method": "patch",
"path": "/api/keystone/domains/42",
"data": {
"id": 42
},
"error": "Unable to edit the domain.",
"testInput": [
{
"id": 42
}
]
},
{
"func": "deleteDomain",
"method": "delete",
"path": "/api/keystone/domains/42",
"error": "Unable to delete the domain.",
"testInput": [
42
]
},
{
"func": "getProjects",
"method": "get",
"path": "/api/keystone/projects/",
"data": {},
"error": "Unable to retrieve the projects."
},
{
"func": "getProjects",
"method": "get",
"path": "/api/keystone/projects/",
"data": {
"params": {
"info": true
}
},
"error": "Unable to retrieve the projects.",
"testInput": [
{
"info": true
}
]
},
{
"func": "createProject",
"method": "post",
"path": "/api/keystone/projects/",
"data": "new project",
"error": "Unable to create the project.",
"testInput": [
"new project"
]
},
{
"func": "deleteProjects",
"method": "delete",
"path": "/api/keystone/projects/",
"data": [
1,
2,
3
],
"error": "Unable to delete the projects.",
"testInput": [
[
1,
2,
3
]
]
},
{
"func": "getProject",
"method": "get",
"path": "/api/keystone/projects/42",
"error": "Unable to retrieve the project.",
"testInput": [
42
]
},
{
"func": "editProject",
"method": "patch",
"path": "/api/keystone/projects/42",
"data": {
"id": 42
},
"error": "Unable to edit the project.",
"testInput": [
{
"id": 42
}
]
},
{
"func": "deleteProject",
"method": "delete",
"path": "/api/keystone/projects/42",
"error": "Unable to delete the project.",
"testInput": [
42
]
},
{
"func": "grantRole",
"method": "put",
"path": "/api/keystone/projects/42/32/22",
"error": "Unable to grant the role.",
"testInput": [
42,
32,
22
]
},
{
"func": "serviceCatalog",
"method": "get",
"path": "/api/keystone/svc-catalog/",
"data": "config",
"error": "Unable to fetch the service catalog.",
"testInput": [
"config"
]
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
});
describe("userSession", function() {
var factory, keystoneAPI;
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
keystoneAPI = {getCurrentUserSession: angular.noop};
$provide.value('hz.api.keystone', keystoneAPI);
$provide.value('$cacheFactory', function() { return 'cache'; });
}));
beforeEach(inject(['hz.api.userSession', function(userSession) {
factory = userSession;
}]));
it('defines the factory', function() {
expect(factory).toBeDefined();
});
it('defines .cache', function() {
expect(factory.cache).toBe("cache");
});
it('defines .get', function() {
expect(factory.get).toBeDefined();
});
describe(".get() features", function() {
var postAction = {then: angular.noop};
beforeEach(function() {
spyOn(keystoneAPI, 'getCurrentUserSession').and.returnValue(postAction);
spyOn(postAction, 'then');
factory.get();
});
it("calls getCurrentUserSession", function() {
expect(keystoneAPI.getCurrentUserSession).toHaveBeenCalled();
});
it("then returns the response's data member", function() {
var func = postAction.then.calls.argsFor(0)[0];
expect(func({data: 'thing'})).toBe("thing");
});
});
});
describe("serviceCatalog", function() {
var factory, q, keystoneAPI, userSession, deferred;
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
keystoneAPI = {serviceCatalog: angular.noop};
$provide.value('hz.api.keystone', keystoneAPI);
userSession = {get: angular.noop};
$provide.value('hz.api.userSession', userSession);
deferred = {promise: angular.noop, reject: angular.noop, resolve: angular.noop};
q = {all: function() {return {then: angular.noop};},
defer: function() { return deferred;}};
$provide.value('$q', q);
$provide.value('$cacheFactory', function() { return 'cache'; });
}));
beforeEach(inject(['hz.api.serviceCatalog', function(serviceCatalog) {
factory = serviceCatalog;
}]));
it('defines the factory', function() {
expect(factory).toBeDefined();
});
it('defines .cache', function() {
expect(factory.cache).toBe("cache");
});
it('defines .get', function() {
expect(factory.get).toBeDefined();
});
describe(".get() features", function() {
var postAction = {then: angular.noop};
beforeEach(function() {
spyOn(keystoneAPI, 'serviceCatalog').and.returnValue(postAction);
spyOn(postAction, 'then');
factory.get();
});
it("gets the service catalog", function() {
expect(keystoneAPI.serviceCatalog).toHaveBeenCalled();
});
it("then returns the response's data member", function() {
var func = postAction.then.calls.argsFor(0)[0];
expect(func({data: 'thing'})).toBe("thing");
});
});
it('defines .ifTypeEnabled', function() {
expect(factory.ifTypeEnabled).toBeDefined();
});
describe(".ifTypeEnabled features", function() {
var postAction = {then: angular.noop};
beforeEach(function() {
spyOn(q, 'all').and.returnValue(postAction);
spyOn(factory, 'get');
spyOn(postAction, 'then');
spyOn(deferred, 'reject');
spyOn(deferred, 'resolve');
});
var callMethod = function(type, data, resolved) {
factory.ifTypeEnabled(type);
expect(q.all).toHaveBeenCalled();
var successFunc = postAction.then.calls.argsFor(0)[0];
var failFunc = postAction.then.calls.argsFor(0)[1];
successFunc(data);
// If we expected this to be resolved, then expect
// both that we did call resolve() and did NOT call reject().
// Vice versa if expecting rejection.
if (resolved) {
expect(deferred.resolve).toHaveBeenCalled();
expect(deferred.reject).not.toHaveBeenCalled();
} else {
expect(deferred.resolve).not.toHaveBeenCalled();
expect(deferred.reject).toHaveBeenCalled();
}
deferred.reject.calls.reset();
failFunc();
expect(deferred.reject).toHaveBeenCalled();
};
it("accepts 'desired' type with no matches; is rejected", function() {
var data = {catalog: [1, 2, 3],
session: {services_region: true}};
callMethod("desired", data, false);
});
it("accepts 'desired' type with matches but no endpoints; is rejected", function() {
var data = {catalog: [1, {type: "desired", endpoints: []}, 3],
session: {services_region: true}};
callMethod("desired", data, false);
});
it("accepts 'desired' type with a match; is resolved", function() {
var data = {catalog: [{type: "desired", endpoints: [{region_id: true}]}],
session: {services_region: true}};
callMethod("desired", data, true);
});
it("accepts 'desired' type with matches and region is true; is resolved", function() {
var data = {catalog: [{type: "desired", endpoints: [{region: true}]}],
session: {services_region: true}};
callMethod("desired", data, true);
});
it("accepts 'desired' type with matches and service_region is true; is resolved", function() {
var data = {catalog: [{type: "identity"}],
session: {services_region: true}};
callMethod("identity", data, true);
});
});
});
})();

View File

@ -36,7 +36,7 @@
this.getNetworks = function() {
return apiService.get('/api/neutron/networks/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve networks.'));
toastService.add('error', gettext('Unable to retrieve the networks.'));
});
};
@ -105,7 +105,7 @@
this.getSubnets = function(network_id) {
return apiService.get('/api/neutron/subnets/', network_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve subnets.'));
toastService.add('error', gettext('Unable to retrieve the subnets.'));
});
};
@ -189,7 +189,7 @@
this.getPorts = function(network_id) {
return apiService.get('/api/neutron/ports/', network_id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve ports.'));
toastService.add('error', gettext('Unable to retrieve the ports.'));
});
};

View File

@ -0,0 +1,99 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Neutron API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.neutron', function(neutronAPI) {
service = neutronAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "getNetworks",
"method": "get",
"path": "/api/neutron/networks/",
"error": "Unable to retrieve the networks."
},
{
"func": "createNetwork",
"method": "post",
"path": "/api/neutron/networks/",
"data": "new net",
"error": "Unable to create the network.",
"testInput": [
"new net"
]
},
{
"func": "getSubnets",
"method": "get",
"path": "/api/neutron/subnets/",
"data": 42,
"error": "Unable to retrieve the subnets.",
"testInput": [
42
]
},
{
"func": "createSubnet",
"method": "post",
"path": "/api/neutron/subnets/",
"data": "new subnet",
"error": "Unable to create the subnet.",
"testInput": [
"new subnet"
]
},
{
"func": "getPorts",
"method": "get",
"path": "/api/neutron/ports/",
"data": 42,
"error": "Unable to retrieve the ports.",
"testInput": [
42
]
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
});
})();

View File

@ -36,7 +36,7 @@ limitations under the License.
this.getKeypairs = function() {
return apiService.get('/api/nova/keypairs/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve keypairs.'));
toastService.add('error', gettext('Unable to retrieve the keypairs.'));
});
};
@ -79,7 +79,7 @@ limitations under the License.
return apiService.get('/api/nova/availzones/')
.error(function () {
toastService.add('error',
gettext('Unable to retrieve availability zones.'));
gettext('Unable to retrieve the availability zones.'));
});
};
@ -117,7 +117,7 @@ limitations under the License.
this.getLimits = function() {
return apiService.get('/api/nova/limits/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve limits.'));
toastService.add('error', gettext('Unable to retrieve the limits.'));
});
};
@ -158,7 +158,7 @@ limitations under the License.
this.getServer = function(id) {
return apiService.get('/api/nova/servers/' + id)
.error(function () {
toastService.add('error', gettext('Unable to retrieve server.'));
toastService.add('error', gettext('Unable to retrieve the server.'));
});
};
@ -188,7 +188,7 @@ limitations under the License.
this.getExtensions = function(config) {
return apiService.get('/api/nova/extensions/', config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve extensions.'));
toastService.add('error', gettext('Unable to retrieve the extensions.'));
});
};
@ -233,7 +233,7 @@ limitations under the License.
}
})
.error(function () {
toastService.add('error', gettext('Unable to retrieve flavors.'));
toastService.add('error', gettext('Unable to retrieve the flavors.'));
});
};
@ -251,7 +251,7 @@ limitations under the License.
if (getExtras) { config.params.get_extras = 'true'; }
return apiService.get('/api/nova/flavors/' + id, config)
.error(function () {
toastService.add('error', gettext('Unable to retrieve flavor.'));
toastService.add('error', gettext('Unable to retrieve the flavor.'));
});
};
@ -265,7 +265,7 @@ limitations under the License.
this.getFlavorExtraSpecs = function(id) {
return apiService.get('/api/nova/flavors/' + id + '/extra-specs')
.error(function () {
toastService.add('error', gettext('Unable to retrieve flavor extra specs.'));
toastService.add('error', gettext('Unable to retrieve the flavor extra specs.'));
});
};
}
@ -314,7 +314,7 @@ limitations under the License.
}
function onDataFailure() {
deferred.reject(gettext('Cannot get nova extension list.'));
deferred.reject(gettext('Cannot get Nova extension list.'));
}
return deferred.promise;

View File

@ -0,0 +1,314 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Nova API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.nova', function(novaAPI) {
service = novaAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "getKeypairs",
"method": "get",
"path": "/api/nova/keypairs/",
"error": "Unable to retrieve the keypairs."
},
{
"func": "createKeypair",
"method": "post",
"path": "/api/nova/keypairs/",
"data": {
"public_key": true
},
"error": "Unable to import the keypair.",
"testInput": [
{
"public_key": true
}
]
},
{
"func": "createKeypair",
"method": "post",
"path": "/api/nova/keypairs/",
"data": {},
"error": "Unable to create the keypair.",
"testInput": [
{}
]
},
{
"func": "getAvailabilityZones",
"method": "get",
"path": "/api/nova/availzones/",
"error": "Unable to retrieve the availability zones."
},
{
"func": "getLimits",
"method": "get",
"path": "/api/nova/limits/",
"error": "Unable to retrieve the limits."
},
{
"func": "createServer",
"method": "post",
"path": "/api/nova/servers/",
"data": "new server",
"error": "Unable to create the server.",
"testInput": [
"new server"
]
},
{
"func": "getServer",
"method": "get",
"path": "/api/nova/servers/42",
"error": "Unable to retrieve the server.",
"testInput": [
42
]
},
{
"func": "getExtensions",
"method": "get",
"path": "/api/nova/extensions/",
"data": "config",
"error": "Unable to retrieve the extensions.",
"testInput": [
"config"
]
},
{
"func": "getFlavors",
"method": "get",
"path": "/api/nova/flavors/",
"data": {
"params": {}
},
"error": "Unable to retrieve the flavors.",
"testInput": [
false,
false
]
},
{
"func": "getFlavors",
"method": "get",
"path": "/api/nova/flavors/",
"data": {
"params": {
"is_public": "true"
}
},
"error": "Unable to retrieve the flavors.",
"testInput": [
true,
false
]
},
{
"func": "getFlavors",
"method": "get",
"path": "/api/nova/flavors/",
"data": {
"params": {
"get_extras": "true"
}
},
"error": "Unable to retrieve the flavors.",
"testInput": [
false,
true
]
},
{
"func": "getFlavors",
"method": "get",
"path": "/api/nova/flavors/",
"data": {
"params": {
"is_public": "true",
"get_extras": "true"
}
},
"error": "Unable to retrieve the flavors.",
"testInput": [
true,
true
]
},
{
"func": "getFlavor",
"method": "get",
"path": "/api/nova/flavors/42",
"data": {
"params": {
"get_extras": "true"
}
},
"error": "Unable to retrieve the flavor.",
"testInput": [
42,
true
]
},
{
"func": "getFlavor",
"method": "get",
"path": "/api/nova/flavors/42",
"data": {
"params": {}
},
"error": "Unable to retrieve the flavor.",
"testInput": [
42,
false
]
},
{
"func": "getFlavorExtraSpecs",
"method": "get",
"path": "/api/nova/flavors/42/extra-specs",
"error": "Unable to retrieve the flavor extra specs.",
"testInput": [
42
]
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
it('getFlavors converts specific property names with : in them', function() {
var postAction = {success: angular.noop};
spyOn(apiService, 'get').and.returnValue(postAction);
spyOn(postAction, 'success').and.returnValue({error: angular.noop});
service.getFlavors();
var func = postAction.success.calls.argsFor(0)[0];
// won't do anything. Need to test that it won't do anything.
func();
var data = {items: [{nada: 'puesNada'}]};
func(data);
expect(data).toEqual({items: [{nada: 'puesNada'}]});
data = {items: [{'OS-FLV-EXT-DATA:ephemeral': true}]};
func(data);
expect(data).toEqual({items: [{'OS-FLV-EXT-DATA:ephemeral': true, ephemeral: true}]});
data = {items: [{'OS-FLV-DISABLED:disabled': true}]};
func(data);
expect(data).toEqual({items: [{'OS-FLV-DISABLED:disabled': true, disabled: true}]});
data = {items: [{'os-flavor-access:is_public': true}]};
func(data);
expect(data).toEqual({items: [{'os-flavor-access:is_public': true, is_public: true}]});
});
});
describe("novaExtensions", function() {
var factory, q, novaAPI;
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
novaAPI = {getExtensions: function() {return {then: angular.noop};}};
q = {defer: function() { return {resolve: angular.noop}; }};
$provide.value('$cacheFactory', function() {return "cache";});
$provide.value('$q', q);
$provide.value('hz.api.nova', novaAPI);
}));
beforeEach(inject(function($injector) {
factory = $injector.get('hz.api.novaExtensions');
}));
it("is defined", function() {
expect(factory).toBeDefined();
});
it("defines .cache", function() {
expect(factory.cache).toBeDefined();
});
it("defines .get", function() {
expect(factory.get).toBeDefined();
var postAction = {then: angular.noop};
spyOn(novaAPI, 'getExtensions').and.returnValue(postAction);
spyOn(postAction, 'then');
factory.get();
expect(novaAPI.getExtensions).toHaveBeenCalledWith({cache: factory.cache});
expect(postAction.then).toHaveBeenCalled();
var func = postAction.then.calls.argsFor(0)[0];
var testData = {data: {items: [1, 2, 3]}};
expect(func(testData)).toEqual([1, 2, 3]);
});
it("defines .ifNameEnabled", function() {
expect(factory.ifNameEnabled).toBeDefined();
var postAction = {then: angular.noop};
var deferred = {reject: angular.noop, resolve: angular.noop};
spyOn(q, 'defer').and.returnValue(deferred);
spyOn(factory, 'get').and.returnValue(postAction);
spyOn(postAction, 'then');
factory.ifNameEnabled("desired");
expect(factory.get).toHaveBeenCalled();
var func1 = postAction.then.calls.argsFor(0)[0];
var func2 = postAction.then.calls.argsFor(0)[1];
spyOn(deferred, 'reject');
func1();
expect(deferred.reject).toHaveBeenCalled();
spyOn(deferred, 'resolve');
var extensions = [{name: "desired"}];
func1(extensions);
expect(deferred.resolve).toHaveBeenCalled();
deferred.reject.calls.reset();
func2();
expect(deferred.reject).toHaveBeenCalledWith('Cannot get Nova extension list.');
});
it("defines .ifEnabled", function() {
expect(factory.ifEnabled).toBeDefined();
});
});
})();

View File

@ -0,0 +1,62 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Policy API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.policy', function(policyAPI) {
service = policyAPI;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "check",
"method": "post",
"path": "/api/policy/",
"data": "rules",
"error": "Policy check failed.",
"testInput": [
"rules"
],
"messageType": "warning"
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
});
})();

View File

@ -61,7 +61,7 @@ limitations under the License.
this.query = function() {
return apiService.get('/api/network/securitygroups/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve security groups.'));
toastService.add('error', gettext('Unable to retrieve the security groups.'));
});
};
}

View File

@ -0,0 +1,59 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
(function() {
'use strict';
describe('Security Group API', function() {
var service;
var apiService = {};
var toastService = {};
beforeEach(module('hz.api'));
beforeEach(module(function($provide) {
window.apiTest.initServices($provide, apiService, toastService);
}));
beforeEach(inject(['hz.api.security-group', function(securityGroup) {
service = securityGroup;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "query",
"method": "get",
"path": "/api/network/securitygroups/",
"error": "Unable to retrieve the security groups."
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
window.apiTest.testCall.apply(this, callParams);
});
});
});
})();

View File

@ -19,7 +19,15 @@ class ServicesTests(test.JasmineTests):
'horizon/js/horizon.js',
'horizon/js/angular/hz.api.module.js',
'horizon/js/angular/services/hz.api.common.js',
'horizon/js/angular/services/hz.api.service.js',
'horizon/js/angular/services/hz.api.cinder.js',
'horizon/js/angular/services/hz.api.config.js',
'horizon/js/angular/services/hz.api.glance.js',
'horizon/js/angular/services/hz.api.keystone.js',
'horizon/js/angular/services/hz.api.neutron.js',
'horizon/js/angular/services/hz.api.nova.js',
'horizon/js/angular/services/hz.api.policy.js',
'horizon/js/angular/services/hz.api.security-group.js',
'dashboard-app/dashboard-app.module.js',
'dashboard-app/login/login.js',
@ -60,10 +68,18 @@ class ServicesTests(test.JasmineTests):
]
specs = [
'horizon/js/angular/services/hz.api.common.spec.js',
'horizon/js/angular/services/hz.api.common-test.spec.js',
'horizon/js/angular/services/hz.api.cinder.spec.js',
'horizon/js/angular/services/hz.api.config.spec.js',
'dashboard-app/login/login.spec.js',
'dashboard-app/utils/helper-functions.spec.js',
'horizon/js/angular/services/hz.api.glance.spec.js',
'horizon/js/angular/services/hz.api.keystone.spec.js',
'horizon/js/angular/services/hz.api.neutron.spec.js',
'horizon/js/angular/services/hz.api.nova.spec.js',
'horizon/js/angular/services/hz.api.policy.spec.js',
'horizon/js/angular/services/hz.api.security-group.spec.js',
'horizon/tests/jasmine/utils.spec.js',
'framework/util/bind-scope/bind-scope.spec.js',
'framework/util/filters/filters.spec.js',