in ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java [448:566]
private boolean registerTestFailIssues(ITeamcityIgnited tcIgnited,
String srvCode,
String suiteId,
String normalizeBranch,
DsTestFailureUi testFailure,
String trackedBranch,
@Nonnull Set<String> suiteTags) {
String name = testFailure.name;
int tname = compactor.getStringId(name);
Integer btId = compactor.getStringIdIfPresent(suiteId);
Integer brNormId = compactor.getStringIdIfPresent(normalizeBranch);
IRunHistory runStat = tcIgnited.getTestRunHist(tname, btId, brNormId);
if (runStat == null)
return false;
IssueType type = null;
Integer firstFailedBuildId = runStat.detectTemplate(EventTemplates.newContributedTestFailure);
if (firstFailedBuildId != null)
type = IssueType.newContributedTestFailure;
if (firstFailedBuildId == null) {
firstFailedBuildId = runStat.detectTemplate(EventTemplates.newFailure);
if (firstFailedBuildId != null) {
type = IssueType.newFailure;
final String flakyComments = runStat.getFlakyComments();
if (!Strings.isNullOrEmpty(flakyComments) &&
runStat.detectTemplate(EventTemplates.newFailureForFlakyTest) != null)
type = IssueType.newFailureForFlakyTest;
}
}
double flakyRate = 0;
if (firstFailedBuildId == null || type == null) {
List<Invocation> invocations = runStat.getInvocations().
filter(invocation -> invocation != null && invocation.status() != InvocationData.MISSING)
.collect(Collectors.toList());
int confidenceOkTestsRow = Math.max(1,
(int) Math.ceil(Math.log(1 - cfg.confidence()) / Math.log(1 - cfg.flakyRate() / 100.0)));
if (invocations.size() >= confidenceOkTestsRow * 2) {
List<Invocation> lastInvocations =
invocations.subList(invocations.size() - confidenceOkTestsRow * 2, invocations.size());
int stableTestRuns = 0;
for (int i = 0; i < confidenceOkTestsRow; i++) {
if (lastInvocations.get(i).status() == RES_OK.getCode())
stableTestRuns++;
else
break;
}
if (stableTestRuns == confidenceOkTestsRow) {
long failedTestRuns = 0;
for (int i = confidenceOkTestsRow; i < confidenceOkTestsRow * 2; i++) {
if (lastInvocations.get(i).status() == RES_FAILURE.getCode())
failedTestRuns++;
}
flakyRate = (double) failedTestRuns / confidenceOkTestsRow * 100;
if (flakyRate > cfg.flakyRate()) {
type = IssueType.newTestWithHighFlakyRate;
firstFailedBuildId = lastInvocations.stream()
.filter(invocation -> invocation.status() == RES_FAILURE.getCode())
.findFirst()
.orElseGet(() -> lastInvocations.get(confidenceOkTestsRow))
.buildId();
}
}
}
}
if (firstFailedBuildId == null && cfg.alwaysFailedTestDetection()) {
firstFailedBuildId = runStat.detectTemplate(EventTemplates.alwaysFailure);
if (firstFailedBuildId != null)
type = IssueType.newAlwaysFailure;
}
if (firstFailedBuildId == null)
return false;
if (type == null)
return false;
int buildId = firstFailedBuildId;
IssueKey issueKey = new IssueKey(srvCode, buildId, name);
if (issuesStorage.containsIssueKey(issueKey))
return false; //duplicate
Issue issue = new Issue(issueKey, type, tcIgnited.getBuildStartTs(issueKey.buildId));
issue.trackedBranchName = trackedBranch;
issue.displayName = testFailure.testName;
issue.webUrl = testFailure.webUrl;
issue.flakyRate = flakyRate;
issue.buildTags.addAll(suiteTags);
locateChanges(tcIgnited, buildId, issue);
logger.info("Register new issue for test fail: " + issue);
issuesStorage.saveIssue(issue);
return true;
}