You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ignite.apache.org by GitBox <gi...@apache.org> on 2018/11/10 17:08:05 UTC

[GitHub] asfgit closed pull request #63: IGNITE-10181 [Tc Bot] Add fail-rate handling for test's page

asfgit closed pull request #63: IGNITE-10181 [Tc Bot] Add fail-rate handling for test's page
URL: https://github.com/apache/ignite-teamcity-bot/pull/63
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

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 e85d34cd..17abef06 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 @@
     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 @@
     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 void initialize(ICredentialsProv prov, ServletContext context) {
         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 @@ private void initStatistics(IStringCompactor compactor, ITeamcity teamcity, ITea
         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 @@ private void initStatistics(IStringCompactor compactor, ITeamcity teamcity, ITea
                 return buildsStatistic;
             }, teamcity.getExecutor());
 
-            buildStaticsFutures.add(buildFuture);
+            buildStaticsFutures.add(buildFut);
         }
 
         buildStaticsFutures.forEach(new Consumer <Future<BuildStatisticsSummary>>() {
@@ -192,7 +192,7 @@ private void initFailedTests(ITeamcity teamcity, List<Integer> buildIds) {
         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 @@ private void initFailedTests(ITeamcity teamcity, List<Integer> buildIds) {
                     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 4a5c37c8..9d979771 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;">' +
-                ' &gt&gt</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;"> &gt&gt</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 77291923..13d83ed0 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 {


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services