@@ -28,6 +28,7 @@ class ShardResult:
2828 index : int
2929 membership : tuple [str , ...]
3030 tests : tuple [TestResult , ...]
31+ elapsed_seconds : float | None
3132
3233
3334def parse_duration (value : str ) -> float :
@@ -70,6 +71,19 @@ def read_trx(path: Path) -> tuple[TestResult, ...]:
7071 return tuple (results )
7172
7273
74+ def read_elapsed_seconds (path : Path ) -> float | None :
75+ if not path .exists ():
76+ return None
77+
78+ with path .open (encoding = "utf-8" , newline = "" ) as stream :
79+ metadata = {
80+ row ["key" ]: row ["value" ]
81+ for row in csv .DictReader (stream , delimiter = "\t " )
82+ }
83+ value = metadata .get ("elapsed_seconds" )
84+ return float (value ) if value is not None else None
85+
86+
7387def load_shards (input_directory : Path ) -> tuple [ShardResult , ...]:
7488 shards = []
7589 for membership_path in sorted (input_directory .rglob ("membership.txt" )):
@@ -81,7 +95,15 @@ def load_shards(input_directory: Path) -> tuple[ShardResult, ...]:
8195 )
8296 trx_path = membership_path .with_name ("results.trx" )
8397 tests = read_trx (trx_path ) if trx_path .exists () else ()
84- shards .append (ShardResult (index = index , membership = membership , tests = tests ))
98+ elapsed_seconds = read_elapsed_seconds (membership_path .with_name ("metadata.tsv" ))
99+ shards .append (
100+ ShardResult (
101+ index = index ,
102+ membership = membership ,
103+ tests = tests ,
104+ elapsed_seconds = elapsed_seconds ,
105+ )
106+ )
85107 return tuple (sorted (shards , key = lambda shard : shard .index ))
86108
87109
@@ -104,7 +126,15 @@ def write_summary(output_directory: Path, shards: tuple[ShardResult, ...], expec
104126 passed = sum (test .outcome == "Passed" for test in shard .tests )
105127 failed = sum (test .outcome == "Failed" for test in shard .tests )
106128 shard_rows .append (
107- (shard .index , len (shard .membership ), len (shard .tests ), passed , failed , f"{ duration :.3f} " )
129+ (
130+ shard .index ,
131+ len (shard .membership ),
132+ len (shard .tests ),
133+ passed ,
134+ failed ,
135+ f"{ duration :.3f} " ,
136+ f"{ shard .elapsed_seconds :.3f} " if shard .elapsed_seconds is not None else "" ,
137+ )
108138 )
109139 for name in shard .membership :
110140 result = result_by_name .get (name )
@@ -121,7 +151,15 @@ def write_summary(output_directory: Path, shards: tuple[ShardResult, ...], expec
121151
122152 write_csv (
123153 output_directory / "shards.csv" ,
124- ("shard" , "assigned" , "reported" , "passed" , "failed" , "duration_seconds" ),
154+ (
155+ "shard" ,
156+ "assigned" ,
157+ "reported" ,
158+ "passed" ,
159+ "failed" ,
160+ "duration_seconds" ,
161+ "elapsed_seconds" ,
162+ ),
125163 shard_rows ,
126164 )
127165 write_csv (
@@ -144,12 +182,14 @@ def write_summary(output_directory: Path, shards: tuple[ShardResult, ...], expec
144182 f"Discovered artifacts for **{ len (shards )} of { expected_shards } ** shards. " ,
145183 f"Assigned tests: **{ total_assigned } **. Reported results: **{ total_reported } **." ,
146184 "" ,
147- "| Shard | Assigned | Reported | Passed | Failed | Test duration |" ,
148- "| ---: | ---: | ---: | ---: | ---: | ---: |" ,
185+ "| Shard | Assigned | Reported | Passed | Failed | Test duration | Elapsed | " ,
186+ "| ---: | ---: | ---: | ---: | ---: | ---: | ---: | " ,
149187 ]
150- for index , assigned , reported , passed , failed , duration in shard_rows :
188+ for index , assigned , reported , passed , failed , duration , elapsed in shard_rows :
189+ elapsed_display = f"{ float (elapsed ) / 60 :.1f} min" if elapsed else "missing"
151190 lines .append (
152- f"| { index } | { assigned } | { reported } | { passed } | { failed } | { float (duration ) / 60 :.1f} min |"
191+ f"| { index } | { assigned } | { reported } | { passed } | { failed } | "
192+ f"{ float (duration ) / 60 :.1f} min | { elapsed_display } |"
153193 )
154194 if missing_shards :
155195 lines .extend (("" , f"Missing shard artifacts: { ', ' .join (map (str , missing_shards ))} ." ))
0 commit comments