diff --git a/src/main/java/com/epam/reportportal/karate/KarateUtils.java b/src/main/java/com/epam/reportportal/karate/KarateUtils.java new file mode 100644 index 0000000..db4ce6d --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/KarateUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.epam.reportportal.karate; + +import javax.annotation.Nonnull; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Set of useful utils related to Karate -> ReportPortal integration + */ +public class KarateUtils { + + private KarateUtils() { + throw new AssertionError("No instances should exist for the class!"); + } + + private static final String PARAMETER_ITEMS_START = "["; + private static final String PARAMETER_ITEMS_END = "]"; + private static final String PARAMETER_ITEMS_DELIMITER = ";"; + private static final String KEY_VALUE_SEPARATOR = ":"; + + /** + * Create a String from a parameter Map to be used as a test key and title + * + * @param example a map of parameters: name->value + * @return a formatted string of parameters + */ + public static String formatExampleKey(@Nonnull final Map example) { + return example.entrySet() + .stream() + .map(e -> e.getKey() + KEY_VALUE_SEPARATOR + e.getValue().toString()) + .collect(Collectors.joining(PARAMETER_ITEMS_DELIMITER, PARAMETER_ITEMS_START, PARAMETER_ITEMS_END)); + } +} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java b/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java index 4fc72d6..416029f 100644 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java @@ -30,6 +30,7 @@ public class ReportPortalPublisher { public static final String SCENARIO_CODE_REFERENCE_PATTERN = "%s/[SCENARIO:%s]"; + public static final String EXAMPLE_CODE_REFERENCE_PATTERN = "%s/[EXAMPLE:%s%s]"; private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalPublisher.class); private final ConcurrentHashMap> featureIdMap = new ConcurrentHashMap<>(); @@ -116,7 +117,8 @@ protected String getCodeRef(Scenario scenario) { return String.format(SCENARIO_CODE_REFERENCE_PATTERN, scenario.getFeature().getResource().getRelativePath(), scenario.getName()); } else { - return null; + return String.format(EXAMPLE_CODE_REFERENCE_PATTERN, scenario.getFeature().getResource().getRelativePath(), + scenario.getName(), KarateUtils.formatExampleKey(scenario.getExampleData())); } } diff --git a/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java new file mode 100644 index 0000000..f36b00d --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java @@ -0,0 +1,80 @@ +package com.epam.reportportal.karate.coderef; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static com.epam.reportportal.karate.utils.TestUtils.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class ExamplesCodeRefTest { + private final String featureId = CommonUtils.namedId("feature_"); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2) + .collect(Collectors.toList()); + private final List>> stepIds = exampleIds.stream() + .map(e -> Pair.of(e, Stream.generate(() -> CommonUtils.namedId("step_")) + .limit(2).collect(Collectors.toList()))) + .collect(Collectors.toList()); + + private static final String EXAMPLE_CODE_REFERENCE_PATTERN = "feature/examples.feature/[EXAMPLE:Verify different maths[%s]]"; + private static final String FIRST_EXAMPLE_CODE_REFERENCE = String.format(EXAMPLE_CODE_REFERENCE_PATTERN, "vara:2;varb:2;result:4"); + private static final String SECOND_EXAMPLE_CODE_REFERENCE = String.format(EXAMPLE_CODE_REFERENCE_PATTERN, "vara:1;varb:2;result:3"); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, stepIds); + mockBatchLogging(client); + } + + @Test + public void test_examples_code_reference() { + var results = TestUtils.runAsReport(rp, "classpath:feature/examples.feature"); + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(captor.capture()); + verify(client, times(2)).startTestItem(same(featureId), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(7)); + + StartTestItemRQ featureRq = items.get(0); + + assertThat(featureRq.getType(), allOf(notNullValue(), equalTo(ItemType.STORY.name()))); + + StartTestItemRQ firstScenarioRq = items.get(1); + assertThat(firstScenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(firstScenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_CODE_REFERENCE))); + + StartTestItemRQ secondScenarioRq = items.get(2); + assertThat(secondScenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(secondScenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_CODE_REFERENCE))); + + List stepRqs = items.subList(3, items.size()); + IntStream.range(0, stepRqs.size()).forEach(i -> { + StartTestItemRQ step = stepRqs.get(i); + assertThat(step.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(step.isHasStats(), equalTo(Boolean.FALSE)); + }); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java b/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java index ab33a9b..3fbc449 100644 --- a/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java +++ b/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java @@ -60,51 +60,51 @@ public static ListenerParameters standardParameters() { } public static void mockLaunch(@Nonnull final ReportPortalClient client, @Nullable final String launchUuid, - @Nullable final String storyUuid, @Nonnull String testClassUuid, + @Nullable final String featureUuid, @Nonnull String scenarioUuid, @Nonnull String stepUuid) { - mockLaunch(client, launchUuid, storyUuid, testClassUuid, Collections.singleton(stepUuid)); + mockLaunch(client, launchUuid, featureUuid, scenarioUuid, Collections.singleton(stepUuid)); } public static void mockLaunch(@Nonnull final ReportPortalClient client, @Nullable final String launchUuid, - @Nullable final String storyUuid, @Nonnull String testClassUuid, + @Nullable final String featureUuid, @Nonnull String scenarioUuid, @Nonnull Collection stepList) { - mockLaunch(client, launchUuid, storyUuid, Collections.singletonList(Pair.of(testClassUuid, stepList))); + mockLaunch(client, launchUuid, featureUuid, Collections.singletonList(Pair.of(scenarioUuid, stepList))); } public static > void mockLaunch( @Nonnull final ReportPortalClient client, @Nullable final String launchUuid, - @Nullable final String storyUuid, @Nonnull final Collection> testSteps) { + @Nullable final String featureUuid, @Nonnull final Collection> scenarioSteps) { String launch = ofNullable(launchUuid).orElse(CommonUtils.namedId("launch_")); when(client.startLaunch(any())).thenReturn(Maybe.just(new StartLaunchRS(launch, 1L))); when(client.finishLaunch(eq(launch), any())).thenReturn(Maybe.just(new OperationCompletionRS())); - mockFeature(client, storyUuid, testSteps); + mockFeature(client, featureUuid, scenarioSteps); } public static > void mockFeature( - @Nonnull final ReportPortalClient client, @Nullable final String storyUuid, - @Nonnull final Collection> testSteps) { - String rootItemId = ofNullable(storyUuid).orElseGet(() -> CommonUtils.namedId(ROOT_SUITE_PREFIX)); - mockFeatures(client, Collections.singletonList(Pair.of(rootItemId, testSteps))); + @Nonnull final ReportPortalClient client, @Nullable final String featureUuid, + @Nonnull final Collection> scenarioSteps) { + String rootItemId = ofNullable(featureUuid).orElseGet(() -> CommonUtils.namedId(ROOT_SUITE_PREFIX)); + mockFeatures(client, Collections.singletonList(Pair.of(rootItemId, scenarioSteps))); } @SuppressWarnings("unchecked") public static > void mockFeatures( @Nonnull final ReportPortalClient client, - @Nonnull final List>>> stories) { - if (stories.isEmpty()) { + @Nonnull final List>>> features) { + if (features.isEmpty()) { return; } - String firstStory = stories.get(0).getKey(); - Maybe first = Maybe.just(new ItemCreatedRS(firstStory, firstStory)); - Maybe[] other = (Maybe[]) stories.subList(1, stories.size()) + String firstFeature = features.get(0).getKey(); + Maybe first = Maybe.just(new ItemCreatedRS(firstFeature, firstFeature)); + Maybe[] other = (Maybe[]) features.subList(1, features.size()) .stream() .map(Pair::getKey) .map(s -> Maybe.just(new ItemCreatedRS(s, s))) .toArray(Maybe[]::new); when(client.startTestItem(any())).thenReturn(first, other); - stories.forEach(i -> { + features.forEach(i -> { Maybe rootFinishMaybe = Maybe.just(new OperationCompletionRS()); when(client.finishTestItem(same(i.getKey()), any())).thenReturn(rootFinishMaybe); mockScenario(client, i.getKey(), i.getValue()); @@ -113,28 +113,28 @@ public static > void mockFeatures( @SuppressWarnings("unchecked") public static > void mockScenario( - @Nonnull final ReportPortalClient client, @Nonnull final String storyUuid, - @Nonnull final Collection> testSteps) { - List> testResponses = testSteps.stream() + @Nonnull final ReportPortalClient client, @Nonnull final String featureUuid, + @Nonnull final Collection> scenarioSteps) { + List> testResponses = scenarioSteps.stream() .map(Pair::getKey) .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) .collect(Collectors.toList()); Maybe first = testResponses.get(0); Maybe[] other = testResponses.subList(1, testResponses.size()).toArray(new Maybe[0]); - when(client.startTestItem(same(storyUuid), any())).thenReturn(first, other); + when(client.startTestItem(same(featureUuid), any())).thenReturn(first, other); - testSteps.forEach(test -> { - String testClassUuid = test.getKey(); + scenarioSteps.forEach(test -> { + String scenarioUuid = test.getKey(); List> stepResponses = test.getValue() .stream() .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) .collect(Collectors.toList()); - when(client.finishTestItem(same(testClassUuid), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + when(client.finishTestItem(same(scenarioUuid), any())).thenReturn(Maybe.just(new OperationCompletionRS())); if (!stepResponses.isEmpty()) { Maybe myFirst = stepResponses.get(0); Maybe[] myOther = stepResponses.subList(1, stepResponses.size()).toArray(new Maybe[0]); - when(client.startTestItem(same(testClassUuid), any())).thenReturn(myFirst, myOther); + when(client.startTestItem(same(scenarioUuid), any())).thenReturn(myFirst, myOther); new HashSet<>(test.getValue()).forEach(testMethodUuid -> when( client.finishTestItem(same(testMethodUuid), any() diff --git a/src/test/resources/feature/examples.feature b/src/test/resources/feature/examples.feature new file mode 100644 index 0000000..19617fc --- /dev/null +++ b/src/test/resources/feature/examples.feature @@ -0,0 +1,10 @@ +Feature: math tests with examples + + Scenario Outline: Verify different maths + Given def mathResult = vara + varb + Then assert mathResult == result + + Examples: + | vara! | varb! | result! | + | 2 | 2 | 4 | + | 1 | 2 | 3 |