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/12 12:37:35 UTC

[ignite-teamcity-bot] branch master updated (f7fc6d3 -> a7c61fe)

This is an automated email from the ASF dual-hosted git repository.

dpavlov pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git.


    from f7fc6d3  Usages of change and change list cache were removed, interface usage for compactor
     new 2f56573  IGNITE-10153 Implement tests running time report - Fixes #64.
     new a7c61fe  Scripts update, page titles added

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |  3 +
 .../ignite/ci/tcbot/chain/BuildChainProcessor.java | 84 +++++++++++++++++++++-
 .../tcbot/chain/TrackedBranchChainsProcessor.java  | 49 ++++++++++++-
 .../ignited/fatbuild/FatBuildCompacted.java        |  4 ++
 .../long_running/FullLRTestsSummary.java}          | 19 ++---
 .../model/long_running/LRTest.java}                | 20 ++++--
 .../long_running/SuiteLRTestsSummary.java}         | 25 +++++--
 .../long_running/BuildsLongRunningTestsReport.java | 56 +++++++++++++++
 .../src/main/webapp/js/common-1.6.js               | 40 +++++++++--
 .../src/main/webapp/js/long_running-1.0.js         | 42 +++++++++++
 .../src/main/webapp/js/testfails-2.1.js            | 31 ++------
 .../src/main/webapp/longRunningTestsReport.html    | 51 +++++++++++++
 12 files changed, 366 insertions(+), 58 deletions(-)
 copy ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/{rest/monitoring/CacheMetricsUi.java => model/long_running/FullLRTestsSummary.java} (71%)
 copy ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/{issue/ProblemRef.java => web/model/long_running/LRTest.java} (67%)
 copy ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/{rest/monitoring/CacheMetricsUi.java => model/long_running/SuiteLRTestsSummary.java} (63%)
 create mode 100644 ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/long_running/BuildsLongRunningTestsReport.java
 create mode 100644 ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
 create mode 100644 ignite-tc-helper-web/src/main/webapp/longRunningTestsReport.html


[ignite-teamcity-bot] 02/02: Scripts update, page titles added

Posted by dp...@apache.org.
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

commit a7c61fe8529ffc3406b4f062cb2545e0a27f94c6
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Mon Nov 12 15:37:24 2018 +0300

    Scripts update, page titles added
