You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2018/11/24 13:56:52 UTC

[ignite-teamcity-bot] branch master updated: IGNITE-9542: New Run stripe implementation: test for blockers detection development - Fixes #83.

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


The following commit(s) were added to refs/heads/master by this push:
     new 8ebb4e9  IGNITE-9542: New Run stripe implementation: test for blockers detection development - Fixes #83.
8ebb4e9 is described below

commit 8ebb4e9b3f1e126c88ce5131da25ccd328d6457c
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Sat Nov 24 16:56:45 2018 +0300

    IGNITE-9542: New Run stripe implementation: test for blockers detection development - Fixes #83.
    
    Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
 .../ignite/ci/tcbot/chain/PrChainsProcessor.java   |  11 +-
 .../apache/ignite/ci/tcmodel/hist/BuildRef.java    |   5 +
 .../org/apache/ignite/ci/tcmodel/result/Build.java |   2 +-
 .../tcmodel/result/problems/ProblemOccurrence.java |   4 +
 .../ci/teamcity/ignited/TeamcityIgnitedImpl.java   |   1 +
 .../model/current/ChainAtServerCurrentStatus.java  |   2 +-
 .../ci/tcbot/chain/BuildChainProcessorTest.java    |  77 ++-------
 .../ci/tcbot/chain/PrChainsProcessorTest.java      | 174 +++++++++++++++++++++
 .../ignited/IgnitedTcInMemoryIntegrationTest.java  |   4 +-
 .../ci/teamcity/ignited/TeamcityIgnitedMock.java   |  80 ++++++++++
 .../ignited/TeamcityIgnitedProviderMock.java       |  41 +++++
 11 files changed, 326 insertions(+), 75 deletions(-)

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 4810a79..8495c41 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
@@ -186,15 +186,10 @@ public class PrChainsProcessor {
         if(noBuilds)
             return null;
 
-        if (summary != null) {
-            for (ChainAtServerCurrentStatus server : summary.servers) {
-                if (!srvId.equals(server.serverName()))
-                    continue;
+        for (ChainAtServerCurrentStatus server : summary.servers) {
+            Map<String, List<SuiteCurrentStatus>> fails = findFailures(server);
 
-                Map<String, List<SuiteCurrentStatus>> fails = findFailures(server);
-
-                fails.forEach((k, v) -> res.addAll(v));
-            }
+            fails.forEach((k, v) -> res.addAll(v));
         }
 
         return res;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
index 89b0c3b..ad627d3 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
@@ -200,4 +200,9 @@ public class BuildRef extends AbstractRef {
     public boolean isUnknown() {
         return STATUS_UNKNOWN.equals(status());
     }
+
+    /** */
+    public void setBranchName(String branch) {
+        this.branchName = branch;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
index 8fec162..026b7e6 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
@@ -190,4 +190,4 @@ public class Build extends BuildRef implements IVersionedEntity {
     public void snapshotDependencies(List<BuildRef> dependencies) {
         snapshotDependencies = dependencies;
     }
-}
\ No newline at end of file
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/problems/ProblemOccurrence.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/problems/ProblemOccurrence.java
index eee412a..7b5afb4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/problems/ProblemOccurrence.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/problems/ProblemOccurrence.java
@@ -99,4 +99,8 @@ public class ProblemOccurrence {
     public void id(String fullStrId) {
         this.id = fullStrId;
     }
+
+    public void setType(String type) {
+        this.type = type;
+    }
 }
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 fa4a0fe..215802f 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
@@ -345,6 +345,7 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
      * @param buildId Build id.
      * @return build start date or null if build is fake stub or start date is not specified.
      */
+    @SuppressWarnings("WeakerAccess")
     @GuavaCached(maximumSize = 2000, cacheNullRval = false)
     @AutoProfiling
     @Nullable public Date getBuildStartDate(int buildId) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
index 2aacb04..87ae388 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
@@ -93,7 +93,7 @@ public class ChainAtServerCurrentStatus {
 
     public void initFromContext(ITeamcity teamcity,
         FullChainRunCtx ctx,
-        @Nullable ITcAnalytics tcAnalytics,
+        ITcAnalytics tcAnalytics,
         @Nullable String baseBranchTc) {
         failedTests = 0;
         failedToFinish = 0;
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
index c09ea1c..c2477dc 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessorTest.java
@@ -17,17 +17,11 @@
 package org.apache.ignite.ci.tcbot.chain;
 
 import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.internal.SingletonScope;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.stream.Collectors;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
@@ -38,21 +32,18 @@ import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 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.BuildRefCompacted;
-import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
-import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
-import org.apache.ignite.ci.teamcity.ignited.InMemoryStringCompactor;
-import org.apache.ignite.ci.teamcity.ignited.SyncMode;
+import org.apache.ignite.ci.teamcity.ignited.*;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.jetbrains.annotations.NotNull;
 import org.junit.Test;
 import org.mockito.Mockito;
 
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static junit.framework.TestCase.*;
 import static org.mockito.Mockito.when;
 
 /**
@@ -67,6 +58,7 @@ public class BuildChainProcessorTest {
 
     /** Pds 1 build type ID. */
     public static final String PDS_1_BT_ID = "Pds1";
+    public static final String BRANCH = "master";
 
     /** Injector. */
     private Injector injector = Guice.createInjector(new AbstractModule() {
@@ -140,7 +132,7 @@ public class BuildChainProcessorTest {
 
             if (suite.suiteName() != null && suite.suiteName().startsWith(UNIQUE_FAILED_TEST)) {
                 for (ITestFailures test : suite.getFailedTests())
-                    assertTrue("Failure found but should be hidden by re-run " + test.getName(), false);
+                    fail("Failure found but should be hidden by re-run " + test.getName());
             }
         }
     }
@@ -201,7 +193,7 @@ public class BuildChainProcessorTest {
         builds.put(pds2.id(), pds2);
     }
 
-    @NotNull public IAnalyticsEnabledTeamcity tcOldMock() {
+    @NotNull public static IAnalyticsEnabledTeamcity tcOldMock() {
         IAnalyticsEnabledTeamcity teamcity = Mockito.mock(IAnalyticsEnabledTeamcity.class);
         when(teamcity.getBuildFailureRunStatProvider()).thenReturn(Mockito.mock(Function.class));
         when(teamcity.getTestRunStatProvider()).thenReturn(Mockito.mock(Function.class));
@@ -209,59 +201,18 @@ public class BuildChainProcessorTest {
     }
 
     @NotNull public ITeamcityIgnited tcIgnitedMock(Map<Integer, FatBuildCompacted> builds) {
-        IStringCompactor c = injector.getInstance(IStringCompactor.class);
-
-        ITeamcityIgnited tcIgnited = Mockito.mock(ITeamcityIgnited.class);
-        when(tcIgnited.getFatBuild(anyInt(), any(SyncMode.class)))
-            .thenAnswer(inv ->
-            {
-                Integer arg = inv.getArgument(0);
-
-                return Preconditions.checkNotNull(builds.get(arg), "Can't find build in map [" + arg + "]");
-            });
-
-        when(tcIgnited.getAllBuildsCompacted(anyString(), anyString()))
-            .thenAnswer(inv -> {
-                String btId = inv.getArgument(0);
-
-                String branch = inv.getArgument(1);
-
-                return builds.values()
-                    .stream()
-                    .filter(fb -> btId.equals(fb.buildTypeId(c)))
-                    //  .filter(fb -> branch.equals(fb.branchName(c)))
-                    .sorted(Comparator.comparing(BuildRefCompacted::id).reversed())
-                    .collect(Collectors.toList());
-            });
-
-        when(tcIgnited.getLastNBuildsFromHistory(anyString(), anyString(), anyInt()))
-            .thenAnswer(inv -> {
-                String btId = inv.getArgument(0);
-
-                String branch = inv.getArgument(1);
-
-                Integer cnt = inv.getArgument(2);
-
-                return builds.values()
-                    .stream()
-                    .filter(fb -> btId.equals(fb.buildTypeId(c)))
-                    // .filter(fb -> branch.equals(fb.branchName(c)))
-                    .sorted(Comparator.comparing(BuildRefCompacted::id).reversed())
-                    .limit(cnt)
-                    .map(BuildRefCompacted::id)
-                    .collect(Collectors.toList());
-            });
-
-        return tcIgnited;
+        return TeamcityIgnitedMock.getMutableMapTeamcityIgnited(builds,
+                injector.getInstance(IStringCompactor.class));
     }
 
-    @NotNull public FatBuildCompacted testFatBuild(IStringCompactor c, int id, String bt) {
+    @NotNull public static FatBuildCompacted testFatBuild(IStringCompactor c, int id, String bt) {
         FatBuildCompacted root = new FatBuildCompacted();
         BuildRef ref = new BuildRef();
         ref.setId(id);
         ref.buildTypeId = bt;
         ref.state = BuildRef.STATE_FINISHED;
         ref.status = BuildRef.STATUS_FAILURE;
+        ref.branchName = BRANCH;
         root.fillFieldsFromBuildRef(c, ref);
 
         assertEquals(root.buildTypeId(c), bt);
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
new file mode 100644
index 0000000..83dd6c3
--- /dev/null
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.chain;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.internal.SingletonScope;
+import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
+import org.apache.ignite.ci.github.pure.IGitHubConnection;
+import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
+import org.apache.ignite.ci.tcmodel.conf.BuildType;
+import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+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.tcmodel.result.tests.TestOccurrenceFull;
+import org.apache.ignite.ci.tcmodel.result.tests.TestRef;
+import org.apache.ignite.ci.teamcity.ignited.*;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
+import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.web.model.current.SuiteCurrentStatus;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PrChainsProcessorTest {
+    public static final String SRV_ID = "apache";
+    private Map<Integer, FatBuildCompacted> apacheBuilds = new ConcurrentHashMap<>();
+
+
+    /**
+     * Injector.
+     */
+    private Injector injector = Guice.createInjector(new AbstractModule() {
+        @Override
+        protected void configure() {
+            bind(IStringCompactor.class).to(InMemoryStringCompactor.class).in(new SingletonScope());
+
+            final IGitHubConnectionProvider ghProv = Mockito.mock(IGitHubConnectionProvider.class);
+            bind(IGitHubConnectionProvider.class).toInstance(ghProv);
+            when(ghProv.server(anyString())).thenReturn(Mockito.mock(IGitHubConnection.class));
+
+            bind(ITeamcityIgnitedProvider.class).to(TeamcityIgnitedProviderMock.class).in(new SingletonScope());
+
+            final ITcServerProvider tcSrvOldProv = Mockito.mock(ITcServerProvider.class);
+
+            final IAnalyticsEnabledTeamcity tcOld = BuildChainProcessorTest.tcOldMock();
+            when(tcSrvOldProv.server(anyString(), any(ICredentialsProv.class))).thenReturn(tcOld);
+
+
+            bind(ITcServerProvider.class).toInstance(tcSrvOldProv);
+
+            super.configure();
+        }
+    });
+
+    @Before
+    public void initBuilds() {
+        final TeamcityIgnitedProviderMock instance = (TeamcityIgnitedProviderMock) injector.getInstance(ITeamcityIgnitedProvider.class);
+        instance.addServer(SRV_ID, apacheBuilds);
+    }
+
+    @Test
+    public void testTestFailureWithoutStatReportedAsBlocker() {
+        IStringCompactor c = injector.getInstance(IStringCompactor.class);
+
+        final String btId = "RunAll";
+        final String branch = "ignite-9542";
+
+        initBuildChain(c, btId, branch);
+
+        PrChainsProcessor prcp = injector.getInstance(PrChainsProcessor.class);
+        final List<SuiteCurrentStatus> suitesStatuses = prcp.getSuitesStatuses(btId,
+                branch, SRV_ID, mock(ICredentialsProv.class));
+
+        assertNotNull(suitesStatuses);
+        assertFalse(suitesStatuses.isEmpty());
+
+        assertTrue(suitesStatuses.stream().anyMatch(
+                s -> s.testFailures.stream().anyMatch(testFailure -> "testWithoutHistory".equals(testFailure.name))
+        ));
+
+        assertTrue(suitesStatuses.stream().anyMatch(s -> "Build".equals(s.suiteId)));
+        assertTrue(suitesStatuses.stream().anyMatch(s -> "CancelledBuild".equals(s.suiteId)));
+    }
+
+    private void initBuildChain(IStringCompactor c, String btId, String branch) {
+        final int id = 1000;
+
+        final FatBuildCompacted chain = createFailedBuild(c, btId, branch, id, 100000);
+
+        final FatBuildCompacted childBuild = createFailedBuild(c, "Cache1", branch, 1001, 100020);
+        TestOccurrenceFull tf = new TestOccurrenceFull();
+        tf.test = new TestRef();
+        tf.test.id = 1L;
+        tf.name = "testWithoutHistory";
+        tf.status = TestOccurrence.STATUS_FAILURE;
+
+        childBuild.addTests(c, Collections.singletonList(tf));
+
+
+        final FatBuildCompacted buildBuild = createFailedBuild(c, "Build", branch, 1002, 100020);
+        final ProblemOccurrence compile = new ProblemOccurrence();
+        compile.setType(ProblemOccurrence.TC_COMPILATION_ERROR);
+        buildBuild.addProblems(c, Collections.singletonList(compile));
+        childBuild.snapshotDependencies(new int[]{buildBuild.id()});
+
+        final Build build = createBuild("CancelledBuild", branch, 1003, 100020);
+        build.status = BuildRef.STATUS_UNKNOWN;
+        build.state = BuildRef.STATE_FINISHED;
+
+        final FatBuildCompacted cancelledBuild = new FatBuildCompacted(c, build);
+
+
+        chain.snapshotDependencies(new int[]{childBuild.id(), cancelledBuild.id()});
+
+        apacheBuilds.put(chain.id(), chain);
+        apacheBuilds.put(childBuild.id(), childBuild);
+        apacheBuilds.put(buildBuild.id(), buildBuild);
+        apacheBuilds.put(cancelledBuild.id(), cancelledBuild);
+    }
+
+    @NotNull
+    public FatBuildCompacted createFailedBuild(IStringCompactor c, String btId, String branch, int id, int ageMs) {
+        final Build build = createBuild(btId, branch, id, ageMs);
+        build.status = BuildRef.STATUS_FAILURE;
+
+        return new FatBuildCompacted(c, build);
+    }
+
+    @NotNull
+    public Build createBuild(String btId, String branch, int id, int ageMs) {
+        final Build build = new Build();
+        build.buildTypeId = btId;
+        final BuildType type = new BuildType();
+        type.id(btId);
+        type.name(btId);
+        build.setBuildType(type);
+        build.setId(id);
+        build.setStartDateTs(System.currentTimeMillis() - ageMs);
+        build.setBranchName(branch);
+        return build;
+    }
+}
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 d3c2046..a0d236a 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
@@ -324,7 +324,7 @@ public class IgnitedTcInMemoryIntegrationTest {
         assertEquals(6, ch.length);
     }
 
-    public void saveTmpFile(Object obj, String name) throws IOException, JAXBException {
+    private void saveTmpFile(Object obj, String name) throws IOException, JAXBException {
         ensureDirExist(new File(name).getParentFile());
 
         try (FileWriter writer = new FileWriter(name)) {
@@ -332,7 +332,7 @@ public class IgnitedTcInMemoryIntegrationTest {
         }
     }
 
-    public <E> E jaxbTestXml(String ref, Class<E> cls) throws IOException, JAXBException {
+    private <E> E jaxbTestXml(String ref, Class<E> cls) throws IOException, JAXBException {
         E refBuild;
         try (InputStream stream = getClass().getResourceAsStream(ref)) {
             refBuild = XmlUtil.load(cls, new InputStreamReader(stream));
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
new file mode 100644
index 0000000..1cc9156
--- /dev/null
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ci.teamcity.ignited;
+
+import com.google.common.base.Preconditions;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.jetbrains.annotations.NotNull;
+import org.mockito.Mockito;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+public class TeamcityIgnitedMock {
+    @NotNull
+    public static ITeamcityIgnited getMutableMapTeamcityIgnited(Map<Integer, FatBuildCompacted> builds, IStringCompactor c) {
+        ITeamcityIgnited tcIgnited = Mockito.mock(ITeamcityIgnited.class);
+        when(tcIgnited.getFatBuild(anyInt(), any(SyncMode.class)))
+            .thenAnswer(inv ->
+            {
+                Integer arg = inv.getArgument(0);
+
+                return Preconditions.checkNotNull(builds.get(arg), "Can't find build in map [" + arg + "]");
+            });
+
+        when(tcIgnited.getAllBuildsCompacted(anyString(), anyString()))
+            .thenAnswer(inv -> {
+                String btId = inv.getArgument(0);
+
+                String branch = inv.getArgument(1);
+
+                return builds.values()
+                    .stream()
+                    .filter(fb -> btId.equals(fb.buildTypeId(c)))
+                    //  .filter(fb -> branch.equals(fb.branchName(c)))
+                    .sorted(Comparator.comparing(BuildRefCompacted::id).reversed())
+                    .collect(Collectors.toList());
+            });
+
+        when(tcIgnited.getLastNBuildsFromHistory(anyString(), anyString(), anyInt()))
+            .thenAnswer(inv -> {
+                String btId = inv.getArgument(0);
+
+                String branch = inv.getArgument(1);
+
+                Integer cnt = inv.getArgument(2);
+
+                return builds.values()
+                    .stream()
+                    .filter(fb -> btId.equals(fb.buildTypeId(c)))
+                    // .filter(fb -> branch.equals(fb.branchName(c)))
+                    .sorted(Comparator.comparing(BuildRefCompacted::id).reversed())
+                    .limit(cnt)
+                    .map(BuildRefCompacted::id)
+                    .collect(Collectors.toList());
+            });
+
+        return tcIgnited;
+    }
+}
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java
new file mode 100644
index 0000000..298ea46
--- /dev/null
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedProviderMock.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ci.teamcity.ignited;
+
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.user.ICredentialsProv;
+
+import javax.inject.Inject;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class TeamcityIgnitedProviderMock implements ITeamcityIgnitedProvider {
+    @Inject IStringCompactor compactor;
+
+    Map<String,Map<Integer, FatBuildCompacted>> tcBuildsData = new ConcurrentHashMap<>();
+
+    public void addServer(String srvId, Map<Integer, FatBuildCompacted> apacheBuilds) {
+        tcBuildsData.put(srvId, apacheBuilds);
+    }
+
+    @Override
+    public ITeamcityIgnited server(String srvId, ICredentialsProv prov) {
+        final Map<Integer, FatBuildCompacted> integerFatBuildCompactedMap = tcBuildsData.get(srvId);
+        return TeamcityIgnitedMock.getMutableMapTeamcityIgnited(integerFatBuildCompactedMap, compactor);
+    }
+}