Add option to view/download test lists

On the guideline page when viewing DefCore capabilities, users
might want to get the test list containing only required or advisory
tests. This patch provides a way for a user to get that test list
to use with RefStack client. The phantomjs version was updated to allow
testing with Blobs.

Change-Id: I9243f5781cb8a688ca3e64645302db5bc4527c37
This commit is contained in:
Paul Van Eck 2016-02-29 08:58:23 -08:00
parent d6124e0117
commit 64f1efe961
7 changed files with 260 additions and 4 deletions

View File

@ -16,7 +16,7 @@
"karma-firefox-launcher": "^0.1.3",
"karma-jasmine": "^0.2.2",
"karma-phantomjs-launcher": "0.2.0",
"phantomjs": "1.9.17",
"phantomjs": "2.1.1",
"protractor": "~1.0.0"
},
"scripts": {

View File

@ -192,3 +192,11 @@ h1, h2, h3, h4, h5, h6 {
a.glyphicon {
text-decoration: none;
}
.test-list-dl {
word-spacing: normal;
}
.test-list-dl:hover {
text-decoration: none;
}

View File

@ -53,6 +53,12 @@
<input type="checkbox" ng-model="ctrl.status.removed">
<span class="removed">Removed</span>
</label>
<a class="test-list-dl pull-right"
title="Get a test list for capabilities matching selected statuses."
ng-click="ctrl.openTestListModal()">
Test List <span class="glyphicon glyphicon-file"></span>
</a>
</div>
<!-- End Capability Filters -->

View File

@ -19,14 +19,14 @@
.module('refstackApp')
.controller('CapabilitiesController', CapabilitiesController);
CapabilitiesController.$inject = ['$http', 'refstackApiUrl'];
CapabilitiesController.$inject = ['$http', '$uibModal', 'refstackApiUrl'];
/**
* RefStack Capabilities Controller
* This controller is for the '/capabilities' page where a user can browse
* through tests belonging to DefCore-defined capabilities.
*/
function CapabilitiesController($http, refstackApiUrl) {
function CapabilitiesController($http, $uibModal, refstackApiUrl) {
var ctrl = this;
ctrl.getVersionList = getVersionList;
@ -34,6 +34,8 @@
ctrl.updateTargetCapabilities = updateTargetCapabilities;
ctrl.filterStatus = filterStatus;
ctrl.getObjectLength = getObjectLength;
ctrl.getTestList = getTestList;
ctrl.openTestListModal = openTestListModal;
/** The target OpenStack marketing program to show capabilities for. */
ctrl.target = 'platform';
@ -182,6 +184,118 @@
return Object.keys(object).length;
}
/**
* This will give a list of tests belonging to capabilities with
* the selected status(es).
*/
function getTestList() {
var caps = ctrl.capabilities.capabilities;
var tests = [];
angular.forEach(ctrl.targetCapabilities,
function (status, cap) {
if (ctrl.status[status]) {
if (ctrl.capabilities.schema === '1.2') {
tests.push.apply(tests, caps[cap].tests);
}
else {
angular.forEach(caps[cap].tests,
function(info, test) {
tests.push(test);
});
}
}
});
return tests;
}
/**
* This will open the modal that will show a list of all tests
* belonging to capabilities with the selected status(es).
*/
function openTestListModal() {
$uibModal.open({
templateUrl: '/components/capabilities/partials' +
'/testListModal.html',
backdrop: true,
windowClass: 'modal',
animation: true,
controller: 'TestListModalController as modal',
size: 'lg',
resolve: {
tests: function () {
return ctrl.getTestList();
},
version: function () {
return ctrl.version.slice(0, -5);
},
status: function () {
return ctrl.status;
}
}
});
}
ctrl.getVersionList();
}
angular
.module('refstackApp')
.controller('TestListModalController', TestListModalController);
TestListModalController.$inject = [
'$uibModalInstance', '$window', 'tests', 'version', 'status'
];
/**
* Test List Modal Controller
* This controller is for the modal that appears if a user wants to see the
* ftest list corresponding to DefCore capabilities with the selected
* statuses.
*/
function TestListModalController($uibModalInstance, $window, tests,
version, status) {
var ctrl = this;
ctrl.tests = tests;
ctrl.version = version;
ctrl.status = status;
ctrl.close = close;
ctrl.getTestListString = getTestListString;
ctrl.downloadTestList = downloadTestList;
/**
* This function will close/dismiss the modal.
*/
function close() {
$uibModalInstance.dismiss('exit');
}
/**
* This function will return a string representing the sorted
* tests list separated by newlines.
*/
function getTestListString() {
return ctrl.tests.sort().join('\n');
}
/**
* Serve the test list as a downloadable file.
*/
function downloadTestList() {
var blob = new Blob([ctrl.getTestListString()], {type: 'text/csv'});
var filename = ctrl.version + '-test-list.txt';
if ($window.navigator.msSaveOrOpenBlob) {
$window.navigator.msSaveBlob(blob, filename);
}
else {
var a = $window.document.createElement('a');
a.href = $window.URL.createObjectURL(blob);
a.download = filename;
$window.document.body.appendChild(a);
a.click();
$window.document.body.removeChild(a);
}
}
}
})();

