synergy/client/app/js/handlers.js (603 lines of code) (raw):
"use strict";
angular.module("synergy.handlers", ["synergy.utils"])
.factory("SynergyHandlers", ["SynergyUtils", function (SynergyUtils) {
var Synergy = {};
Synergy.interfaces = {};
Synergy.control = {};
Synergy.interfaces.observer = {
listeners: [],
subscribe: function (callback, event) {
},
publish: function (data, $scope, event) {
},
unsubscribe: function (fn, event) {
}
};
Synergy.interfaces.logger = {
level: {
"INFO": 2,
"DEBUG": 1
},
printLevel: 2,
title: "",
msg: "",
style: "alert-info",
print: false,
printMessage: function (title, msg, style) {
},
log: function (title, msg, level, style) {
},
error: function (title, msg, level, style) {
}
};
Synergy.interfaces.server = {
init: function (endpoints) {
this.endpoints = endpoints;
},
endpoints: {},
buildURL: function (endpoint, parameters) {
}
};
/**
* Handles file uploads
* @param {Array} acceptedTypes - e.g. ["image/png"]
* @param {String} dropElementID - ID of element where files are being dropped
* @param {Number} uploadLimit - file size limit in bytes
* @param {String} url - target URL used for uploading
* @param {Function} onSuccess callback
* @param {Function} onFail callback
* @returns {undefined}
*/
Synergy.control.FileUploader = function (acceptedTypes, dropElementID, uploadLimit, url, onSuccess, onFail) {
this.event = null;
this.url = url;
this.file = {};
var self = this;
var dropbox = window.document.getElementById(dropElementID);
function dragEnter(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.cancelBubble = true;
}
function dragExit(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.cancelBubble = true;
}
function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.cancelBubble = true;
}
/**
*
* @param {Event} evt
*/
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.cancelBubble = true;
var files = evt.dataTransfer.files;
var count = files.length;
if (count > 0) {
if (files[0].size > uploadLimit) {
onFail("File Too Large", "Maximum allowed size is " + uploadLimit / 1000000 + " MB", "INFO", "alert-error");
} else {
if (fileIsValid(files[0])) {
handleFile(files[0]);
} else {
onFail("Unsupported file", "Supported formats are " + printAccepted(), "INFO", "alert-error");
}
}
}
}
function printAccepted() {
var s = "";
for (var i = 0, max = acceptedTypes.length; i < max; i += 1) {
s += acceptedTypes[i] + " ";
}
return s;
}
function fileIsValid(file) {
if (acceptedTypes.length < 1) {
return true;
} else {
for (var i = 0, max = acceptedTypes.length; i < max; i += 1) {
if (file.type === acceptedTypes[i]) {
return true;
}
}
return false;
}
}
if (dropbox !== null) {
if (dropbox.addEventListener) {
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", drop, false);
} else {
dropbox.attachEvent("ondragenter", dragEnter);
dropbox.attachEvent("ondragexit", dragExit);
dropbox.attachEvent("ondragover", dragOver);
dropbox.attachEvent("ondrop", drop);
}
}
function showTitleDialog(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.cancelBubble = true;
self.event = evt;
self.file = (self.event.dataTransfer.files.length > 0) ? self.event.dataTransfer.files[0] : {};
$("#addImageModal").modal("toggle");
}
this.uploadFileFromFileChooser = function (fdid) {
var file = window.document.getElementById(fdid).files[0];
if (file) {
if (file.size > uploadLimit) {
onFail("File Too Large", "Maximum allowed size is " + uploadLimit / 1000000 + " MB", "INFO", "alert-error");
} else {
handleFile(file);
}
}
};
this.uploadImage = function (url) {
self.url = url;
var files = self.event.dataTransfer.files;
var count = files.length;
if (self.file) {
if (self.file > uploadLimit) {
onFail("File Too Large", "Maximum allowed size is " + uploadLimit / 1000000 + " MB", "INFO", "alert-error");
} else {
if (fileIsValid(self.file)) {
handleFile(self.file);
} else {
onFail("Unsupported file", "Supported formats are " + printAccepted(), "INFO", "alert-error");
}
}
}
};
this.initForImages = function (container) {
var dropbox = window.document.getElementById(container);
if (dropbox !== null) {
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", showTitleDialog, false);
}
};
function handleFile(file) {
$("#progressContainer").attr("class", "progress");
var xhr = new window.XMLHttpRequest();
xhr.open("POST", self.url, true);
xhr.onerror = function () {
onFail("Upload failed", "", "INFO", "alert-error");
onFail("Upload failed", this.responseText, "DEBUG", "alert-error");
};
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
onSuccess("Done", "Upload finished", "INFO", "alert-success", file.name, xhr.responseText);
} else {
onFail("Upload failed", "", "INFO", "alert-error");
onFail("Upload failed", this.responseText + ":" + this.status, "DEBUG", "alert-error");
}
}
};
xhr.upload.addEventListener("progress", function (event) {
var loaded = (parseInt(event.loaded / event.total * 100));
$("#progressBar").css("width", loaded + "%");
}, false);
var formData = new window.FormData();
formData.append("myfile", file);
xhr.send(formData);
}
};
/**
* Logger implenetation
* @returns {Synergy.control.SynergyLogger}
*/
Synergy.control.SynergyLogger = function () {
};
Synergy.control.SynergyLogger.prototype = Object.create(Synergy.interfaces.logger);
Synergy.control.SynergyLogger.prototype.printMessage = function (title, msg, style) {
this.style = style || "alert-info";
this.title = title;
this.msg = msg.substring(0, (msg.length > 200) ? 200 : msg.length);
this.date = Date();
};
Synergy.control.SynergyLogger.prototype.showMsg = function (title, msg, style) {
this.style = style || "alert-info";
this.title = title;
this.msg = msg;
this.print = true;
};
Synergy.control.SynergyLogger.prototype.log = function (title, msg, level, style) {
if (window.console && window.console.log) {
window.console.log(title + ": " + msg);
}
if (this.level[level] >= this.printLevel) {
this.print = true;
this.printMessage(title, msg, style);
}
};
/**
* Logs only to console, never to UI
*/
Synergy.control.SynergyLogger.prototype.logHTTPError = function (data, status, headers, config) {
window.console.error("Action failed >> ");
if (data && data.length > 0) {
window.console.error(data);
}
window.console.error("HTTP Status code: " + status);
window.console.error(config);
window.console.error(" <<");
};
Synergy.control.SynergyLogger.prototype.error = function (title, msg, level, style) {
if (window.console && window.console.error) {
window.console.error(title + ": " + msg);
}
if (this.level[level] >= this.printLevel) {
this.print = true;
this.printMessage(title, msg, style);
}
};
/**
* Observer implementation
* @returns {Synergy.control.SynergyObserver}
*/
Synergy.control.SynergyObserver = function () {
};
Synergy.control.SynergyObserver.prototype = Object.create(Synergy.interfaces.observer);
Synergy.control.SynergyObserver.prototype.subscribe = function (callback, event) {
event = event || "any";
if (typeof this.listeners[event] === "undefined") {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
};
Synergy.control.SynergyObserver.prototype.publish = function (data, $scope, event) {
event = event || "any";
var subs = this.listeners[event] || [];
for (var i = 0, max = subs.length; i < max; i += 1) {
subs[i]($scope, data, event);
}
};
Synergy.control.SynergyObserver.prototype.unsubscribe = function (fn, event) {
event = event || "any";
var subs = this.listeners[event] || [];
for (var i = 0, max = subs.length; i < max; i += 1) {
if (subs[i] === fn) {
subs.splice(i, 1);
}
}
};
/**
* Server implementation
* @param {type} endpoints
* @returns {SynergyServer}
*/
Synergy.control.SynergyServer = function (endpoints) {
var self = this;
this.endpoints = endpoints;
this.patterns = {
"php": function (endpoint, parameters) {
var url = "";
for (var parameter in parameters) {
if (parameters.hasOwnProperty(parameter)) {
try {
url += "&" + parameter + "=" + encodeURIComponent(parameters[parameter]);
} catch (e) {
window.console.error(e);
}
}
}
return (url.length > 1) ? self.endpoints[endpoint] + "?" + url : self.endpoints[endpoint];
}
};
};
Synergy.control.SynergyServer.prototype = Object.create(Synergy.interfaces.server);
Synergy.control.SynergyServer.prototype.preferredPattern = "php";
/**
*
* @param {String} key to find URL by in Synergy.control.SynergyServer().endpoints
* @param {Object} parameters object with all parameters
*/
Synergy.control.SynergyServer.prototype.buildURL = function (endpoint, parameters) {
return this.patterns[this.preferredPattern].call(undefined, endpoint, parameters);
};
/**
* @class text
* @param {type} allData
* @returns {undefined}
*/
Synergy.control.ArchiveDataFilter = function (allData) {
var filteredAssignments = {};
this.allData = allData;
this.allData.testRun = SynergyUtils.shallowClone(allData.testRun);
this.allData.testRun.membersCount = 0;
this.allData.testRun.completed = 0;
this.allData.testRun.total = 0;
var allIssues = SynergyUtils.shallowCloneArray(allData.issues);
this.allData.issues = [];
var self = this;
/**
* Filters data to contain only assignments where last updated is between given timestamps
* @param {Number} start timestamp
* @param {Number} stop timestamp
*/
this.getData = function (start, stop) {
var _user;
var _lu;
for (var key in this.allData.assigneesOverview) {
if (this.allData.assigneesOverview.hasOwnProperty(key)) {
_user = this.allData.assigneesOverview[key];
for (var i = 0, max = _user.assignments.length; i < max; i++) {
if (_user.assignments[i].hasOwnProperty("lastUpdated")) {
_lu = lastUpdatedToTimestamp(_user.assignments[i].lastUpdated);
if (_lu >= start && _lu <= stop) {
addAssignment(_user, _user.assignments[i], key);
}
}
}
}
}
var _reviews = [];
for (var ii = 0, maxx = this.allData.reviews.length; ii < maxx; ii++) {
if (this.allData.reviews[ii].hasOwnProperty("lastUpdated")) {
_lu = lastUpdatedToTimestamp(this.allData.reviews[ii].lastUpdated);
if (_lu >= start && _lu <= stop) {
_reviews.push(this.allData.reviews[ii]);
}
}
}
this.allData.reviews = _reviews;
this.allData.assigneesOverview = filteredAssignments;
return this.allData;
};
function addAssignment(user, assignment, username) {
if (!filteredAssignments.hasOwnProperty(username)) {
filteredAssignments[username] = {
name: user.name,
tribes: [],
assignments: []
};
for (var i = 0, max = user.tribes.length; i < max; i++) {
filteredAssignments[username].tribes[i] = SynergyUtils.shallowClone(user.tribes[i]);
}
self.allData.testRun.membersCount++;
}
self.allData.testRun.total += assignment.totalCases;
self.allData.testRun.completed += assignment.completedCases;
filteredAssignments[username].assignments.push(assignment);
addAssignmentIssue(assignment);
}
function addAssignmentIssue(assignment) {
if (assignment.issues.length < 1) {
return;
}
var _id;
var matchingIssue;
var matchingFullIssue;
var filterA = function (e) {
return e.bugId === _id;
};
for (var i = 0, max = assignment.issues.length; i < max; i++) {
_id = parseInt(assignment.issues[i], 10);
matchingIssue = self.allData.issues.filter(filterA);
if (matchingIssue.length < 1) {
matchingFullIssue = allIssues.filter(filterA);
if (matchingFullIssue.length > 0) {
self.allData.issues.push(matchingFullIssue[0]);
}
}
}
}
function lastUpdatedToTimestamp(d) {
if (d.length < 1) {
return -1;
}
try {
var _d = new Date();
var _split = d.split(" "); //17 Feb 2014 09:39:24 UTC
_d.setUTCFullYear(parseInt(_split[2], 10));
_d.setUTCMonth(SynergyUtils.monthsNames.shortName.indexOf(_split[1]));
_d.setUTCDate(parseInt(_split[0], 10));
var _split2 = _split[3].split(":");
_d.setUTCHours(parseInt(_split2[0], 10));
_d.setUTCMinutes(parseInt(_split2[1], 10));
_d.setUTCSeconds(parseInt(_split2[2], 10));
return _d.getTime();
} catch (e) {
return -1;
}
}
};
return Synergy.control;
}])
.factory("SynergyIssue", [function () {
var Issue = {};
/**
* @class RunIssuesCollector
* @returns {RunIssuesCollector}
*/
Issue.RunIssuesCollector = function () {
this.issuesStats = {
total: 0,
opened: 0,
P1: 0,
P2: 0,
P3: 0,
P4: 0,
unknown: 0,
P1Issues: [],
P2Issues: [],
P3Issues: [],
P4Issues: [],
unknownIssues: [],
unresolvedIssues: []
};
this.issues = {};
this.addIssue = function (issue) {
if (!this.issues[issue.bugId + "_"]) {
this.issuesStats.total++;
this.issuesStats[issue.priority]++;
if (issue.status.toLowerCase() !== "resolved" && issue.status.toLowerCase() !== "closed" && issue.status.toLowerCase() !== "verified" && issue.status.toLowerCase() !== "unknown") {
this.issuesStats.opened++;
this.issuesStats.unresolvedIssues.push(issue);
}
this.issues[issue.bugId + "_"] = issue;
this.issuesStats[issue.priority + "Issues"].push(issue);
}
};
this.addIssues = function (bugs) {
for (var i = 0, max = bugs.length; i < max; i++) {
this.addIssue(bugs[i]);
}
};
};
return Issue;
}]).factory("TestRunCoverageHandler", ["VersionHandler", function (versionHandler) {
function TestRunCoverageHandler() {}
TestRunCoverageHandler.prototype.getLatestMatchingSpecification = function (specificationContainer, selectedVersions, platforms) {
var maxIndex = -1;
var _val;
// get latest version
var allMatchingIds = []; // all ids across all versions
var allMatchingVersions = []; // all versions across all versions
var matching = []; // all versions across all versions
for (var j = 0, maxj = selectedVersions.length; j < maxj; j++) { // go over versions; latest first
for (var i = 0, max = specificationContainer.specifications.length; i < max; i++) { // This will as a side effect also filter out all specifications that don't exists in selected version
_val = versionHandler.getVersionFloatValue(specificationContainer.specifications[i].version);
if (_val === selectedVersions[j].floatValue && specificationContainer.specifications[i].id !== -1) {
// selectedVersions are ordered decreasingly so first matched version is the latest version
maxIndex = i;
break;
}
}
// so that if we found specification with given version, no need to
// conttinue looking. This will as a side effect also filter out
// all specifications that don't exists in selected version
if (maxIndex !== -1) {
break;
}
}
if (maxIndex === -1) {
return null;
} else {
// need to get all possible versions of given assignment so that
// if there are 2 assigmnets for the "same specification" but different
// version (e.g. 8.0 and 7.4), we can use both assigments to get coverage numbers
specificationContainer.specifications.forEach(function (s) {
if (s.id !== -1) { // if specification ID is !== -1, it means given spec exists for given version
allMatchingIds.push(s.id);
allMatchingVersions.push(s.version);
matching.push({
specificationId: s.id,
version: s.version
});
}
});
return {
id: specificationContainer.specifications[maxIndex].id,
isVisible: true,
title: specificationContainer.title,
version: specificationContainer.specifications[maxIndex].version,
coverage: generateResults(platforms),
matchingIds: allMatchingIds,
matchingVersions: allMatchingVersions,
matching: matching
};
}
};
/**
* Sets data for specification row for each platform
*/
TestRunCoverageHandler.prototype.collectSpecificationsTotalsPerPlatform = function (specifications, assignments, platforms, selectedVersions) {
var platformsMap = platformArrayToObj(platforms);
var foundInfo;
for (var i = 0, max = specifications.length; i < max; i++) {// go over all specifications to find matching assignments
for (var j = 0, maxj = assignments.length; j < maxj; j++) {
if (specifications[i].isVisible && platformsMap[assignments[j].platform].isVisible) { // increase coverage in given platform by matching assignment
foundInfo = getMatchingInfo(assignments[j].specificationId, specifications[i].matching);
if (foundInfo !== null && isAssigmentForAnyVersion(foundInfo.version, selectedVersions)) {
specifications[i].coverage[assignments[j].platform].totalCases += assignments[j].total;
specifications[i].coverage[assignments[j].platform].finishedCases += assignments[j].completed;
}
}
}
}
return specifications;
};
function getMatchingInfo(specificationId, matchingSpecs) {
for (var i = 0, max = matchingSpecs.length; i < max; i++) {
if (matchingSpecs[i].specificationId === specificationId) {
return matchingSpecs[i];
}
}
return null;
}
/**
* To avoid if you select e.g. version 2 in code coverage, it will show also
* test assignments against version 1
*/
function isAssigmentForAnyVersion(assignmentVersion, selectedVersions) {
for (var i = 0, max = selectedVersions.length; i < max; i++) {
if (selectedVersions[i].name === assignmentVersion) {
return true;
}
}
return false;
}
/**
* Sets data for total value for each specification accross all platforms
*/
TestRunCoverageHandler.prototype.getSpecificationTotalAcrossPlatforms = function (specifications, platforms) {
var results = [];
var totalCases = 0;
var finishedCases = 0;
for (var i = 0, max = specifications.length; i < max; i++) {
totalCases = 0;
finishedCases = 0;
for (var j = 0, maxj = platforms.length; j < maxj; j++) {
if (platforms[j].isVisible && specifications[i].isVisible) {
totalCases += specifications[i].coverage[platforms[j].name].totalCases;
finishedCases += specifications[i].coverage[platforms[j].name].finishedCases;
}
}
results.push({totalCases: totalCases, finishedCases: finishedCases});
}
return results;
};
TestRunCoverageHandler.prototype.resetColumn = function (specifications, platforms) {
for (var i = 0, max = specifications.length; i < max; i++) {// go over all specifications to find matching assignments
specifications[i].total.totalCases = 0;
specifications[i].total.finishedCases = 0;
for (var j = 0, maxj = platforms.length; j < maxj; j++) {
specifications[i].coverage[platforms[j].name].totalCases = 0;
specifications[i].coverage[platforms[j].name].finishedCases = 0;
}
}
return specifications;
};
/**
* Returns data for Total row in table (last row)
*/
TestRunCoverageHandler.prototype.getTotalRow = function (specifications, platforms) {
var results = generateResults(platforms);
for (var i = 0, max = specifications.length; i < max; i++) {
for (var j = 0, maxj = platforms.length; j < maxj; j++) {
if (specifications[i].coverage.hasOwnProperty(platforms[j].name) &&
specifications[i].isVisible &&
platforms[j].isVisible) {
results[platforms[j].name].totalCases += specifications[i].coverage[platforms[j].name].totalCases;
results[platforms[j].name].finishedCases += specifications[i].coverage[platforms[j].name].finishedCases;
}
}
}
return results;
};
/**
* Returns data for total cell (all specs in all platforms)
*/
TestRunCoverageHandler.prototype.getTotals = function (specifications, platforms) {
var totals = {
totalCases: 0,
finishedCases: 0
};
for (var i = 0, max = specifications.length; i < max; i++) {
for (var j = 0, maxj = platforms.length; j < maxj; j++) {
if (platforms[j].isVisible && specifications[i].isVisible) {
totals.totalCases += specifications[i].coverage[platforms[j].name].totalCases;
totals.finishedCases += specifications[i].coverage[platforms[j].name].finishedCases;
}
}
}
return totals;
};
/**
*
* @param {type} specifications
* @param {type} specificationSizeCache cache to check if given spec's size is already known
* @returns {Object} object with array property called "ids" and array contains spec IDs
*/
TestRunCoverageHandler.prototype.getEmptySpecifications = function (specifications, specificationSizeCache) {
var obj = {
ids: []
};
for (var i = 0, max = specifications.length; i < max; i++) {
for (var platform in specifications[i].coverage) {
if (specifications[i].coverage.hasOwnProperty(platform) &&
specifications[i].coverage[platform].totalCases === 0 &&
!specificationSizeCache.hasOwnProperty(specifications[i].id + "") &&
obj.ids.indexOf(specifications[i].id) < 0) {
obj.ids.push(specifications[i].id);
}
}
}
return obj;
};
TestRunCoverageHandler.prototype.addCaseCounts = function (specifications, sizeMap) {
for (var i = 0, max = specifications.length; i < max; i++) {
for (var platform in specifications[i].coverage) {
if (specifications[i].coverage.hasOwnProperty(platform) &&
specifications[i].coverage[platform].totalCases === 0) {
specifications[i].coverage[platform].totalCases += sizeMap[specifications[i].id];
}
}
}
return specifications;
};
function platformArrayToObj(platforms) {
var obj = {};
for (var i = 0, max = platforms.length; i < max; i++) {
obj[platforms[i].name] = platforms[i];
}
return obj;
}
function generateResults(platforms) {
var o = {};
for (var i = 0, max = platforms.length; i < max; i++) {
o[platforms[i].name] = {
totalCases: 0,
finishedCases: 0
};
}
return o;
}
return new TestRunCoverageHandler();
}]).factory("VersionHandler", [function () {
function VersionHandler() {}
var VERSION_PATTERN = /(^\d+\.)(.*)/;
VersionHandler.prototype.getVersionFloatValue = function (version) {
var result = VERSION_PATTERN.exec(version);
if (result !== null && result.length >= 3) {
var end = result[2].replace(/\./g, "");
return parseFloat(result[1] + end);
} else {
return parseFloat(version);
}
};
return new VersionHandler();
}]);