Skip to content

Commit f5c10ea

Browse files
committed
results_parser: add save_flaky_failures feature
1 parent fe7cf5a commit f5c10ea

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

flapy/results_parser.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,126 @@ def save_cta_tables(self, flaky_col: str, method: str, cta_save_dir: str):
15501550
)
15511551
))
15521552

1553+
def _save_flaky_failures_iteration(self, row: pd.Series, outcomes: List[str], save_dir: str) -> None:
1554+
"""Helper function to parallelize save_flaky_failures
1555+
1556+
:row: row from PassedFailed CSV of a flaky iteration
1557+
:outcomes: which outcomes are you interested in? e.g. ["Failed_sameOrder"]
1558+
:save_dir: directory to save the junit files to
1559+
:returns: None
1560+
"""
1561+
try:
1562+
iteration = Iteration(row["Iteration"])
1563+
1564+
for outcome in outcomes:
1565+
files = [
1566+
x
1567+
for x in iteration.get_files(JunitXmlFile)
1568+
if x.get_num() in eval_string_to_set(row[outcome])
1569+
]
1570+
url_without_slash = row["Project_URL"].replace("/", " ")
1571+
git_hash = row["Project_Hash"]
1572+
test_id = to_nodeid(*row[test_cols]).replace("/", " ")
1573+
proj_savedir = (
1574+
Path(save_dir) / f"{url_without_slash}@{git_hash[:6]}" / test_id / outcome
1575+
)
1576+
for file_ in files:
1577+
file_.tarinfo.name = Path(iteration.p.name) / os.path.basename(
1578+
file_.tarinfo.name
1579+
)
1580+
print(f"extracting {file_=} to {proj_savedir}")
1581+
iteration.get_archive().extract(file_.tarinfo, proj_savedir)
1582+
1583+
iteration.close_archive()
1584+
except Exception as e:
1585+
logging.error(f"{type(e).__name__}: '{e}' in iteration {row['Iteration']}")
1586+
1587+
def save_flaky_failures(
1588+
self, save_dir: str, outcome: str, flaky_types: List[str], proj_csv: str = None
1589+
) -> None:
1590+
"""Extract all junit files in which a flaky test failed.
1591+
1592+
This can be useful to find the root cause of the flaky failure.
1593+
1594+
:save_dir: directory to save the junit files to
1595+
They will be saved in the following format:
1596+
1597+
save_dir/FLAKY_TYPE/PROJ_URL@PROJ_HASH/TEST_NODEID/OUTCOME/ITERATION/JUNIT_FILE
1598+
1599+
Slashes in PROJ_URL are being replaced with spaces
1600+
NOTE: if the project-url starts with ".", e.g. a local path ("./minimal_example"), the folder will be hidden
1601+
1602+
:outcome: which outcomes do you want to filter for (same, random, any)
1603+
1604+
:flaky_type: what kind of flaky tests do you want to consider?
1605+
values: (order-dependent, non-order-dependent, infrastructure flaky, not flaky)
1606+
KNOWN ISSUE: you cannot properly pass a list as an argument, because fire interprets the "-" in "order-dependent"
1607+
1608+
:proj_csv: only consider projects in this csv file (needs `proj_cols`)
1609+
"""
1610+
1611+
# Check input arguments
1612+
if isinstance(flaky_types, str):
1613+
flaky_types = [flaky_types]
1614+
for flaky_type in flaky_types:
1615+
if flaky_type not in FlakinessType.all_types:
1616+
raise ValueError(f"Unknown flaky type '{flaky_type}'")
1617+
1618+
logging.info("Generate tests overview")
1619+
passed_failed = PassedFailed(self.get_passed_failed())
1620+
to = passed_failed.to_tests_overview()
1621+
1622+
logging.info("Start export")
1623+
# Filter for specified projects
1624+
if proj_csv is not None:
1625+
proj_df = pd.read_csv(proj_csv)[proj_cols]
1626+
to = to.merge(proj_df)
1627+
1628+
if outcome == "random":
1629+
outcomes = [
1630+
# "Passed_randomOrder",
1631+
"Failed_randomOrder",
1632+
"Error_randomOrder",
1633+
# "Skipped_randomOrder",
1634+
]
1635+
elif outcome == "same":
1636+
outcomes = [
1637+
# "Passed_sameOrder",
1638+
"Failed_sameOrder",
1639+
"Error_sameOrder",
1640+
# "Skipped_sameOrder",
1641+
]
1642+
elif outcome == "any":
1643+
outcomes = [
1644+
# "Passed_sameOrder",
1645+
"Failed_sameOrder",
1646+
"Error_sameOrder",
1647+
# "Skipped_sameOrder",
1648+
# "Passed_randomOrder",
1649+
"Failed_randomOrder",
1650+
"Error_randomOrder",
1651+
# "Skipped_randomOrder",
1652+
]
1653+
else:
1654+
raise ValueError(f"Unknown value for argument outcome")
1655+
1656+
for f_type in flaky_types:
1657+
# Filter for flaky tests
1658+
flaky_tests = to[to["flaky?"] == f_type][proj_cols + test_cols]
1659+
print(f"{flaky_tests=}")
1660+
pf_flaky = passed_failed._df.merge(flaky_tests)
1661+
print(f"{pf_flaky=}")
1662+
1663+
pool = multiprocessing.Pool()
1664+
pool.map(
1665+
partial(
1666+
self._save_flaky_failures_iteration,
1667+
outcomes=outcomes,
1668+
save_dir=f"{save_dir}/{f_type}",
1669+
),
1670+
map(lambda x: x[1], pf_flaky.iterrows()),
1671+
)
1672+
15531673

15541674
class ResultsDir(IterationCollection):
15551675
"""

0 commit comments

Comments
 (0)