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/24 18:28:38 UTC

[ignite-teamcity-bot] branch ignite-9542-new-run-stripe updated: IGNITE-9542: New Run stripe implementation: new statistic empty entries

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

dpavlov pushed a commit to branch ignite-9542-new-run-stripe
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/ignite-9542-new-run-stripe by this push:
     new 26f6c7a  IGNITE-9542: New Run stripe implementation: new statistic empty entries
26f6c7a is described below

commit 26f6c7a5326da753b5ca51cf02f40db651aec5bf
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Sat Nov 24 21:28:34 2018 +0300

    IGNITE-9542: New Run stripe implementation: new statistic empty entries
---
 ...ITestFailures.java => IMultTestOccurrence.java} |  4 +-
 .../apache/ignite/ci/analysis/MultBuildRunCtx.java |  6 +-
 .../org/apache/ignite/ci/analysis/RunStat.java     | 50 ++++------------
 .../ignite/ci/analysis/TestCompactedMult.java      |  2 +-
 .../ignite/ci/tcbot/chain/PrChainsProcessor.java   |  4 +-
 .../tcbot/chain/TrackedBranchChainsProcessor.java  |  2 +-
 .../ignite/ci/teamcity/ignited/IRunHistory.java    | 68 ++++++++++++++++++++++
 .../ci/teamcity/ignited/ITeamcityIgnited.java      |  4 ++
 .../ci/teamcity/ignited/TeamcityIgnitedImpl.java   |  7 +++
 .../{buildstat => runhist}/RunHistCompacted.java   | 51 ++++++++++++++--
 .../RunHistCompactedDao.java                       |  3 +-
 .../ignited/{buildstat => runhist}/RunHistKey.java | 33 ++++++++++-
 .../RunHistKey.java => runhist/RunHistSync.java}   | 33 +++++++++--
 .../model/current/ChainAtServerCurrentStatus.java  | 22 +++----
 .../ci/web/model/current/SuiteCurrentStatus.java   | 48 +++++++++------
 .../ignite/ci/web/model/current/TestFailure.java   | 18 +++---
 .../ignite/ci/web/model/hist/TestHistory.java      |  7 ++-
 .../ignite/ci/web/rest/GetChainResultsAsHtml.java  |  6 +-
 .../ci/web/rest/build/GetBuildTestFailures.java    | 11 ++--
 .../ci/tcbot/chain/BuildChainProcessorTest.java    |  6 +-
 .../ci/tcbot/chain/PrChainsProcessorTest.java      | 42 ++++++++++---
 .../ci/teamcity/ignited/TeamcityIgnitedMock.java   | 45 ++++++++++++++
 .../ignited/TeamcityIgnitedProviderMock.java       |  3 +-
 23 files changed, 353 insertions(+), 122 deletions(-)

diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ITestFailures.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/IMultTestOccurrence.java
similarity index 91%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ITestFailures.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/IMultTestOccurrence.java
index 7cfc21c..f903306 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ITestFailures.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/IMultTestOccurrence.java
@@ -21,9 +21,9 @@ import java.util.stream.Stream;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrenceFull;
 
 /**
- * Multiple test ocurrence
+ * Multiple test occurrence. For single build context - max 1 failure
  */
