2626import com .epam .reportportal .service .tree .TestItemTree ;
2727import com .epam .reportportal .utils .*;
2828import com .epam .reportportal .utils .files .ByteSource ;
29+ import com .epam .reportportal .utils .formatting .MarkdownUtils ;
2930import com .epam .reportportal .utils .http .ContentType ;
3031import com .epam .reportportal .utils .properties .SystemAttributesExtractor ;
3132import com .epam .ta .reportportal .ws .model .FinishExecutionRQ ;
6162import static com .epam .reportportal .cucumber .Utils .*;
6263import static com .epam .reportportal .cucumber .util .ItemTreeUtils .createKey ;
6364import static com .epam .reportportal .cucumber .util .ItemTreeUtils .retrieveLeaf ;
65+ import static com .epam .reportportal .utils .formatting .ExceptionUtils .getStackTrace ;
66+ import static com .epam .reportportal .utils .formatting .MarkdownUtils .formatDataTable ;
6467import static java .lang .String .format ;
6568import static java .util .Optional .ofNullable ;
6669import static org .apache .commons .lang3 .StringUtils .isBlank ;
6770import static org .apache .commons .lang3 .StringUtils .isNotBlank ;
68- import static org .apache .commons .lang3 .exception .ExceptionUtils .getStackTrace ;
6971
7072/**
7173 * Abstract Cucumber formatter/reporter for Report Portal
@@ -83,7 +85,6 @@ public abstract class AbstractReporter implements Formatter, Reporter {
8385 private static final String METHOD_OPENING_BRACKET = "(" ;
8486 private static final String DOCSTRING_DECORATOR = "\n \" \" \" \n " ;
8587 private static final String ERROR_FORMAT = "Error:\n %s" ;
86- private static final String DESCRIPTION_ERROR_FORMAT = "%s\n " + ERROR_FORMAT ;
8788
8889 public static final TestItemTree ITEM_TREE = new TestItemTree ();
8990 private static volatile ReportPortal REPORT_PORTAL = ReportPortal .builder ().build ();
@@ -97,11 +98,11 @@ public abstract class AbstractReporter implements Formatter, Reporter {
9798 /**
9899 * This map uses to record the description of the scenario and the step to append the error to the description.
99100 */
100- private final Map <String , String > descriptionsMap = new ConcurrentHashMap <>();
101+ private final Map <Maybe < String > , String > descriptionsMap = new ConcurrentHashMap <>();
101102 /**
102103 * This map uses to record errors to append to the description.
103104 */
104- private final Map <String , Throwable > errorMap = new ConcurrentHashMap <>();
105+ private final Map <Maybe < String > , Throwable > errorMap = new ConcurrentHashMap <>();
105106
106107 private AtomicBoolean finished = new AtomicBoolean (false );
107108
@@ -273,8 +274,7 @@ protected void beforeScenario(Scenario scenario, String outlineIteration) {
273274 scenarioContext .setId (startScenario (featureContext .getId (), rq ));
274275 scenarioContext .setLine (scenario .getLine ());
275276 scenarioContext .setFeatureUri (uri );
276- scenarioContext .getId ()
277- .subscribe (id -> descriptionsMap .put (id , ofNullable (rq .getDescription ()).orElse (StringUtils .EMPTY )));
277+ descriptionsMap .put (scenarioContext .getId (), ofNullable (rq .getDescription ()).orElse (StringUtils .EMPTY ));
278278 if (myLaunch .getParameters ().isCallbackReportingEnabled ()) {
279279 addToTree (featureContext , scenarioContext );
280280 }
@@ -294,33 +294,34 @@ private void removeFromTree(RunningContext.FeatureContext featureContext, Runnin
294294 */
295295 @ Nonnull
296296 @ SuppressWarnings ("unused" )
297- protected Maybe <FinishTestItemRQ > buildFinishTestItemRequest (@ Nonnull Maybe <String > itemId , @ Nullable ItemStatus status ) {
298- return itemId .map (id -> {
299- FinishTestItemRQ rq = new FinishTestItemRQ ();
300- if (status == ItemStatus .FAILED ) {
301- Optional <String > currentDescription = Optional .ofNullable (descriptionsMap .get (id ));
302- Optional <Throwable > currentError = Optional .ofNullable (errorMap .get (id ));
303- currentDescription .flatMap (description -> currentError
304- .map (errorMessage -> resolveDescriptionErrorMessage (description , errorMessage )))
305- .ifPresent (rq ::setDescription );
306- }
307- ofNullable (status ).ifPresent (s -> rq .setStatus (s .name ()));
308- rq .setEndTime (Calendar .getInstance ().getTime ());
309- return rq ;
310- });
297+ protected FinishTestItemRQ buildFinishTestItemRequest (@ Nonnull Maybe <String > itemId , @ Nullable ItemStatus status ) {
298+ FinishTestItemRQ rq = new FinishTestItemRQ ();
299+ if (status == ItemStatus .FAILED ) {
300+ Optional <String > currentDescription = Optional .ofNullable (descriptionsMap .get (itemId ));
301+ Optional <Throwable > currentError = Optional .ofNullable (errorMap .get (itemId ));
302+ currentDescription .flatMap (description -> currentError .map (errorMessage -> resolveDescriptionErrorMessage (
303+ description ,
304+ errorMessage
305+ ))).ifPresent (rq ::setDescription );
306+ }
307+ ofNullable (status ).ifPresent (s -> rq .setStatus (s .name ()));
308+ rq .setEndTime (Calendar .getInstance ().getTime ());
309+ return rq ;
311310 }
312311
313312 /**
314313 * Resolve description
314+ *
315315 * @param currentDescription Current description
316- * @param error Error message
316+ * @param error Error message
317317 * @return Description with error
318318 */
319319 private String resolveDescriptionErrorMessage (String currentDescription , Throwable error ) {
320+ String errorStr = format (ERROR_FORMAT , getStackTrace (error , new Throwable ()));
320321 return Optional .ofNullable (currentDescription )
321322 .filter (StringUtils ::isNotBlank )
322- .map (description -> format ( DESCRIPTION_ERROR_FORMAT , currentDescription , error ))
323- .orElse (format ( ERROR_FORMAT , error ) );
323+ .map (description -> MarkdownUtils . asTwoParts ( currentDescription , errorStr ))
324+ .orElse (errorStr );
324325 }
325326
326327 /**
@@ -334,9 +335,9 @@ protected void finishTestItem(@Nullable Maybe<String> itemId, @Nullable ItemStat
334335 LOGGER .error ("BUG: Trying to finish unspecified test item." );
335336 return ;
336337 }
338+ FinishTestItemRQ finishTestItemRQ = buildFinishTestItemRequest (itemId , status );
337339 //noinspection ReactiveStreamsUnusedPublisher
338- Maybe <FinishTestItemRQ > finishTestItemRQMaybe = buildFinishTestItemRequest (itemId , status );
339- finishTestItemRQMaybe .subscribe (finishTestItemRQ -> launch .get ().finishTestItem (itemId , finishTestItemRQ ));
340+ launch .get ().finishTestItem (itemId , finishTestItemRQ );
340341 }
341342
342343 /**
@@ -427,7 +428,8 @@ protected Maybe<String> startStep(@Nonnull Maybe<String> scenarioId, @Nonnull St
427428 }
428429
429430 private void addToTree (@ Nonnull RunningContext .ScenarioContext scenarioContext , @ Nullable String text , @ Nullable Maybe <String > stepId ) {
430- retrieveLeaf (scenarioContext .getFeatureUri (),
431+ retrieveLeaf (
432+ scenarioContext .getFeatureUri (),
431433 scenarioContext .getLine (),
432434 ITEM_TREE
433435 ).ifPresent (scenarioLeaf -> scenarioLeaf .getChildItems ().put (createKey (text ), TestItemTree .createTestItemLeaf (stepId )));
@@ -446,7 +448,7 @@ protected void beforeStep(Step step, Match match) {
446448 context .setCurrentStepId (stepId );
447449 String stepText = step .getName ();
448450 if (rq .isHasStats ()) {
449- stepId . subscribe ( id -> descriptionsMap .put (id , ofNullable (rq .getDescription ()).orElse (StringUtils .EMPTY ) ));
451+ descriptionsMap .put (stepId , ofNullable (rq .getDescription ()).orElse (StringUtils .EMPTY ));
450452 }
451453
452454 if (launch .get ().getParameters ().isCallbackReportingEnabled ()) {
@@ -483,8 +485,8 @@ protected StartTestItemRQ buildStartHookRequest(boolean isBefore) {
483485 /**
484486 * Start before/after-hook item on Report Portal
485487 *
486- * @param parentId parent item id
487- * @param rq hook start request
488+ * @param parentId parent item id
489+ * @param rq hook start request
488490 * @return hook item id
489491 */
490492 @ Nonnull
@@ -545,14 +547,14 @@ protected void reportResult(@Nonnull Result result, @Nullable String message) {
545547 if (errorMessage != null ) {
546548 sendLog (errorMessage , level );
547549 } else if (result .getError () != null ) {
548- sendLog (getStackTrace (result .getError ()), level );
550+ sendLog (getStackTrace (result .getError (), new Throwable () ), level );
549551 }
550552 RunningContext .ScenarioContext currentScenario = getCurrentScenarioContext ();
551553 ItemStatus itemStatus = mapStatus (result .getStatus ());
552554 currentScenario .updateStatus (itemStatus );
553555 if (itemStatus == ItemStatus .FAILED ) {
554- currentScenario .getId (). subscribe ( id -> errorMap . put ( id , result .getError () ));
555- currentScenario .getCurrentStepId (). subscribe ( id -> errorMap . put ( id , result .getError () ));
556+ errorMap . put ( currentScenario .getId (), result .getError ());
557+ errorMap . put ( currentScenario .getCurrentStepId (), result .getError ());
556558 }
557559 }
558560
@@ -619,7 +621,8 @@ private static String getDataType(@Nonnull byte[] data) {
619621 public void embedding (String mimeType , byte [] data ) {
620622 String type = ofNullable (mimeType ).filter (ContentType ::isValidType ).orElseGet (() -> getDataType (data ));
621623 String attachmentName = ofNullable (type ).map (t -> t .substring (0 , t .indexOf ("/" ))).orElse ("" );
622- ReportPortal .emitLog (new ReportPortalMessage (ByteSource .wrap (data ), type , attachmentName ),
624+ ReportPortal .emitLog (
625+ new ReportPortalMessage (ByteSource .wrap (data ), type , attachmentName ),
623626 "UNKNOWN" ,
624627 Calendar .getInstance ().getTime ()
625628 );
@@ -749,7 +752,8 @@ protected TestCaseIdEntry getTestCaseId(@Nonnull Match match, @Nullable String c
749752 if (method == null ) {
750753 return getTestCaseId (codeRef , match .getArguments ());
751754 }
752- return TestCaseIdUtils .getTestCaseId (method .getAnnotation (TestCaseId .class ),
755+ return TestCaseIdUtils .getTestCaseId (
756+ method .getAnnotation (TestCaseId .class ),
753757 method ,
754758 codeRef ,
755759 (List <Object >) ARGUMENTS_TRANSFORM .apply (match .getArguments ())
@@ -913,8 +917,9 @@ protected List<ParameterResource> getParameters(@Nonnull Step step, @Nullable St
913917 .filter (ds -> !ds .isEmpty ())
914918 .ifPresent (ds -> params .add (Pair .of ("docstring" , StringEscapeUtils .escapeHtml4 (ds ))));
915919 ofNullable (step .getRows ()).filter (rows -> !rows .isEmpty ())
916- .ifPresent (rows -> params .add (Pair .of ("datatable" ,
917- Utils .formatDataTable (rows .stream ().map (Row ::getCells ).collect (Collectors .toList ()))
920+ .ifPresent (rows -> params .add (Pair .of (
921+ "datatable" ,
922+ formatDataTable (rows .stream ().map (Row ::getCells ).collect (Collectors .toList ()))
918923 )));
919924 return params .isEmpty () ? Collections .emptyList () : ParameterUtils .getParameters (codeRef , params );
920925 }
0 commit comments