4141import java .io .FileInputStream ;
4242import java .io .IOException ;
4343import java .io .Serializable ;
44+ import java .time .OffsetDateTime ;
4445import java .util .ArrayList ;
4546import java .util .Collections ;
4647import java .util .HashMap ;
@@ -73,6 +74,7 @@ public final class SuiteResult implements Serializable {
7374 private final String stdout ;
7475 private final String stderr ;
7576 private float duration ;
77+ private long startTime ;
7678 private final Map <String , String > properties ;
7779
7880 /**
@@ -242,6 +244,14 @@ private SuiteResult(File xmlReport, Element suite, boolean keepLongStdio, boolea
242244 this .enclosingBlocks .addAll (pipelineTestDetails .getEnclosingBlocks ());
243245 this .enclosingBlockNames .addAll (pipelineTestDetails .getEnclosingBlockNames ());
244246 }
247+
248+ // check for timestamp attribute and set start time if present
249+ if (timestamp != null && !timestamp .equals ("" )) {
250+ this .startTime = parseTime (timestamp );
251+ }
252+ else {
253+ this .startTime = -1 ;
254+ }
245255
246256 // check for test suite time attribute
247257 if ((this .time = suite .attributeValue ("time" )) != null ) {
@@ -254,6 +264,8 @@ private SuiteResult(File xmlReport, Element suite, boolean keepLongStdio, boolea
254264 addCase (new CaseResult (this , suite , "<init>" , keepLongStdio , keepProperties ));
255265 }
256266
267+ // offset for start time of cases if none is case timestamp is not specified
268+ long caseStartOffset = 0 ;
257269 List <Element > testCases = suite .elements ("testcase" );
258270 for (Element e : testCases ) {
259271 // https://issues.jenkins-ci.org/browse/JENKINS-1233 indicates that
@@ -274,8 +286,20 @@ private SuiteResult(File xmlReport, Element suite, boolean keepLongStdio, boolea
274286 // are at odds with each other --- when both are present,
275287 // one wants to use @name from <testsuite>,
276288 // the other wants to use @classname from <testcase>.
289+
290+ CaseResult caze = new CaseResult (this , e , classname , keepLongStdio , keepProperties );
277291
278- addCase (new CaseResult (this , e , classname , keepLongStdio , keepProperties ));
292+ // If timestamp is present for <testcase> set startTime of new CaseResult.
293+ String caseStart = e .attributeValue ("timestamp" );
294+ if (caseStart != null && !caseStart .equals ("" )) {
295+ caze .setStartTime (parseTime (caseStart ));
296+ }
297+ // Else estimate start time using sum of previous case durations in suite
298+ else if (startTime != -1 ) {
299+ caze .setStartTime (startTime + caseStartOffset );
300+ caseStartOffset += (long )(caze .getDuration () * 1000 );
301+ }
302+ addCase (caze );
279303 }
280304
281305 String stdout = CaseResult .possiblyTrimStdio (cases , keepLongStdio , suite .elementText ("system-out" ));
@@ -437,6 +461,14 @@ public hudson.tasks.junit.TestResult getParent() {
437461 public String getTimestamp () {
438462 return timestamp ;
439463 }
464+
465+ public long getStartTime () {
466+ return startTime ;
467+ }
468+
469+ public void setStartTime (long start ) {
470+ this .startTime = start ;
471+ }
440472
441473 @ Exported (visibility =9 )
442474 public String getId () {
@@ -495,6 +527,25 @@ public void setParent(hudson.tasks.junit.TestResult parent) {
495527 c .freeze (this );
496528 return true ;
497529 }
530+
531+ /**
532+ * Parses time as epoch milli from time string
533+ * @param time
534+ * @return time in epoch milli
535+ */
536+ public long parseTime (String time ) {
537+ try {
538+ // if time is not in supported format due to missing zulu and offset
539+ if (time .charAt (time .length () - 1 ) != 'Z' && !time .contains ("+" ) && time .lastIndexOf ("-" ) <= 7 )
540+ time += 'Z' ;
541+ OffsetDateTime odt = OffsetDateTime .parse (time .replace (" " , "" ));
542+ return odt .toInstant ().toEpochMilli ();
543+ } catch (Exception e ) {
544+ // If time format causes error in parsing print message and return -1
545+ LOGGER .warning ("Could not parse start time from timestamp." );
546+ return -1 ;
547+ }
548+ }
498549
499550 private static final long serialVersionUID = 1L ;
500551
0 commit comments