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/01 19:26:02 UTC

[ignite-teamcity-bot] 01/02: IGNITE-9849 Refactor Master trends page - Fixes #57.

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

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

commit ce8f7a13de3e80b3e2228326083f42153c197a07
Author: zzzadruga <zz...@gmail.com>
AuthorDate: Thu Nov 1 22:23:26 2018 +0300

    IGNITE-9849 Refactor Master trends page - Fixes #57.
    
    Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
 .../java/org/apache/ignite/ci/db/DbMigrations.java |   3 +
 .../ci/teamcity/ignited/BuildRefCompacted.java     |   2 +-
 .../ignite/ci/teamcity/ignited/BuildRefDao.java    |   1 +
 .../ci/teamcity/ignited/ITeamcityIgnited.java      |  21 ++-
 .../ci/teamcity/ignited/TeamcityIgnitedImpl.java   | 154 ++++++++++++++++++-
 .../ci/teamcity/ignited/TeamcityIgnitedModule.java |   2 +-
 .../ignited/buildcondition}/BuildCondition.java    |   2 +-
 .../buildcondition}/BuildConditionCompacted.java   |   4 +-
 .../ignited/buildcondition}/BuildConditionDao.java |  10 +-
 .../ignited/fatbuild/FatBuildCompacted.java        |  45 +++++-
 .../ignited/fatbuild/ProblemCompacted.java         |   6 +-
 .../teamcity/ignited/fatbuild/TestCompacted.java   |   4 +
 .../web/model/current/BuildStatisticsSummary.java  | 170 +++++++++++----------
 .../ignite/ci/web/model/hist/BuildsHistory.java    |  37 +++--
 .../ci/web/rest/build/GetBuildTestFailures.java    |  14 +-
 .../src/main/webapp/comparison.html                |  48 +++---
 .../src/main/webapp/css/style-1.5.css              |  57 +++++++
 17 files changed, 429 insertions(+), 151 deletions(-)

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 824dc4a..5b5eb21 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
@@ -66,6 +66,8 @@ public class DbMigrations {
 
     private static final String BUILD_STATISTICS = "buildStatistics";
 
+    private static final String BUILD_CONDITIONS_CACHE_NAME = "buildConditions";
+
     public static final String TESTS_COUNT_7700 = ",count:7700";
 
     //V1 caches, 1024 parts
@@ -407,6 +409,7 @@ public class DbMigrations {
         applyDestroyIgnCacheMigration(TESTS);
         applyDestroyIgnCacheMigration(STAT);
         applyDestroyIgnCacheMigration(BUILD_STATISTICS);
+        applyDestroyCacheMigration(BUILD_CONDITIONS_CACHE_NAME, BUILD_CONDITIONS_CACHE_NAME);
         applyDestroyCacheMigration(TEAMCITY_BUILD_CACHE_NAME_OLD, TEAMCITY_BUILD_CACHE_NAME_OLD);
     }
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefCompacted.java
index a3aff88..a0f6d36 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/BuildRefCompacted.java
@@ -140,7 +140,7 @@ public class BuildRefCompacted {
     }
 
     /** */
-    private int status() {
+    public int status() {
         return status;
     }
 
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 0d7467a..8a9a264 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
@@ -34,6 +34,7 @@ import org.apache.ignite.ci.db.TcHelperDb;
 import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.di.cache.GuavaCached;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.util.GridIntList;
 import org.jetbrains.annotations.NotNull;
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 cfdaa2e..3e69094 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
@@ -17,9 +17,10 @@
 package org.apache.ignite.ci.teamcity.ignited;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import javax.annotation.Nullable;
-import org.apache.ignite.ci.tcbot.condition.BuildCondition;
+import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildCondition;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
@@ -40,7 +41,7 @@ public interface ITeamcityIgnited {
     public String host();
 
     /**
-     * Retun all builds for branch and suite, without relation to its status.
+     * Return all builds for branch and suite, without relation to its status.
      *
      * @param buildTypeId Build type identifier.
      * @param branchName Branch name.
@@ -50,7 +51,6 @@ public interface ITeamcityIgnited {
             @Nullable String buildTypeId,
             @Nullable String branchName);
 
-
     /**
      * Retun all builds for branch and suite, without relation to its status.
      *
@@ -63,6 +63,21 @@ public interface ITeamcityIgnited {
         @Nullable String branchName);
 
     /**
+     * Return all builds for branch and suite with finish status.
+     *
+     * @param buildTypeId Build type identifier.
+     * @param branchName Branch name.
+     * @param sinceDate Since date.
+     * @param untilDate Until date.
+     * @return list of builds in history in finish status.
+     */
+    public List<BuildRefCompacted> getFinishedBuildsCompacted(
+        @Nullable String buildTypeId,
+        @Nullable String branchName,
+        @Nullable Date sinceDate,
+        @Nullable Date untilDate);
+
+    /**
      * Trigger build. Enforces TC Bot to load all builds related to this triggered one.
      *
      * @param buildTypeId Build type identifier.
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 ce05e93..ec1bf22 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
@@ -18,12 +18,13 @@ package org.apache.ignite.ci.teamcity.ignited;
 
 
 import com.google.common.collect.Sets;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.scheduler.IScheduler;
-import org.apache.ignite.ci.tcbot.condition.BuildCondition;
-import org.apache.ignite.ci.tcbot.condition.BuildConditionDao;
+import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildCondition;
+import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildConditionDao;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
@@ -44,6 +45,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
+import static org.apache.ignite.ci.tcmodel.hist.BuildRef.STATUS_UNKNOWN;
+
 public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     /** Logger. */
     private static final Logger logger = LoggerFactory.getLogger(TeamcityIgnitedImpl.class);
@@ -117,6 +120,153 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     }
 
     /** {@inheritDoc} */
+    public List<BuildRefCompacted> getFinishedBuildsCompacted(
+        @Nullable String buildTypeId,
+        @Nullable String branchName,
+        @Nullable Date sinceDate,
+        @Nullable Date untilDate) {
+        final int allDatesOutOfBounds = -1;
+        final int someDatesOutOfBounds = -2;
+        final int invalidVal = -3;
+        final int unknownStatus = compactor.getStringId(STATUS_UNKNOWN);
+
+        List<BuildRefCompacted> buildRefs = getBuildHistoryCompacted(buildTypeId, branchName)
+            .stream().filter(b -> b.status() != unknownStatus).collect(Collectors.toList());
+
+        int idSince = 0;
+        int idUntil = buildRefs.size() - 1;
+
+        if (sinceDate != null) {
+            idSince = binarySearchDate(buildRefs, 0, buildRefs.size(), sinceDate, true);
+            idSince = (idSince == someDatesOutOfBounds) ? 0 : idSince;
+        }
+
+        if (untilDate != null) {
+            idUntil = (idSince < 0) ? allDatesOutOfBounds :
+                binarySearchDate(buildRefs, idSince, buildRefs.size(), untilDate, false);
+            idUntil = (idUntil == someDatesOutOfBounds) ? buildRefs.size() - 1 : idUntil;
+        }
+
+        if (idSince == invalidVal || idUntil == invalidVal) {
+            AtomicBoolean stopFilter = new AtomicBoolean();
+            AtomicBoolean addBuild = new AtomicBoolean();
+
+            return buildRefs.stream()
+                .filter(b -> {
+                    if (stopFilter.get())
+                        return addBuild.get();
+
+                    FatBuildCompacted build = getFatBuild(b.id());
+
+                    if (build == null || build.isFakeStub())
+                        return false;
+
+                    Date date = build.getStartDate();
+
+                    if (sinceDate != null && untilDate != null)
+                        if ((date.after(sinceDate) || date.equals(sinceDate)) &&
+                            (date.before(untilDate) || date.equals(untilDate)))
+                            return true;
+                        else {
+                            if (date.after(untilDate)) {
+                                stopFilter.set(true);
+                                addBuild.set(false);
+                            }
+
+                            return false;
+                        }
+                    else if (sinceDate != null) {
+                        if (date.after(sinceDate) || date.equals(sinceDate)) {
+                            stopFilter.set(true);
+                            addBuild.set(true);
+
+                            return true;
+                        }
+
+                        return false;
+                    }
+                    else {
+                        if (date.after(untilDate)) {
+                            stopFilter.set(true);
+                            addBuild.set(false);
+
+                            return false;
+                        }
+
+                        return true;
+                    }
+                })
+                .collect(Collectors.toList());
+        } else if (idSince == allDatesOutOfBounds || idUntil == allDatesOutOfBounds)
+            return Collections.emptyList();
+        else
+            return buildRefs.subList(idSince, idUntil + 1);
+    }
+
+    /**
+     * @param buildRefs Build refs list.
+     * @param fromIdx From index.
+     * @param toIdx To index.
+     * @param key Key.
+     * @param since {@code true} If key is sinceDate, {@code false} is untilDate.
+     *
+     * @return {@value >= 0} Build id from list with min interval between key. If since {@code true}, min interval
+     * between key and same day or later. If since {@code false}, min interval between key and same day or earlier;
+     * {@value -1} All dates out of bounds. If sinceDate after last list element date or untilDate before first list
+     * element;
+     * {@value -2} Some dates out of bounds. If sinceDate before first list element or untilDate after last list
+     * element;
+     * {@value -3} Invalid value. If method get null or fake stub build.
+     */
+    private int binarySearchDate(List<BuildRefCompacted> buildRefs, int fromIdx, int toIdx, Date key, boolean since) {
+        final int allDatesOutOfBounds = -1;
+        final int someDatesOutOfBounds = -2;
+        final int invalidVal = -3;
+
+        int low = fromIdx;
+        int high = toIdx - 1;
+        long minDiff = key.getTime();
+        int minDiffId = since ? low : high;
+        long temp;
+
+        FatBuildCompacted highBuild = getFatBuild(buildRefs.get(high).id());
+        FatBuildCompacted lowBuild = getFatBuild(buildRefs.get(low).id());
+
+        if (highBuild != null && !highBuild.isFakeStub()){
+            if (highBuild.getStartDate().before(key))
+                return since ? allDatesOutOfBounds : someDatesOutOfBounds;
+        }
+
+        if (lowBuild != null && !lowBuild.isFakeStub()){
+            if (lowBuild.getStartDate().after(key))
+                return since ? someDatesOutOfBounds : allDatesOutOfBounds;
+        }
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            FatBuildCompacted midVal = getFatBuild(buildRefs.get(mid).id());
+
+            if (midVal != null && !midVal.isFakeStub()) {
+                if (midVal.getStartDate().after(key))
+                    high = mid - 1;
+                else if (midVal.getStartDate().before(key))
+                    low = mid + 1;
+                else
+                    return mid;
+
+                temp = midVal.getStartDate().getTime() - key.getTime();
+
+                if ((temp > 0 == since) && (Math.abs(temp) < minDiff)) {
+                    minDiff = Math.abs(temp);
+                    minDiffId = mid;
+                }
+            } else
+                return invalidVal;
+        }
+        return minDiffId;
+    }
+
+    /** {@inheritDoc} */
     @AutoProfiling
     @Override public List<BuildRef> getBuildHistory(
             @Nullable String buildTypeId,
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java
index 691c6d9..ceb427f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java
@@ -18,7 +18,7 @@ package org.apache.ignite.ci.teamcity.ignited;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.internal.SingletonScope;
-import org.apache.ignite.ci.tcbot.condition.BuildConditionDao;
+import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildConditionDao;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeDao;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeSync;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildDao;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildCondition.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildCondition.java
similarity index 97%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildCondition.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildCondition.java
index 6a1e0fa..ac50f48 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildCondition.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildCondition.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.tcbot.condition;
+package org.apache.ignite.ci.teamcity.ignited.buildcondition;
 
 import java.util.Date;
 import java.util.Objects;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionCompacted.java
similarity index 95%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionCompacted.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionCompacted.java
index 430eb8d..93074cd 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionCompacted.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.tcbot.condition;
+package org.apache.ignite.ci.teamcity.ignited.buildcondition;
 
 import java.util.Date;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
@@ -44,7 +44,7 @@ public class BuildConditionCompacted {
     }
 
     /**
-     * @param compactor Compacter.
+     * @param compactor Compactor.
      * @param cond Build condition.
      */
     public BuildConditionCompacted(IStringCompactor compactor, BuildCondition cond) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
similarity index 87%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionDao.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
index 633eddc..5862b14 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/condition/BuildConditionDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildcondition/BuildConditionDao.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.tcbot.condition;
+package org.apache.ignite.ci.teamcity.ignited.buildcondition;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
-import org.apache.ignite.ci.db.TcHelperDb;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 
+import static org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor.getCache8PartsConfig;
+
 public class BuildConditionDao {
     /** Cache name*/
-    public static final String BUILD_CONDITIONS_CACHE_NAME = "buildConditions";
+    public static final String BUILDS_CONDITIONS_CACHE_NAME = "buildsConditions";
 
     /** Ignite provider. */
     @Inject private Provider<Ignite> igniteProvider;
@@ -42,7 +43,7 @@ public class BuildConditionDao {
      */
     public void init () {
         Ignite ignite = igniteProvider.get();
-        buildsCache = ignite.getOrCreateCache(TcHelperDb.getCacheV2Config(BUILD_CONDITIONS_CACHE_NAME));
+        buildsCache = ignite.getOrCreateCache(getCache8PartsConfig(BUILDS_CONDITIONS_CACHE_NAME));
     }
 
     /**
@@ -50,7 +51,6 @@ public class BuildConditionDao {
      * @param buildId Build id.
      */
     private long buildIdToCacheKey(long srvIdMaskHigh, int buildId) {
-
         return (long)buildId | srvIdMaskHigh << 32;
     }
 
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 04f2a63..b062a54 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
@@ -18,6 +18,8 @@ package org.apache.ignite.ci.teamcity.ignited.fatbuild;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.ignite.ci.analysis.IVersionedEntity;
 import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.ci.tcmodel.conf.BuildType;
@@ -56,6 +58,10 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
     /**   flag offset. */
     public static final int FAKE_BUILD_F = 4;
+
+    /** Failed to start flag offset. */
+    public static final int FAILED_TO_START_F = 6;
+
     public static final int[] EMPTY = new int[0];
 
     /** Entity fields version. */
@@ -121,15 +127,25 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
             name = compactor.getStringId(type.getName());
         }
 
+        AtomicBoolean failedToStart = new AtomicBoolean();
+
         int[] arr = build.getSnapshotDependenciesNonNull().stream()
-            .filter(b -> b.getId() != null).mapToInt(BuildRef::getId).toArray();
+            .filter(b -> {
+                if (!(failedToStart.get() || b.isNotCancelled()))
+                    failedToStart.set(true);
+
+                return b.getId() != null;
+            }).mapToInt(BuildRef::getId).toArray();
 
         snapshotDeps = arr.length > 0 ? arr : null;
 
         setFlag(DEF_BR_F, build.defaultBranch);
         setFlag(COMPOSITE_F, build.composite);
 
-        if(build.isFakeStub())
+        if (failedToStart.get())
+            setFlag(FAILED_TO_START_F, true);
+
+        if (build.isFakeStub())
             setFlag(FAKE_BUILD_F, true);
     }
 
@@ -246,12 +262,17 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
         TestOccurrencesFull testOccurrences = new TestOccurrencesFull();
 
-        testOccurrences.setTests(res);
         testOccurrences.count = res.size();
+        testOccurrences.setTests(res);
 
         return testOccurrences;
     }
 
+    /** Start date. */
+    public Date getStartDate() {
+        return new Date(startDate);
+    }
+
     /** {@inheritDoc} */
     @Override public boolean equals(Object o) {
         if (this == o)
@@ -290,6 +311,24 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
         return flag != null && flag;
     }
 
+    /**
+     *
+     */
+    public boolean isFakeStub() {
+        Boolean flag = getFlag(FAKE_BUILD_F);
+
+        return flag != null && flag;
+    }
+
+    /**
+     *
+     */
+    public boolean isFailedToStart() {
+        Boolean flag = getFlag(FAILED_TO_START_F);
+
+        return flag != null && flag;
+    }
+
     public Stream<TestCompacted> getFailedNotMutedTests(IStringCompactor compactor) {
         if (tests == null)
             return Stream.of();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProblemCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProblemCompacted.java
index f15c418..9340682 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProblemCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProblemCompacted.java
@@ -82,7 +82,7 @@ public class ProblemCompacted {
 
         String fullStrId =
                 "problem:(id:" + id + ")," +
-                        " build:(id:" + buildId + ")";
+                        "build:(id:" + buildId + ")";
         occurrence.id(fullStrId);
         occurrence.type = compactor.getStringFromId(type);
         occurrence.identity = compactor.getStringFromId(identity);
@@ -148,6 +148,10 @@ public class ProblemCompacted {
                 || compactor.getStringId(ProblemOccurrence.SNAPSHOT_DEPENDENCY_ERROR_BUILD_PROCEEDS_TYPE) == type;
     }
 
+    public int type() {
+        return type;
+    }
+
     @Override public String toString() {
         return MoreObjects.toStringHelper(this)
             .add("id", id)
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 753a0ba..2433849 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
@@ -345,6 +345,10 @@ public class TestCompacted {
         return investigatedFlag != null && investigatedFlag;
     }
 
+    public int status() {
+        return status;
+    }
+
     @Nullable
     public Integer getDuration() {
         return duration < 0 ? null : duration;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/BuildStatisticsSummary.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/BuildStatisticsSummary.java
index 0c604cd..c8dc04e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/BuildStatisticsSummary.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/BuildStatisticsSummary.java
@@ -27,19 +27,23 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import javax.annotation.Nonnull;
-import org.apache.ignite.ci.ITeamcity;
-import org.apache.ignite.ci.tcmodel.hist.BuildRef;
-import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.tcmodel.result.TestOccurrencesRef;
-import org.apache.ignite.ci.tcmodel.result.problems.ProblemOccurrence;
-import org.apache.ignite.ci.web.rest.parms.FullQueryParams;
+import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.ProblemCompacted;
+
+import static org.apache.ignite.ci.tcmodel.hist.BuildRef.STATUS_SUCCESS;
+import static org.apache.ignite.ci.tcmodel.result.problems.ProblemOccurrence.*;
 
 /**
  * Summary of build statistics.
  */
 public class BuildStatisticsSummary {
+    /** String ids. */
+    public static HashMap<String, Integer> strIds = new HashMap<>();
+
     /** Short problem names. */
     public static final String TOTAL = "TOTAL";
 
@@ -51,10 +55,10 @@ public class BuildStatisticsSummary {
 
     static {
         shortProblemNames.put(TOTAL, "TT");
-        shortProblemNames.put(ProblemOccurrence.TC_EXECUTION_TIMEOUT, "ET");
-        shortProblemNames.put(ProblemOccurrence.TC_JVM_CRASH, "JC");
-        shortProblemNames.put(ProblemOccurrence.TC_OOME, "OO");
-        shortProblemNames.put(ProblemOccurrence.TC_EXIT_CODE, "EC");
+        shortProblemNames.put(TC_EXECUTION_TIMEOUT, "ET");
+        shortProblemNames.put(TC_JVM_CRASH, "JC");
+        shortProblemNames.put(TC_OOME, "OO");
+        shortProblemNames.put(TC_EXIT_CODE, "EC");
 
         fullProblemNames = shortProblemNames.inverse();
     }
@@ -66,10 +70,10 @@ public class BuildStatisticsSummary {
     public String startDate;
 
     /** Test occurrences. */
-    public TestOccurrencesRef testOccurrences;
+    public TestOccurrencesRef testOccurrences = new TestOccurrencesRef();
 
     /** List of problem occurrences. */
-    private List<ProblemOccurrence> problemOccurrenceList;
+    private List<ProblemCompacted> problemOccurrenceList;
 
     /** Duration (seconds). */
     public long duration;
@@ -86,13 +90,21 @@ public class BuildStatisticsSummary {
     /**
      * @param buildId Build id.
      */
-    public BuildStatisticsSummary(Integer buildId){
+    public BuildStatisticsSummary(Integer buildId) {
         this.buildId = buildId;
     }
 
     /** Initialize build statistics. */
-    public void initialize(@Nonnull final ITeamcity teamcity) {
-        Build build = teamcity.getBuild(buildId);
+    public void initialize(@Nonnull final IStringCompactor compactor, @Nonnull final ITeamcityIgnited ignitedTeamcity) {
+        if (strIds.isEmpty()) {
+            strIds.put(STATUS_SUCCESS, compactor.getStringId(STATUS_SUCCESS));
+            strIds.put(TC_EXIT_CODE, compactor.getStringId(TC_EXIT_CODE));
+            strIds.put(TC_OOME, compactor.getStringId(TC_OOME));
+            strIds.put(TC_JVM_CRASH, compactor.getStringId(TC_JVM_CRASH));
+            strIds.put(TC_EXECUTION_TIMEOUT, compactor.getStringId(TC_EXECUTION_TIMEOUT));
+        }
+
+        FatBuildCompacted build = ignitedTeamcity.getFatBuild(buildId);
 
         isFakeStub = build.isFakeStub();
 
@@ -100,113 +112,107 @@ public class BuildStatisticsSummary {
             return;
 
         DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy'T'HH:mm:ss");
-        dateFormat.format(build.getFinishDate());
+
         startDate = dateFormat.format(build.getStartDate());
 
-        testOccurrences = build.testOccurrences;
+        int[] arr = new int[4];
 
-        duration = (build.getFinishDate().getTime() - build.getStartDate().getTime()) / 1000;
+        build.getAllTests().forEach(t -> {
+                if (t.getIgnoredFlag())
+                    arr[0]++;
+                else if (t.getMutedFlag())
+                    arr[1]++;
+                else if (t.status() != strIds.get(STATUS_SUCCESS))
+                    arr[2]++;
 
-        List<BuildRef> snapshotDependencies = getSnapshotDependencies(teamcity, build);
+            arr[3]++;
+        });
 
-        List<BuildRef> snapshotDependenciesWithProblems = getBuildsWithProblems(snapshotDependencies);
+        testOccurrences.ignored = arr[0];
+        testOccurrences.muted = arr[1];
+        testOccurrences.failed = arr[2];
+        testOccurrences.count = arr[3];
+        testOccurrences.passed = testOccurrences.count - testOccurrences.failed - testOccurrences.ignored -
+            testOccurrences.muted;
 
-        problemOccurrenceList = getProblems(teamcity, snapshotDependenciesWithProblems);
+        duration = build.buildDuration(compactor) / 1000;
 
-        totalProblems = getRes();
-    }
+        List<FatBuildCompacted> snapshotDependencies = getSnapshotDependencies(ignitedTeamcity, buildId);
 
-    private long getExecutionTimeoutCount(String buildTypeId) {
-        return getProblemsStream(buildTypeId).filter(ProblemOccurrence::isExecutionTimeout).count();
-    }
+        List<FatBuildCompacted> snapshotDependenciesWithProblems = getBuildsWithProblems(snapshotDependencies);
 
-    private long getJvmCrashProblemCount(String buildTypeId) {
-        return getProblemsStream(buildTypeId).filter(ProblemOccurrence::isJvmCrash).count();
-    }
+        problemOccurrenceList = getProblems(snapshotDependenciesWithProblems);
 
-    private long getExitCodeProblemsCount(String buildTypeId) {
-        return getProblemsStream(buildTypeId).filter(ProblemOccurrence::isExitCode).count();
+        totalProblems = getBuildTypeProblemsCount();
     }
 
-    private long getOomeProblemCount(String buildTypeId) {
-        return getProblemsStream(buildTypeId).filter(ProblemOccurrence::isOome).count();
+    /**
+     * @param problemName Problem name.
+     */
+    private long getProblemsCount(String problemName) {
+        if (problemOccurrenceList == null)
+            return 0;
+
+        return problemOccurrenceList.stream()
+            .filter(Objects::nonNull)
+            .filter(p -> p.type() == strIds.get(problemName)).count();
     }
 
     /**
      * Problems for all snapshot-dependencies.
      *
-     * @param teamcity Teamcity.
+     * @param builds Builds.
      */
-    private List<ProblemOccurrence> getProblems(@Nonnull final ITeamcity teamcity, List<BuildRef> builds){
-        List<ProblemOccurrence> problemOccurrences = new ArrayList<>();
-
-        for (BuildRef buildRef : builds)
-            problemOccurrences.addAll(teamcity
-                .getProblems(buildRef)
-                .getProblemsNonNull());
-
+    private List<ProblemCompacted> getProblems(List<FatBuildCompacted> builds) {
+        List<ProblemCompacted> problemOccurrences = new ArrayList<>();
+
+        for (FatBuildCompacted build : builds) {
+            problemOccurrences.addAll(
+                build.problems()
+            );
+        }
         return problemOccurrences;
     }
 
     /**
      * Snapshot-dependencies for build.
      *
-     * @param teamcity Teamcity.
-     * @param buildRef Build reference.
+     * @param ignitedTeamcity ignitedTeamcity.
+     * @param buildId Build Id.
      */
-    private List<BuildRef> getSnapshotDependencies(@Nonnull final ITeamcity teamcity, BuildRef buildRef){
-        FullQueryParams key = new FullQueryParams();
+    private List<FatBuildCompacted> getSnapshotDependencies(@Nonnull final ITeamcityIgnited ignitedTeamcity,
+        Integer buildId) {
+        List<FatBuildCompacted> snapshotDependencies = new ArrayList<>();
+        FatBuildCompacted build = ignitedTeamcity.getFatBuild(buildId);
 
-        key.setServerId(teamcity.serverId());
-        key.setBuildId(buildRef.getId());
+        if (build.snapshotDependencies().length > 0) {
+            for (Integer id : build.snapshotDependencies())
+                snapshotDependencies.addAll(getSnapshotDependencies(ignitedTeamcity, id));
+        }
 
-        return teamcity.getConfigurations(key).getBuilds();
-    }
+        snapshotDependencies.add(build);
 
+        return snapshotDependencies;
+    }
     /**
      * Builds without status "Success".
      */
-    private List<BuildRef> getBuildsWithProblems(List<BuildRef> builds){
+    private List<FatBuildCompacted> getBuildsWithProblems(List<FatBuildCompacted> builds) {
         return builds.stream()
-            .filter(b -> !b.isSuccess())
+            .filter(b -> b.status() != strIds.get(STATUS_SUCCESS))
             .collect(Collectors.toList());
     }
 
     /**
-     * @param buildTypeId Build type id (if null - for all problems).
-     */
-    private Stream<ProblemOccurrence> getProblemsStream(String buildTypeId) {
-        if (problemOccurrenceList == null)
-            return Stream.empty();
-
-        return problemOccurrenceList.stream()
-            .filter(Objects::nonNull)
-            .filter(p -> buildTypeId == null || buildTypeId.equals(p.buildRef.buildTypeId));
-    }
-
-    /**
-     * Short build run result (without snapshot-dependencies result).
-     *
-     * @return printable result;
-     */
-    private Map<String, Long> getRes(){
-        return getBuildTypeProblemsCount(null);
-    }
-
-
-    /**
      * BuildType problems count (EXECUTION TIMEOUT, JVM CRASH, OOMe, EXIT CODE, TOTAL PROBLEMS COUNT).
-     *
-     * @param buildTypeId Build type id.
      */
-    private Map<String, Long> getBuildTypeProblemsCount(String buildTypeId){
+    private Map<String, Long> getBuildTypeProblemsCount() {
         Map<String, Long> occurrences = new HashMap<>();
 
-        occurrences.put(shortProblemNames.get(ProblemOccurrence.TC_EXECUTION_TIMEOUT),
-            getExecutionTimeoutCount(buildTypeId));
-        occurrences.put(shortProblemNames.get(ProblemOccurrence.TC_JVM_CRASH), getJvmCrashProblemCount(buildTypeId));
-        occurrences.put(shortProblemNames.get(ProblemOccurrence.TC_OOME), getOomeProblemCount(buildTypeId));
-        occurrences.put(shortProblemNames.get(ProblemOccurrence.TC_EXIT_CODE), getExitCodeProblemsCount(buildTypeId));
+        occurrences.put(shortProblemNames.get(TC_EXECUTION_TIMEOUT), getProblemsCount(TC_EXECUTION_TIMEOUT));
+        occurrences.put(shortProblemNames.get(TC_JVM_CRASH), getProblemsCount(TC_JVM_CRASH));
+        occurrences.put(shortProblemNames.get(TC_OOME), getProblemsCount(TC_OOME));
+        occurrences.put(shortProblemNames.get(TC_EXIT_CODE), getProblemsCount(TC_EXIT_CODE));
         occurrences.put(shortProblemNames.get(TOTAL), occurrences.values().stream().mapToLong(Long::longValue).sum());
 
         return occurrences;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
index 0f22a0e..e85d34c 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/BuildsHistory.java
@@ -19,9 +19,7 @@ package org.apache.ignite.ci.web.model.hist;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
 import java.io.UncheckedIOException;
-import java.lang.reflect.Array;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -32,21 +30,20 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 import javax.servlet.ServletContext;
-import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
 import org.apache.ignite.ci.ITcHelper;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.tcbot.chain.BuildChainProcessor;
 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.TestOccurrences;
+import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
+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.user.ICredentialsProv;
 import org.apache.ignite.ci.web.CtxListener;
 import org.apache.ignite.ci.web.model.current.BuildStatisticsSummary;
-import org.apache.ignite.ci.web.rest.exception.ServiceUnauthorizedException;
 import org.apache.ignite.ci.web.rest.parms.FullQueryParams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -92,25 +89,26 @@ public class BuildsHistory {
 
     /** */
     public void initialize(ICredentialsProv prov, ServletContext context) {
-        if (!prov.hasAccess(srvId))
-            throw ServiceUnauthorizedException.noCreds(srvId);
+        final IStringCompactor compactor = CtxListener.getInjector(context).getInstance(IStringCompactor.class);
 
         ITcHelper tcHelper = CtxListener.getTcHelper(context);
 
-        IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, prov);
+        ITeamcity teamcity = tcHelper.server(srvId, prov);
 
         ITeamcityIgnitedProvider tcIgnitedProv = CtxListener.getInjector(context)
             .getInstance(ITeamcityIgnitedProvider.class);
 
-        ITeamcityIgnited ignited = tcIgnitedProv.server(srvId, prov);
+        ITeamcityIgnited ignitedTeamcity = tcIgnitedProv.server(srvId, prov);
 
-        int[] finishedBuildsIds = teamcity.getBuildNumbersFromHistory(buildTypeId, branchName,
-            sinceDateFilter, untilDateFilter);
+        List<Integer> finishedBuildsIds = ignitedTeamcity
+            .getFinishedBuildsCompacted(buildTypeId, branchName, sinceDateFilter, untilDateFilter)
+            .stream().mapToInt(BuildRefCompacted::id).boxed()
+            .collect(Collectors.toList());
 
-        Map<Integer, Boolean> buildIdsWithConditions = IntStream.of(finishedBuildsIds)
-            .boxed().collect(Collectors.toMap(v -> v, ignited::buildIsValid,  (e1, e2) -> e1, LinkedHashMap::new));
+        Map<Integer, Boolean> buildIdsWithConditions = finishedBuildsIds.stream()
+            .collect(Collectors.toMap(v -> v, ignitedTeamcity::buildIsValid,  (e1, e2) -> e1, LinkedHashMap::new));
 
-        initStatistics(teamcity, buildIdsWithConditions);
+        initStatistics(compactor, teamcity, ignitedTeamcity, buildIdsWithConditions);
 
         List<Integer> validBuilds = buildIdsWithConditions.keySet()
             .stream()
@@ -130,24 +128,23 @@ public class BuildsHistory {
     }
 
     /** */
-    private void initStatistics(IAnalyticsEnabledTeamcity teamcity, Map<Integer, Boolean> buildIdsWithConditions) {
+    private void initStatistics(IStringCompactor compactor, ITeamcity teamcity, ITeamcityIgnited ignited,
+        Map<Integer, Boolean> buildIdsWithConditions) {
         List<Future<BuildStatisticsSummary>> buildStaticsFutures = new ArrayList<>();
 
         for (int buildId : buildIdsWithConditions.keySet()) {
             Future<BuildStatisticsSummary> buildFuture = CompletableFuture.supplyAsync(() -> {
                 BuildStatisticsSummary buildsStatistic = new BuildStatisticsSummary(buildId);
                 buildsStatistic.isValid = buildIdsWithConditions.get(buildId);
-
-                buildsStatistic.initialize(teamcity);
+                buildsStatistic.initialize(compactor, ignited);
 
                 return buildsStatistic;
-
             }, teamcity.getExecutor());
 
             buildStaticsFutures.add(buildFuture);
         }
 
-        buildStaticsFutures.forEach(new Consumer<Future<BuildStatisticsSummary>>() {
+        buildStaticsFutures.forEach(new Consumer <Future<BuildStatisticsSummary>>() {
             @Override public void accept(Future<BuildStatisticsSummary> v) {
                 try {
                     BuildStatisticsSummary buildsStatistic = v.get();
@@ -191,7 +188,7 @@ public class BuildsHistory {
     }
 
     /** */
-    private void initFailedTests(IAnalyticsEnabledTeamcity teamcity, List<Integer> buildIds) {
+    private void initFailedTests(ITeamcity teamcity, List<Integer> buildIds) {
         List<Future<Void>> buildProcessorFutures = new ArrayList<>();
 
         for (int buildId : buildIds) {
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 e1300c3..40aba93 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,10 +19,11 @@ package org.apache.ignite.ci.web.rest.build;
 
 import com.google.common.collect.BiMap;
 import java.text.ParseException;
+import java.util.Date;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import com.google.inject.Injector;
-import org.apache.ignite.ci.tcbot.condition.BuildCondition;
+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;
@@ -34,8 +35,6 @@ 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.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.current.BuildStatisticsSummary;
@@ -68,7 +67,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
 public class GetBuildTestFailures {
     public static final String BUILD = "build";
     public static final String TEST_FAILURES_SUMMARY_CACHE_NAME = BUILD + "TestFailuresSummary";
-    public static final String BUILDS_STATISTICS_SUMMARY_CACHE_NAME = BUILD + "sStatisticsSummary";
+
     @Context
     private ServletContext ctx;
 
@@ -262,7 +261,12 @@ public class GetBuildTestFailures {
 
         BuildsHistory buildsHist = builder.build();
 
-        buildsHist.initialize(ICredentialsProv.get(req), ctx);
+        final ICredentialsProv prov = ICredentialsProv.get(req);
+
+        if (!prov.hasAccess(srvId))
+            throw ServiceUnauthorizedException.noCreds(srvId);
+
+        buildsHist.initialize(prov, ctx);
 
         return buildsHist;
     }
diff --git a/ignite-tc-helper-web/src/main/webapp/comparison.html b/ignite-tc-helper-web/src/main/webapp/comparison.html
index 1d4c13c..82cf096 100644
--- a/ignite-tc-helper-web/src/main/webapp/comparison.html
+++ b/ignite-tc-helper-web/src/main/webapp/comparison.html
@@ -34,7 +34,7 @@
         <td style="text-align: center;" id="info2"></td>
     </tr>
     <tr><td class="field">DURATION</td>
-        <td class="icon"><img id="clickGraphDuration" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphDuration" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Duration1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="Duration2" data-allow-highlight="true"></td>
     </tr>
@@ -45,7 +45,7 @@
     </tr><tr></tr>
     <tr><td class="section">TESTS</td><td></td><td class="mmm title 1"></td><td class="mmm title 2"></td></tr>
     <tr><td class="field">COUNT</td>
-        <td class="icon"><img id="clickGraphCount" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphCount" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Count1" data-allow-highlight="false"></td>
         <td class="mmm data 2" id="Count2" data-allow-highlight="false"></td>
     </tr>
@@ -55,7 +55,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphCount2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">PASSED</td>
-        <td class="icon"><img id="clickGraphPassed" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphPassed" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Passed1" data-allow-highlight="false"></td>
         <td class="mmm data 2" id="Passed2" data-allow-highlight="false"></td>
     </tr>
@@ -65,7 +65,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphPassed2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">FAILED</td>
-        <td class="icon"><img id="clickGraphFailed" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphFailed" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Failed1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="Failed2" data-allow-highlight="true"></td>
     </tr>
@@ -75,7 +75,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphFailed2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">IGNORED</td>
-        <td class="icon"><img id="clickGraphIgnored" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphIgnored" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Ignored1" data-allow-highlight="false"></td>
         <td class="mmm data 2" id="Ignored2" data-allow-highlight="false"></td>
     </tr>
@@ -85,7 +85,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphIgnored2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">MUTED</td>
-        <td class="icon"><img id="clickGraphMuted" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphMuted" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="Muted1" data-allow-highlight="false"></td>
         <td class="mmm data 2" id="Muted2" data-allow-highlight="false"></td></tr>
     <tr id="showGraphMuted" style="display: none;"><td></td>
@@ -96,7 +96,7 @@
     <tr><td class="section">PROBLEMS</td><td></td><td class="mmm title 1"></td><td class="mmm title 2"></td></tr>
     <tr style="display: none;"><td></td><td></td><td></td></tr>
     <tr><td class="field">TOTAL</td>
-        <td class="icon"><img id="clickGraphTT" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphTT" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="TT1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="TT2" data-allow-highlight="true"></td></tr>
     <tr id="showGraphTT" style="display: none;"><td></td>
@@ -105,7 +105,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphTT2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">EXECUTION TIMEOUT</td>
-        <td class="icon"><img id="clickGraphET" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphET" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="ET1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="ET2" data-allow-highlight="true"></td>
     </tr>
@@ -115,7 +115,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphET2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">JVM CRASH</td>
-        <td class="icon"><img id="clickGraphJC" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphJC" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="JC1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="JC2" data-allow-highlight="true"></td>
     </tr>
@@ -125,7 +125,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphJC2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">OOME</td>
-        <td class="icon"><img id="clickGraphOO" src='/img/browser.png'></td>
+        <td class="icon"></td>
         <td class="mmm data 1" id="OO1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="OO2" data-allow-highlight="true"></td>
     </tr>
@@ -135,7 +135,7 @@
         <td style="text-align: center;"><svg class="graph 2" id="graphOO2" width="500" height="200"></svg></td>
     </tr>
     <tr><td class="field">EXIT CODE</td>
-        <td class="icon"><img id="clickGraphEC" src='/img/browser.png'></td>
+        <td class="icon"><p class="tooltips"><img id="clickGraphEC" src='/img/browser.png'><span>show graph</span></p></td>
         <td class="mmm data 1" id="EC1" data-allow-highlight="true"></td>
         <td class="mmm data 2" id="EC2" data-allow-highlight="true"></td>
     </tr>
@@ -175,15 +175,10 @@
 
 <div id="version"></div>
 <script>
-    let oneWeekAgo = new Date(),
-        twoWeekAgo = new Date(),
-        invalidInclude = false,
+    let invalidInclude = false,
         markBuildId = 0,
         testsTrigger = false;
 
-    oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
-    twoWeekAgo.setDate(twoWeekAgo.getDate() - 14);
-
     function getDateFewWeeksAgo(numberOfWeeksAgo) {
         let date = new Date();
 
@@ -196,8 +191,8 @@
     /** Structure for storing tests by suites parsed response for every date interval. */
     let mergedTestsResults = {1 : {}, 2 : {} };
 
-    let dateIntervals = {1: {start: moment(oneWeekAgo), end: moment()},
-        2: {start: moment(twoWeekAgo), end: moment(oneWeekAgo)}};
+    let dateIntervals = {1: {start: moment(getDateFewWeeksAgo(1)), end: moment()},
+        2: {start: moment(getDateFewWeeksAgo(2)), end: moment(getDateFewWeeksAgo(1))}};
 
     function showTooltip(message) {
         $("#tooltipText").html(message);
@@ -533,8 +528,11 @@
 
         compareAndHighlight(stat);
 
-        function time(ms){
-            return moment(ms * 1000).utcOffset(0).format("H:mm");
+        function time(s) {
+            let h = parseInt(s / 3600),
+                m = parseInt((s % 3600) / 60);
+
+            return h + ":" + ((m < 10) ? "0" : "") + m;
         }
     }
 
@@ -555,7 +553,7 @@
 
         mergedTestsResults[num] = {};
 
-        let url = 'rest/build/history?sinceDate=' + sinceDate.format("DDMMYYYY") +
+        let url = 'rest/build/history?server=apache&buildType=IgniteTests24Java8_RunAll&sinceDate=' + sinceDate.format("DDMMYYYY") +
             '000001&untilDate=' + untilDate.format("DDMMYYYY") + '235959';
 
         if (!testsTrigger)
@@ -596,7 +594,7 @@
         let anotherNum = (stat.num === 1) ? 2 : 1,
             thisElement = $('#' + stat.name + stat.num),
             anotherElement =  $('#' + stat.name + anotherNum),
-            thisMedian = stat.median;
+            thisMedian = stat.median - ((stat.name === duration) ? stat.median % 60 : 0);
 
         if (thisElement.data('allowHighlight').toString() === "true") {
             let anotherMedian = parseMedian(anotherElement.text());
@@ -613,8 +611,8 @@
     }
 
     $(document).ready(function() {
-        loadData(1, moment(oneWeekAgo), moment(), testsTrigger);
-        loadData(2, moment(twoWeekAgo), moment(oneWeekAgo), testsTrigger);
+        loadData(1, moment(getDateFewWeeksAgo(1)), moment(), testsTrigger);
+        loadData(2, moment(getDateFewWeeksAgo(2)), moment(getDateFewWeeksAgo(1)), testsTrigger);
 
         $.ajax({ url: "rest/branches/version",  success: showVersionInfo, error: showErrInLoadStatus });
     });
diff --git a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
index 309328c..1c20db8 100644
--- a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
+++ b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
@@ -455,3 +455,60 @@ div.tooltip {
 	font-size: 48px;
 	color: #E60000;
 }
+
+.far.fa-chart-bar, .fas.fa-chart-area, .fas.fa-chart-pie, .fas.fa-angle-double-down {
+	font-size: 20px;
+	color: #12AD5E;
+}
+
+.fas.fa-chart-pie:hover {
+	transform: scale(1.2);
+
+}
+
+.fas.fa-angle-right {
+	font-size: 18px;
+	transform: scale(0.8) translateX(0.3em) translateY(2px);
+	transition: transform .25s;
+	display: inline-block;
+}
+
+.testClass:hover > i {
+	transform: scale(1.2) translateX(0.8em) translateY(1px);
+}
+
+p.tooltips {
+	position: relative;
+	display: inline;
+}
+p.tooltips span {
+	position: absolute;
+	width:100px;
+	color: #FFFFFF;
+	background: #000000;
+	height: 30px;
+	line-height: 30px;
+	text-align: center;
+	visibility: hidden;
+	border-radius: 5px;
+}
+p.tooltips span:after {
+	content: '';
+	position: absolute;
+	top: 50%;
+	right: 100%;
+	margin-top: -8px;
+	width: 0; height: 0;
+	border-right: 8px solid #000000;
+	border-top: 8px solid transparent;
+	border-bottom: 8px solid transparent;
+}
+p:hover.tooltips span {
+	visibility: visible;
+	opacity: 0.8;
+	left: 100%;
+	top: 50%;
+	margin-top: -15px;
+	margin-left: 15px;
+	z-index: 999;
+}