-public interface ITestFailures {
+public interface IMultTestOccurrence {
     String getName();
 
     boolean isInvestigated();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
index 2e55f62..2a942de 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
@@ -255,8 +255,8 @@ public class MultBuildRunCtx implements ISuiteResults {
         return CollectionUtil.top(logSizeBytes.entrySet().stream(), 3 ,comparing).stream();
     }
 
-    public Stream<? extends ITestFailures> getTopLongRunning() {
-        Comparator<ITestFailures> comparing = Comparator.comparing(ITestFailures::getAvgDurationMs);
+    public Stream<? extends IMultTestOccurrence> getTopLongRunning() {
+        Comparator<IMultTestOccurrence> comparing = Comparator.comparing(IMultTestOccurrence::getAvgDurationMs);
 
         Map<Integer, TestCompactedMult> res = new HashMap<>();
 
@@ -267,7 +267,7 @@ public class MultBuildRunCtx implements ISuiteResults {
         return CollectionUtil.top(res.values().stream(), 3, comparing).stream();
     }
 
-    public List<ITestFailures> getFailedTests() {
+    public List<IMultTestOccurrence> getFailedTests() {
         Map<Integer, TestCompactedMult> res = new HashMap<>();
 
         builds.forEach(singleBuildRunCtx -> {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/RunStat.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/RunStat.java
index 7bed35a..0f116ba 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/RunStat.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/RunStat.java
@@ -29,6 +29,7 @@ import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.ci.issue.EventTemplate;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrence;
+import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
 import org.jetbrains.annotations.NotNull;
 
 import static org.apache.ignite.ci.analysis.RunStat.RunStatus.RES_CRITICAL_FAILURE;
@@ -40,7 +41,7 @@ import static org.apache.ignite.ci.analysis.RunStat.RunStatus.RES_OK;
  * Test or Build run statistics.
  */
 @Persisted
-public class RunStat {
+public class RunStat implements IRunHistory {
     public static final int MAX_LATEST_RUNS = 100;
 
     /**
@@ -174,39 +175,17 @@ public class RunStat {
         return name;
     }
 
-    public float getFailRateAllHist() {
-        if (runs == 0)
-            return 1.0f;
 
-        return 1.0f * failures / runs;
-    }
 
-    public int getFailuresAllHist() {
+   @Override public int getFailuresAllHist() {
         return failures;
     }
 
-    public int getRunsAllHist() {
+   @Override public int getRunsAllHist() {
         return runs;
     }
 
-    /**
-     * @return
-     */
-    public String getFailPercentAllHistPrintable() {
-        return getPercentPrintable(getFailRateAllHist() * 100.0f);
-    }
 
-    /**
-     * @return float representing fail rate
-     */
-    public float getFailRate() {
-        int runs = getRunsCount();
-
-        if (runs == 0)
-            return 1.0f;
-
-        return 1.0f * getFailuresCount() / runs;
-    }
 
     /**
      * @return float representing fail rate
@@ -220,7 +199,7 @@ public class RunStat {
         return 1.0f * getCriticalFailuresCount() / runs;
     }
 
-    public int getFailuresCount() {
+    @Override public int getFailuresCount() {
         if (latestRuns == null)
             return 0;
 
@@ -234,21 +213,16 @@ public class RunStat {
         return (int)latestRuns.values().stream().filter(res -> res.status == RES_CRITICAL_FAILURE).count();
     }
 
-    public int getRunsCount() {
+    @Override public int getRunsCount() {
         return latestRuns == null ? 0 : latestRuns.size();
     }
 
-    public String getFailPercentPrintable() {
-        return getPercentPrintable(getFailRate() * 100.0f);
-    }
 
     public String getCriticalFailPercentPrintable() {
-        return getPercentPrintable(getCriticalFailRate() * 100.0f);
+        return IRunHistory.getPercentPrintable(getCriticalFailRate() * 100.0f);
     }
 
-    private static String getPercentPrintable(float percent) {
-        return String.format("%.1f", percent).replace(".", ",");
-    }
+
 
     public long getAverageDurationMs() {
         if (runsWithDuration == 0)
@@ -301,14 +275,14 @@ public class RunStat {
      * @return
      */
     @Nullable
-    public List<Integer> getLatestRunResults() {
+    @Override public List<Integer> getLatestRunResults() {
         if (latestRuns == null)
             return Collections.emptyList();
 
         return latestRuns.values().stream().map(info -> info.status.code).collect(Collectors.toList());
     }
 
-    private int[] concatArr(int[] arr1, int[] arr2) {
+    private static int[] concatArr(int[] arr1, int[] arr2) {
         int[] arr1and2 = new int[arr1.length + arr2.length];
         System.arraycopy(arr1, 0, arr1and2, 0, arr1.length);
         System.arraycopy(arr2, 0, arr1and2, arr1.length, arr2.length);
@@ -354,7 +328,7 @@ public class RunStat {
     }
 
     @Nullable
-    private TestId checkTemplateAtPos(int[] template, int centralEvtBuild, List<Map.Entry<TestId, RunInfo>> histAsArr,
+    private static TestId checkTemplateAtPos(int[] template, int centralEvtBuild, List<Map.Entry<TestId, RunInfo>> histAsArr,
         int idx) {
         for (int tIdx = 0; tIdx < template.length; tIdx++) {
             RunInfo curStatus = histAsArr.get(idx + tIdx).getValue();
@@ -381,7 +355,7 @@ public class RunStat {
     }
 
     @Nullable
-    public String getFlakyComments() {
+    @Override public String getFlakyComments() {
         if (latestRuns == null)
             return null;
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/TestCompactedMult.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/TestCompactedMult.java
index e76dcf7..2b80f40 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/TestCompactedMult.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/TestCompactedMult.java
@@ -25,7 +25,7 @@ import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrenceFull;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.TestCompacted;
 
-public class TestCompactedMult implements ITestFailures {
+public class TestCompactedMult implements IMultTestOccurrence {
     private final List<TestCompacted> occurrences = new ArrayList<>();
     private IStringCompactor compactor;
     private long avgDuration = -1;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
index 8495c41..476308d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
@@ -40,12 +40,10 @@ import org.apache.ignite.ci.web.model.current.SuiteCurrentStatus;
 import org.apache.ignite.ci.web.model.current.TestFailure;
 import org.apache.ignite.ci.web.model.current.TestFailuresSummary;
 import org.apache.ignite.ci.web.rest.parms.FullQueryParams;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.inject.Inject;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -146,7 +144,7 @@ public class PrChainsProcessor {
                 runningUpdates.addAndGet(cnt0);
 
             //fail rate reference is always default (master)
-            chainStatus.initFromContext(teamcity, ctx, teamcity, baseBranch);
+            chainStatus.initFromContext(tcIgnited, teamcity, ctx, teamcity, baseBranch);
         }
 
         res.addChainOnServer(chainStatus);
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 be329aa..da4188b 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
@@ -108,7 +108,7 @@ public class TrackedBranchChainsProcessor {
                 if (cnt > 0)
                     runningUpdates.addAndGet(cnt);
 
-                chainStatus.initFromContext(teamcity, ctx, teamcity, baseBranchTc);
+                chainStatus.initFromContext(tcIgnited, teamcity, ctx, teamcity, baseBranchTc);
 
                 return chainStatus;
             })
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/IRunHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/IRunHistory.java
new file mode 100644
index 0000000..2d3eac8
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/IRunHistory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.teamcity.ignited;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+/**
+ * Test or Build run statistics.
+ */
+public interface IRunHistory {
+    public int getRunsCount();
+    public int getFailuresCount();
+
+    public static String getPercentPrintable(float percent) {
+        return String.format("%.1f", percent).replace(".", ",");
+    }
+
+    default public String getFailPercentPrintable() {
+        return getPercentPrintable(getFailRate() * 100.0f);
+    }
+
+    public int getFailuresAllHist();
+
+    public int getRunsAllHist();
+
+    default public float getFailRateAllHist() {
+        if (getRunsAllHist() == 0)
+            return 1.0f;
+
+        return 1.0f * getFailuresAllHist() / getRunsAllHist();
+    }
+
+    default public String getFailPercentAllHistPrintable() {
+        return IRunHistory.getPercentPrintable(getFailRateAllHist() * 100.0f);
+    }
+
+    /**
+     * @return float representing fail rate
+     */
+     default public float getFailRate() {
+        int runs = getRunsCount();
+
+        if (runs == 0)
+            return 1.0f;
+
+        return 1.0f * getFailuresCount() / runs;
+    }
+
+    @Nullable
+    List<Integer> getLatestRunResults();
+
+    String getFlakyComments();
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
index 5bf5b66..d2280a1 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
@@ -20,6 +20,8 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import javax.annotation.Nullable;
+
+import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildCondition;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
@@ -123,4 +125,6 @@ public interface ITeamcityIgnited {
      * @param cnt Count.
      */
     @NotNull public List<Integer> getLastNBuildsFromHistory(String btId, String branchForTc, int cnt);
+
+    @Nullable IRunHistory getTestRunHist(TestInBranch testInBranch);
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
index 215802f..ed7c93e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.ignite.ci.ITeamcity;
+import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.cache.GuavaCached;
@@ -308,6 +309,12 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
         return chains;
     }
 
+    @Override
+    public IRunHistory getTestRunHist(TestInBranch testInBranch) {
+        //todo implement loading test data
+        return null;
+    }
+
     public List<String> branchForQuery(@Nullable String branchName) {
         if (ITeamcity.DEFAULT.equals(branchName))
             return Lists.newArrayList(branchName, "refs/heads/master", "master");
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompacted.java
similarity index 61%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompacted.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompacted.java
index 7723c09..417d60c 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompacted.java
@@ -15,12 +15,17 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.teamcity.ignited.buildstat;
+package org.apache.ignite.ci.teamcity.ignited.runhist;
 
+import com.google.common.collect.Lists;
 import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.ci.analysis.IVersionedEntity;
+import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
 
-public class RunHistCompacted implements IVersionedEntity {
+import javax.annotation.Nullable;
+import java.util.List;
+
+public class RunHistCompacted implements IVersionedEntity, IRunHistory {
     /** Latest version. */
     private static final int LATEST_VERSION = 1;
 
@@ -37,13 +42,20 @@ public class RunHistCompacted implements IVersionedEntity {
     /**
      * Runs registered all the times.
      */
-    private int runs;
+    private int allHistRuns;
 
     /**
      * Failures registered all the times.
      */
-    private int failures;
+    private int allHistFailures;
+
 
+    public RunHistCompacted() {}
+
+    public RunHistCompacted(RunHistKey k) {
+        testNameOrSuite = k.testNameOrSuite();
+        srvId = k.srvId();
+    }
 
     /** {@inheritDoc} */
     @Override public int version() {
@@ -54,4 +66,35 @@ public class RunHistCompacted implements IVersionedEntity {
     @Override public int latestVersion() {
         return LATEST_VERSION;
     }
+
+    @Override
+    public int getRunsCount() {
+        return 10; //todo implement
+    }
+
+    @Override
+    public int getFailuresCount() {
+        return 10; //todo implement
+    }
+
+    @Override
+    public int getFailuresAllHist() {
+        return allHistFailures;
+    }
+
+    @Override
+    public int getRunsAllHist() {
+        return allHistRuns;
+    }
+
+    @Nullable
+    @Override
+    public List<Integer> getLatestRunResults() {
+        return Lists.newArrayList();
+    }
+
+    @Override
+    public String getFlakyComments() {
+        return null;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompactedDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompactedDao.java
similarity index 94%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompactedDao.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompactedDao.java
index c0c1184..42eb4d2 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistCompactedDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistCompactedDao.java
@@ -15,14 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.teamcity.ignited.buildstat;
+package org.apache.ignite.ci.teamcity.ignited.runhist;
 
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.ci.db.TcHelperDb;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
-import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
 import org.apache.ignite.configuration.CacheConfiguration;
 
 import javax.inject.Inject;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistKey.java
similarity index 51%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistKey.java
index c95e49d..b4f3390 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistKey.java
@@ -15,10 +15,41 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.teamcity.ignited.buildstat;
+package org.apache.ignite.ci.teamcity.ignited.runhist;
+
+import com.google.common.base.Objects;
 
 public class RunHistKey {
     private int srvId;
     private int testNameOrSuite;
     private int branch;
+
+    public RunHistKey(int srvId, int testName, int branchName) {
+        this.srvId = srvId;
+        this.testNameOrSuite = testName;
+        this.branch = branchName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        RunHistKey histKey = (RunHistKey) o;
+        return srvId == histKey.srvId &&
+                testNameOrSuite == histKey.testNameOrSuite &&
+                branch == histKey.branch;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(srvId, testNameOrSuite, branch);
+    }
+
+    public int testNameOrSuite() {
+        return testNameOrSuite;
+    }
+
+    public int srvId() {
+        return srvId;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
similarity index 52%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
index c95e49d..5b332fc 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildstat/RunHistKey.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
@@ -15,10 +15,33 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.teamcity.ignited.buildstat;
+package org.apache.ignite.ci.teamcity.ignited.runhist;
+
+import org.apache.ignite.ci.teamcity.pure.ITeamcityConn;
+import org.apache.ignite.internal.util.GridConcurrentHashSet;
+
+import javax.annotation.concurrent.GuardedBy;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public class RunHistSync {
+    /**
+     * Scope of work: builds to be loaded from a connection.
+     */
+    private static class SyncTask {
+        ITeamcityConn conn;
+        Set<Integer> ids = new HashSet<>();
+
+        GridConcurrentHashSet<Integer> loadingBuilds = new GridConcurrentHashSet<>();
+    }
+
+    @GuardedBy("this")
+    private Map<String, SyncTask> buildToLoad = new HashMap<>();
+
 
-public class RunHistKey {
-    private int srvId;
-    private int testNameOrSuite;
-    private int branch;
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
index 87ae388..7dcff6d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
@@ -27,8 +27,9 @@ import javax.annotation.Nullable;
 import org.apache.ignite.ci.ITcAnalytics;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
-import org.apache.ignite.ci.analysis.ITestFailures;
+import org.apache.ignite.ci.analysis.IMultTestOccurrence;
 import org.apache.ignite.ci.analysis.MultBuildRunCtx;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.util.CollectionUtil;
 import org.apache.ignite.internal.util.typedef.T2;
 
@@ -91,10 +92,11 @@ public class ChainAtServerCurrentStatus {
         this.branchName = branchTc;
     }
 
-    public void initFromContext(ITeamcity teamcity,
-        FullChainRunCtx ctx,
-        ITcAnalytics tcAnalytics,
-        @Nullable String baseBranchTc) {
+    public void initFromContext(ITeamcityIgnited tcIgnited,
+                                @Deprecated ITeamcity teamcity,
+                                FullChainRunCtx ctx,
+                                @Deprecated ITcAnalytics tcAnalytics,
+                                @Nullable String baseBranchTc) {
         failedTests = 0;
         failedToFinish = 0;
         //todo mode with not failed
@@ -104,7 +106,7 @@ public class ChainAtServerCurrentStatus {
             suite -> {
                 final SuiteCurrentStatus suiteCurStatus = new SuiteCurrentStatus();
 
-                suiteCurStatus.initFromContext(teamcity, suite, tcAnalytics, baseBranchTc);
+                suiteCurStatus.initFromContext(tcIgnited, teamcity, suite, tcAnalytics, baseBranchTc);
 
                 failedTests += suiteCurStatus.failedTests;
                 if (suite.hasAnyBuildProblemExceptTestOrSnapshot() || suite.onlyCancelledBuilds())
@@ -119,18 +121,18 @@ public class ChainAtServerCurrentStatus {
         webToHist = buildWebLink(teamcity, ctx);
         webToBuild = buildWebLinkToBuild(teamcity, ctx);
 
-        Stream<T2<MultBuildRunCtx, ITestFailures>> allLongRunning = ctx.suites().flatMap(
+        Stream<T2<MultBuildRunCtx, IMultTestOccurrence>> allLongRunning = ctx.suites().flatMap(
             suite -> suite.getTopLongRunning().map(t -> new T2<>(suite, t))
         );
-        Comparator<T2<MultBuildRunCtx, ITestFailures>> durationComp
+        Comparator<T2<MultBuildRunCtx, IMultTestOccurrence>> durationComp
             = Comparator.comparing((pair) -> pair.get2().getAvgDurationMs());
 
         CollectionUtil.top(allLongRunning, 3, durationComp).forEach(
             pairCtxAndOccur -> {
                 MultBuildRunCtx suite = pairCtxAndOccur.get1();
-                ITestFailures longRunningOccur = pairCtxAndOccur.get2();
+                IMultTestOccurrence longRunningOccur = pairCtxAndOccur.get2();
 
-                TestFailure failure = createOrrucForLongRun(teamcity, suite, tcAnalytics, longRunningOccur, baseBranchTc);
+                TestFailure failure = createOrrucForLongRun(tcIgnited, teamcity, suite, tcAnalytics, longRunningOccur, baseBranchTc);
 
                 failure.testName = "[" + suite.suiteName() + "] " + failure.testName; //may be separate field
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
index 2216edc..5934e0f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
@@ -26,12 +26,11 @@ import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.apache.ignite.ci.ITcAnalytics;
 import org.apache.ignite.ci.ITeamcity;
-import org.apache.ignite.ci.analysis.ITestFailures;
+import org.apache.ignite.ci.analysis.IMultTestOccurrence;
 import org.apache.ignite.ci.analysis.MultBuildRunCtx;
 import org.apache.ignite.ci.analysis.RunStat;
 import org.apache.ignite.ci.analysis.SuiteInBranch;
@@ -39,6 +38,8 @@ import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.analysis.TestLogCheckResult;
 import org.apache.ignite.ci.issue.EventTemplates;
 import org.apache.ignite.ci.issue.ProblemRef;
+import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.web.model.hist.FailureSummary;
 import org.apache.ignite.ci.web.rest.GetBuildLog;
 import org.jetbrains.annotations.NotNull;
@@ -51,6 +52,8 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
  * Represent Suite result
  */
 @SuppressWarnings("WeakerAccess") public class SuiteCurrentStatus extends FailureSummary {
+    private static final boolean NEW_RUN_STAT = true;
+
     /** Suite Name */
     public String name;
 
@@ -121,10 +124,11 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
     /** Possible blocker: filled for PR and builds checks, mean there was stable execution in master, but */
     public Boolean possibleBlocker;
 
-    public void initFromContext(@Nonnull final ITeamcity teamcity,
-        @Nonnull final MultBuildRunCtx suite,
-        @NotNull final ITcAnalytics tcAnalytics,
-        @Nullable final String baseBranch) {
+    public void initFromContext(ITeamcityIgnited tcIgnited,
+                                @Nonnull final ITeamcity teamcity,
+                                @Nonnull final MultBuildRunCtx suite,
+                                @NotNull final ITcAnalytics tcAnalytics,
+                                @Nullable final String baseBranch) {
 
         name = suite.suiteName();
 
@@ -132,7 +136,7 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         String curBranchNormalized = normalizeBranch(suite.branchName());
 
         String suiteId = suite.suiteId();
-        initStat(tcAnalytics, failRateNormalizedBranch, curBranchNormalized, suiteId);
+        initSuiteStat(tcAnalytics, failRateNormalizedBranch, curBranchNormalized, suiteId);
 
         Set<String> collect = suite.lastChangeUsers().collect(Collectors.toSet());
 
@@ -148,11 +152,11 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         webToHistBaseBranch = buildWebLink(teamcity, suite, baseBranch);
         webToBuild = buildWebLinkToBuild(teamcity, suite);
 
-        List<ITestFailures> tests = suite.getFailedTests();
-        Function<ITestFailures, Float> function = foccur -> {
+        List<IMultTestOccurrence> tests = suite.getFailedTests();
+        Function<IMultTestOccurrence, Float> function = foccur -> {
             TestInBranch testInBranch = new TestInBranch(foccur.getName(), failRateNormalizedBranch);
 
-            RunStat apply = tcAnalytics.getTestRunStatProvider().apply(testInBranch);
+            IRunHistory apply = tcIgnited.getTestRunHist(testInBranch);
 
             return apply == null ? 0f : apply.getFailRate();
         };
@@ -162,13 +166,16 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         tests.forEach(occurrence -> {
             final TestFailure failure = new TestFailure();
             failure.initFromOccurrence(occurrence, teamcity, suite.projectId(), suite.branchName(), baseBranch);
-            failure.initStat(tcAnalytics.getTestRunStatProvider(), failRateNormalizedBranch, curBranchNormalized);
+            failure.initStat(
+                    NEW_RUN_STAT
+                            ? tcIgnited::getTestRunHist
+                            : tcAnalytics.getTestRunStatProvider(), failRateNormalizedBranch, curBranchNormalized);
 
             testFailures.add(failure);
         });
 
         suite.getTopLongRunning().forEach(occurrence -> {
-            final TestFailure failure = createOrrucForLongRun(teamcity, suite, tcAnalytics, occurrence, baseBranch);
+            final TestFailure failure = createOrrucForLongRun(tcIgnited, teamcity, suite, tcAnalytics, occurrence, baseBranch);
 
             topLongRunning.add(failure);
         });
@@ -211,7 +218,7 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         // todo implement this logic in suite possibleBlocker = suite.hasPossibleBlocker();
     }
 
-    private void initStat(@Nullable ITcAnalytics tcAnalytics, String failRateNormalizedBranch, String curBranchNormalized, String suiteId) {
+    private void initSuiteStat(@Nullable ITcAnalytics tcAnalytics, String failRateNormalizedBranch, String curBranchNormalized, String suiteId) {
         if (Strings.isNullOrEmpty(suiteId) || tcAnalytics == null)
             return;
 
@@ -267,17 +274,20 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         return failure;
     }
 
-    @NotNull public static TestFailure createOrrucForLongRun(@Nonnull ITeamcity teamcity,
-        @Nonnull MultBuildRunCtx suite,
-        @Nullable final ITcAnalytics tcAnalytics,
-        final ITestFailures occurrence,
-        @Nullable final String failRateBranch) {
+    @NotNull public static TestFailure createOrrucForLongRun(ITeamcityIgnited tcIgnited,
+                                                             @Nonnull ITeamcity teamcity,
+                                                             @Nonnull MultBuildRunCtx suite,
+                                                             @Nullable final ITcAnalytics tcAnalytics,
+                                                             final IMultTestOccurrence occurrence,
+                                                             @Nullable final String failRateBranch) {
         final TestFailure failure = new TestFailure();
 
         failure.initFromOccurrence(occurrence, teamcity, suite.projectId(), suite.branchName(), failRateBranch);
 
         if (tcAnalytics != null) {
-            failure.initStat(tcAnalytics.getTestRunStatProvider(),
+            failure.initStat(NEW_RUN_STAT
+                            ? tcIgnited::getTestRunHist
+                            : tcAnalytics.getTestRunStatProvider(),
                 normalizeBranch(failRateBranch),
                 normalizeBranch(suite.branchName()));
         }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/TestFailure.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/TestFailure.java
index c3c28a3..a807e4e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/TestFailure.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/TestFailure.java
@@ -27,12 +27,13 @@ import java.util.regex.Pattern;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.apache.ignite.ci.ITeamcity;
-import org.apache.ignite.ci.analysis.ITestFailures;
+import org.apache.ignite.ci.analysis.IMultTestOccurrence;
 import org.apache.ignite.ci.analysis.RunStat;
 import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.issue.EventTemplates;
 import org.apache.ignite.ci.issue.ProblemRef;
 import org.apache.ignite.ci.logs.LogMsgToWarn;
+import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
 import org.apache.ignite.ci.web.model.hist.FailureSummary;
 import org.apache.ignite.ci.web.model.hist.TestHistory;
 import org.jetbrains.annotations.NotNull;
@@ -97,7 +98,7 @@ import static org.apache.ignite.ci.web.model.current.SuiteCurrentStatus.branchFo
      * @param branchName
      * @param baseBranchName base branch name (e.g. master).
      */
-    public void initFromOccurrence(@Nonnull final ITestFailures failure,
+    public void initFromOccurrence(@Nonnull final IMultTestOccurrence failure,
         @Nonnull final ITeamcity teamcity,
         @Nullable final String projectId,
         @Nullable final String branchName,
@@ -190,7 +191,7 @@ import static org.apache.ignite.ci.web.model.current.SuiteCurrentStatus.branchFo
      * @param failRateNormalizedBranch Base branch: Fail rate and flakyness detection normalized branch.
      * @param curBranchNormalized Cur branch normalized.
      */
-    public void initStat(@Nullable final Function<TestInBranch, RunStat> runStatSupplier,
+    public void initStat(@Nullable final Function<TestInBranch, ? extends IRunHistory> runStatSupplier,
         String failRateNormalizedBranch,
         String curBranchNormalized) {
         if (runStatSupplier == null)
@@ -198,11 +199,11 @@ import static org.apache.ignite.ci.web.model.current.SuiteCurrentStatus.branchFo
 
         TestInBranch testInBranch = new TestInBranch(name, failRateNormalizedBranch);
 
-        final RunStat stat = runStatSupplier.apply(testInBranch);
+        final IRunHistory stat = runStatSupplier.apply(testInBranch);
 
         histBaseBranch.init(stat);
 
-        RunStat statForProblemsDetection = null;
+        IRunHistory statForProblemsDetection = null;
 
         if (!curBranchNormalized.equals(failRateNormalizedBranch)) {
             TestInBranch testInBranchS = new TestInBranch(name, curBranchNormalized);
@@ -217,13 +218,14 @@ import static org.apache.ignite.ci.web.model.current.SuiteCurrentStatus.branchFo
         } else
             statForProblemsDetection = stat;
 
-        if (statForProblemsDetection != null) {
-            RunStat.TestId testId = statForProblemsDetection.detectTemplate(EventTemplates.newFailure);
+        if (statForProblemsDetection != null && statForProblemsDetection instanceof RunStat) {
+            final RunStat forProblemsDetection = (RunStat) statForProblemsDetection;
+            RunStat.TestId testId = forProblemsDetection.detectTemplate(EventTemplates.newFailure);
 
             if (testId != null)
                 problemRef = new ProblemRef("New Failure");
 
-            RunStat.TestId recentContributedTestId = statForProblemsDetection.detectTemplate(EventTemplates.newContributedTestFailure);
+            RunStat.TestId recentContributedTestId = forProblemsDetection.detectTemplate(EventTemplates.newContributedTestFailure);
 
             if (recentContributedTestId != null)
                 problemRef = new ProblemRef("Recently contributed test failure");
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/TestHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/TestHistory.java
index d25ec92..6c1743b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/TestHistory.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/TestHistory.java
@@ -21,6 +21,7 @@ import com.google.common.base.Objects;
 import java.util.List;
 import javax.annotation.Nullable;
 import org.apache.ignite.ci.analysis.RunStat;
+import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
 import org.jetbrains.annotations.NotNull;
 
 /**
@@ -28,10 +29,10 @@ import org.jetbrains.annotations.NotNull;
  */
 public class TestHistory {
     /** 'All the time' runs history statistic. */
-    @Nullable public FailureSummary allTime = new FailureSummary();
+    public FailureSummary allTime = new FailureSummary();
 
     /** Latest runs history statistic. */
-    @Nullable public FailureSummary recent = new FailureSummary();
+    public FailureSummary recent = new FailureSummary();
 
     /** Latest runs, 0,1,2 values for each run. */
     @Nullable public List<Integer> latestRuns;
@@ -39,7 +40,7 @@ public class TestHistory {
     /** Non null flaky comments means there is flakiness detected in the the branch. */
     @Nullable public String flakyComments;
 
-    public void init(@Nullable RunStat stat) {
+    public void init(@Nullable IRunHistory stat) {
         if (stat == null)
             return;
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/GetChainResultsAsHtml.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/GetChainResultsAsHtml.java
index a84afc2..1b72d4c 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/GetChainResultsAsHtml.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/GetChainResultsAsHtml.java
@@ -75,10 +75,10 @@ public class GetChainResultsAsHtml {
         ITcServerProvider tcHelper = injector.getInstance(ITcServerProvider.class);
         final ICredentialsProv creds = ICredentialsProv.get(req);
         IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, creds);
-        ITeamcityIgnited teamcityIgnited = injector.getInstance(ITeamcityIgnitedProvider.class).server(srvId, creds);
+        ITeamcityIgnited tcIgn = injector.getInstance(ITeamcityIgnitedProvider.class).server(srvId, creds);
 
         final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity,
-            teamcityIgnited,
+            tcIgn,
             Collections.singletonList(buildId),
             LatestRebuildMode.NONE,
             ProcessLogsMode.SUITE_NOT_COMPLETE,
@@ -92,7 +92,7 @@ public class GetChainResultsAsHtml {
 
         status.chainName = ctx.suiteName();
 
-        status.initFromContext(teamcity, ctx, teamcity, failRateBranch);
+        status.initFromContext(tcIgn, teamcity, ctx, teamcity, failRateBranch);
 
         res.append(showChainAtServerData(status));
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/GetBuildTestFailures.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/GetBuildTestFailures.java
index f0df8f8..0ad6c3e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/GetBuildTestFailures.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/GetBuildTestFailures.java
@@ -19,22 +19,19 @@ package org.apache.ignite.ci.web.rest.build;
 
 import com.google.common.collect.BiMap;
 import java.text.ParseException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
+
 import com.google.inject.Injector;
 import org.apache.ignite.ci.tcbot.trends.MasterTrendsService;
 import org.apache.ignite.ci.teamcity.ignited.SyncMode;
 import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildCondition;
 import org.apache.ignite.ci.tcbot.chain.BuildChainProcessor;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
-import org.apache.ignite.ci.ITcHelper;
 import org.apache.ignite.ci.ITeamcity;
 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.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
-import org.apache.ignite.ci.tcmodel.result.tests.TestRef;
 import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
 import org.apache.ignite.ci.user.ICredentialsProv;
 import org.apache.ignite.ci.web.model.current.BuildStatisticsSummary;
@@ -132,14 +129,14 @@ public class GetBuildTestFailures {
             throw ServiceUnauthorizedException.noCreds(srvId);
 
         IAnalyticsEnabledTeamcity teamcity = tcSrvProvider.server(srvId, prov);
-        ITeamcityIgnited teamcityIgnited = tcIgnitedProv.server(srvId, prov);
+        ITeamcityIgnited tcIgnited = tcIgnitedProv.server(srvId, prov);
 
         String failRateBranch = ITeamcity.DEFAULT;
 
         ProcessLogsMode procLogs = (checkAllLogs != null && checkAllLogs) ? ProcessLogsMode.ALL : ProcessLogsMode.SUITE_NOT_COMPLETE;
 
         final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity,
-            teamcityIgnited,
+            tcIgnited,
             Collections.singletonList(buildId),
             LatestRebuildMode.NONE,
             procLogs,
@@ -153,7 +150,7 @@ public class GetBuildTestFailures {
         if (cnt > 0)
             runningUpdates.addAndGet(cnt);
 
-        chainStatus.initFromContext(teamcity, ctx, teamcity, failRateBranch);
+        chainStatus.initFromContext(tcIgnited, teamcity, ctx, teamcity, failRateBranch);
 
         res.addChainOnServer(chainStatus);
 
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
index c2477dc..8e6390c 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
@@ -25,7 +25,7 @@ import com.google.inject.internal.SingletonScope;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
-import org.apache.ignite.ci.analysis.ITestFailures;
+import org.apache.ignite.ci.analysis.IMultTestOccurrence;
 import org.apache.ignite.ci.analysis.MultBuildRunCtx;
 import org.apache.ignite.ci.analysis.mode.LatestRebuildMode;
 import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
@@ -99,7 +99,7 @@ public class BuildChainProcessorTest {
             else
                 assertTrue(suite.failedTests() >= 1);
 
-            for (ITestFailures test : suite.getFailedTests()) {
+            for (IMultTestOccurrence test : suite.getFailedTests()) {
                 if (test.getName().startsWith(UNIQUE_FAILED_TEST))
                     assertEquals(1, test.failuresCount());
                 else if (test.getName().equals(TEST_FAILING_EVERY_TIME))
@@ -131,7 +131,7 @@ public class BuildChainProcessorTest {
             System.out.println(suite.getFailedTestsNames().collect(Collectors.toList()));
 
             if (suite.suiteName() != null && suite.suiteName().startsWith(UNIQUE_FAILED_TEST)) {
-                for (ITestFailures test : suite.getFailedTests())
+                for (IMultTestOccurrence test : suite.getFailedTests())
                     fail("Failure found but should be hidden by re-run " + test.getName());
             }
         }
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
index 83dd6c3..b85a8d6 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
@@ -16,11 +16,13 @@
  */
 package org.apache.ignite.ci.tcbot.chain;
 
+import com.google.common.collect.Lists;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.internal.SingletonScope;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
+import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.github.pure.IGitHubConnection;
 import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
 import org.apache.ignite.ci.tcmodel.conf.BuildType;
@@ -55,6 +57,8 @@ import static org.mockito.Mockito.when;
 
 public class PrChainsProcessorTest {
     public static final String SRV_ID = "apache";
+    public static final String TEST_WITH_HISTORY_FAILING_IN_MASTER = "testWithHistoryFailingInMaster";
+
     private Map<Integer, FatBuildCompacted> apacheBuilds = new ConcurrentHashMap<>();
 
 
@@ -77,7 +81,6 @@ public class PrChainsProcessorTest {
             final IAnalyticsEnabledTeamcity tcOld = BuildChainProcessorTest.tcOldMock();
             when(tcSrvOldProv.server(anyString(), any(ICredentialsProv.class))).thenReturn(tcOld);
 
-
             bind(ITcServerProvider.class).toInstance(tcSrvOldProv);
 
             super.configure();
@@ -112,6 +115,10 @@ public class PrChainsProcessorTest {
 
         assertTrue(suitesStatuses.stream().anyMatch(s -> "Build".equals(s.suiteId)));
         assertTrue(suitesStatuses.stream().anyMatch(s -> "CancelledBuild".equals(s.suiteId)));
+
+        assertFalse(suitesStatuses.stream().anyMatch(
+                s -> s.testFailures.stream().anyMatch(testFailure -> TEST_WITH_HISTORY_FAILING_IN_MASTER.equals(testFailure.name))
+        ));
     }
 
     private void initBuildChain(IStringCompactor c, String btId, String branch) {
@@ -120,14 +127,12 @@ public class PrChainsProcessorTest {
         final FatBuildCompacted chain = createFailedBuild(c, btId, branch, id, 100000);
 
         final FatBuildCompacted childBuild = createFailedBuild(c, "Cache1", branch, 1001, 100020);
-        TestOccurrenceFull tf = new TestOccurrenceFull();
-        tf.test = new TestRef();
-        tf.test.id = 1L;
-        tf.name = "testWithoutHistory";
-        tf.status = TestOccurrence.STATUS_FAILURE;
 
-        childBuild.addTests(c, Collections.singletonList(tf));
+        TestOccurrenceFull tf = createFailedTest(1L, "testWithoutHistory");
+
+        TestOccurrenceFull tf2 = createFailedTest(2L, TEST_WITH_HISTORY_FAILING_IN_MASTER);
 
+        childBuild.addTests(c, Lists.newArrayList(tf, tf2));
 
         final FatBuildCompacted buildBuild = createFailedBuild(c, "Build", branch, 1002, 100020);
         final ProblemOccurrence compile = new ProblemOccurrence();
@@ -141,13 +146,34 @@ public class PrChainsProcessorTest {
 
         final FatBuildCompacted cancelledBuild = new FatBuildCompacted(c, build);
 
-
         chain.snapshotDependencies(new int[]{childBuild.id(), cancelledBuild.id()});
 
         apacheBuilds.put(chain.id(), chain);
         apacheBuilds.put(childBuild.id(), childBuild);
         apacheBuilds.put(buildBuild.id(), buildBuild);
         apacheBuilds.put(cancelledBuild.id(), cancelledBuild);
+
+        for (int i = 0; i < 10; i++) {
+            final FatBuildCompacted masterBuild = createFailedBuild(c, "Cache1",
+                    ITeamcity.DEFAULT, 5000+i, 100000+(i*10000));
+
+            final TestOccurrenceFull testInMaster = createFailedTest(2L, TEST_WITH_HISTORY_FAILING_IN_MASTER);
+
+            masterBuild.addTests(c, Lists.newArrayList(testInMaster));
+
+            apacheBuilds.put(masterBuild.id(), masterBuild);
+        }
+    }
+
+    @NotNull
+    private TestOccurrenceFull createFailedTest(long id1, String name) {
+        TestOccurrenceFull tf = new TestOccurrenceFull();
+        tf.test = new TestRef();
+
+        tf.test.id = id1;
+        tf.name = name;
+        tf.status = TestOccurrence.STATUS_FAILURE;
+        return tf;
     }
 
     @NotNull
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
index 1cc9156..2e392c6 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
@@ -18,12 +18,16 @@
 package org.apache.ignite.ci.teamcity.ignited;
 
 import com.google.common.base.Preconditions;
+import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistCompacted;
+import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistKey;
 import org.jetbrains.annotations.NotNull;
 import org.mockito.Mockito;
 
 import java.util.Comparator;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -35,6 +39,9 @@ public class TeamcityIgnitedMock {
     @NotNull
     public static ITeamcityIgnited getMutableMapTeamcityIgnited(Map<Integer, FatBuildCompacted> builds, IStringCompactor c) {
         ITeamcityIgnited tcIgnited = Mockito.mock(ITeamcityIgnited.class);
+        Map<RunHistKey, RunHistCompacted> histCache = new ConcurrentHashMap<>();
+        final int srvId = 0;
+
         when(tcIgnited.getFatBuild(anyInt(), any(SyncMode.class)))
             .thenAnswer(inv ->
             {
@@ -75,6 +82,44 @@ public class TeamcityIgnitedMock {
                     .collect(Collectors.toList());
             });
 
+        when(tcIgnited.getTestRunHist(any(TestInBranch.class)))
+                .thenAnswer((inv) -> {
+                    final TestInBranch t = inv.getArgument(0);
+                    final String name = t.name;
+                    final String branch = t.branch;
+
+                    if(histCache.isEmpty()) {
+                        initHistory(histCache, builds, srvId);
+                    }
+
+                    final Integer tstName = c.getStringIdIfPresent(name);
+                    if(tstName==null)
+                        return null;
+
+                    final Integer branchId = c.getStringIdIfPresent(branch);
+                    if(branchId==null)
+                        return null;
+
+                    final RunHistKey key = new RunHistKey(srvId, tstName, branchId);
+
+                    final RunHistCompacted runHistCompacted = histCache.get(key);
+
+                    System.out.println("Test history " + name + " in " + branch + " => " + runHistCompacted);
+                    return runHistCompacted;
+                });
+
         return tcIgnited;
     }
+
+    private static void initHistory(Map<RunHistKey, RunHistCompacted> histCache, Map<Integer, FatBuildCompacted> builds, int srvId) {
+        for (FatBuildCompacted next : builds.values()) {
+            next.getAllTests().forEach(t->{
+                RunHistKey histKey = new RunHistKey(srvId, t.testName(), next.branchName() );
+
+                final RunHistCompacted hist = histCache.computeIfAbsent(histKey, RunHistCompacted::new);
+
+
+            });
+        }
+    }
 }
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java
index 298ea46..f9f0eca 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java
@@ -27,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
 public class TeamcityIgnitedProviderMock implements ITeamcityIgnitedProvider {
     @Inject IStringCompactor compactor;
 
-    Map<String,Map<Integer, FatBuildCompacted>> tcBuildsData = new ConcurrentHashMap<>();
+    private Map<String, Map<Integer, FatBuildCompacted>> tcBuildsData = new ConcurrentHashMap<>();
 
     public void addServer(String srvId, Map<Integer, FatBuildCompacted> apacheBuilds) {
         tcBuildsData.put(srvId, apacheBuilds);
@@ -36,6 +36,7 @@ public class TeamcityIgnitedProviderMock implements ITeamcityIgnitedProvider {
     @Override
     public ITeamcityIgnited server(String srvId, ICredentialsProv prov) {
         final Map<Integer, FatBuildCompacted> integerFatBuildCompactedMap = tcBuildsData.get(srvId);
+
         return TeamcityIgnitedMock.getMutableMapTeamcityIgnited(integerFatBuildCompactedMap, compactor);
     }
 }