You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2018/11/10 17:08:00 UTC
[ignite-teamcity-bot] branch master updated: IGNITE-10181 [Tc Bot]
Add fail-rate handling for test's page - Fixes #63.
This is an automated email from the ASF dual-hosted git repository.
dpavlov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git
The following commit(s) were added to refs/heads/master by this push:
new a52f7cd IGNITE-10181 [Tc Bot] Add fail-rate handling for test's page - Fixes #63.
a52f7cd is described below
commit a52f7cd6e5fc3248e4c291eb9974ed9b4a70656d
Author: ololo3000 <pm...@gmail.com>
AuthorDate: Sat Nov 10 20:07:51 2018 +0300
IGNITE-10181 [Tc Bot] Add fail-rate handling for test's page - Fixes #63.
Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
.../ignite/ci/web/model/hist/BuildsHistory.java | 47 ++++++-----
.../src/main/webapp/comparison.html | 95 +++++++++++++---------
.../src/main/webapp/css/style-1.5.css | 62 +++++++++++++-
3 files changed, 140 insertions(+), 64 deletions(-)
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
index e85d34c..17abef0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
@@ -73,7 +73,7 @@ public class BuildsHistory {
private Date untilDateFilter;
/** */
- private Map<String, Set<String>> mergedTestsBySuites = new ConcurrentHashMap<>();
+ private Map<String, Map<String, Float>> mergedTestsBySuites = new ConcurrentHashMap<>();
/** */
private boolean skipTests;
@@ -88,14 +88,14 @@ public class BuildsHistory {
private static final Logger logger = LoggerFactory.getLogger(BuildsHistory.class);
/** */
- public void initialize(ICredentialsProv prov, ServletContext context) {
- final IStringCompactor compactor = CtxListener.getInjector(context).getInstance(IStringCompactor.class);
+ public void initialize(ICredentialsProv prov, ServletContext ctx) {
+ final IStringCompactor compactor = CtxListener.getInjector(ctx).getInstance(IStringCompactor.class);
- ITcHelper tcHelper = CtxListener.getTcHelper(context);
+ ITcHelper tcHelper = CtxListener.getTcHelper(ctx);
ITeamcity teamcity = tcHelper.server(srvId, prov);
- ITeamcityIgnitedProvider tcIgnitedProv = CtxListener.getInjector(context)
+ ITeamcityIgnitedProvider tcIgnitedProv = CtxListener.getInjector(ctx)
.getInstance(ITeamcityIgnitedProvider.class);
ITeamcityIgnited ignitedTeamcity = tcIgnitedProv.server(srvId, prov);
@@ -118,10 +118,10 @@ public class BuildsHistory {
if (!skipTests)
initFailedTests(teamcity, validBuilds);
- ObjectMapper objectMapper = new ObjectMapper();
+ ObjectMapper objMapper = new ObjectMapper();
try {
- mergedTestsJson = objectMapper.writeValueAsString(mergedTestsBySuites);
+ mergedTestsJson = objMapper.writeValueAsString(mergedTestsBySuites);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
@@ -133,7 +133,7 @@ public class BuildsHistory {
List<Future<BuildStatisticsSummary>> buildStaticsFutures = new ArrayList<>();
for (int buildId : buildIdsWithConditions.keySet()) {
- Future<BuildStatisticsSummary> buildFuture = CompletableFuture.supplyAsync(() -> {
+ Future<BuildStatisticsSummary> buildFut = CompletableFuture.supplyAsync(() -> {
BuildStatisticsSummary buildsStatistic = new BuildStatisticsSummary(buildId);
buildsStatistic.isValid = buildIdsWithConditions.get(buildId);
buildsStatistic.initialize(compactor, ignited);
@@ -141,7 +141,7 @@ public class BuildsHistory {
return buildsStatistic;
}, teamcity.getExecutor());
- buildStaticsFutures.add(buildFuture);
+ buildStaticsFutures.add(buildFut);
}
buildStaticsFutures.forEach(new Consumer <Future<BuildStatisticsSummary>>() {
@@ -192,7 +192,7 @@ public class BuildsHistory {
List<Future<Void>> buildProcessorFutures = new ArrayList<>();
for (int buildId : buildIds) {
- Future<Void> buildFuture = CompletableFuture.supplyAsync(() -> {
+ Future<Void> buildFut = CompletableFuture.supplyAsync(() -> {
Map<Integer, String> configurations = getConfigurations(teamcity, buildId);
Build build = teamcity.getBuild(teamcity.getBuildHrefById(buildId));
@@ -206,26 +206,31 @@ public class BuildsHistory {
if(configurationName == null)
continue;
- Set<String> tests = mergedTestsBySuites.computeIfAbsent(configurationName,
- k -> new HashSet<>());
+ Map<String, Float> tests = mergedTestsBySuites.computeIfAbsent(configurationName,
+ k -> new HashMap<>());
- if (!tests.add(testOccurrence.getName()))
- continue;
+ String testName = testOccurrence.getName();
+
+ if (!tests.containsKey(testName)) {
+ tests.put(testName, 0F);
+
+ FullQueryParams key = new FullQueryParams();
- FullQueryParams key = new FullQueryParams();
+ key.setServerId(srvId);
+ key.setProjectId(projectId);
+ key.setTestName(testOccurrence.getName());
+ key.setSuiteId(configurationName);
- key.setServerId(srvId);
- key.setProjectId(projectId);
- key.setTestName(testOccurrence.getName());
- key.setSuiteId(configurationName);
+ teamcity.getTestRef(key);
+ }
- teamcity.getTestRef(key);
+ tests.put(testName, tests.get(testName) + 1F / buildIds.size());
}
return null;
}, teamcity.getExecutor());
- buildProcessorFutures.add(buildFuture);
+ buildProcessorFutures.add(buildFut);
}
buildProcessorFutures.forEach(v -> {
diff --git a/ignite-tc-helper-web/src/main/webapp/comparison.html b/ignite-tc-helper-web/src/main/webapp/comparison.html
index 4a5c37c..9d97977 100644
--- a/ignite-tc-helper-web/src/main/webapp/comparison.html
+++ b/ignite-tc-helper-web/src/main/webapp/comparison.html
@@ -152,13 +152,15 @@
<td class="total data 2" id="RunsCount2"></td>
</tr>
</table><br>
-<table style="table-layout: fixed" id="testsTable" class="testsTable">
+<table id="testsTable" class="testsTable">
<tbody>
<tr>
- <th class="failedTestsHeader" width="13%">FAILED TESTS</th>
- <th width="3%"><div class="switch-btn tests"></div></th>
- <th width="42%"></th>
- <th width="42%"></th>
+ <th class="testsTableTitleHeader">FAILED TESTS</th>
+ <th class="testsTableBtnHeader"><div class="switch-btn tests"></div></th>
+ <th class="testsTableDataHeader1"></th>
+ <th class="testsTableDataHeader2">Fail-rate treshold:
+ <input id="treshold" class="treshold" type="number" min="0" max="100" value="0" onchange="refreshTests()">%
+ </th>
</tr>
</tbody>
</table>
@@ -175,10 +177,16 @@
<div id="version"></div>
<script>
+ const FAIL_RATE_DIFF_TRESHOLD = 0.1;
+
let invalidInclude = false,
markBuildId = 0,
testsTrigger = false;
+ function refreshTests() {
+ printTests(generateTestsResultsComparison(mergedTestsResults));
+ }
+
function getDateFewWeeksAgo(numberOfWeeksAgo) {
let date = new Date();
@@ -350,7 +358,7 @@
});
}
- function mergeSuits(results) {
+ function mergeSuites(results) {
let mergedSuites = new Set();
for (let key of Object.keys(results)) {
@@ -364,19 +372,17 @@
function printTests(results) {
$(TESTS_TABLE + " tr:not(:first-child)").remove();
- let markedRow = true;
-
- for (let suite of mergeSuits(results).sort()) {
+ for (let suite of mergeSuites(results).sort()) {
let suiteName = suite.split('_').filter((value, index) => index != 0).join('_');
let testsCntCells = '';
let testsCells = '';
for (let key of Object.keys(results)) {
let obj = results[key];
- let testLength = !obj.hasOwnProperty(suite) || obj[suite].length == 0 ?
- '' : obj[suite].length;
+ let testsCnt = !obj.hasOwnProperty(suite) || Object.keys(obj[suite]).length == 0 ?
+ '' : Object.keys(obj[suite]).length;
- testsCntCells = testsCntCells + '<td class="testsCntCell"><p id="' + suite + '">' + testLength + '</p></td>';
+ testsCntCells = testsCntCells + '<td class="testsCntCell"><p id="' + suite + '">' + testsCnt + '</p></td>';
testsCells = testsCells + '<td class="testsCell">' + getSuiteTestsHtml(results, suite, key) + '</td>'
}
@@ -391,57 +397,68 @@
}
}
- function generateCompareTestsResults(results) {
- let compareTestsResults = {};
+ function generateTestsResultsComparison(results) {
+ let testsResultsComparison = {};
for (let key of Object.keys(results)) {
- let uniqueObj = {};
+ let obj = {};
for (let suite of Object.keys(results[key])) {
- let allTests = [];
+ let otherTests = {};
- for (let key2 of Object.keys(results)) {
- if (key == key2)
+ for (let otherKey of Object.keys(results)) {
+ if (key == otherKey)
continue;
- allTests = allTests.concat(results[key2][suite]);
+ otherTests = Object.assign({}, results[otherKey][suite]);
}
- let uniqTests = results[key][suite].filter(function(test) {
- return allTests.indexOf(test) == -1;
- });
+ let newFailedTests = {};
- if (uniqTests.length != 0)
- uniqueObj[suite] = uniqTests;
+ for (let testName of Object.keys(results[key][suite])) {
+ let failRate = results[key][suite][testName];
+ let otherFailRate = otherTests[testName];
+
+ if ((otherFailRate == null || failRate - otherFailRate > FAIL_RATE_DIFF_TRESHOLD)
+ && failRate > $('#treshold').val()/100)
+ newFailedTests[testName] = failRate;
+ }
+
+ if (Object.keys(newFailedTests).length != 0)
+ obj[suite] = newFailedTests;
}
- compareTestsResults[key] = uniqueObj;
+ testsResultsComparison[key] = obj;
}
- return compareTestsResults;
+ return testsResultsComparison;
}
function getSuiteTestsHtml(results, suite, key) {
- if (!results[key].hasOwnProperty(suite) || results[key][suite].length === 0)
+ if (!results[key].hasOwnProperty(suite) || Object.keys(results[key][suite]).length == 0)
return '';
- let res = '<body><div id="' + suite + key + '"style="cursor: default; margin-left: 10px;">';
+ let res = '<table class="innerTestTable">\n';
- for (let test of results[key][suite].sort()) {
- let list = test.toString().split(".");
+ for (let testName of Object.keys(results[key][suite]).sort()) {
+ let list = testName.toString().split(".");
if (list.length < 2)
- list = test.toString().split(":");
+ list = testName.toString().split(":");
- let testName = list.pop();
+ let testMethodName = list.pop();
let testClass = list.pop();
-
- res += '<p align="left" title="' + test + '">' + testClass + '.' + testName +
- '<a href="#" onclick="getTestRef(\'' + test + '\'' + ',\'' + suite + '\'); return false;">' +
- ' >></a>' + '</p>'
+ let failRate = results[key][suite][testName];
+
+ res += '<tr>' +
+ '<td class="innerTestName"><p title="' + testName + '">' + testClass + '.' + testMethodName + '</p></td>' +
+ '<td class="innerFailRate"><p title="Test\'s fail-rate for corresponding date period">' +
+ Number((failRate * 100).toFixed(1)) + '%</p></td>' +
+ '<td class="innerTcLink"><a href="#" onclick="getTestRef(\'' +
+ testName + '\',\'' + suite + '\'); return false;"> >></a></td></tr>';
}
- res += '</div></body>';
+ res += '</table>';
return res;
}
@@ -571,7 +588,7 @@
printImportantMessage(num, "#ff0000", "Invalid server response. Unable to parse JSON");
}
- printTests(generateCompareTestsResults(mergedTestsResults));
+ printTests(generateTestsResultsComparison(mergedTestsResults));
},
error: showErrInLoadStatus,
timeout: 1800000
@@ -1006,7 +1023,7 @@
updateColumn(2);
if (isDefinedAndFilled(mergedTestsResults))
- printTests(generateCompareTestsResults(mergedTestsResults));
+ printTests(generateTestsResultsComparison(mergedTestsResults));
}
function multiFormat(date) {
diff --git a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
index 7729192..13d83ed 100644
--- a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
+++ b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
@@ -313,6 +313,8 @@ form li:after
}
.testsCell {
+ padding-right: 2%;
+ padding-left: 2%;
cursor: default;
word-wrap: break-word;
vertical-align: top;
@@ -337,20 +339,72 @@ form li:after
}
.testsTable {
+ table-layout: fixed;
width: 96%;
border-collapse: collapse;
margin-left: 2%;
margin-right: 2%;
}
-.testsTable tr:nth-child(4n + 2) {
- background-color: #fafaff;
+.innerTestName {
+ width: 85%;
+ padding-right: 2%;
+ vertical-align: middle;
+ text-align: left;
}
-.failedTestsHeader {
+.innerFailRate {
+ width: 10%;
vertical-align: middle;
+ text-align: center;
+}
+
+.innerTcLink {
+ width: 5%;
+ vertical-align: middle;
+ text-align: center;
+}
+
+.testsTableBtnHeader {
+ width: 3%;
+ vertical-align: middle;
+}
+
+.testsTableDataHeader1 {
+ width: 42%;
+ vertical-align: middle;
+ text-align: center;
+}
+
+.testsTableDataHeader2 {
+ width: 42%;
+ vertical-align: middle;
+ text-align: right;
+}
+
+.treshold {
+ width: 8%;
+}
+
+.innerTestTable {
+ table-layout: fixed;
+ width: 96%;
+ border-collapse: collapse;
+ margin-left: 2%;
+ margin-right: 2%;
+}
+
+.testsTable tr.testsCntRow:nth-child(4n + 2) {
+ background-color: #fafaff;
+}
+
+.testsTableTitleHeader {
text-align: left;
- padding: 5px
+ width: 13%;
+ vertical-align: middle;
+ padding-left: 5px;
+ padding-bottom: 10px;
+ padding-top: 10px;
}
td.details-control {