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/10/25 11:34:20 UTC

[ignite-teamcity-bot] branch ignite-9848-load-all-builds updated: First call to new service (builds not load in advance), metrics were removed (old impl).

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

dpavlov pushed a commit to branch ignite-9848-load-all-builds
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/ignite-9848-load-all-builds by this push:
     new a3eb657  First call to new service (builds not load in advance), metrics were removed (old impl).
a3eb657 is described below

commit a3eb657c3065b8632915f8d30bd388f21342c636
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Thu Oct 25 14:34:07 2018 +0300

    First call to new service (builds not load in advance), metrics were removed (old impl).
---
 .../main/java/org/apache/ignite/ci/ITeamcity.java  |  75 +------
 .../apache/ignite/ci/analysis/ISuiteResults.java   |   2 +-
 .../apache/ignite/ci/analysis/MultBuildRunCtx.java |   2 +
 .../ignite/ci/analysis/SingleBuildRunCtx.java      |  10 +-
 .../java/org/apache/ignite/ci/db/DbMigrations.java |   4 +-
 .../org/apache/ignite/ci/runners/BuildHistory.java |  30 ---
 .../ignite/ci/runners/BuildMetricsHistory.java     |  63 ------
 .../apache/ignite/ci/runners/FailuresHistory.java  |  37 ----
 .../ci/tcbot/builds/CompareBuildsService.java      |  99 +++++++++
 .../ignite/ci/tcbot/chain/BuildChainProcessor.java | 101 +++++++++-
 .../ignite/ci/tcbot/chain/PrChainsProcessor.java   |   8 +-
 .../tcbot/chain/TrackedBranchChainsProcessor.java  |   7 +-
 .../ignite/ci/teamcity/ignited/BuildRefDao.java    |   6 +-
 .../ignite/ci/teamcity/ignited/FatBuildDao.java    |  31 +--
 .../ci/teamcity/ignited/ITeamcityIgnited.java      |   6 +
 .../ci/teamcity/ignited/TeamcityIgnitedImpl.java   |  18 +-
 .../ignited/fatbuild/FatBuildCompacted.java        |  36 +++-
 .../teamcity/ignited/fatbuild/TestCompacted.java   |  20 ++
 .../ignite/ci/teamcity/pure/ITeamcityConn.java     |   2 +
 .../java/org/apache/ignite/ci/web/CtxListener.java |   9 +-
 .../ignite/ci/web/model/chart/ChartData.java       |  79 --------
 .../ignite/ci/web/model/chart/TestsMetrics.java    |  60 ------
 .../ignite/ci/web/rest/GetChainResultsAsHtml.java  |  12 +-
 .../org/apache/ignite/ci/web/rest/Metrics.java     | 220 --------------------
 .../ignite/ci/web/rest/build/CompareBuilds.java    |  64 +-----
 .../ci/web/rest/build/GetBuildTestFailures.java    |  20 +-
 ignite-tc-helper-web/src/main/webapp/chart.html    | 223 +--------------------
 .../ignited/IgnitedTcInMemoryIntegrationTest.java  |  26 ++-
 28 files changed, 358 insertions(+), 912 deletions(-)

diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
index 628581f..b97ead4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
@@ -136,17 +136,18 @@ public interface ITeamcity extends ITeamcityConn {
         return getFinishedBuilds(projectId, branchNameForHist, sinceDate, untilDate, null).stream().mapToInt(BuildRef::getId).toArray();
     }
 
+    @Deprecated
     Build getBuild(String href);
 
