Skip to content

Commit

Permalink
Merge pull request #66 from reportportal/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
HardNorth authored Oct 19, 2020
2 parents 19b0aa1 + 1ae9677 commit 4b6fd1b
Show file tree
Hide file tree
Showing 8 changed files with 433 additions and 294 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## [Unreleased]
### Changed
- Many static methods from Util class were moved to AbstractReporter class and made protected to ease extension

## [5.0.0-RC-1]
### Added
Expand Down
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ dependencies {
api 'com.epam.reportportal:client-java:5.0.11'
api 'com.epam.reportportal:commons-model:5.0.0'
api 'com.google.code.findbugs:jsr305:3.0.2'

api 'info.cukes:gherkin:2.12.2'

implementation 'org.apache.commons:commons-text:1.9'

testImplementation 'org.aspectj:aspectjweaver:1.9.2'
testImplementation 'info.cukes:cucumber-java:1.2.6'
testImplementation 'info.cukes:cucumber-testng:1.2.6'
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=5.0.0-RC-2-SNAPSHOT
version=5.0.0-SNAPSHOT
description=EPAM Report portal. Cucumber version 1 integration
458 changes: 397 additions & 61 deletions src/main/java/com/epam/reportportal/cucumber/AbstractReporter.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public static class ScenarioContext {
private Maybe<String> id;
private ItemStatus status;
private Integer line;
private String currentText;
private String featureUri;

public ScenarioContext() {
Expand Down Expand Up @@ -160,10 +159,6 @@ public void setLine(Integer scenarioLine) {
line = scenarioLine;
}

public void setCurrentText(String stepText) {
currentText = stepText;
}

public void setFeatureUri(String featureUri) {
this.featureUri = featureUri;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ protected void afterLaunch() {
LOGGER.debug("There is no scenarios in the launch");
return;
}
Utils.finishTestItem(launch.get(), rootSuiteId.get());
finishTestItem(rootSuiteId.get());
rootSuiteId = null;
super.afterLaunch();
}
Expand Down
233 changes: 8 additions & 225 deletions src/main/java/com/epam/reportportal/cucumber/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,214 +15,26 @@
*/
package com.epam.reportportal.cucumber;

import com.epam.reportportal.annotations.TestCaseId;
import com.epam.reportportal.annotations.attribute.Attributes;
import com.epam.reportportal.listeners.ItemStatus;
import com.epam.reportportal.service.Launch;
import com.epam.reportportal.service.ReportPortal;
import com.epam.reportportal.service.item.TestCaseIdEntry;
import com.epam.reportportal.utils.AttributeParser;
import com.epam.reportportal.utils.ParameterUtils;
import com.epam.reportportal.utils.TestCaseIdUtils;
import com.epam.ta.reportportal.ws.model.FinishTestItemRQ;
import com.epam.ta.reportportal.ws.model.ParameterResource;
import com.epam.ta.reportportal.ws.model.StartTestItemRQ;
import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ;
import gherkin.formatter.Argument;
import gherkin.formatter.model.*;
import io.reactivex.Maybe;
import io.reactivex.annotations.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rp.com.google.common.base.Strings;
import rp.com.google.common.collect.ImmutableMap;
import gherkin.formatter.model.Match;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.util.Optional.ofNullable;

public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
private static final String TABLE_SEPARATOR = "|";
private static final String DOCSTRING_DECORATOR = "\n\"\"\"\n";
private static final String STEP_DEFINITION_FIELD_NAME = "stepDefinition";
private static final String GET_LOCATION_METHOD_NAME = "getLocation";
private static final String METHOD_OPENING_BRACKET = "(";
private static final String METHOD_FIELD_NAME = "method";

//@formatter:off
private static final Map<String, ItemStatus> STATUS_MAPPING = ImmutableMap.<String, ItemStatus>builder()
.put("passed", ItemStatus.PASSED)
.put("failed", ItemStatus.FAILED)
.put("skipped", ItemStatus.SKIPPED)
.put("pending", ItemStatus.SKIPPED)
.put("undefined", ItemStatus.SKIPPED).build();
//@formatter:on

private Utils() {
}

public static void finishTestItem(Launch rp, Maybe<String> itemId) {
finishTestItem(rp, itemId, null);
}

public static void finishTestItem(Launch rp, Maybe<String> itemId, ItemStatus status) {
if (itemId == null) {
LOGGER.error("BUG: Trying to finish unspecified test item.");
return;
}

FinishTestItemRQ rq = new FinishTestItemRQ();
ofNullable(status).ifPresent(s -> rq.setStatus(s.name()));
rq.setEndTime(Calendar.getInstance().getTime());

rp.finishTestItem(itemId, rq);

}

public static Maybe<String> startNonLeafNode(Launch rp, Maybe<String> rootItemId, String name, String description, String codeRef,
List<Tag> tags, String type) {
StartTestItemRQ rq = new StartTestItemRQ();
rq.setDescription(description);
rq.setCodeRef(codeRef);
rq.setName(name);
rq.setAttributes(extractAttributes(tags));
rq.setStartTime(Calendar.getInstance().getTime());
rq.setType(type);
if ("STEP".equals(type)) {
rq.setTestCaseId(ofNullable(Utils.getTestCaseId(codeRef, null)).map(TestCaseIdEntry::getId).orElse(null));
}

return rp.startTestItem(rootItemId, rq);
}

static void sendLog(final String message, final String level) {
ReportPortal.emitLog(message, level, Calendar.getInstance().getTime());
}

/**
* Transform tags from Cucumber to RP format
*
* @param tags - Cucumber tags
* @return set of tags
*/
public static Set<ItemAttributesRQ> extractAttributes(List<Tag> tags) {
Set<ItemAttributesRQ> result = new HashSet<>();
for (Tag tag : tags) {
result.add(new ItemAttributesRQ(null, tag.getName()));
}
return result;
}

/**
* Map Cucumber statuses to RP log levels
*
* @param cukesStatus - Cucumber status
* @return regular log level
*/
public static String mapLevel(String cukesStatus) {
if (cukesStatus.equalsIgnoreCase("passed")) {
return "INFO";
} else if (cukesStatus.equalsIgnoreCase("skipped")) {
return "WARN";
} else {
return "ERROR";
}
}

/**
* Map Cucumber statuses to RP
*
* @param cukesStatus - Cucumber status
* @return regular status
*/
@Nonnull
public static ItemStatus mapStatus(String cukesStatus) {
if (Strings.isNullOrEmpty(cukesStatus)) {
return ItemStatus.FAILED;
}
ItemStatus status = STATUS_MAPPING.get(cukesStatus.toLowerCase());
return null == status ? ItemStatus.FAILED : status;
}

/**
* Generate multiline argument (DataTable or DocString) representation
*
* @param step - Cucumber step object
* @return - transformed multiline argument (or empty string if there is
* none)
*/
public static String buildMultilineArgument(Step step) {
List<DataTableRow> table = step.getRows();
DocString ds = step.getDocString();
StringBuilder marg = new StringBuilder();
StringBuilder markDownSeparator = new StringBuilder();
if (table != null) {
marg.append("\r\n\r\n");
for (Row row : table) {
marg.append(TABLE_SEPARATOR);
for (String cell : row.getCells()) {
marg.append(" ").append(cell).append(" ").append(TABLE_SEPARATOR);
}
marg.append("\r\n");
if (markDownSeparator.length() == 0) {
markDownSeparator.append(TABLE_SEPARATOR).append("-").append(TABLE_SEPARATOR);
marg.append(markDownSeparator);
marg.append("\r\n");
}
}
}

if (ds != null) {
marg.append(DOCSTRING_DECORATOR).append(ds.getValue()).append(DOCSTRING_DECORATOR);
}
return marg.toString();
}

@Nullable
public static Set<ItemAttributesRQ> getAttributes(Match match) {
try {
Method method = retrieveMethod(match);
Attributes attributesAnnotation = method.getAnnotation(Attributes.class);
if (attributesAnnotation != null) {
return AttributeParser.retrieveAttributes(attributesAnnotation);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
return null;
}
return null;
}

@Nullable
public static String getCodeRef(Match match) {

try {
Field stepDefinitionField = match.getClass().getDeclaredField(STEP_DEFINITION_FIELD_NAME);
stepDefinitionField.setAccessible(true);
Object javaStepDefinition = stepDefinitionField.get(match);
Method getLocationMethod = javaStepDefinition.getClass().getDeclaredMethod(GET_LOCATION_METHOD_NAME, boolean.class);
getLocationMethod.setAccessible(true);
String fullCodeRef = String.valueOf(getLocationMethod.invoke(javaStepDefinition, true));
return fullCodeRef != null ? fullCodeRef.substring(0, fullCodeRef.indexOf(METHOD_OPENING_BRACKET)) : null;
} catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
return null;
}

}

@Nonnull
public static String getCodeRef(@Nonnull String uri, int line) {
return uri + ":" + line;
}

/**
* Generate name representation
*
Expand All @@ -231,18 +43,13 @@ public static String getCodeRef(@Nonnull String uri, int line) {
* @param argument - main text to process
* @return transformed string
*/
public static String buildName(String prefix, String infix, String argument) {
@Nonnull
public static String buildName(@Nullable String prefix, @Nullable String infix, @Nullable String argument) {
return (prefix == null ? "" : prefix) + infix + argument;
}

static List<ParameterResource> getParameters(String codeRef, Match match) {
List<Pair<String, String>> params = ofNullable(match.getArguments()).map(a -> IntStream.range(0, a.size())
.mapToObj(i -> Pair.of("arg" + i, a.get(i).getVal()))
.collect(Collectors.toList())).orElse(null);
return ParameterUtils.getParameters(codeRef, params);
}

private static Method retrieveMethod(Match match) throws NoSuchFieldException, IllegalAccessException {
@Nullable
public static Method retrieveMethod(@Nonnull Match match) throws NoSuchFieldException, IllegalAccessException {
Field stepDefinitionField = match.getClass().getDeclaredField(STEP_DEFINITION_FIELD_NAME);
stepDefinitionField.setAccessible(true);
Object javaStepDefinition = stepDefinitionField.get(match);
Expand All @@ -251,32 +58,8 @@ private static Method retrieveMethod(Match match) throws NoSuchFieldException, I
return (Method) methodField.get(javaStepDefinition);
}

private static final Function<List<Argument>, List<?>> ARGUMENTS_TRANSFORM = arguments -> ofNullable(arguments).map(args -> args.stream()
public static final Function<List<Argument>, List<?>> ARGUMENTS_TRANSFORM = arguments -> ofNullable(arguments).map(args -> args.stream()
.map(Argument::getVal)
.collect(Collectors.toList())).orElse(null);

@SuppressWarnings("unchecked")
public static TestCaseIdEntry getTestCaseId(Match match, String codeRef) {
try {
Method method = retrieveMethod(match);
return TestCaseIdUtils.getTestCaseId(
method.getAnnotation(TestCaseId.class),
method,
codeRef,
(List<Object>) ARGUMENTS_TRANSFORM.apply(match.getArguments())
);
} catch (NoSuchFieldException | IllegalAccessException e) {
return getTestCaseId(codeRef, match.getArguments());
}
}

@SuppressWarnings("unchecked")
private static TestCaseIdEntry getTestCaseId(String codeRef, List<Argument> arguments) {
return TestCaseIdUtils.getTestCaseId(codeRef, (List<Object>) ARGUMENTS_TRANSFORM.apply(arguments));
}

@Nonnull
public static String getDescription(@Nonnull String uri) {
return uri;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ public static class InlineParametersTestStepReporter extends AbstractTestNGCucum

}

@CucumberOptions(features = "src/test/resources/features/BasicDocStringParameters.feature", glue = {
"com.epam.reportportal.cucumber.integration.feature" }, plugin = { "pretty",
"com.epam.reportportal.cucumber.integration.TestStepReporter" })
public static class DocstringParameterTestStepReporter extends AbstractTestNGCucumberTests {

}

private final String launchId = CommonUtils.namedId("launch_");
private final String suiteId = CommonUtils.namedId("suite_");
private final List<String> testIds = Stream.generate(() -> CommonUtils.namedId("test_")).limit(3).collect(Collectors.toList());
Expand Down Expand Up @@ -157,4 +164,19 @@ public void verify_inline_parameters() {
assertThat(param3.getKey(), equalTo("my name"));
assertThat(param3.getValue(), equalTo("string"));
}

@Test
public void verify_docstring_parameters() {
TestUtils.runTests(DocstringParameterTestStepReporter.class);

ArgumentCaptor<StartTestItemRQ> captor = ArgumentCaptor.forClass(StartTestItemRQ.class);
verify(client, times(4)).startTestItem(same(testIds.get(0)), captor.capture());

List<StartTestItemRQ> items = captor.getAllValues();
List<ParameterResource> params = items.get(2).getParameters();
assertThat(params, allOf(notNullValue(), hasSize(1)));
ParameterResource param1 = params.get(0);
assertThat(param1.getKey(), equalTo("java.lang.String"));
assertThat(param1.getValue(), equalTo("My very long parameter\nWith some new lines"));
}
}

0 comments on commit 4b6fd1b

Please sign in to comment.