---
 ignite-tc-helper-web/src/main/webapp/js/common-1.6.js      | 14 +++++++-------
 .../src/main/webapp/js/long_running-1.0.js                 | 10 +++++-----
 ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js   |  4 ++--
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
index 8fab111..97149be 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
@@ -130,13 +130,13 @@ function showMenu(menuData) {
     } else {
         res += "<div class=\"navbar\">";
         res += "<a href=\"/\">Home</a>";
-        res += "<a href=\"/prs.html\">PR/Branch check</a>";
-        res += "<a href=\"/guard.html\">Test status</a>";
-        res += "<a href=\"/comparison.html\">Master Trends</a>";
-        res += "<a href=\"/compare.html\">Compare builds</a>";
-        res += "<a href=\"/issues.html\">Issues history</a>";
-        //uncomment when Visa history is merged:
-        res += "<a href=\"/visas.html\">Visas history</a>";
+        res += "<a href=\"/prs.html\" title='PR or branch check'>PR Check</a>";
+        res += "<a href=\"/guard.html\" title='Monitoring: Current test failures in tracked Branches'>Test Status</a>";
+        res += "<a href=\"/comparison.html\" title='Monitoring: Test failures trends and graphs'>Master Trends</a>";
+        res += "<a href=\"/longRunningTestsReport.html\" title='Monitoring: Long running tests report''>Test Durations</a>";
+        res += "<a href=\"/compare.html\" title='Compare builds tests test'>Compare builds</a>";
+        res += "<a href=\"/issues.html\" title='Detected issues list'>Issues history</a>";
+        res += "<a href=\"/visas.html\" title='Issued TC Bot Visa history'>Visas history</a>";
 
 
         res += "<div class='topnav-right'>";
diff --git a/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js b/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
index 635abc8..925fb02 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
@@ -1,5 +1,5 @@
 function showLongRunningTestsSummary(result) {
-    var res = "<table>"
+    var res = "<table>";
 
     for (var i = 0; i < result.suiteSummaries.length; i++) {
         var summary = result.suiteSummaries[i];
@@ -7,8 +7,8 @@ function showLongRunningTestsSummary(result) {
         res += "<tr>";
 
         res += "<td>";
-        res += "<span>" + summary.name + "</span>"
-        res += "<span> [avg test duration: " + summary.testAvgTimePrintable + "] </span>"
+        res += "<span>" + summary.name + "</span>";
+        res += "<span> [avg test duration: " + summary.testAvgTimePrintable + "] </span>";
 
         res += "<span class='container'>";
         res += " <a href='javascript:void(0);' class='header'>" + more + "</a>";
@@ -28,7 +28,7 @@ function showLongRunningTestsSummary(result) {
 }
 
 function convertLRTestsList(tests) {
-    var res = "<table>"
+    var res = "<table>";
     for (var i = 0; i < tests.length; i++) {
         res += "<tr>";
         res += "<td>" + tests[i].name;
@@ -36,7 +36,7 @@ function convertLRTestsList(tests) {
         res += tests[i].timePrintable;
         res += "</td></tr>";
     }
-    res += "</table>"
+    res += "</table>";
 
     return res;
 }
diff --git a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
index e74dded..e31fa3d 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
@@ -102,9 +102,9 @@ function showChainCurrentStatusData(server, settings) {
     res += "] ";
     res += "[";
     res += "<a href='longRunningTestsReport.html'>";
-    res += "long running tests report"
+    res += "long running tests report";
     res += "</a>";
-    res += "]"
+    res += "]";
     res += "</b>";
 
     var mInfo = "";


[ignite-teamcity-bot] 01/02: IGNITE-10153 Implement tests running time report - Fixes #64.

Posted by dp...@apache.org.
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

commit 2f565739048b54c33f1015a2bc5c5f9696e25950
Author: Sergey Chugunov <se...@gmail.com>
AuthorDate: Mon Nov 12 15:34:00 2018 +0300

    IGNITE-10153 Implement tests running time report - Fixes #64.
    
    Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
 .gitignore                                         |  3 +
 .../ignite/ci/tcbot/chain/BuildChainProcessor.java | 84 +++++++++++++++++++++-
 .../tcbot/chain/TrackedBranchChainsProcessor.java  | 49 ++++++++++++-
 .../ignited/fatbuild/FatBuildCompacted.java        |  4 ++
 .../web/model/long_running/FullLRTestsSummary.java | 32 +++++++++
 .../ignite/ci/web/model/long_running/LRTest.java   | 39 ++++++++++
 .../model/long_running/SuiteLRTestsSummary.java    | 42 +++++++++++
 .../long_running/BuildsLongRunningTestsReport.java | 56 +++++++++++++++
 .../src/main/webapp/js/common-1.6.js               | 26 +++++++
 .../src/main/webapp/js/long_running-1.0.js         | 42 +++++++++++
 .../src/main/webapp/js/testfails-2.1.js            | 33 ++-------
 .../src/main/webapp/longRunningTestsReport.html    | 51 +++++++++++++
 12 files changed, 431 insertions(+), 30 deletions(-)

diff --git a/.gitignore b/.gitignore
index 73dc836..fa67cf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,9 @@
 .idea/
 *.iml
 
+# gradle build files
+.gradle/
+
 # Package Files #
 *.jar
 *.war
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
index 325fffc..06d181d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ci.tcbot.chain;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
@@ -50,6 +51,8 @@ import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.util.FutureUtil;
 import org.apache.ignite.ci.web.TcUpdatePool;
+import org.apache.ignite.ci.web.model.long_running.LRTest;
+import org.apache.ignite.ci.web.model.long_running.SuiteLRTestsSummary;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -69,6 +72,85 @@ public class BuildChainProcessor {
     @Inject private IStringCompactor compactor;
 
     /**
+     * Collects data about all long-running tests (run time more than one minute) across all suites in RunAll chain
+     * in master branch.
+     *
+     * @param teamcityIgnited interface to TC bot database.
+     * @param entryPoints
+     * @return list of summaries about individual suite runs.
+     */
+    public List<SuiteLRTestsSummary> loadLongRunningTestsSummary(
+        ITeamcityIgnited teamcityIgnited,
+        Collection<BuildRef> entryPoints
+    ) {
+        final List<SuiteLRTestsSummary> res = new ArrayList<>();
+
+        if (entryPoints.isEmpty())
+            return res;
+
+        Map<Integer, FatBuildCompacted> builds = new ConcurrentHashMap<>();
+
+        final Stream<FatBuildCompacted> entryPointsFatBuilds = entryPoints.stream().map(BuildRef::getId)
+            .filter(Objects::nonNull)
+            .filter(id -> !builds.containsKey(id)) //load and propagate only new entry points
+            .map(id -> builds.computeIfAbsent(id, teamcityIgnited::getFatBuild));
+
+        final ExecutorService svc = tcUpdatePool.getService();
+
+        final Stream<FatBuildCompacted> depsFirstLevel = entryPointsFatBuilds
+            .map(ref -> svc.submit(() -> dependencies(teamcityIgnited, builds, ref)))
+            .collect(Collectors.toList())
+            .stream()
+            .flatMap(fut -> FutureUtil.getResult(fut));
+
+        depsFirstLevel
+            .filter(b -> !b.isComposite() && b.getTestsCount() > 0)
+            .forEach(b ->
+            {
+                List<LRTest> lrTests = new ArrayList<>();
+
+                b.getAllTests()
+                    .filter(t -> t.getDuration() > 60 * 1000)
+                    .forEach(
+                        t -> lrTests
+                            .add(new LRTest(t.testName(compactor), t.getDuration(), null))
+                    );
+
+                if (!lrTests.isEmpty()) {
+                    Collections.sort(lrTests, (test0, test1) -> {
+                        long t0 = test0.time;
+                        long t1 = test1.time;
+
+                        if (t0 < t1)
+                            return 1;
+
+                        if (t0 == t1)
+                            return 0;
+
+                        return -1;
+                    });
+
+                    res.add(
+                        new SuiteLRTestsSummary(b.buildTypeName(compactor),
+                            b.buildDuration(compactor) / b.getTestsCount(),
+                            lrTests));
+                }
+            });
+
+        Collections.sort(res, (s0, s1) -> {
+            if (s0.testAvgTime < s1.testAvgTime)
+                return 1;
+
+            if (s0.testAvgTime == s1.testAvgTime)
+                return 0;
+
+            return -1;
+        });
+
+        return res;
+    }
+
+    /**
      * @param teamcity Teamcity.
      * @param teamcityIgnited
      * @param entryPoints Entry points.
@@ -111,7 +193,7 @@ public class BuildChainProcessor {
                 .stream()
                 .flatMap(fut -> FutureUtil.getResult(fut));
 
-        // builds may became non unique because of rece in filtering and acquiring deps
+        // builds may became non unique because of race in filtering and acquiring deps
         final List<Future<Stream<FatBuildCompacted>>> phase3Submitted = secondLevelDeps
                 .map((fatBuild) -> svc.submit(
                         () -> replaceWithRecent(teamcityIgnited, includeLatestRebuild, builds, fatBuild, entryPoints.size())))
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/TrackedBranchChainsProcessor.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/TrackedBranchChainsProcessor.java
index 2d61c43..5385273 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/TrackedBranchChainsProcessor.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/TrackedBranchChainsProcessor.java
@@ -23,18 +23,19 @@ import java.util.stream.Collectors;
 import javax.inject.Inject;
 import org.apache.ignite.ci.HelperConfig;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
-import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
-import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
-import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
 import org.apache.ignite.ci.analysis.mode.LatestRebuildMode;
 import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
 import org.apache.ignite.ci.conf.BranchTracked;
 import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
+import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
 import org.apache.ignite.ci.user.ICredentialsProv;
 import org.apache.ignite.ci.web.model.current.ChainAtServerCurrentStatus;
 import org.apache.ignite.ci.web.model.current.TestFailuresSummary;
+import org.apache.ignite.ci.web.model.long_running.FullLRTestsSummary;
 import org.apache.ignite.ci.web.rest.parms.FullQueryParams;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -124,4 +125,46 @@ public class TrackedBranchChainsProcessor {
 
         return res;
     }
+
+    /**
+     * Collects data about all long-running tests (run time more than one minute) within one transfer object.
+     *
+     * @param branch
+     * @param creds
+     * @return
+     */
+    public FullLRTestsSummary getTrackedBranchLongRunningTestsSummary(@Nullable String branch,
+        ICredentialsProv creds) {
+        FullLRTestsSummary summary = new FullLRTestsSummary();
+
+        final String branchNn = isNullOrEmpty(branch) ? FullQueryParams.DEFAULT_TRACKED_BRANCH_NAME : branch;
+        final BranchTracked tracked = HelperConfig.getTrackedBranches().getBranchMandatory(branchNn);
+
+        tracked.chains.stream()
+            .filter(chainTracked -> creds.hasAccess(chainTracked.serverId))
+            .map(chainTracked -> {
+                final String srvId = chainTracked.serverId;
+
+                final String branchForTc = chainTracked.getBranchForRestMandatory();
+
+                IAnalyticsEnabledTeamcity teamcity = srvProv.server(srvId, creds);
+
+                ITeamcityIgnited tcIgnited = tcIgnitedProv.server(srvId, creds);
+
+                final List<BuildRef> buildsList = teamcity.getFinishedBuildsIncludeSnDepFailed(
+                    chainTracked.getSuiteIdMandatory(),
+                    branchForTc);
+
+                List<BuildRef> chains = buildsList.stream()
+                    .filter(ref -> !ref.isFakeStub())
+                    .sorted(Comparator.comparing(BuildRef::getId).reversed())
+                    .limit(1)
+                    .filter(b -> b.getId() != null).collect(Collectors.toList());
+
+                return chainProc.loadLongRunningTestsSummary(tcIgnited, chains);
+            })
+            .forEach(summary::addSuiteSummaries);
+
+        return summary;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
index 2426d92..9c07e63 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
@@ -355,6 +355,10 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
         return tests.stream();
     }
 
+    public int getTestsCount() {
+        return tests != null ? tests.size() : 0;
+    }
+
     public Stream<String> getAllTestNames(IStringCompactor compactor) {
         return getAllTests().map(t -> t.testName(compactor));
     }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/FullLRTestsSummary.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/FullLRTestsSummary.java
new file mode 100644
index 0000000..b71a77e
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/FullLRTestsSummary.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.ignite.ci.web.model.long_running;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+@SuppressWarnings("WeakerAccess")
+public class FullLRTestsSummary {
+    public List<SuiteLRTestsSummary> suiteSummaries = new ArrayList<>();
+
+    public void addSuiteSummaries(List<SuiteLRTestsSummary> summaries) {
+        suiteSummaries.addAll(summaries);
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/LRTest.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/LRTest.java
new file mode 100644
index 0000000..e1f57e0
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/LRTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.ignite.ci.web.model.long_running;
+
+import static org.apache.ignite.ci.util.TimeUtil.millisToDurationPrintable;
+
+/**
+ *
+ */
+public class LRTest {
+    public String name;
+
+    public long time;
+
+    public String timePrintable;
+
+    public String webLink;
+
+    public LRTest(String name, long time, String webLink) {
+        this.name = name;
+        this.time = time;
+        timePrintable = millisToDurationPrintable(time);
+        this.webLink = webLink;
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/SuiteLRTestsSummary.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/SuiteLRTestsSummary.java
new file mode 100644
index 0000000..2ae2b0c
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/long_running/SuiteLRTestsSummary.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.ignite.ci.web.model.long_running;
+
+import java.util.List;
+
+import static org.apache.ignite.ci.util.TimeUtil.millisToDurationPrintable;
+
+/**
+ *
+ */
+@SuppressWarnings("WeakerAccess")
+public class SuiteLRTestsSummary {
+    public String name;
+
+    public long testAvgTime;
+
+    public String testAvgTimePrintable;
+
+    public List<LRTest> tests;
+
+    public SuiteLRTestsSummary(String name, long testAvgTime, List<LRTest> tests) {
+        this.name = name;
+        this.testAvgTime = testAvgTime;
+        testAvgTimePrintable = millisToDurationPrintable(testAvgTime);
+        this.tests = tests;
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/long_running/BuildsLongRunningTestsReport.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/long_running/BuildsLongRunningTestsReport.java
new file mode 100644
index 0000000..42d29f9
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/long_running/BuildsLongRunningTestsReport.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.ignite.ci.web.rest.long_running;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import org.apache.ignite.ci.tcbot.chain.TrackedBranchChainsProcessor;
+import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.web.CtxListener;
+import org.apache.ignite.ci.web.model.long_running.FullLRTestsSummary;
+import org.jetbrains.annotations.Nullable;
+
+@Path(BuildsLongRunningTestsReport.LONG_RUNNING_SUMMARY)
+@Produces(MediaType.APPLICATION_JSON)
+public class BuildsLongRunningTestsReport {
+    public static final String LONG_RUNNING_SUMMARY = "long_running";
+
+    /** Servlet Context. */
+    @Context
+    private ServletContext ctx;
+
+    /** Current Request. */
+    @Context
+    private HttpServletRequest req;
+
+    @GET
+    @Path("summary")
+    @Produces(MediaType.APPLICATION_JSON)
+    public FullLRTestsSummary getBranch(@Nullable @QueryParam("branch") String branchOrNull) {
+        final ICredentialsProv creds = ICredentialsProv.get(req);
+
+        final TrackedBranchChainsProcessor tbProc = CtxListener.getInjector(ctx).getInstance(TrackedBranchChainsProcessor.class);
+
+        return tbProc.getTrackedBranchLongRunningTestsSummary(null, creds);
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
index 3b5a72c..8fab111 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
@@ -1,3 +1,6 @@
+var more = "<button class='more white short'><i class='fas fa-caret-down'></i></button>";
+var less = "<button class='more white short'><i class='fas fa-caret-up'></i></button>";
+
 function isDefinedAndFilled(val) {
     return typeof val !== 'undefined' && val != null
 }
@@ -313,3 +316,26 @@ function tryToFillAutocompleteLists() {
         }
     }
 }
+
+/**
+* Inits "More/Hide" UI element allowing to show/hide blocks of additional info.
+*/
+function initMoreInfo() {
+    var header = $(".header");
+
+    header.unbind("click");
+    header.click(function() {
+        $header = $(this);
+        //getting the next element
+        $content = $header.next();
+        //open up the content needed, toggle the slide: slide up if visible, slide down if not.
+        $content.slideToggle(500, function() {
+            //execute this after slideToggle is done
+            //change text of header based on visibility of content div
+            $header.html(function() {
+                //change text based on condition
+                return $content.is(":visible") ? less : more;
+            });
+        });
+    });
+}
diff --git a/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js b/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
new file mode 100644
index 0000000..635abc8
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/webapp/js/long_running-1.0.js
@@ -0,0 +1,42 @@
+function showLongRunningTestsSummary(result) {
+    var res = "<table>"
+
+    for (var i = 0; i < result.suiteSummaries.length; i++) {
+        var summary = result.suiteSummaries[i];
+
+        res += "<tr>";
+
+        res += "<td>";
+        res += "<span>" + summary.name + "</span>"
+        res += "<span> [avg test duration: " + summary.testAvgTimePrintable + "] </span>"
+
+        res += "<span class='container'>";
+        res += " <a href='javascript:void(0);' class='header'>" + more + "</a>";
+        res += "<div class='content'>";
+        res += convertLRTestsList(summary.tests);
+        res += "</div>";
+        res += "</span>";
+
+        res += "</td></tr>";
+
+        res += "<tr><td>&nbsp;</td></tr>";
+    }
+
+    setTimeout(initMoreInfo, 100);
+
+    return res + "</table>";
+}
+
+function convertLRTestsList(tests) {
+    var res = "<table>"
+    for (var i = 0; i < tests.length; i++) {
+        res += "<tr>";
+        res += "<td>" + tests[i].name;
+        res += "</td><td>";
+        res += tests[i].timePrintable;
+        res += "</td></tr>";
+    }
+    res += "</table>"
+
+    return res;
+}
diff --git a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
index 8262276..e74dded 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
@@ -3,9 +3,6 @@
 //triggerConfirm & triggerDialog element should be provided on page (may be hidden)
 var g_initMoreInfoDone = false;
 
-var more = "<button class='more white short'><i class='fas fa-caret-down'></i></button>";
-var less = "<button class='more white short'><i class='fas fa-caret-up'></i></button>";
-
 /** Object used to notify git. See ChainAtServerCurrentStatus Java class. */
 var g_srv_to_notify_git;
 
@@ -102,7 +99,12 @@ function showChainCurrentStatusData(server, settings) {
     res += " <a href='" + server.webToBuild + "' title='" + altTxt + "'>";
     res += "tests " + server.failedTests + " suites " + server.failedToFinish + "";
     res += " </a>";
-    res += "]";
+    res += "] ";
+    res += "[";
+    res += "<a href='longRunningTestsReport.html'>";
+    res += "long running tests report"
+    res += "</a>";
+    res += "]"
     res += "</b>";
 
     var mInfo = "";
@@ -974,25 +976,4 @@ function drawLatestRunsBlock(state, len) {
         runColor = "black";
 
     return "<span style='background-color: " + runColor + "; width:" + (len * 1) + "px; height:10px; display: inline-block;'></span>";
-}
-
-
-function initMoreInfo() {
-    var header = $(".header");
-
-    header.unbind("click");
-    header.click(function() {
-        $header = $(this);
-        //getting the next element
-        $content = $header.next();
-        //open up the content needed - toggle the slide- if visible, slide up, if not slidedown.
-        $content.slideToggle(500, function() {
-            //execute this after slideToggle is done
-            //change text of header based on visibility of content div
-            $header.html(function() {
-                //change text based on condition
-                return $content.is(":visible") ? less : more;
-            });
-        });
-    });
-}
+}
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/webapp/longRunningTestsReport.html b/ignite-tc-helper-web/src/main/webapp/longRunningTestsReport.html
new file mode 100644
index 0000000..3b25e22
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/webapp/longRunningTestsReport.html
@@ -0,0 +1,51 @@
+<html lang="en">
+<head>
+    <title>Apache Ignite Teamcity Bot - Long Running Tests Report</title>
+    <link rel="icon" href="img/leaf-icon-png-7066.png">
+    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
+    <link rel="stylesheet" href="css/style-1.5.css">
+
+    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
+          integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
+
+    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
+    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
+
+    <script src="js/common-1.6.js"></script>
+    <script src="js/long_running-1.0.js"></script>
+
+    <script>
+        $(document).ready(function() {
+            $.getScript("js/long_running-1.0.js", function(data, textStatus, jqxhr){ });
+
+            loadData();
+        });
+
+        function loadData() {
+            var longRunningUrl = "rest/long_running/summary?branch=master";
+
+            $("#loadStatus").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Please wait");
+
+            $.ajax({
+                url: longRunningUrl,
+
+                success: function(result) {
+                    $("#loadStatus").html("");
+
+                    showData(result);
+                },
+
+                error: showErrInLoadStatus
+            });
+        }
+
+        function showData(result) {
+            $("#divLongRunningSummary").html(showLongRunningTestsSummary(result));
+        }
+    </script>
+</head>
+<body>
+    <div id="loadStatus"></div>
+    <div id="divLongRunningSummary"></div>
+</body>
+</html>
\ No newline at end of file