@@ -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
15541674class ResultsDir (IterationCollection ):
15551675 """
0 commit comments