Update test list UI to use API

The UI will now allow more flexibility in selecting what test
list should be listed/downloaded.

Change-Id: Ie7f928e297b1329a501d7fdf532461fc0a87fe64
This commit is contained in:
Paul Van Eck 2016-04-17 22:09:25 -07:00
parent d2467afcfc
commit d0f0d640ca
4 changed files with 117 additions and 141 deletions

View File

@ -69,6 +69,17 @@ h1, h2, h3, h4, h5, h6 {
padding: 10px;
}
.checkbox-test-list {
word-spacing: normal;
background: none;
}
.checkbox-test-list .info-hover {
font-size: 12px;
color: #878787;
cursor: help;
}
.capabilities {
color: #4B4B4B;
}
@ -179,6 +190,7 @@ h1, h2, h3, h4, h5, h6 {
.tests-modal-content textarea {
font-size: .9em;
resize: none;
}
.test-detail {

View File

@ -34,7 +34,6 @@
ctrl.updateTargetCapabilities = updateTargetCapabilities;
ctrl.filterStatus = filterStatus;
ctrl.getObjectLength = getObjectLength;
ctrl.getTestList = getTestList;
ctrl.openTestListModal = openTestListModal;
/** The target OpenStack marketing program to show capabilities for. */
@ -184,33 +183,6 @@
return Object.keys(object).length;
}
/**
* This will give a list of tests belonging to capabilities with
* the selected status(es).
*/
function getTestList() {
if (!ctrl.guidelines) {
return;
}
var caps = ctrl.guidelines.capabilities;
var tests = [];
angular.forEach(ctrl.targetCapabilities,
function (status, cap) {
if (ctrl.status[status]) {
if (ctrl.guidelines.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).
@ -225,15 +197,12 @@
controller: 'TestListModalController as modal',
size: 'lg',
resolve: {
tests: function () {
return ctrl.getTestList();
},
version: function () {
if (!ctrl.version) {
return;
}
return ctrl.version.slice(0, -5);
},
target: function () {
return ctrl.target;
},
status: function () {
return ctrl.status;
}
@ -249,7 +218,8 @@
.controller('TestListModalController', TestListModalController);
TestListModalController.$inject = [
'$uibModalInstance', '$window', 'tests', 'version', 'status'
'$uibModalInstance', '$window', '$http', 'version',
'target', 'status', 'refstackApiUrl'
];
/**
@ -258,17 +228,20 @@
* test list corresponding to DefCore capabilities with the selected
* statuses.
*/
function TestListModalController($uibModalInstance, $window, tests,
version, status) {
function TestListModalController($uibModalInstance, $window, $http, version,
target, status, refstackApiUrl) {
var ctrl = this;
ctrl.tests = tests;
ctrl.version = version;
ctrl.target = target;
ctrl.status = status;
ctrl.url = refstackApiUrl;
ctrl.close = close;
ctrl.getTestListString = getTestListString;
ctrl.downloadTestList = downloadTestList;
ctrl.updateTestListString = updateTestListString;
ctrl.aliases = true;
ctrl.flagged = false;
/**
* This function will close/dismiss the modal.
@ -278,33 +251,62 @@
}
/**
* This function will return a string representing the sorted
* tests list separated by newlines.
* This function will return a list of statuses based on which ones
* are selected.
*/
function getTestListString() {
if (!ctrl.tests) {
return;
}
return ctrl.tests.sort().join('\n');
function getStatusList() {
var statusList = [];
angular.forEach(ctrl.status, function(value, key) {
if (value) {
statusList.push(key);
}
});
return statusList;
}
/**
* Serve the test list as a downloadable file.
* This will get the list of tests from the API and update the
* controller's test list string variable.
*/
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);
function updateTestListString() {
var statuses = getStatusList();
if (!statuses.length) {
ctrl.error = 'No tests matching selected criteria.';
return;
}
ctrl.testListUrl = [
ctrl.url, '/guidelines/', ctrl.version, '/tests?',
'target=', ctrl.target, '&',
'type=', statuses.join(','), '&',
'alias=', ctrl.aliases.toString(), '&',
'flag=', ctrl.flagged.toString()
].join('');
ctrl.testListRequest =
$http.get(ctrl.testListUrl).
then(function successCallback(response) {
ctrl.error = null;
ctrl.testListString = response.data;
if (!ctrl.testListString) {
ctrl.testListCount = 0;
}
else {
ctrl.testListCount =
ctrl.testListString.split('\n').length;
}
}, function errorCallback(response) {
ctrl.testListString = null;
ctrl.testListCount = null;
if (angular.isObject(response.data) &&
response.data.message) {
ctrl.error = 'Error retrieving test list: ' +
response.data.message;
}
else {
ctrl.error = 'Unknown error retrieving test list.';
}
});
}
updateTestListString();
}
})();

View File

@ -1,24 +1,46 @@
<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>
<h4>Test List ({{modal.testListCount}})</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>
<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 class="checkbox checkbox-test-list">
<label><input type="checkbox" ng-model="modal.aliases" ng-change="modal.updateTestListString()">Aliases</label>
<span class="glyphicon glyphicon-info-sign info-hover" aria-hidden="true"
title="Include test aliases as tests may have been renamed over time. It does not hurt to include these."></span>
&nbsp;
<label><input type="checkbox" ng-model="modal.flagged" ng-change="modal.updateTestListString()">Flagged</label>
<span class="glyphicon glyphicon-info-sign info-hover" aria-hidden="true"
title="Include flagged tests.">
</span>
</div>
<p ng-hide="modal.error"> Alternatively, get the test list directly from the API on your CLI:</p>
<code ng-hide="modal.error">wget "{{modal.testListUrl}}" -O {{modal.version}}-test-list.txt</code>
</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 cg-busy="{promise:modal.testListRequest,message:'Loading'}"></div>
<div ng-show="modal.error" class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
{{modal.error}}
</div>
<div class="form-group">
<textarea class="form-control" rows="16" id="tests" wrap="off">{{modal.testListString}}</textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-if="modal.tests.length>0" type="button" ng-click="modal.downloadTestList()">Download</button>
<a target="_blank" href="{{modal.testListUrl}}" download="{{modal.version + '-test-list.txt'}}">
<button class="btn btn-primary" ng-if="modal.testListCount > 0" type="button">
Download
</button>
</a>
<button class="btn btn-primary" type="button" ng-click="modal.close()">Close</button>
</div>
</div>

View File

@ -153,42 +153,6 @@ 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.guidelines = {
'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.guidelines = {
'schema': '1.2',
'capabilities' : {
'cap-1': {
'tests': ['test_1', 'test_2']
},
'cap-2': {
'tests': ['test_3']
}
}
};
expect(ctrl.getTestList()).toEqual(['test_1', 'test_2']);
});
it('should have a method to open a modal for the relevant test list',
function () {
var modal;
@ -211,51 +175,27 @@ describe('Refstack controllers', function () {
$window = _$window_;
ctrl = $controller('TestListModalController',
{$uibModalInstance: modalInstance,
tests: ['t1', 't2'],
target: 'platform',
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',
it('should have a method to download the test list 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();
var fakeResp = 'test1\ntest2\ntest3';
$httpBackend.expectGET(fakeApiUrl +
'/guidelines/2016.01/tests?target=platform&' +
'type=required&alias=true&flag=false').respond(fakeResp);
$httpBackend.flush();
ctrl.updateTestListString();
expect(ctrl.testListCount).toBe(3);
});
});