-    default Build getBuild(int id) {
-        return getBuild(getBuildHrefById(id));
+    default Build getBuild(int buildId) {
+        return getBuild(getBuildHrefById(buildId));
     }
 
     @NotNull default String getBuildHrefById(int id) {
         return buildHref(id);
     }
 
-    @NotNull  static String buildHref(int id) {
+    @NotNull static String buildHref(int id) {
         return "app/rest/latest/builds/id:" + Integer.toString(id);
     }
 
@@ -179,74 +180,6 @@ public interface ITeamcity extends ITeamcityConn {
      */
     IssuesUsagesList getIssuesUsagesList(String href);
 
-    /**
-     * Runs deep collection of all related statistics for particular build.
-     *
-     * @param build Build from history with references to tests.
-     * @return Full context.
-     */
-    @Nonnull default MultBuildRunCtx loadTestsAndProblems(@Nonnull Build build) {
-        MultBuildRunCtx ctx = new MultBuildRunCtx(build);
-
-        loadTestsAndProblems(build, ctx);
-
-        return ctx;
-    }
-
-    default SingleBuildRunCtx loadTestsAndProblems(@Nonnull Build build, @Deprecated MultBuildRunCtx mCtx) {
-        SingleBuildRunCtx ctx = new SingleBuildRunCtx(build);
-        if (build.problemOccurrences != null)
-            ctx.setProblems(getProblems(build).getProblemsNonNull());
-
-        if (build.lastChanges != null) {
-            for (ChangeRef next : build.lastChanges.changes) {
-                if(!isNullOrEmpty(next.href)) {
-                    // just to cache this change
-                    getChange(next.href);
-                }
-            }
-        }
-
-        if (build.changesRef != null) {
-            ChangesList changeList = getChangesList(build.changesRef.href);
-            // System.err.println("changes: " + changeList);
-            if (changeList.changes != null) {
-                for (ChangeRef next : changeList.changes) {
-                    if (!isNullOrEmpty(next.href)) {
-                        // just to cache this change
-                        ctx.addChange(getChange(next.href));
-                    }
-                }
-            }
-        }
-
-        if (build.testOccurrences != null && !build.isComposite()) {
-            String normalizedBranch = BuildChainProcessor.normalizeBranch(build);
-
-            List<TestOccurrence> tests
-                = getTests(build.testOccurrences.href + TESTS_COUNT_7700, normalizedBranch).getTests();
-
-            ctx.setTests(tests);
-
-            mCtx.addTests(tests);
-
-            for (TestOccurrence next : tests) {
-                if (next.href != null && next.isFailedTest()) {
-                    CompletableFuture<TestOccurrenceFull> testFullFut = getTestFull(next.href);
-
-                    String testInBuildId = next.getId();
-
-                    mCtx.addTestInBuildToTestFull(testInBuildId, testFullFut);
-                }
-            }
-        }
-
-        if (build.statisticsRef != null)
-            mCtx.setStat(getBuildStatistics(build.statisticsRef.href));
-
-        return ctx;
-    }
-
     CompletableFuture<File> unzipFirstFile(CompletableFuture<File> fut);
 
     CompletableFuture<File> downloadBuildLogZip(int id);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ISuiteResults.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ISuiteResults.java
index e060dfa..0d1b175 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ISuiteResults.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/ISuiteResults.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.ci.analysis;
 
 /**
- * Results from one or several builds
+ * Results from one or several builds for specific build type.
  */
 public interface ISuiteResults {
     boolean hasTimeoutProblem();
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 29ecc76..bc0ec3e 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
@@ -56,6 +56,7 @@ public class MultBuildRunCtx implements ISuiteResults {
     /** Builds: Single execution. */
     private List<SingleBuildRunCtx> builds = new CopyOnWriteArrayList<>();
 
+    @Deprecated
     /** Tests: Map from full test name to multiple test occurrence. */
     private final Map<String, MultTestFailureOccurrences> tests = new ConcurrentSkipListMap<>();
 
@@ -304,6 +305,7 @@ public class MultBuildRunCtx implements ISuiteResults {
         return tests.values().stream().filter(MultTestFailureOccurrences::hasFailedButNotMuted);
     }
 
+    @Deprecated
     public void addTests(Iterable<TestOccurrence> tests) {
         for (TestOccurrence next : tests) {
             this.tests.computeIfAbsent(next.name,
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
index 99ee2e7..8ecfc88 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
@@ -30,6 +30,8 @@ import org.apache.ignite.ci.tcmodel.changes.Change;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.tcmodel.result.problems.ProblemOccurrence;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrence;
+import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.util.FutureUtil;
 import org.jetbrains.annotations.Nullable;
 
@@ -37,8 +39,11 @@ import org.jetbrains.annotations.Nullable;
  * Single build ocurrence,
  */
 public class SingleBuildRunCtx implements ISuiteResults {
+    @Deprecated
     private Build build;
 
+    private FatBuildCompacted buildCompacted;
+
     /** Logger check result future. */
     private CompletableFuture<LogCheckResult> logCheckResultFut;
 
@@ -47,10 +52,13 @@ public class SingleBuildRunCtx implements ISuiteResults {
 
     private List<Change> changes = new ArrayList<>();
 
+    @Deprecated
     private List<TestOccurrence> tests = new ArrayList<>();
 
-    public SingleBuildRunCtx(Build build) {
+    public SingleBuildRunCtx(Build build,
+        FatBuildCompacted buildCompacted, IStringCompactor compactor) {
         this.build = build;
+        this.buildCompacted = buildCompacted;
     }
 
     public Build getBuild() {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/DbMigrations.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/DbMigrations.java
index 19f807b..e6c4942 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/DbMigrations.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/DbMigrations.java
@@ -43,7 +43,6 @@ import org.apache.ignite.ci.tcmodel.result.stat.Statistics;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrenceFull;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrences;
 import org.apache.ignite.ci.tcmodel.result.tests.TestRef;
-import org.apache.ignite.ci.web.rest.Metrics;
 import org.apache.ignite.ci.web.rest.build.GetBuildTestFailures;
 import org.apache.ignite.ci.web.rest.pr.GetPrTestFailures;
 import org.apache.ignite.ci.web.rest.tracked.GetTrackedBranchTestResults;
@@ -277,8 +276,7 @@ public class DbMigrations {
         });
 
         applyRemoveCache(GetTrackedBranchTestResults.ALL_TEST_FAILURES_SUMMARY);
-        applyRemoveCache(Metrics.FAILURES_PUBLIC);
-        applyRemoveCache(Metrics.FAILURES_PRIVATE);
+
         applyRemoveCache(GetTrackedBranchTestResults.TEST_FAILURES_SUMMARY_CACHE_NAME);
         applyRemoveCache(GetBuildTestFailures.TEST_FAILURES_SUMMARY_CACHE_NAME);
         applyRemoveCache(GetPrTestFailures.CURRENT_PR_FAILURES);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildHistory.java
deleted file mode 100644
index 4dfbc32..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildHistory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.runners;
-
-import java.util.Map;
-import java.util.TreeMap;
-import org.apache.ignite.ci.analysis.FullChainRunCtx;
-
-/**
- *
- */
-
-@Deprecated
-public class BuildHistory {
-    public Map<String, FullChainRunCtx> map = new TreeMap<>();
-}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildMetricsHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildMetricsHistory.java
deleted file mode 100644
index d63c7c7..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/BuildMetricsHistory.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.runners;
-
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.stream.Stream;
-import org.apache.ignite.ci.analysis.FullChainRunCtx;
-import org.apache.ignite.ci.analysis.SuiteInBranch;
-
-@Deprecated
-public class BuildMetricsHistory {
-    private Map<SuiteInBranch, BuildHistory> map = new TreeMap<>();
-    private LinkedHashSet<SuiteInBranch> keys = new LinkedHashSet<>();
-    public Map<String, FailuresHistory> failuresHistoryMap = new TreeMap<>();
-
-    public BuildHistory history(SuiteInBranch id) {
-        return map.computeIfAbsent(id, k -> {
-            keys.add(k);
-            return new BuildHistory();
-        });
-    }
-
-    public Set<SuiteInBranch> builds() {
-        return keys;
-    }
-
-    public TreeSet<String> dates() {
-        Stream<String> stream = map.values().stream().flatMap(v -> v.map.keySet().stream());
-        TreeSet<String> dates = new TreeSet<>();
-        stream.forEach(dates::add);
-        return dates;
-    }
-
-    public FullChainRunCtx build(SuiteInBranch next, String date) {
-        BuildHistory hist = map.get(next);
-        if (hist == null)
-            return null;
-        return hist.map.get(date);
-    }
-
-    public void addSuiteResult(String suiteName, boolean ok) {
-        failuresHistoryMap.computeIfAbsent(suiteName, k -> new FailuresHistory())
-            .addRun(ok);
-    }
-}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/FailuresHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/FailuresHistory.java
deleted file mode 100644
index 7e0fdce..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/FailuresHistory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.runners;
-
-class FailuresHistory {
-    int success = 0;
-    int totalRun = 0;
-
-    public void addRun(boolean ok) {
-        totalRun++;
-        if (ok)
-            success++;
-    }
-
-    public String passRateStr() {
-        return String.format("%.2f", passRate());
-    }
-
-    public double passRate() {
-        return (double)(success) / totalRun;
-    }
-}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/builds/CompareBuildsService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/builds/CompareBuildsService.java
new file mode 100644
index 0000000..b383dc5
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/builds/CompareBuildsService.java
@@ -0,0 +1,99 @@
+/*
+ * 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.tcbot.builds;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.inject.Inject;
+import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
+import org.apache.ignite.ci.ITeamcity;
+import org.apache.ignite.ci.analysis.MultBuildRunCtx;
+import org.apache.ignite.ci.tcbot.chain.BuildChainProcessor;
+import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+import org.apache.ignite.ci.tcmodel.result.Build;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CompareBuildsService {
+    /** */
+    private static final Logger logger = LoggerFactory.getLogger(CompareBuildsService.class);
+
+    @Inject ITcServerProvider helper;
+    @Inject ICredentialsProv prov;
+    @Inject BuildChainProcessor bcp;
+    @Inject ITeamcityIgnitedProvider tcIgnitedProv;
+
+    public List<String> tests0(String srvId, Integer buildId ) {
+        IAnalyticsEnabledTeamcity teamcity = helper.server(srvId, prov);
+
+        String hrefById = teamcity.getBuildHrefById(buildId);
+        BuildRef buildRef = new BuildRef();
+
+        buildRef.setId(buildId);
+        buildRef.href = hrefById;
+
+        ITeamcityIgnited srv = tcIgnitedProv.server(srvId, prov);
+
+        return tests0(teamcity, srv, buildRef, bcp);
+    }
+
+    /** */
+    private List<String> tests0(ITeamcity tc, ITeamcityIgnited server,
+        BuildRef ref, BuildChainProcessor bcp) {
+        List<String> tests = new ArrayList<>();
+
+        Build build = tc.getBuild(ref.href);
+
+        if (build.isComposite()) {
+            List<BuildRef> deps = build.getSnapshotDependenciesNonNull();
+
+            logger.info("Build {} is composite ({}).", build.getId(), deps.size());
+
+            for (BuildRef ref0 : deps)
+                tests.addAll(tests0(tc, server, ref0, bcp));
+        }
+        else {
+            logger.info("Loading tests for build {}.", build.getId());
+
+            MultBuildRunCtx buildCtx = new MultBuildRunCtx(build);
+
+            buildCtx.addBuild(bcp.loadTestsAndProblems(tc, build, buildCtx, server));
+
+            for (String testName : buildCtx.tests())
+                tests.add(extractTestName(testName));
+        }
+
+        return tests;
+    }
+
+
+    /**
+     * Get rid from suite name.
+     * @param testFullName Test full name.
+     * @return Test name.
+     */
+    private String extractTestName(String testFullName) {
+        int pos = testFullName.indexOf(": ");
+
+        return pos >= 0 ? testFullName.substring(pos + 2) : testFullName;
+    }
+}
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 921619b..c24e15b 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
@@ -23,12 +23,14 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.annotation.Nonnull;
 import javax.inject.Inject;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
 import org.apache.ignite.ci.ITeamcity;
@@ -40,8 +42,16 @@ import org.apache.ignite.ci.analysis.SuiteInBranch;
 import org.apache.ignite.ci.analysis.mode.LatestRebuildMode;
 import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
 import org.apache.ignite.ci.di.AutoProfiling;
+import org.apache.ignite.ci.tcmodel.changes.ChangeRef;
+import org.apache.ignite.ci.tcmodel.changes.ChangesList;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
+import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrence;
+import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrenceFull;
+import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
+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.jetbrains.annotations.NotNull;
@@ -49,6 +59,9 @@ import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.apache.ignite.ci.db.DbMigrations.TESTS_COUNT_7700;
+
 /**
  * Process whole Build Chain, E.g. runAll at particular server, including all builds involved
  */
@@ -59,8 +72,13 @@ public class BuildChainProcessor {
     /** TC REST updates pool. */
     @Inject private TcUpdatePool tcUpdatePool;
 
+    @Inject private ITeamcityIgnitedProvider teamcityIgnitedProvider;
+
+    @Inject private IStringCompactor compactor;
+
     /**
      * @param teamcity Teamcity.
+     * @param teamcityIgnited
      * @param entryPoints Entry points.
      * @param includeLatestRebuild Include latest rebuild.
      * @param procLog Process logger.
@@ -70,6 +88,7 @@ public class BuildChainProcessor {
     @AutoProfiling
     public FullChainRunCtx loadFullChainContext(
         IAnalyticsEnabledTeamcity teamcity,
+        ITeamcityIgnited teamcityIgnited,
         Collection<BuildRef> entryPoints,
         LatestRebuildMode includeLatestRebuild,
         ProcessLogsMode procLog,
@@ -104,7 +123,7 @@ public class BuildChainProcessor {
         final List<Future<? extends Stream<? extends BuildRef>>> phase2Submitted = phase1Submitted.stream()
                 .map(FutureUtil::getResult)
                 .map((s) -> svc.submit(
-                        () -> processBuildList(teamcity, buildsCtxMap, s)))
+                        () -> processBuildList(teamcity, teamcityIgnited, buildsCtxMap, s)))
                 .collect(Collectors.toList());
 
         phase2Submitted.forEach(FutureUtil::getResult);
@@ -141,25 +160,85 @@ public class BuildChainProcessor {
     }
 
     @NotNull
-    public static Stream<? extends BuildRef> processBuildList(ITeamcity teamcity,
-                                                              Map<String, MultBuildRunCtx> buildsCtxMap,
-                                                              Stream<? extends BuildRef> list) {
+    public Stream<? extends BuildRef> processBuildList(ITeamcity teamcity,
+        ITeamcityIgnited teamcityIgnited, Map<String, MultBuildRunCtx> buildsCtxMap,
+        Stream<? extends BuildRef> list) {
         list.forEach((BuildRef ref) -> {
-            processBuildAndAddToCtx(teamcity, buildsCtxMap, ref);
+            Build build = teamcity.getBuild(ref.getId());
+
+            if (build == null || build.isFakeStub())
+                return;
+
+            MultBuildRunCtx ctx = buildsCtxMap.computeIfAbsent(build.buildTypeId, k -> new MultBuildRunCtx(build));
+
+            ctx.addBuild(loadTestsAndProblems(teamcity, build, ctx, teamcityIgnited));
         });
 
         return list;
     }
 
-    public static void processBuildAndAddToCtx(ITeamcity teamcity, Map<String, MultBuildRunCtx> buildsCtxMap, BuildRef buildRef) {
-        Build build = teamcity.getBuild(buildRef.href);
+    /**
+     * Runs deep collection of all related statistics for particular build.
+     *
+     * @param tcIgnited
+     * @param build Build from history with references to tests.
+     * @return Full context.
+     */
+    public SingleBuildRunCtx loadTestsAndProblems(ITeamcity teamcity, @Nonnull Build build,
+        @Deprecated MultBuildRunCtx mCtx, ITeamcityIgnited tcIgnited) {
+
+        FatBuildCompacted buildCompacted = tcIgnited.getFatBuild(build.getId());
+        SingleBuildRunCtx ctx = new SingleBuildRunCtx(build, buildCompacted, compactor);
+        if (build.problemOccurrences != null)
+            ctx.setProblems(teamcity.getProblems(build).getProblemsNonNull());
+
+        if (build.lastChanges != null) {
+            for (ChangeRef next : build.lastChanges.changes) {
+                if(!isNullOrEmpty(next.href)) {
+                    // just to cache this change
+                    teamcity.getChange(next.href);
+                }
+            }
+        }
+
+        if (build.changesRef != null) {
+            ChangesList changeList = teamcity.getChangesList(build.changesRef.href);
+            // System.err.println("changes: " + changeList);
+            if (changeList.changes != null) {
+                for (ChangeRef next : changeList.changes) {
+                    if (!isNullOrEmpty(next.href)) {
+                        // just to cache this change
+                        ctx.addChange(teamcity.getChange(next.href));
+                    }
+                }
+            }
+        }
+
+        if (build.testOccurrences != null && !build.isComposite()) {
+            String normalizedBranch = BuildChainProcessor.normalizeBranch(build);
+
+            List<TestOccurrence> tests
+                = teamcity.getTests(build.testOccurrences.href + TESTS_COUNT_7700, normalizedBranch).getTests();
+
+            ctx.setTests(tests);
 
-        if (build == null || build.isFakeStub())
-            return;
+            mCtx.addTests(tests);
+
+            for (TestOccurrence next : tests) {
+                if (next.href != null && next.isFailedTest()) {
+                    CompletableFuture<TestOccurrenceFull> testFullFut = teamcity.getTestFull(next.href);
+
+                    String testInBuildId = next.getId();
+
+                    mCtx.addTestInBuildToTestFull(testInBuildId, testFullFut);
+                }
+            }
+        }
 
-        MultBuildRunCtx ctx = buildsCtxMap.computeIfAbsent(build.buildTypeId, k -> new MultBuildRunCtx(build));
+        if (build.statisticsRef != null)
+            mCtx.setStat(teamcity.getBuildStatistics(build.statisticsRef.href));
 
-        ctx.addBuild(teamcity.loadTestsAndProblems(build, ctx));
+        return ctx;
     }
 
     @NotNull
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 afa8a6c..1828345 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
@@ -18,6 +18,8 @@ package org.apache.ignite.ci.tcbot.chain;
 
 import com.google.common.base.Strings;
 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.ITeamcity;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
@@ -49,6 +51,9 @@ public class PrChainsProcessor {
 
     /** Tc server provider. */
     @Inject ITcServerProvider tcSrvProvider;
+
+    /** Tc server provider. */
+    @Inject ITeamcityIgnitedProvider tcIgnitedProvider;
     @Inject IGitHubConnectionProvider gitHubConnProvider;
 
     /**
@@ -77,6 +82,7 @@ public class PrChainsProcessor {
 
         //using here non persistent TC allows to skip update statistic
         IAnalyticsEnabledTeamcity teamcity = tcSrvProvider.server(srvId, creds);
+        ITeamcityIgnited tcIgnited = tcIgnitedProvider.server(srvId, creds);
 
         IGitHubConnection gitHubConn = gitHubConnProvider.server(srvId);
 
@@ -117,7 +123,7 @@ public class PrChainsProcessor {
 
         String baseBranch = Strings.isNullOrEmpty(baseBranchForTc) ? ITeamcity.DEFAULT : baseBranchForTc;
 
-        final FullChainRunCtx val = buildChainProcessor.loadFullChainContext(teamcity, chains,
+        final FullChainRunCtx val = buildChainProcessor.loadFullChainContext(teamcity, tcIgnited, chains,
             rebuild,
             logs, buildResMergeCnt == 1,
             baseBranch);
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 11e1b97..2d61c43 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,6 +23,8 @@ 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;
@@ -41,6 +43,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
 
 public class TrackedBranchChainsProcessor {
     @Inject private ITcServerProvider srvProv;
+    @Inject private ITeamcityIgnitedProvider tcIgnitedProv;
 
     /** Chains processor. */
     @Inject private BuildChainProcessor chainProc;
@@ -75,6 +78,8 @@ public class TrackedBranchChainsProcessor {
 
                 IAnalyticsEnabledTeamcity teamcity = srvProv.server(srvId, creds);
 
+                ITeamcityIgnited tcIgnited = tcIgnitedProv.server(srvId, creds);
+
                 final List<BuildRef> builds = teamcity.getFinishedBuildsIncludeSnDepFailed(
                     chainTracked.getSuiteIdMandatory(),
                     branchForTc);
@@ -96,7 +101,7 @@ public class TrackedBranchChainsProcessor {
                 boolean includeScheduled = buildResMergeCnt == 1;
 
                 final FullChainRunCtx ctx = chainProc.loadFullChainContext(teamcity,
-                    chains,
+                    tcIgnited, chains,
                     rebuild,
                     logs,
                     includeScheduled,
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefDao.java
index 6febf4f..a018654 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefDao.java
@@ -55,7 +55,7 @@ public class BuildRefDao {
         buildsCache = igniteProvider.get().getOrCreateCache(cfg);
     }
 
-    @NotNull protected Stream<BuildRefCompacted> compactedBuildsForServer(long srvId) {
+    @NotNull protected Stream<BuildRefCompacted> compactedBuildsForServer(int srvId) {
         return StreamSupport.stream(buildsCache.spliterator(), false)
             .filter(entry -> entry.getKey() >> 32 == srvId)
             .map(javax.cache.Cache.Entry::getValue);
@@ -105,7 +105,7 @@ public class BuildRefDao {
      * @param buildTypeId Build type id.
      * @param bracnhNameQry Bracnh name query.
      */
-    @NotNull public List<BuildRef> findBuildsInHistory(long srvId,
+    @NotNull public List<BuildRef> findBuildsInHistory(int srvId,
         @Nullable String buildTypeId,
         String bracnhNameQry) {
 
@@ -127,7 +127,7 @@ public class BuildRefDao {
     /**
      * @param srvId Server id.
      */
-    public List<BuildRefCompacted> getQueuedAndRunning(long srvId) {
+    public List<BuildRefCompacted> getQueuedAndRunning(int srvId) {
         GridIntList list = new GridIntList(2);
         Integer stateQueuedId = compactor.getStringIdIfPresent(BuildRef.STATE_QUEUED);
         if (stateQueuedId != null)
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/FatBuildDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/FatBuildDao.java
index d2151f9..e215674 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/FatBuildDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/FatBuildDao.java
@@ -57,39 +57,30 @@ public class FatBuildDao {
         buildsCache = igniteProvider.get().getOrCreateCache(TcHelperDb.getCacheV2Config(TEAMCITY_FAT_BUILD_CACHE_NAME));
     }
 
-
     /**
      * @param srvIdMaskHigh Server id mask high.
      * @param build Build data.
      * @param tests TestOccurrences.
+     * @return Fat Build saved (if modifications detected)
      */
-    public int saveBuild(long srvIdMaskHigh,
+    public FatBuildCompacted saveBuild(long srvIdMaskHigh,
         Build build,
         List<TestOccurrences> tests) {
-        Set<Long> ids = Stream.of(build).map(BuildRef::getId)
-            .filter(Objects::nonNull)
-            .map(buildId -> buildIdToCacheKey(srvIdMaskHigh, buildId))
-            .collect(Collectors.toSet());
 
-        Map<Long, FatBuildCompacted> existingEntries = buildsCache.getAll(ids);
-        Map<Long, FatBuildCompacted> entriesToPut = new TreeMap<>();
+        long cacheKey = buildIdToCacheKey(srvIdMaskHigh, build.getId());
+        FatBuildCompacted existingEntry = buildsCache.get(cacheKey);
 
-        FatBuildCompacted compacted = new FatBuildCompacted(compactor, build);
+        FatBuildCompacted newBuild = new FatBuildCompacted(compactor, build);
 
         for (TestOccurrences next : tests)
-            compacted.addTests(compactor, next.getTests());
-
-        long cacheKey = buildIdToCacheKey(srvIdMaskHigh, compacted.id());
-        FatBuildCompacted buildPersisted = existingEntries.get(cacheKey);
+            newBuild.addTests(compactor, next.getTests());
 
-        if (buildPersisted == null || !buildPersisted.equals(compacted))
-            entriesToPut.put(cacheKey, compacted);
-
-        int size = entriesToPut.size();
-        if (size != 0)
-            buildsCache.putAll(entriesToPut);
+        if (existingEntry == null || !existingEntry.equals(newBuild)) {
+            buildsCache.put(cacheKey, newBuild);
+            return newBuild;
+        }
 
-        return size;
+        return null;
     }
 
     /**
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 fadf0fb..b2e6b32 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,7 @@ import java.util.List;
 import javax.annotation.Nullable;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 
 /**
  *
@@ -56,4 +57,9 @@ public interface ITeamcityIgnited {
     public static int serverIdToInt(String srvId) {
         return Math.abs(srvId.hashCode());
     }
+
+    /**
+     * @param id Id.
+     */
+    public FatBuildCompacted getFatBuild(int id);
 }
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 0667976..fec5680 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
@@ -17,6 +17,7 @@
 package org.apache.ignite.ci.teamcity.ignited;
 
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -32,6 +33,7 @@ import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.scheduler.IScheduler;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.teamcity.pure.ITeamcityConn;
 
 public class TeamcityIgnitedImpl implements ITeamcityIgnited {
@@ -47,8 +49,11 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     /** Build reference DAO. */
     @Inject private BuildRefDao buildRefDao;
 
+    /** Build DAO. */
+    @Inject private FatBuildDao fatBuildDao;
+
     /** Server ID mask for cache Entries. */
-    private long srvIdMaskHigh;
+    private int srvIdMaskHigh;
 
 
     public void init(String srvId, ITeamcityConn conn) {
@@ -91,6 +96,17 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
         return build;
     }
 
+    @Override public FatBuildCompacted getFatBuild(int buildId) {
+        FatBuildCompacted build = fatBuildDao.getFatBuild(srvIdMaskHigh, buildId);
+        if (build != null)
+            return build;
+
+        //todo some sort of locking to avoid double requests
+        Build build1 = conn.getBuild(buildId);
+
+        return fatBuildDao.saveBuild(srvIdMaskHigh, build1, new ArrayList<>());
+    }
+
     /**
      *
      */
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 a92b2a5..af26004 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
@@ -16,10 +16,10 @@
  */
 package org.apache.ignite.ci.teamcity.ignited.fatbuild;
 
+import com.google.common.base.Objects;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
-import java.util.Objects;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 import org.apache.ignite.ci.analysis.IVersionedEntity;
@@ -41,6 +41,8 @@ import org.jetbrains.annotations.Nullable;
 public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEntity {
     /** Latest version. */
     private static final int LATEST_VERSION = 0;
+    public static final int DEF_BR_F = 0;
+    public static final int COMPOSITE_F = 2;
 
     /** Entity fields version. */
     private short _ver;
@@ -102,8 +104,8 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
         snapshotDeps = arr.length > 0 ? arr : null;
 
-        setFlag(0, build.defaultBranch);
-        setFlag(2, build.composite);
+        setFlag(DEF_BR_F, build.defaultBranch);
+        setFlag(COMPOSITE_F, build.composite);
     }
 
     /**
@@ -160,8 +162,9 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
             res.snapshotDependencies(snapshotDependencies);
         }
 
-        res.defaultBranch = getFlag(0);
-        res.composite = getFlag(2);
+        res.defaultBranch = getFlag(DEF_BR_F);
+        res.composite = getFlag(COMPOSITE_F);
+
     }
 
     /**
@@ -220,4 +223,27 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
         return testOccurrences;
     }
+
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+        FatBuildCompacted that = (FatBuildCompacted)o;
+        return _ver == that._ver &&
+            startDate == that.startDate &&
+            finishDate == that.finishDate &&
+            queuedDate == that.queuedDate &&
+            projectId == that.projectId &&
+            name == that.name &&
+            Objects.equal(tests, that.tests) &&
+            Objects.equal(snapshotDeps, that.snapshotDeps) &&
+            Objects.equal(flags, that.flags);
+    }
+
+    @Override public int hashCode() {
+        return Objects.hashCode(super.hashCode(), _ver, startDate, finishDate, queuedDate, projectId, name, tests, snapshotDeps, flags);
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
index ceceb5d..0f25fdc 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.ci.teamcity.ignited.fatbuild;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import java.util.BitSet;
 import org.apache.ignite.ci.analysis.RunStat;
@@ -121,4 +122,23 @@ public class TestCompacted {
     private int idInBuild() {
         return idInBuild;
     }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        TestCompacted compacted = (TestCompacted)o;
+        return idInBuild == compacted.idInBuild &&
+            name == compacted.name &&
+            status == compacted.status &&
+            duration == compacted.duration &&
+            Objects.equal(flags, compacted.flags);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return Objects.hashCode(idInBuild, name, status, duration, flags);
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
index 516bd5a..dccfe60 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
@@ -32,6 +32,8 @@ public interface ITeamcityConn {
      */
     public String host();
 
+    public Build getBuild(int buildId);
+
     public List<BuildRef> getBuildRefs(String fullUrl, AtomicReference<String> nextPage);
 
     /**
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/CtxListener.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/CtxListener.java
index f52517f..11c454c 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/CtxListener.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/CtxListener.java
@@ -46,6 +46,7 @@ public class CtxListener implements ServletContextListener {
     /** Javax.Injector property code for servlet context. */
     public static final String INJECTOR = "injector";
 
+    @Deprecated
     public static ITcHelper getTcHelper(ServletContext ctx) {
         return getInjector(ctx).getInstance(ITcHelper.class);
     }
@@ -58,14 +59,6 @@ public class CtxListener implements ServletContextListener {
         return getInjector(ctx).getInstance(BackgroundUpdater.class);
     }
 
-    public static IAnalyticsEnabledTeamcity server(@QueryParam("serverId") @Nullable String srvId,
-                                                   ServletContext ctx,
-                                                   HttpServletRequest req) {
-        ITcHelper tcHelper = getTcHelper(ctx);
-        final ICredentialsProv creds = ICredentialsProv.get(req);
-        return tcHelper.server(srvId, creds);
-    }
-
     /** {@inheritDoc} */
     @Override public void contextInitialized(ServletContextEvent sctxEvt) {
         initLoggerBridge();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/ChartData.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/ChartData.java
deleted file mode 100644
index 5ac503b..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/ChartData.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.chart;
-
-import com.google.common.base.Preconditions;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-/**
- *
- */
-@Deprecated
-public class ChartData<K> {
-    /** Captions for measurements at axis X */
-    public List<String> axisX;
-
-    public List<LineData> lines = new ArrayList<>();
-
-    public List<String> legendLabels = new ArrayList<>();
-
-    transient Map<K, Integer> keyToLineMapping = new HashMap<>();
-
-    public ChartData(String... axisX) {
-        this.axisX = new ArrayList<>(Arrays.asList(axisX));
-    }
-
-    public void addEmptyLine(K key) {
-        addEmptyLine(key, null);
-    }
-
-    public void addEmptyLine(K key, Function<K, String> legendFunction) {
-        keyToLineMapping.computeIfAbsent(key, (k) -> {
-            int index = lines.size();
-            addLine(new LineData());
-            if (legendFunction != null) {
-                legendLabels.add(legendFunction.apply(k));
-            }
-            return index;
-        });
-    }
-
-    public void addLine(LineData data) {
-        lines.add(data);
-    }
-
-    public int addAxisXLabel(String label) {
-        int idx = axisX.size();
-        axisX.add(label);
-        return idx;
-    }
-
-    public void addMeasurement(K mappedKey, int idx, Double value) {
-        Integer lineId = keyToLineMapping.get(mappedKey);
-        Preconditions.checkState(lineId != null, "Error key [" + mappedKey + "] has no mapped line");
-        LineData data = lines.get(lineId);
-        Preconditions.checkState(data != null, "Error key [" + mappedKey + "] has null mapped line");
-
-        data.addMeasurementAt(idx, value);
-    }
-}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/TestsMetrics.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/TestsMetrics.java
deleted file mode 100644
index fa69657..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/chart/TestsMetrics.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.chart;
-
-import com.google.common.base.Preconditions;
-import java.util.Set;
-import org.apache.ignite.ci.analysis.SuiteInBranch;
-import org.apache.ignite.ci.web.IBackgroundUpdatable;
-
-/**
- * 
- */
-@Deprecated
-public class TestsMetrics implements IBackgroundUpdatable {
-    public ChartData<SuiteInBranch> failed = new ChartData<>();
-    public ChartData<SuiteInBranch> notrun = new ChartData<>();
-    public ChartData<SuiteInBranch> muted = new ChartData<>();
-    public ChartData<SuiteInBranch> total = new ChartData<>();
-
-    public boolean updateRequired;
-
-    public void initBuilds(Set<SuiteInBranch> builds) {
-        builds.forEach(branch -> {
-            failed.addEmptyLine(branch, SuiteInBranch::getBranch);
-            notrun.addEmptyLine(branch);
-            muted.addEmptyLine(branch);
-            total.addEmptyLine(branch);
-        });
-    }
-
-    public int addAxisXLabel(String label) {
-        int idx1 = failed.addAxisXLabel(label);
-        int idx2 = notrun.addAxisXLabel(label);
-        int idx3 = muted.addAxisXLabel(label);
-        int idx4 = total.addAxisXLabel(label);
-        Preconditions.checkState(idx1 == idx2);
-        Preconditions.checkState(idx3 == idx4);
-        Preconditions.checkState(idx1 == idx3);
-        return idx1;
-    }
-
-    @Override public void setUpdateRequired(boolean update) {
-        this.updateRequired = update;
-    }
-}
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 78811ae..a8ab2a5 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
@@ -29,6 +29,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 
 import com.google.inject.Injector;
+import org.apache.ignite.ci.ITcHelper;
 import org.apache.ignite.ci.tcbot.chain.BuildChainProcessor;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
 import org.apache.ignite.ci.ITeamcity;
@@ -36,6 +37,10 @@ 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.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.util.FutureUtil;
 import org.apache.ignite.ci.web.CtxListener;
 import org.apache.ignite.ci.web.model.current.ChainAtServerCurrentStatus;
@@ -72,9 +77,12 @@ public class GetChainResultsAsHtml {
         build.href = hrefById;
         String failRateBranch = ITeamcity.DEFAULT;
 
-        IAnalyticsEnabledTeamcity teamcity = CtxListener.server(srvId, ctx, req);
+        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);
 
-        final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity, Collections.singletonList(build),
+        final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity, teamcityIgnited, Collections.singletonList(build),
             LatestRebuildMode.NONE,
             ProcessLogsMode.SUITE_NOT_COMPLETE, false,
             failRateBranch);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/Metrics.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/Metrics.java
deleted file mode 100644
index af804b3..0000000
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/Metrics.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-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 org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
-import org.apache.ignite.ci.tcbot.chain.BuildChainProcessor;
-import org.apache.ignite.ci.HelperConfig;
-import org.apache.ignite.ci.ITeamcity;
-import org.apache.ignite.ci.analysis.FullChainRunCtx;
-import org.apache.ignite.ci.analysis.MultBuildRunCtx;
-import org.apache.ignite.ci.analysis.SuiteInBranch;
-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.conf.ChainAtServerTracked;
-import org.apache.ignite.ci.runners.BuildHistory;
-import org.apache.ignite.ci.runners.BuildMetricsHistory;
-import org.apache.ignite.ci.tcmodel.hist.BuildRef;
-import org.apache.ignite.ci.tcmodel.result.Build;
-import org.apache.ignite.ci.user.ICredentialsProv;
-import org.apache.ignite.ci.web.BackgroundUpdater;
-import org.apache.ignite.ci.web.CtxListener;
-import org.apache.ignite.ci.web.rest.exception.ServiceUnauthorizedException;
-import org.apache.ignite.ci.web.model.chart.ChartData;
-import org.apache.ignite.ci.web.model.chart.TestsMetrics;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import static java.util.Collections.singletonList;
-
-@Path("metrics")
-@Produces("application/json")
-@Deprecated
-public class Metrics {
-    public static final String FAILURES_PUBLIC = "failures.public";
-    public static final String FAILURES_PRIVATE = "failures.private";
-    @Context
-    private ServletContext ctx;
-
-    @Context
-    private HttpServletRequest req;
-
-
-    @Deprecated
-    public void collectHistory(BuildMetricsHistory history,
-        IAnalyticsEnabledTeamcity teamcity, String id, String branch)  {
-
-        BuildChainProcessor bcp = CtxListener.getInjector(ctx).getInstance(BuildChainProcessor.class);
-
-        final SuiteInBranch branchId = new SuiteInBranch(id, branch);
-        final BuildHistory suiteHist = history.history(branchId);
-        final List<BuildRef> all = teamcity.getFinishedBuildsIncludeSnDepFailed(id, branch);
-        final List<Build> fullBuildInfoList = all.stream()
-            .map(b -> teamcity.getBuild(b.href))
-            .filter(Objects::nonNull)
-            .filter(b -> b.getId() != null)
-            .collect(Collectors.toList());
-
-        for (Build next : fullBuildInfoList) {
-            Date parse = next.getFinishDate();
-            String dateForMap = new SimpleDateFormat("yyyyMMdd").format(parse);
-            suiteHist.map.computeIfAbsent(dateForMap, k -> {
-                FullChainRunCtx ctx = bcp.loadFullChainContext(teamcity,
-                    singletonList(next),
-                    LatestRebuildMode.NONE,
-                    ProcessLogsMode.DISABLED, false,
-                    ITeamcity.DEFAULT);
-
-                if (ctx == null)
-                    return null;
-
-                for (MultBuildRunCtx suite : ctx.suites()) {
-                    boolean suiteOk = suite.failedTests() == 0 && !suite.hasCriticalProblem();
-                    history.addSuiteResult(teamcity.serverId() + "\t" + suite.suiteName(), suiteOk);
-                }
-                return ctx;
-            });
-        }
-    }
-
-    @GET
-    @Path("failuresNoCache")
-    public TestsMetrics getFailuresNoCache() {
-        BuildMetricsHistory history = new BuildMetricsHistory();
-        final String branch = "master";
-        final BranchTracked tracked = HelperConfig.getTrackedBranches().getBranchMandatory(branch);
-        List<ChainAtServerTracked> chains = tracked.chains;
-
-        //todo take from branches.json
-        final String serverId = "public";
-        final ICredentialsProv prov = ICredentialsProv.get(req);
-
-        if (!prov.hasAccess(serverId))
-            throw ServiceUnauthorizedException.noCreds(serverId);
-
-        IAnalyticsEnabledTeamcity teamcity = CtxListener.server(serverId, ctx, req);
-
-        collectHistory(history, teamcity, "IgniteTests24Java8_RunAll", "refs/heads/master");
-
-        return convertToChart(history);
-    }
-
-    @GET
-    @Path("failures")
-    public TestsMetrics getFailures() {
-        final BackgroundUpdater updater = CtxListener.getInjector(ctx).getInstance(BackgroundUpdater.class);
-        return updater.get(FAILURES_PUBLIC, null, "", k -> getFailuresNoCache(), false);
-
-    }
-
-    @GET
-    @Path("failuresPrivate")
-    public TestsMetrics getFailuresPrivate(@Nullable @QueryParam("param") String msg) {
-        final BackgroundUpdater updater = CtxListener.getBackgroundUpdater(ctx);
-        return updater.get(FAILURES_PRIVATE, null, "", k -> getFailuresPrivateNoCache(), false);
-    }
-
-
-    @GET
-    @Path("failuresPrivateNoCache")
-    @NotNull public TestsMetrics getFailuresPrivateNoCache() {
-        //todo take from branches.json
-        BuildMetricsHistory hist = new BuildMetricsHistory();
-        final String srvId = "private";
-
-        final ICredentialsProv prov = ICredentialsProv.get(req);
-
-        if (!prov.hasAccess(srvId))
-            throw ServiceUnauthorizedException.noCreds(srvId);
-
-        IAnalyticsEnabledTeamcity teamcity = CtxListener.server(srvId, ctx, req);
-
-        collectHistory(hist, teamcity, "id8xIgniteGridGainTestsJava8_RunAll", "refs/heads/master");
-
-        return convertToChart(hist);
-    }
-
-    @NotNull
-    private TestsMetrics convertToChart(BuildMetricsHistory hist) {
-        TestsMetrics testsMetrics = new TestsMetrics();
-        Set<SuiteInBranch> builds = hist.builds();
-        testsMetrics.initBuilds(builds);//to initialize internal mapping build->idx
-
-        for (String date : hist.dates()) {
-            Date mddd;
-            try {
-                mddd = new SimpleDateFormat("yyyyMMdd").parse(date);
-            }
-            catch (ParseException e) {
-                continue;
-            }
-            String dispDate = new SimpleDateFormat("dd.MM").format(mddd);
-            int axisXIdx = testsMetrics.addAxisXLabel(dispDate);
-            for (SuiteInBranch next : hist.builds()) {
-                FullChainRunCtx suiteCtx = hist.build(next, date);
-                if (suiteCtx != null) {
-                    testsMetrics.failed.addMeasurement(next, axisXIdx, (double)suiteCtx.failedTests());
-                    testsMetrics.muted.addMeasurement(next, axisXIdx, (double)suiteCtx.mutedTests());
-                    testsMetrics.notrun.addMeasurement(next, axisXIdx, (double)suiteCtx.buildProblems());
-                    testsMetrics.total.addMeasurement(next, axisXIdx, (double)suiteCtx.totalTests());
-                }
-            }
-        }
-
-        removeOddLabels(testsMetrics.failed);
-        removeOddLabels(testsMetrics.muted);
-        removeOddLabels(testsMetrics.notrun);
-        removeOddLabels(testsMetrics.total);
-        return testsMetrics;
-    }
-
-    private void removeOddLabels(ChartData<SuiteInBranch> failed) {
-        final List<String> x = failed.axisX;
-        if (x.size() > 15) {
-            double labelWeigh = 15.0 / x.size() ;
-            double curWeight=1;
-            int idx;
-            for (int i = 0; i < x.size(); i++) {
-                if (curWeight >= 1) {
-                    curWeight = 0;
-                    //keep label here
-                    continue;
-                }
-                curWeight += labelWeigh;
-                x.set(i, "");
-            }
-        }
-    }
-
-}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/CompareBuilds.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/CompareBuilds.java
index 8bd9062..e46ce5a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/CompareBuilds.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/build/CompareBuilds.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.ci.web.rest.build;
 
-import java.util.ArrayList;
+import com.google.inject.Injector;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -29,25 +29,16 @@ 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.IAnalyticsEnabledTeamcity;
-import org.apache.ignite.ci.ITcHelper;
-import org.apache.ignite.ci.ITeamcity;
+import org.apache.ignite.ci.tcbot.builds.CompareBuildsService;
 import org.apache.ignite.ci.util.Diff;
-import org.apache.ignite.ci.analysis.MultBuildRunCtx;
-import org.apache.ignite.ci.tcmodel.hist.BuildRef;
-import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.user.ICredentialsProv;
 import org.apache.ignite.ci.web.CtxListener;
 import org.apache.ignite.ci.web.rest.exception.ServiceUnauthorizedException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** */
 @Path("compare")
 @Produces(MediaType.APPLICATION_JSON)
 public class CompareBuilds {
-    /** */
-    private static final Logger logger = LoggerFactory.getLogger(CompareBuilds.class);
 
     /** */
     @Context
@@ -125,58 +116,13 @@ public class CompareBuilds {
 
     /** */
     private List<String> tests(String srv, Integer buildId) {
-        final ITcHelper helper = CtxListener.getTcHelper(ctx);
+        Injector injector = CtxListener.getInjector(ctx);
+        CompareBuildsService compareBuildsSvc = injector.getInstance(CompareBuildsService.class);
         final ICredentialsProv prov = ICredentialsProv.get(req);
 
         if (!prov.hasAccess(srv))
             throw ServiceUnauthorizedException.noCreds(srv);
 
-        IAnalyticsEnabledTeamcity teamcity = helper.server(srv, prov);
-
-        String hrefById = teamcity.getBuildHrefById(buildId);
-        BuildRef buildRef = new BuildRef();
-
-        buildRef.setId(buildId);
-        buildRef.href = hrefById;
-
-        return tests0(teamcity, buildRef);
-
-    }
-
-    /** */
-    private List<String> tests0(ITeamcity tc, BuildRef ref) {
-        List<String> tests = new ArrayList<>();
-
-        Build build = tc.getBuild(ref.href);
-
-        if (build.isComposite()) {
-            List<BuildRef> deps = build.getSnapshotDependenciesNonNull();
-
-            logger.info("Build {} is composite ({}).", build.getId(), deps.size());
-
-            for (BuildRef ref0 : deps)
-                tests.addAll(tests0(tc, ref0));
-        }
-        else {
-            logger.info("Loading tests for build {}.", build.getId());
-
-            MultBuildRunCtx buildCtx = tc.loadTestsAndProblems(build);
-
-            for (String testName : buildCtx.tests())
-                tests.add(extractTestName(testName));
-        }
-
-        return tests;
-    }
-
-    /**
-     * Get rid from suite name.
-     * @param testFullName Test full name.
-     * @return Test name.
-     */
-    private String extractTestName(String testFullName) {
-        int pos = testFullName.indexOf(": ");
-
-        return pos >= 0 ? testFullName.substring(pos + 2) : testFullName;
+        return compareBuildsSvc.tests0(srv, buildId);
     }
 }
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 fdfe218..f72b3da 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
@@ -30,6 +30,9 @@ import org.apache.ignite.ci.analysis.mode.LatestRebuildMode;
 import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.tests.TestRef;
+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.hist.BuildsHistory;
 import org.apache.ignite.ci.web.BackgroundUpdater;
@@ -107,21 +110,23 @@ public class GetBuildTestFailures {
     @GET
     @Path("failuresNoCache")
     @NotNull public TestFailuresSummary getBuildTestFailsNoCache(
-        @QueryParam("serverId") String serverId,
+        @QueryParam("serverId") String srvId,
         @QueryParam("buildId") Integer buildId,
         @Nullable @QueryParam("checkAllLogs") Boolean checkAllLogs) {
-        final ITcHelper helper = CtxListener.getTcHelper(ctx);
         final ICredentialsProv prov = ICredentialsProv.get(req);
         final Injector injector = CtxListener.getInjector(ctx);
+        ITeamcityIgnitedProvider tcIgnitedProv = injector.getInstance(ITeamcityIgnitedProvider.class);
+        ITcServerProvider tcSrvProvider = injector.getInstance(ITcServerProvider.class);
         final BuildChainProcessor buildChainProcessor = injector.getInstance(BuildChainProcessor.class);
 
         final TestFailuresSummary res = new TestFailuresSummary();
         final AtomicInteger runningUpdates = new AtomicInteger();
 
-        if(!prov.hasAccess(serverId))
-            throw ServiceUnauthorizedException.noCreds(serverId);
+        if(!prov.hasAccess(srvId))
+            throw ServiceUnauthorizedException.noCreds(srvId);
 
-        IAnalyticsEnabledTeamcity teamcity = helper.server(serverId, prov);
+        IAnalyticsEnabledTeamcity teamcity = tcSrvProvider.server(srvId, prov);
+        ITeamcityIgnited teamcityIgnited = tcIgnitedProv.server(srvId, prov);
 
         //processChainByRef(teamcity, includeLatestRebuild, build, true, true)
         String hrefById = teamcity.getBuildHrefById(buildId);
@@ -132,13 +137,12 @@ public class GetBuildTestFailures {
 
         ProcessLogsMode procLogs = (checkAllLogs != null && checkAllLogs) ? ProcessLogsMode.ALL : ProcessLogsMode.SUITE_NOT_COMPLETE;
 
-        final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity, Collections.singletonList(build),
+        final FullChainRunCtx ctx = buildChainProcessor.loadFullChainContext(teamcity, teamcityIgnited, Collections.singletonList(build),
                 LatestRebuildMode.NONE,
                 procLogs, false,
             failRateBranch);
 
-
-        final ChainAtServerCurrentStatus chainStatus = new ChainAtServerCurrentStatus(serverId, ctx.branchName());
+        final ChainAtServerCurrentStatus chainStatus = new ChainAtServerCurrentStatus(srvId, ctx.branchName());
 
         int cnt = (int) ctx.getRunningUpdates().count();
         if (cnt > 0)
diff --git a/ignite-tc-helper-web/src/main/webapp/chart.html b/ignite-tc-helper-web/src/main/webapp/chart.html
index e2b9de8..bc3eb0c 100644
--- a/ignite-tc-helper-web/src/main/webapp/chart.html
+++ b/ignite-tc-helper-web/src/main/webapp/chart.html
@@ -1,224 +1,5 @@
-<html>
-<head>
-    <title>Ignite Teamcity Build Status metrics</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">
-    <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>
-
-    <link rel="stylesheet"
-          href="http://cdn.jsdelivr.net/chartist.js/latest/chartist.min.css">
-    <link rel="stylesheet" href="css/style-1.5.css">
-
-
-    <script src="http://cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/chartist-plugin-legend/0.6.2/chartist-plugin-legend.js"></script>
-
-
-    <script src="js/common-1.6.js"></script>
-
-    <style>
-    .ct-chart {
-        position: relative;
-    }
-    .ct-legend {
-        position: relative;
-        z-index: 10;
-        list-style: none;
-    }
-    .ct-legend li {
-        position: relative;
-        padding-left: 23px;
-        margin-bottom: 3px;
-        cursor: pointer;
-    }
-    .ct-legend li:before {
-        width: 12px;
-        height: 12px;
-        position: absolute;
-        left: 0;
-        content: '';
-        border: 3px solid transparent;
-        border-radius: 2px;
-    }
-    .ct-legend li.inactive:before {
-        background: transparent;
-    }
-    .ct-legend.ct-legend-inside {
-        position: absolute;
-        top: 0;
-        right: 0;
-    }
-    .ct-legend .ct-series-0:before {
-        background-color: #d70206;
-        border-color: #d70206;
-    }
-    .ct-legend .ct-series-1:before {
-        background-color: #f05b4f;
-        border-color: #f05b4f;
-    }
-    .ct-legend .ct-series-2:before {
-        background-color: #f4c63d;
-        border-color: #f4c63d;
-    }
-    .ct-legend .ct-series-3:before {
-        background-color: #d17905;
-        border-color: #d17905;
-    }
-    .ct-legend .ct-series-4:before {
-        background-color: #453d3f;
-        border-color: #453d3f;
-    }
-
-    </style>
-
-</head>
-<body>
 <script>
- var requests=0;
- $(function() {
-     setTimeout(load, 100);
-      //todo fix setInterval(load, 60000);
- });
-
-
- function load1() {
-     $("#loadStatus").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Please wait");
-
-     requests++;
-     $.ajax({
-        url: "/rest/metrics/failures",
-
-        success: function(result) {
-            requests--;
-            if(result.updateRequired && requests<=1) {
-                 setTimeout(load1, 2000);
-                 $("#loadStatus").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Updating");
-            } else {
-                 $("#loadStatus").html("");
-            }
-
-            showChart('.ct-chart-failed', result.failed, 'legend');
-            showChart('.ct-chart-notrun', result.notrun, 'legend');
-            showChart('.ct-chart-muted', result.muted, 'legend');
-            showChart('.ct-chart-total', result.total, 'legend');
-        }
-     })
- }
-
- function load2() {
-     $("#loadStatus2").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Please wait");
-
-     requests++;
-     $.ajax({
-        url: "/rest/metrics/failuresPrivate",
-
-        success: function(result) {
-            requests--;
-            if(result.updateRequired && requests<=2) {
-                 setTimeout(load2, 2000);
-                 $("#loadStatus2").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Updating");
-            } else {
-                 $("#loadStatus2").html("");
-            }
-            showChart('.ct-chart-failed-private', result.failed, 'legend-private');
-            showChart('.ct-chart-notrun-private', result.notrun, 'legend-private');
-            showChart('.ct-chart-muted-private', result.muted, 'legend-private');
-            showChart('.ct-chart-total-private', result.total, 'legend-private');
-        }
-     })
- }
-
-
- function load() {
-     load1();
-     load2();
- }
-
- function showChart(element, chartData, legendId) {
-     var data = [];
-     for(i=0; i<chartData.lines.length; i++) {
-        data[i]=chartData.lines[i].values;
-     }
-     var legendDiv = document.getElementById(legendId);
-     legendDiv.innerHTML = '';
-     new Chartist.Line(element, {
-         labels: chartData.axisX,
-         series: data
-     }, {
-         fullWidth: true,
-         lineSmooth: Chartist.Interpolation.cardinal({
-            fillHoles: true,
-         }),
-
-         showArea: true,
-         chartPadding: {
-             right: 30
-         },
-         plugins: [
-            Chartist.plugins.legend({
-                legendNames: chartData.legendLabels,
-                position: legendDiv
-            })
-         ]
-     });
- } 
-
+    window.location='comparison.html';
 </script>
 
-
-<div id="loadStatus"></div>
-<div id="loadStatus2"></div>
-<div><a href=".">Home</a><br></div>
-
-<table style="">
-    <tr>
-        <th> <div id="legend"></div>
-        </th>
-        <th><div id="legend-private"></div>
-        </th>
-    </tr>
-    <tr>
-        <td>
-            Failed tests:
-            <div class="ct-chart-failed" style="width: 1000px; height: 400px;"></div>
-        </td>
-        <td>
-            Failed tests:
-            <div class="ct-chart-failed-private" style="width: 1000px; height: 400px;"></div>
-        </td>
-    </tr>
-
-    <tr>
-        <td>
-            Not runned suites:
-            <div class="ct-chart-notrun" style="width: 1000px; height: 400px;"></div>
-        </td>
-        <td>
-            Not runned suites:
-            <div class="ct-chart-notrun-private" style="width: 1000px; height: 400px;"></div>
-        </td>
-    </tr>
-    <tr>
-        <td>
-            Muted failures:
-            <div class="ct-chart-muted" style="width: 1000px; height: 400px;"></div>
-        </td>
-        <td>
-            Muted failures:
-            <div class="ct-chart-muted-private" style="width: 1000px; height: 400px;"></div>
-        </td>
-    </tr>
-    <tr>
-    <td>
-        Total tests:
-        <div class="ct-chart-total" style="width: 1000px; height: 400px;"></div>
-    </td>
-    <td>
-        Total tests:
-        <div class="ct-chart-total-private" style="width: 1000px; height: 400px;"></div>
-    </td>
-</tr>
-</table> 
-</body>
-</html>
\ No newline at end of file
+<a href="comparison.html">Page moved here</a>
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
index 1efc666..779c83d 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
@@ -26,7 +26,10 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.stream.Collectors;
 import javax.xml.bind.JAXBException;
 import org.apache.ignite.Ignite;
@@ -53,6 +56,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 
 import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
 import static org.apache.ignite.ci.HelperConfig.ensureDirExist;
 import static org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor.STRINGS_CACHE;
@@ -247,7 +251,7 @@ public class IgnitedTcInMemoryIntegrationTest {
     @Test
     public void testFatBuild() throws JAXBException, IOException {
         Build refBuild = jaxbTestXml("/build.xml", Build.class);
-        TestOccurrences tests = jaxbTestXml("/testList.xml", TestOccurrences.class);
+        TestOccurrences testsRef = jaxbTestXml("/testList.xml", TestOccurrences.class);
 
         Injector injector = Guice.createInjector(new AbstractModule() {
             @Override protected void configure() {
@@ -260,9 +264,9 @@ public class IgnitedTcInMemoryIntegrationTest {
         stor.init();
 
         int srvIdMaskHigh = ITeamcityIgnited.serverIdToInt(APACHE);
-        List<TestOccurrences> occurrences = Collections.singletonList(tests);
-        int i = stor.saveBuild(srvIdMaskHigh, refBuild, occurrences);
-        assertEquals(1, i);
+        List<TestOccurrences> occurrences = Collections.singletonList(testsRef);
+        FatBuildCompacted buildCompacted = stor.saveBuild(srvIdMaskHigh, refBuild, occurrences);
+        assertNotNull(buildCompacted);
 
         FatBuildCompacted fatBuild = stor.getFatBuild(srvIdMaskHigh, 2153237);
 
@@ -273,9 +277,9 @@ public class IgnitedTcInMemoryIntegrationTest {
         saveTmpFile(refBuild, "src/test/tmp/buildRef.xml");
         saveTmpFile(actBuild, "src/test/tmp/buildAct.xml");
 
-        TestOccurrences occurrencesAct = fatBuild.getTestOcurrences(compactor);
-        saveTmpFile(tests, "src/test/tmp/testListRef.xml");
-        saveTmpFile(occurrencesAct, "src/test/tmp/testListAct.xml");
+        TestOccurrences testsAct = fatBuild.getTestOcurrences(compactor);
+        saveTmpFile(testsRef, "src/test/tmp/testListRef.xml");
+        saveTmpFile(testsAct, "src/test/tmp/testListAct.xml");
 
         assertEquals(refBuild.getId(), actBuild.getId());
         assertEquals(refBuild.status(), actBuild.status());
@@ -288,6 +292,14 @@ public class IgnitedTcInMemoryIntegrationTest {
         assertEquals(refBt.getName(), actBt.getName());
         assertEquals(refBt.getProjectId(), actBt.getProjectId());
         assertEquals(refBt.getId(), actBt.getId());
+
+        Set<String> testNamesAct = new TreeSet<>();
+        testsAct.getTests().forEach(testOccurrence -> testNamesAct.add(testOccurrence.name));
+
+
+        Set<String> testNamesRef = new TreeSet<>();
+        testsRef.getTests().forEach(testOccurrence -> testNamesRef.add(testOccurrence.name));
+        assertEquals(testNamesRef, testNamesAct);
     }
 
     public void saveTmpFile(Object obj, String name) throws IOException, JAXBException {