Skip to content

Commit 5745a4e

Browse files
[CI] Explain Flaky Failures
This patch adds functionality to the premerge advisor to explain away flaky failures. For this, we just look to see that the failure observed is failing for a sufficient amount of time, in our case 200 commits. Pull Request: llvm#641
1 parent c971183 commit 5745a4e

File tree

2 files changed

+112
-13
lines changed

2 files changed

+112
-13
lines changed

premerge/advisor/advisor_lib.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,10 @@ def _try_explain_flaky_failure(
143143
).fetchall()
144144
commit_indices = []
145145
for failure_message, commit_index in test_name_matches:
146-
if failure_message == test_failure.message:
146+
if failure_message == test_failure["message"]:
147147
commit_indices.append(commit_index)
148+
if len(commit_indices) == 0:
149+
return None
148150
commit_range = max(commit_indices) - min(commit_indices)
149151
if commit_range > EXPLAINED_FLAKY_MIN_COMMIT_RANGE:
150152
return {
@@ -165,23 +167,26 @@ def explain_failures(
165167
commit_index = git_utils.get_commit_index(
166168
explanation_request["base_commit_sha"], repository_path, db_connection
167169
)
168-
explained_at_head = _try_explain_failing_at_head(
170+
# We want to try and explain flaky failures first. Otherwise we might
171+
# explain a flaky failure as a failure at head if there is a recent
172+
# failure in the last couple of commits.
173+
explained_as_flaky = _try_explain_flaky_failure(
169174
db_connection,
170175
test_failure,
171-
explanation_request["base_commit_sha"],
172-
commit_index,
173176
explanation_request["platform"],
174177
)
175-
if explained_at_head:
176-
explanations.append(explained_at_head)
178+
if explained_as_flaky:
179+
explanations.append(explained_as_flaky)
177180
continue
178-
explained_as_flaky = _try_explain_flaky_failure(
181+
explained_at_head = _try_explain_failing_at_head(
179182
db_connection,
180183
test_failure,
184+
explanation_request["base_commit_sha"],
185+
commit_index,
181186
explanation_request["platform"],
182187
)
183-
if explained_as_flaky:
184-
explanations.append(explained_as_flaky)
188+
if explained_at_head:
189+
explanations.append(explained_at_head)
185190
continue
186191
explanations.append(
187192
{"name": test_failure["name"], "explained": False, "reason": None}

premerge/advisor/advisor_lib_test.py

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ def setUp(self):
8686
[
8787
("8d29a3bb6f3d92d65bf5811b53bf42bf63685359", 1),
8888
("6b7064686b706f7064656d6f6e68756e74657273", 2),
89+
("6a6f73687561747265656a6f7368756174726565", 201),
90+
("6269677375726269677375726269677375726269", 202),
91+
("6d746c616e676c65796d746c616e676c65796d74", 203),
8992
],
9093
)
9194
self.repository_path_dir = tempfile.TemporaryDirectory()
@@ -281,11 +284,102 @@ def test_no_explain_different_message(self):
281284
],
282285
)
283286

287+
def _setup_flaky_test_info(
288+
self,
289+
source_type="postcommit",
290+
message="failed in way 1",
291+
second_failure_sha="6269677375726269677375726269677375726269",
292+
):
293+
failures_info = [
294+
{
295+
"source_type": source_type,
296+
"base_commit_sha": "8d29a3bb6f3d92d65bf5811b53bf42bf63685359",
297+
"source_id": "10000",
298+
"failures": [
299+
{"name": "a.ll", "message": message},
300+
],
301+
"platform": "linux-x86_64",
302+
},
303+
{
304+
"source_type": source_type,
305+
"base_commit_sha": second_failure_sha,
306+
"source_id": "100001",
307+
"failures": [
308+
{"name": "a.ll", "message": message},
309+
],
310+
"platform": "linux-x86_64",
311+
},
312+
]
313+
for failure_info in failures_info:
314+
advisor_lib.upload_failures(
315+
failure_info, self.db_connection, self.repository_path
316+
)
317+
318+
def _get_flaky_test_explanations(self):
319+
explanation_request = {
320+
"failures": [{"name": "a.ll", "message": "failed in way 1"}],
321+
"base_commit_sha": "6d746c616e676c65796d746c616e676c65796d74",
322+
"platform": "linux-x86_64",
323+
}
324+
return advisor_lib.explain_failures(
325+
explanation_request, self.repository_path, self.db_connection
326+
)
327+
284328
def test_explain_flaky(self):
285-
pass
329+
self._setup_flaky_test_info()
330+
self.assertListEqual(
331+
self._get_flaky_test_explanations(),
332+
[
333+
{
334+
"name": "a.ll",
335+
"explained": True,
336+
"reason": "This test is flaky in main.",
337+
}
338+
],
339+
)
340+
341+
def test_no_explain_flaky_different_message(self):
342+
self._setup_flaky_test_info(message="failed in way 2")
343+
self.assertListEqual(
344+
self._get_flaky_test_explanations(),
345+
[
346+
{
347+
"name": "a.ll",
348+
"explained": False,
349+
"reason": None,
350+
}
351+
],
352+
)
286353

354+
# Test that we do not explain away flaky failures from pull request data.
355+
# PRs might have the same failures multiple times across a large span of
356+
# base commits, which might accidentally trigger the heuristic.
287357
def test_no_explain_flaky_pullrequest_data(self):
288-
pass
358+
self._setup_flaky_test_info(source_type="pull_request")
359+
self.assertListEqual(
360+
self._get_flaky_test_explanations(),
361+
[
362+
{
363+
"name": "a.ll",
364+
"explained": False,
365+
"reason": None,
366+
}
367+
],
368+
)
289369

290-
def test_no_explain_flaky_long_subsequence(self):
291-
pass
370+
# Test that if all of the flaky failures are within a small range, we do
371+
# not report this as a flaky failure.
372+
def test_no_explain_flaky_small_range(self):
373+
self._setup_flaky_test_info(
374+
second_failure_sha="6b7064686b706f7064656d6f6e68756e74657273"
375+
)
376+
self.assertListEqual(
377+
self._get_flaky_test_explanations(),
378+
[
379+
{
380+
"name": "a.ll",
381+
"explained": False,
382+
"reason": None,
383+
}
384+
],
385+
)

0 commit comments

Comments
 (0)