
This change will modify a number of things about the way we manage guideline sources - it allows the api to pull guidelines from a list of additional guideline sources, as specified in conf - changes the object returned by the guidelines api from a list to a dictionary of lists pertaining to a specific guideline type Change-Id: Ic42197b32d4c9030a35e613cae8cc64dca794c85
930 lines
37 KiB
JavaScript
930 lines
37 KiB
JavaScript
/*
|
|
* 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';
|
|
|
|
angular
|
|
.module('refstackApp')
|
|
.controller('ResultsReportController', ResultsReportController);
|
|
|
|
ResultsReportController.$inject = [
|
|
'$http', '$stateParams', '$window',
|
|
'$uibModal', 'refstackApiUrl', 'raiseAlert'
|
|
];
|
|
|
|
/**
|
|
* RefStack Results Report Controller
|
|
* This controller is for the '/results/<test run ID>' page where a user can
|
|
* view details for a specific test run.
|
|
*/
|
|
function ResultsReportController($http, $stateParams, $window,
|
|
$uibModal, refstackApiUrl, raiseAlert) {
|
|
|
|
var ctrl = this;
|
|
|
|
ctrl.getVersionList = getVersionList;
|
|
ctrl.getResults = getResults;
|
|
ctrl.isResultAdmin = isResultAdmin;
|
|
ctrl.isShared = isShared;
|
|
ctrl.shareTestRun = shareTestRun;
|
|
ctrl.deleteTestRun = deleteTestRun;
|
|
ctrl.updateVerificationStatus = updateVerificationStatus;
|
|
ctrl.updateGuidelines = updateGuidelines;
|
|
ctrl.getTargetCapabilities = getTargetCapabilities;
|
|
ctrl.buildCapabilityV1_2 = buildCapabilityV1_2;
|
|
ctrl.buildCapabilityV1_3 = buildCapabilityV1_3;
|
|
ctrl.buildCapabilitiesObject = buildCapabilitiesObject;
|
|
ctrl.isTestFlagged = isTestFlagged;
|
|
ctrl.getFlaggedReason = getFlaggedReason;
|
|
ctrl.isCapabilityShown = isCapabilityShown;
|
|
ctrl.isTestShown = isTestShown;
|
|
ctrl.getCapabilityTestCount = getCapabilityTestCount;
|
|
ctrl.getStatusTestCount = getStatusTestCount;
|
|
ctrl.openFullTestListModal = openFullTestListModal;
|
|
ctrl.openEditTestModal = openEditTestModal;
|
|
getVersionList();
|
|
|
|
/** The testID extracted from the URL route. */
|
|
ctrl.testId = $stateParams.testID;
|
|
|
|
/** The target OpenStack marketing program to compare against. */
|
|
ctrl.target = 'platform';
|
|
|
|
/** Mappings of Interop WG components to marketing program names. */
|
|
ctrl.targetMappings = {
|
|
'platform': 'Openstack Powered Platform',
|
|
'compute': 'OpenStack Powered Compute',
|
|
'object': 'OpenStack Powered Object Storage',
|
|
'dns': 'OpenStack with DNS',
|
|
'orchestration': 'OpenStack with orchestration'
|
|
};
|
|
|
|
/** The schema version of the currently selected guideline data. */
|
|
ctrl.schemaVersion = null;
|
|
|
|
/** The selected test status used for test filtering. */
|
|
ctrl.testStatus = 'total';
|
|
|
|
/** The HTML template that all accordian groups will use. */
|
|
ctrl.detailsTemplate = 'components/results-report/partials/' +
|
|
'reportDetails.html';
|
|
|
|
/**
|
|
* Retrieve an array of available guideline files from the Refstack
|
|
* API server, sort this array reverse-alphabetically, and store it in
|
|
* a scoped variable. The scope's selected version is initialized to
|
|
* the latest (i.e. first) version here as well. After a successful API
|
|
* call, the function to update the capabilities is called.
|
|
* Sample API return array: ["2015.03.json", "2015.04.json"]
|
|
*/
|
|
function getVersionList() {
|
|
if (ctrl.target === 'dns' || ctrl.target === 'orchestration') {
|
|
ctrl.gl_type = ctrl.target;
|
|
|
|
} else {
|
|
ctrl.gl_type = 'powered';
|
|
}
|
|
var content_url = refstackApiUrl + '/guidelines';
|
|
ctrl.versionsRequest =
|
|
$http.get(content_url).success(function (data) {
|
|
let gl_files = data[ctrl.gl_type];
|
|
let gl_names = gl_files.map((gl_obj) => gl_obj.name);
|
|
ctrl.versionList = gl_names.sort().reverse();
|
|
let file_names = gl_files.map((gl_obj) => gl_obj.file);
|
|
ctrl.fileList = file_names.sort().reverse();
|
|
|
|
if (!ctrl.version) {
|
|
// Default to the first approved guideline which is
|
|
// expected to be at index 1.
|
|
ctrl.version = ctrl.versionList[1];
|
|
ctrl.versionFile = ctrl.fileList[1];
|
|
} else {
|
|
let versionIndex =
|
|
ctrl.versionList.indexOf(ctrl.version);
|
|
ctrl.versionFile = ctrl.fileList[versionIndex];
|
|
}
|
|
ctrl.updateGuidelines();
|
|
}).error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.error = 'Error retrieving version list: ' +
|
|
angular.toJson(error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Retrieve results from the Refstack API server based on the test
|
|
* run id in the URL. This function is the first function that will
|
|
* be called from the controller. Upon successful retrieval of results,
|
|
* the function that gets the version list will be called.
|
|
*/
|
|
function getResults() {
|
|
var content_url = refstackApiUrl + '/results/' + ctrl.testId;
|
|
ctrl.resultsRequest =
|
|
$http.get(content_url).success(function (data) {
|
|
ctrl.resultsData = data;
|
|
ctrl.version = ctrl.resultsData.meta.guideline;
|
|
ctrl.isVerified = ctrl.resultsData.verification_status;
|
|
if (ctrl.resultsData.meta.target) {
|
|
ctrl.target = ctrl.resultsData.meta.target;
|
|
}
|
|
getVersionList();
|
|
}).error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.resultsData = null;
|
|
ctrl.error = 'Error retrieving results from server: ' +
|
|
angular.toJson(error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This tells you whether the current user has administrative
|
|
* privileges for the test result.
|
|
* @returns {Boolean} true if the user has admin privileges.
|
|
*/
|
|
function isResultAdmin() {
|
|
return Boolean(ctrl.resultsData &&
|
|
(ctrl.resultsData.user_role === 'owner' ||
|
|
ctrl.resultsData.user_role === 'foundation'));
|
|
}
|
|
/**
|
|
* This tells you whether the current results are shared with the
|
|
* community or not.
|
|
* @returns {Boolean} true if the results are shared
|
|
*/
|
|
function isShared() {
|
|
return Boolean(ctrl.resultsData &&
|
|
'shared' in ctrl.resultsData.meta);
|
|
}
|
|
|
|
/**
|
|
* This will send an API request in order to share or unshare the
|
|
* current results based on the passed in shareState.
|
|
* @param {Boolean} shareState - Whether to share or unshare results.
|
|
*/
|
|
function shareTestRun(shareState) {
|
|
var content_url = [
|
|
refstackApiUrl, '/results/', ctrl.testId, '/meta/shared'
|
|
].join('');
|
|
if (shareState) {
|
|
ctrl.shareRequest =
|
|
$http.post(content_url, 'true').success(function () {
|
|
ctrl.resultsData.meta.shared = 'true';
|
|
raiseAlert('success', '', 'Test run shared!');
|
|
}).error(function (error) {
|
|
raiseAlert('danger', error.title, error.detail);
|
|
});
|
|
} else {
|
|
ctrl.shareRequest =
|
|
$http.delete(content_url).success(function () {
|
|
delete ctrl.resultsData.meta.shared;
|
|
raiseAlert('success', '', 'Test run unshared!');
|
|
}).error(function (error) {
|
|
raiseAlert('danger', error.title, error.detail);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This will send a request to the API to delete the current
|
|
* test results set.
|
|
*/
|
|
function deleteTestRun() {
|
|
var content_url = [
|
|
refstackApiUrl, '/results/', ctrl.testId
|
|
].join('');
|
|
ctrl.deleteRequest =
|
|
$http.delete(content_url).success(function () {
|
|
$window.history.back();
|
|
}).error(function (error) {
|
|
raiseAlert('danger', error.title, error.detail);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This will send a request to the API to delete the current
|
|
* test results set.
|
|
*/
|
|
function updateVerificationStatus() {
|
|
var content_url = [
|
|
refstackApiUrl, '/results/', ctrl.testId
|
|
].join('');
|
|
var data = {'verification_status': ctrl.isVerified};
|
|
ctrl.updateRequest =
|
|
$http.put(content_url, data).success(
|
|
function () {
|
|
ctrl.resultsData.verification_status = ctrl.isVerified;
|
|
raiseAlert('success', '',
|
|
'Verification status changed!');
|
|
}).error(function (error) {
|
|
ctrl.isVerified = ctrl.resultsData.verification_status;
|
|
raiseAlert('danger', error.title, error.detail);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This will contact the Refstack API server to retrieve the JSON
|
|
* content of the guideline file corresponding to the selected
|
|
* version. A function to construct an object from the capability
|
|
* data will be called upon successful retrieval.
|
|
*/
|
|
function updateGuidelines() {
|
|
ctrl.guidelineData = null;
|
|
ctrl.showError = false;
|
|
|
|
ctrl.content_url = refstackApiUrl + '/guidelines/' +
|
|
ctrl.versionFile;
|
|
let getparams = {'gl_file': ctrl.versionFile};
|
|
ctrl.capsRequest =
|
|
$http.get(ctrl.content_url, getparams).success(function (data) {
|
|
ctrl.guidelineData = data;
|
|
if ('metadata' in data && data.metadata.schema >= '2.0') {
|
|
ctrl.schemaVersion = data.metadata.schema;
|
|
ctrl.guidelineStatus =
|
|
data.metadata.os_trademark_approval.status;
|
|
ctrl.releases =
|
|
data.metadata.os_trademark_approval.releases;
|
|
} else {
|
|
ctrl.schemaVersion = data.schema;
|
|
ctrl.guidelineStatus = data.status;
|
|
ctrl.releases = data.releases;
|
|
}
|
|
ctrl.buildCapabilitiesObject();
|
|
}).error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.guidelineData = null;
|
|
ctrl.error = 'Error retrieving guideline date: ' +
|
|
angular.toJson(error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This will get all the capabilities relevant to the target and
|
|
* their corresponding statuses.
|
|
* @returns {Object} Object containing each capability and their status
|
|
*/
|
|
function getTargetCapabilities() {
|
|
var components = ctrl.guidelineData.components;
|
|
var targetCaps = {};
|
|
var targetComponents = null;
|
|
var old_type = ctrl.gl_type;
|
|
if (ctrl.target === 'dns' || ctrl.target === 'orchestration') {
|
|
ctrl.gl_type = ctrl.target;
|
|
} else {
|
|
ctrl.gl_type = 'powered';
|
|
}
|
|
// If it has not been updated since the last program type change,
|
|
// will need to update the list
|
|
if (old_type !== ctrl.gl_type) {
|
|
ctrl.getVersionList();
|
|
return false;
|
|
}
|
|
|
|
// The 'platform' target is comprised of multiple components, so
|
|
// we need to get the capabilities belonging to each of its
|
|
// components.
|
|
if (ctrl.target === 'platform' || ctrl.schemaVersion >= '2.0') {
|
|
if ('add-ons' in ctrl.guidelineData) {
|
|
targetComponents = ['os_powered_' + ctrl.target];
|
|
} else if (ctrl.schemaVersion >= '2.0') {
|
|
var platformsMap = {
|
|
'platform': 'OpenStack Powered Platform',
|
|
'compute': 'OpenStack Powered Compute',
|
|
'object': 'OpenStack Powered Storage',
|
|
};
|
|
targetComponents = ctrl.guidelineData.platforms[
|
|
platformsMap[ctrl.target]].components.map(
|
|
function(c) {
|
|
return c.name;
|
|
}
|
|
);
|
|
} else {
|
|
targetComponents = ctrl.guidelineData.platform.required;
|
|
}
|
|
|
|
// This will contain status priority values, where lower
|
|
// values mean higher priorities.
|
|
var statusMap = {
|
|
required: 1,
|
|
advisory: 2,
|
|
deprecated: 3,
|
|
removed: 4
|
|
};
|
|
|
|
// For each component required for the platform program.
|
|
angular.forEach(targetComponents, function (component) {
|
|
var componentList = components[component];
|
|
if (ctrl.schemaVersion >= '2.0') {
|
|
componentList = componentList.capabilities;
|
|
}
|
|
// Get each capability list belonging to each status.
|
|
angular.forEach(componentList,
|
|
function (caps, status) {
|
|
// For each capability.
|
|
angular.forEach(caps, function(cap) {
|
|
// If the capability has already been added.
|
|
if (cap in targetCaps) {
|
|
// If the status priority value is less
|
|
// than the saved priority value, update
|
|
// the value.
|
|
if (statusMap[status] <
|
|
statusMap[targetCaps[cap]]) {
|
|
targetCaps[cap] = status;
|
|
}
|
|
} else {
|
|
targetCaps[cap] = status;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
angular.forEach(components[ctrl.target],
|
|
function (caps, status) {
|
|
angular.forEach(caps, function(cap) {
|
|
targetCaps[cap] = status;
|
|
});
|
|
});
|
|
}
|
|
return targetCaps;
|
|
}
|
|
|
|
/**
|
|
* This will build the a capability object for schema version 1.2.
|
|
* This object will contain the information needed to form a report in
|
|
* the HTML template.
|
|
* @param {String} capId capability ID
|
|
*/
|
|
function buildCapabilityV1_2(capId) {
|
|
var cap = {
|
|
'id': capId,
|
|
'passedTests': [],
|
|
'notPassedTests': [],
|
|
'passedFlagged': [],
|
|
'notPassedFlagged': []
|
|
};
|
|
var capDetails = ctrl.guidelineData.capabilities[capId];
|
|
// Loop through each test belonging to the capability.
|
|
angular.forEach(capDetails.tests,
|
|
function (testId) {
|
|
// If the test ID is in the results' test list, add
|
|
// it to the passedTests array.
|
|
if (ctrl.resultsData.results.indexOf(testId) > -1) {
|
|
cap.passedTests.push(testId);
|
|
if (capDetails.flagged.indexOf(testId) > -1) {
|
|
cap.passedFlagged.push(testId);
|
|
}
|
|
} else {
|
|
cap.notPassedTests.push(testId);
|
|
if (capDetails.flagged.indexOf(testId) > -1) {
|
|
cap.notPassedFlagged.push(testId);
|
|
}
|
|
}
|
|
});
|
|
return cap;
|
|
}
|
|
|
|
/**
|
|
* This will build the a capability object for schema version 1.3 and
|
|
* above. This object will contain the information needed to form a
|
|
* report in the HTML template.
|
|
* @param {String} capId capability ID
|
|
*/
|
|
function buildCapabilityV1_3(capId) {
|
|
var cap = {
|
|
'id': capId,
|
|
'passedTests': [],
|
|
'notPassedTests': [],
|
|
'passedFlagged': [],
|
|
'notPassedFlagged': []
|
|
};
|
|
|
|
// For cases where a capability listed in components is not
|
|
// in the capabilities object.
|
|
if (!(capId in ctrl.guidelineData.capabilities)) {
|
|
return cap;
|
|
}
|
|
|
|
// Loop through each test belonging to the capability.
|
|
angular.forEach(ctrl.guidelineData.capabilities[capId].tests,
|
|
function (details, testId) {
|
|
var passed = false;
|
|
|
|
// If the test ID is in the results' test list.
|
|
if (ctrl.resultsData.results.indexOf(testId) > -1) {
|
|
passed = true;
|
|
} else if ('aliases' in details) {
|
|
var len = details.aliases.length;
|
|
for (var i = 0; i < len; i++) {
|
|
var alias = details.aliases[i];
|
|
if (ctrl.resultsData.results.indexOf(alias) > -1) {
|
|
passed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add to correct array based on whether the test was
|
|
// passed or not.
|
|
if (passed) {
|
|
cap.passedTests.push(testId);
|
|
if ('flagged' in details) {
|
|
cap.passedFlagged.push(testId);
|
|
}
|
|
} else {
|
|
cap.notPassedTests.push(testId);
|
|
if ('flagged' in details) {
|
|
cap.notPassedFlagged.push(testId);
|
|
}
|
|
}
|
|
});
|
|
return cap;
|
|
}
|
|
|
|
/**
|
|
* This will check the schema version of the current capabilities file,
|
|
* and will call the correct method to build an object based on the
|
|
* capability data retrieved from the Refstack API server.
|
|
*/
|
|
function buildCapabilitiesObject() {
|
|
// This is the object template where 'count' is the number of
|
|
// total tests that fall under the given status, and 'passedCount'
|
|
// is the number of tests passed. The 'caps' array will contain
|
|
// objects with details regarding each capability.
|
|
ctrl.caps = {
|
|
'required': {'caps': [], 'count': 0, 'passedCount': 0,
|
|
'flagFailCount': 0, 'flagPassCount': 0},
|
|
'advisory': {'caps': [], 'count': 0, 'passedCount': 0,
|
|
'flagFailCount': 0, 'flagPassCount': 0},
|
|
'deprecated': {'caps': [], 'count': 0, 'passedCount': 0,
|
|
'flagFailCount': 0, 'flagPassCount': 0},
|
|
'removed': {'caps': [], 'count': 0, 'passedCount': 0,
|
|
'flagFailCount': 0, 'flagPassCount': 0}
|
|
};
|
|
var capMethod = null;
|
|
|
|
switch (ctrl.schemaVersion) {
|
|
case '1.2':
|
|
capMethod = 'buildCapabilityV1_2';
|
|
break;
|
|
case '1.3':
|
|
case '1.4':
|
|
case '1.5':
|
|
case '1.6':
|
|
case '2.0':
|
|
capMethod = 'buildCapabilityV1_3';
|
|
break;
|
|
default:
|
|
ctrl.showError = true;
|
|
ctrl.guidelineData = null;
|
|
ctrl.error = 'The schema version for the guideline ' +
|
|
'file selected (' + ctrl.schemaVersion +
|
|
') is currently not supported.';
|
|
return;
|
|
}
|
|
|
|
// Get test details for each relevant capability and store
|
|
// them in the scope's 'caps' object.
|
|
var targetCaps = ctrl.getTargetCapabilities();
|
|
angular.forEach(targetCaps, function(status, capId) {
|
|
var cap = ctrl[capMethod](capId);
|
|
ctrl.caps[status].count +=
|
|
cap.passedTests.length + cap.notPassedTests.length;
|
|
ctrl.caps[status].passedCount += cap.passedTests.length;
|
|
ctrl.caps[status].flagPassCount += cap.passedFlagged.length;
|
|
ctrl.caps[status].flagFailCount +=
|
|
cap.notPassedFlagged.length;
|
|
ctrl.caps[status].caps.push(cap);
|
|
});
|
|
|
|
ctrl.requiredPassPercent = ctrl.caps.required.passedCount *
|
|
100 / ctrl.caps.required.count;
|
|
|
|
ctrl.totalRequiredFailCount = ctrl.caps.required.count -
|
|
ctrl.caps.required.passedCount;
|
|
ctrl.totalRequiredFlagCount =
|
|
ctrl.caps.required.flagFailCount +
|
|
ctrl.caps.required.flagPassCount;
|
|
ctrl.totalNonFlagCount = ctrl.caps.required.count -
|
|
ctrl.totalRequiredFlagCount;
|
|
ctrl.nonFlagPassCount = ctrl.totalNonFlagCount -
|
|
(ctrl.totalRequiredFailCount -
|
|
ctrl.caps.required.flagFailCount);
|
|
|
|
ctrl.nonFlagRequiredPassPercent = ctrl.nonFlagPassCount *
|
|
100 / ctrl.totalNonFlagCount;
|
|
}
|
|
|
|
/**
|
|
* This will check if a given test is flagged.
|
|
* @param {String} test ID of the test to check
|
|
* @param {Object} capObj capability that test is under
|
|
* @returns {Boolean} truthy value if test is flagged
|
|
*/
|
|
function isTestFlagged(test, capObj) {
|
|
if (!capObj) {
|
|
return false;
|
|
}
|
|
return ctrl.schemaVersion === '1.2' &&
|
|
capObj.flagged.indexOf(test) > -1 ||
|
|
ctrl.schemaVersion >= '1.3' &&
|
|
capObj.tests[test].flagged;
|
|
}
|
|
|
|
/**
|
|
* This will return the reason a test is flagged. An empty string
|
|
* will be returned if the passed in test is not flagged.
|
|
* @param {String} test ID of the test to check
|
|
* @param {String} capObj capability that test is under
|
|
* @returns {String} reason
|
|
*/
|
|
function getFlaggedReason(test, capObj) {
|
|
if (ctrl.schemaVersion === '1.2' &&
|
|
ctrl.isTestFlagged(test, capObj)) {
|
|
|
|
// Return a generic message since schema 1.2 does not
|
|
// provide flag reasons.
|
|
return 'Interop Working Group has flagged this test.';
|
|
} else if (ctrl.schemaVersion >= '1.3' &&
|
|
ctrl.isTestFlagged(test, capObj)) {
|
|
|
|
return capObj.tests[test].flagged.reason;
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This will check the if a capability should be shown based on the
|
|
* test filter selected. If a capability does not have any tests
|
|
* belonging under the given filter, it should not be shown.
|
|
* @param {Object} capability Built object for capability
|
|
* @returns {Boolean} true if capability should be shown
|
|
*/
|
|
function isCapabilityShown(capability) {
|
|
return ctrl.testStatus === 'total' ||
|
|
ctrl.testStatus === 'passed' &&
|
|
capability.passedTests.length > 0 ||
|
|
ctrl.testStatus === 'not passed' &&
|
|
capability.notPassedTests.length > 0 ||
|
|
ctrl.testStatus === 'flagged' &&
|
|
capability.passedFlagged.length +
|
|
capability.notPassedFlagged.length > 0;
|
|
}
|
|
|
|
/**
|
|
* This will check the if a test should be shown based on the test
|
|
* filter selected.
|
|
* @param {String} test ID of the test
|
|
* @param {Object} capability Built object for capability
|
|
* @return {Boolean} true if test should be shown
|
|
*/
|
|
function isTestShown(test, capability) {
|
|
return ctrl.testStatus === 'total' ||
|
|
ctrl.testStatus === 'passed' &&
|
|
capability.passedTests.indexOf(test) > -1 ||
|
|
ctrl.testStatus === 'not passed' &&
|
|
capability.notPassedTests.indexOf(test) > -1 ||
|
|
ctrl.testStatus === 'flagged' &&
|
|
(capability.passedFlagged.indexOf(test) > -1 ||
|
|
capability.notPassedFlagged.indexOf(test) > -1);
|
|
}
|
|
|
|
/**
|
|
* This will give the number of tests belonging under the selected
|
|
* test filter for a given capability.
|
|
* @param {Object} capability Built object for capability
|
|
* @returns {Number} number of tests under filter
|
|
*/
|
|
function getCapabilityTestCount(capability) {
|
|
if (ctrl.testStatus === 'total') {
|
|
return capability.passedTests.length +
|
|
capability.notPassedTests.length;
|
|
} else if (ctrl.testStatus === 'passed') {
|
|
return capability.passedTests.length;
|
|
} else if (ctrl.testStatus === 'not passed') {
|
|
return capability.notPassedTests.length;
|
|
} else if (ctrl.testStatus === 'flagged') {
|
|
return capability.passedFlagged.length +
|
|
capability.notPassedFlagged.length;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This will give the number of tests belonging under the selected
|
|
* test filter for a given status.
|
|
* @param {String} capability status
|
|
* @returns {Number} number of tests for status under filter
|
|
*/
|
|
function getStatusTestCount(status) {
|
|
if (!ctrl.caps) {
|
|
return -1;
|
|
} else if (ctrl.testStatus === 'total') {
|
|
return ctrl.caps[status].count;
|
|
} else if (ctrl.testStatus === 'passed') {
|
|
return ctrl.caps[status].passedCount;
|
|
} else if (ctrl.testStatus === 'not passed') {
|
|
return ctrl.caps[status].count -
|
|
ctrl.caps[status].passedCount;
|
|
} else if (ctrl.testStatus === 'flagged') {
|
|
return ctrl.caps[status].flagFailCount +
|
|
ctrl.caps[status].flagPassCount;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This will open the modal that will show the full list of passed
|
|
* tests for the current results.
|
|
*/
|
|
function openFullTestListModal() {
|
|
$uibModal.open({
|
|
templateUrl: '/components/results-report/partials' +
|
|
'/fullTestListModal.html',
|
|
backdrop: true,
|
|
windowClass: 'modal',
|
|
animation: true,
|
|
controller: 'FullTestListModalController as modal',
|
|
size: 'lg',
|
|
resolve: {
|
|
tests: function () {
|
|
return ctrl.resultsData.results;
|
|
},
|
|
gl_type: function () {
|
|
return ctrl.gl_type;
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This will open the modal that will all a user to edit test run
|
|
* metadata.
|
|
*/
|
|
function openEditTestModal() {
|
|
$uibModal.open({
|
|
templateUrl: '/components/results-report/partials' +
|
|
'/editTestModal.html',
|
|
backdrop: true,
|
|
windowClass: 'modal',
|
|
animation: true,
|
|
controller: 'EditTestModalController as modal',
|
|
size: 'lg',
|
|
resolve: {
|
|
resultsData: function () {
|
|
return ctrl.resultsData;
|
|
},
|
|
gl_type: function () {
|
|
return ctrl.gl_type;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
getResults();
|
|
}
|
|
|
|
angular
|
|
.module('refstackApp')
|
|
.controller('FullTestListModalController', FullTestListModalController);
|
|
|
|
FullTestListModalController.$inject =
|
|
['$uibModalInstance', 'tests', 'gl_type'];
|
|
|
|
/**
|
|
* Full Test List Modal Controller
|
|
* This controller is for the modal that appears if a user wants to see the
|
|
* full list of passed tests on a report page.
|
|
*/
|
|
function FullTestListModalController($uibModalInstance, tests, gl_type) {
|
|
var ctrl = this;
|
|
|
|
ctrl.tests = tests;
|
|
ctrl.gl_type = gl_type;
|
|
|
|
/**
|
|
* This function will close/dismiss the modal.
|
|
*/
|
|
ctrl.close = function () {
|
|
$uibModalInstance.dismiss('exit');
|
|
};
|
|
|
|
/**
|
|
* This function will return a string representing the sorted
|
|
* tests list separated by newlines.
|
|
*/
|
|
ctrl.getTestListString = function () {
|
|
return ctrl.tests.sort().join('\n');
|
|
};
|
|
}
|
|
|
|
angular
|
|
.module('refstackApp')
|
|
.controller('EditTestModalController', EditTestModalController);
|
|
|
|
EditTestModalController.$inject = [
|
|
'$uibModalInstance', '$http', '$state', 'raiseAlert',
|
|
'refstackApiUrl', 'resultsData', 'gl_type'
|
|
];
|
|
|
|
/**
|
|
* Edit Test Modal Controller
|
|
* This controller is for the modal that appears if a user wants to edit
|
|
* test run metadata.
|
|
*/
|
|
function EditTestModalController($uibModalInstance, $http, $state,
|
|
raiseAlert, refstackApiUrl, resultsData, gl_type) {
|
|
|
|
var ctrl = this;
|
|
|
|
ctrl.getVersionList = getVersionList;
|
|
ctrl.getUserProducts = getUserProducts;
|
|
ctrl.associateProductVersion = associateProductVersion;
|
|
ctrl.getProductVersions = getProductVersions;
|
|
ctrl.saveChanges = saveChanges;
|
|
|
|
ctrl.resultsData = resultsData;
|
|
ctrl.metaCopy = angular.copy(resultsData.meta);
|
|
ctrl.prodVersionCopy = angular.copy(resultsData.product_version);
|
|
ctrl.gl_type = gl_type;
|
|
|
|
ctrl.getVersionList();
|
|
ctrl.getUserProducts();
|
|
|
|
/**
|
|
* Retrieve an array of available capability files from the Refstack
|
|
* API server, sort this array reverse-alphabetically, and store it in
|
|
* a scoped variable.
|
|
* Sample API return array: ["2015.03.json", "2015.04.json"]
|
|
*/
|
|
function getVersionList() {
|
|
if (ctrl.versionList) {
|
|
return;
|
|
}
|
|
var content_url = refstackApiUrl + '/guidelines';
|
|
ctrl.versionsRequest =
|
|
$http.get(content_url).success(function (data) {
|
|
let gl_files = data[ctrl.gl_type];
|
|
let gl_names = gl_files.map((gl_obj) => gl_obj.name);
|
|
ctrl.versionList = gl_names.sort().reverse();
|
|
ctrl.version = ctrl.versionList[1];
|
|
}).error(function (error) {
|
|
raiseAlert('danger', error.title,
|
|
'Unable to retrieve version list');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get products user has management rights to or all products depending
|
|
* on the passed in parameter value.
|
|
*/
|
|
function getUserProducts() {
|
|
var contentUrl = refstackApiUrl + '/products';
|
|
ctrl.productsRequest =
|
|
$http.get(contentUrl).success(function (data) {
|
|
ctrl.products = {};
|
|
angular.forEach(data.products, function(prod) {
|
|
if (prod.can_manage) {
|
|
ctrl.products[prod.id] = prod;
|
|
}
|
|
});
|
|
if (ctrl.prodVersionCopy) {
|
|
ctrl.selectedProduct = ctrl.products[
|
|
ctrl.prodVersionCopy.product_info.id
|
|
];
|
|
}
|
|
ctrl.getProductVersions();
|
|
}).error(function (error) {
|
|
ctrl.products = null;
|
|
ctrl.showError = true;
|
|
ctrl.error =
|
|
'Error retrieving Products listing from server: ' +
|
|
angular.toJson(error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a PUT request to the API server to associate a product with
|
|
* a test result.
|
|
*/
|
|
function associateProductVersion() {
|
|
var verId = ctrl.selectedVersion ?
|
|
ctrl.selectedVersion.id : null;
|
|
var testId = resultsData.id;
|
|
var url = refstackApiUrl + '/results/' + testId;
|
|
ctrl.associateRequest = $http.put(url, {'product_version_id':
|
|
verId})
|
|
.error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.showSuccess = false;
|
|
ctrl.error =
|
|
'Error associating product version with test run: ' +
|
|
angular.toJson(error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all versions for a product.
|
|
*/
|
|
function getProductVersions() {
|
|
if (!ctrl.selectedProduct) {
|
|
ctrl.productVersions = [];
|
|
ctrl.selectedVersion = null;
|
|
return;
|
|
}
|
|
|
|
var url = refstackApiUrl + '/products/' +
|
|
ctrl.selectedProduct.id + '/versions';
|
|
ctrl.getVersionsRequest = $http.get(url)
|
|
.success(function (data) {
|
|
ctrl.productVersions = data;
|
|
if (ctrl.prodVersionCopy &&
|
|
ctrl.prodVersionCopy.product_info.id ===
|
|
ctrl.selectedProduct.id) {
|
|
ctrl.selectedVersion = ctrl.prodVersionCopy;
|
|
} else {
|
|
angular.forEach(data, function(ver) {
|
|
if (!ver.version) {
|
|
ctrl.selectedVersion = ver;
|
|
}
|
|
});
|
|
}
|
|
}).error(function (error) {
|
|
raiseAlert('danger', error.title, error.detail);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a PUT request to the server with the changes.
|
|
*/
|
|
function saveChanges() {
|
|
ctrl.showError = false;
|
|
ctrl.showSuccess = false;
|
|
var metaBaseUrl = [
|
|
refstackApiUrl, '/results/', resultsData.id, '/meta/'
|
|
].join('');
|
|
var metaFields = ['target', 'guideline', 'shared'];
|
|
var meta = ctrl.metaCopy;
|
|
angular.forEach(metaFields, function(field) {
|
|
var oldMetaValue = field in ctrl.resultsData.meta ?
|
|
ctrl.resultsData.meta[field] : '';
|
|
if (field in meta && oldMetaValue !== meta[field]) {
|
|
var metaUrl = metaBaseUrl + field;
|
|
if (meta[field]) {
|
|
ctrl.assocRequest = $http.post(metaUrl, meta[field])
|
|
.success(function() {
|
|
ctrl.resultsData.meta[field] = meta[field];
|
|
})
|
|
.error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.showSuccess = false;
|
|
ctrl.error =
|
|
'Error associating metadata with ' +
|
|
'test run: ' + angular.toJson(error);
|
|
});
|
|
} else {
|
|
ctrl.unassocRequest = $http.delete(metaUrl)
|
|
.success(function () {
|
|
delete ctrl.resultsData.meta[field];
|
|
delete meta[field];
|
|
})
|
|
.error(function (error) {
|
|
ctrl.showError = true;
|
|
ctrl.showSuccess = false;
|
|
ctrl.error =
|
|
'Error associating metadata with ' +
|
|
'test run: ' + angular.toJson(error);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
ctrl.associateProductVersion();
|
|
if (!ctrl.showError) {
|
|
ctrl.showSuccess = true;
|
|
$state.reload();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will close/dismiss the modal.
|
|
*/
|
|
ctrl.close = function () {
|
|
$uibModalInstance.dismiss('exit');
|
|
};
|
|
}
|
|
})();
|