View File

@ -10,7 +10,7 @@ variable 'capabilities'.
<em>{{capability.description}}</em><br />
Status: <span class="{{ctrl.targetCapabilities[capability.id]}}">{{ctrl.targetCapabilities[capability.id]}}</span><br />
<span ng-if="capability.project">Project: {{capability.project | capitalize}}<br /></span>
<a ng-click="showAchievements = !hshowAchievements">Achievements ({{capability.achievements.length}})</a><br />
<a ng-click="showAchievements = !showAchievements">Achievements ({{capability.achievements.length}})</a><br />
<ol uib-collapse="!showAchievements" class="list-inline">
<li ng-repeat="achievement in capability.achievements">
{{achievement}}

View File

@ -0,0 +1,24 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" aria-hidden="true" ng-click="modal.close()">&times;</button>
<h4>Test List ({{modal.tests.length}})</h4>
<p>Use this test list with <a title="refstack-client" target="_blank"href="https://github.com/openstack/refstack-client">refstack-client</a>
to run only tests in the {{modal.version}} DefCore guideline from capabilities with the following statuses:
</p>
<ul class="list-inline">
<li class="required" ng-if="modal.status.required"> Required</li>
<li class="advisory" ng-if="modal.status.advisory"> Advisory</li>
<li class="deprecated" ng-if="modal.status.deprecated"> Deprecated</li>
<li class="removed" ng-if="modal.status.removed"> Removed</li>
</ul>
</div>
<div class="modal-body tests-modal-content">
<div class="form-group">
<textarea class="form-control" rows="20" id="tests" wrap="off">{{modal.getTestListString()}}</textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="modal.downloadTestList()">Download</button>
<button class="btn btn-primary" type="button" ng-click="modal.close()">Close</button>
</div>
</div>

View File

@ -152,6 +152,110 @@ describe('Refstack controllers', function () {
};
expect(ctrl.getObjectLength(testObject)).toBe(2);
});
it('should have a function to get a list of tests belonging to ' +
'capabilities with the selected statuses',
function () {
ctrl.targetCapabilities = {'cap-1': 'required',
'cap-2': 'advisory'};
ctrl.capabilities = {
'schema': 1.4,
'capabilities' : {
'cap-1': {
'tests': {
'test_1': {'idempotent_id': 'id-1234'},
'test_2': {'idempotent_id': 'id-5678'}
}
},
'cap-2': {
'tests': {
'test_3': {'idempotent_id': 'id-1233'}
}
}
}
};
expect(ctrl.getTestList()).toEqual(['test_1', 'test_2']);
ctrl.capabilities = {
'schema': 1.2,
'capabilities' : {
'cap-1': {
'tests': ['test_1', 'test_2']
},
'cap-2': {
'tests': ['test_3']
}
}
};
});
it('should have a method to open a modal for the relevant test list',
function () {
var modal;
inject(function ($uibModal) {
modal = $uibModal;
});
spyOn(modal, 'open');
ctrl.openTestListModal();
expect(modal.open).toHaveBeenCalled();
});
});
describe('TestListModalController', function () {
var modalInstance, ctrl, $window;
beforeEach(inject(function ($controller, _$window_) {
modalInstance = {
dismiss: jasmine.createSpy('modalInstance.dismiss')
};
$window = _$window_;
ctrl = $controller('TestListModalController',
{$uibModalInstance: modalInstance,
tests: ['t1', 't2'],
version: '2016.01',
status: {required: true, advisory: false}}
);
}));
it('should assign inputs to variables', function () {
expect(ctrl.tests).toEqual(['t1', 't2']);
expect(ctrl.version).toEqual('2016.01');
expect(ctrl.status).toEqual({required: true, advisory: false});
});
it('should have a method to close the modal',
function () {
ctrl.close();
expect(modalInstance.dismiss).toHaveBeenCalledWith('exit');
});
it('should have a method to convert the tests to a string',
function () {
ctrl.tests = ['t2', 't1', 't3'];
var expectedString = 't1\nt2\nt3';
expect(ctrl.getTestListString()).toEqual(expectedString);
});
it('should have a method to download a test list',
function () {
var fakeElement = $window.document.createElement('a');
spyOn($window.document, 'createElement').and.callFake(
function() {
return fakeElement;
});
spyOn($window.document.body, 'appendChild').and.callFake(
function() {
return true;
});
spyOn($window.document.body, 'removeChild').and.callFake(
function() {
return true;
});
ctrl.downloadTestList();
var doc = $window.document;
expect(doc.createElement).toHaveBeenCalledWith('a');
expect(doc.body.appendChild).toHaveBeenCalled();
expect(doc.body.removeChild).toHaveBeenCalled();
});
});
describe('resultsController', function () {