Added test pattern for searching always failed tests. Fixes #191

Signed-off-by: Slava Koptilin <slava.koptilin@gmail.com>
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
index 313ce2e..1f3ac88 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
@@ -126,6 +126,13 @@
         return confidence == null || confidence < 0 || confidence > 1 ? ITcBotConfig.DEFAULT_CONFIDENCE : confidence;
     }
 
+    /** {@inheritDoc} */
+    @Override public Boolean alwaysFailedTestDetection() {
+        Boolean alwaysFailedTestDetection = getConfig().alwaysFailedTestDetection();
+
+        return alwaysFailedTestDetection != null && alwaysFailedTestDetection;
+    }
+
     @Override
     public ITrackedBranchesConfig getTrackedBranches() {
         return getConfig();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
index c488331..2c85de8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
@@ -528,6 +528,13 @@
             }
         }
 
+        if (firstFailedBuildId == null && cfg.alwaysFailedTestDetection()) {
+            firstFailedBuildId = runStat.detectTemplate(EventTemplates.alwaysFailure);
+
+            if (firstFailedBuildId != null)
+                type = IssueType.newAlwaysFailure;
+        }
+
         if (firstFailedBuildId == null)
             return false;
 
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
index 7f778bb..91098eb 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
@@ -102,6 +102,11 @@
                 return DEFAULT_CONFIDENCE;
             }
 
+            /** */
+            @Override public Boolean alwaysFailedTestDetection() {
+                return false;
+            }
+
             @Override  public ITrackedBranchesConfig getTrackedBranches() {
                 return tracked;
             }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
index 63e1448..bb97a9c 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITcBotConfig.java
@@ -45,6 +45,9 @@
     /** */
     public Double confidence();
 
+    /** */
+    public Boolean alwaysFailedTestDetection();
+
     /**
      * @return Tracked branches configuration for TC Bot.
      */
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
index be76dbc..6f078c2 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/TcBotJsonConfig.java
@@ -44,6 +44,9 @@
     /** Сonfidence (used with flaky tests). */
     @Nullable private Double confidence;
 
+    /** Always failed test detection. */
+    @Nullable private Boolean alwaysFailedTestDetection;
+
     /** Additional list Servers to be used for validation of PRs, but not for tracking any branches. */
     private List<TcServerConfig> tcServers = new ArrayList<>();
 
@@ -105,6 +108,13 @@
         return confidence;
     }
 
+    /**
+     * @return Is always failed test detection enabled.
+     */
+    @Nullable public Boolean alwaysFailedTestDetection() {
+        return alwaysFailedTestDetection;
+    }
+
     public Optional<TcServerConfig> getTcConfig(String code) {
         return tcServers.stream().filter(s -> Objects.equals(code, s.getCode())).findAny();
     }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/EventTemplates.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/EventTemplates.java
index 4a45b2a..6d1f50b 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/EventTemplates.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/EventTemplates.java
@@ -55,10 +55,15 @@
                     FAIL, FAIL}
     );
 
+    public static final EventTemplate alwaysFailure = new EventTemplate(
+        new int[]{FAIL, FAIL, FAIL, FAIL, FAIL, FAIL},
+        new int[]{FAIL, FAIL, FAIL, FAIL, FAIL, FAIL}
+    );
+
     public static ArrayList<EventTemplate> templates;
 
     static {
         templates = Lists.newArrayList(newFailure, newCriticalFailure,
-            newContributedTestFailure, newFailureForFlakyTest);
+            newContributedTestFailure, newFailureForFlakyTest, alwaysFailure);
     }
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssueType.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssueType.java
index 7ba27b1..f80f668 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssueType.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/issue/IssueType.java
@@ -37,7 +37,10 @@
     newTrustedSuiteFailure("newTrustedSuiteFailure", "New Trusted Suite failure"),
 
     /** New failure for flaky test. */
-    newTestWithHighFlakyRate("newTestWithHighFlakyRate", "Test with high flaky rate");
+    newTestWithHighFlakyRate("newTestWithHighFlakyRate", "Test with high flaky rate"),
+
+    /** New always failure test. */
+    newAlwaysFailure("newAlwaysFailure", "Always failed test");
 
     /** Code. */
     private final String code;
@@ -58,6 +61,8 @@
                 return newTrustedSuiteFailure;
             case "Test with high flaky rate":
                 return newTestWithHighFlakyRate;
+            case "Always failed test":
+                return newAlwaysFailure;
         }
 
         throw new IllegalArgumentException("Illegal issue type: " + displayName);
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/ui/DsTestFailureUi.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/ui/DsTestFailureUi.java
index df3f948..9f85413 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/ui/DsTestFailureUi.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/ui/DsTestFailureUi.java
@@ -217,6 +217,10 @@
             if (statForProblemsDetection.detectTemplate(EventTemplates.newContributedTestFailure) != null)
                 problemRef = new DsProblemRef("Recently contributed test failure");
 
+
+            if (statForProblemsDetection.detectTemplate(EventTemplates.alwaysFailure) != null)
+                problemRef = new DsProblemRef("Always failed test");
+
             if (statForProblemsDetection.isFlaky()
                     && statForProblemsDetection.detectTemplate(EventTemplates.newFailureForFlakyTest) != null)
                 problemRef = new DsProblemRef("New failure of flaky test");