diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java index 6254647..6c51607 100644 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java @@ -42,6 +42,7 @@ import java.util.Calendar; import java.util.Date; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; @@ -57,7 +58,7 @@ public class ReportPortalHook implements RuntimeHook { private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalHook.class); protected final MemoizingSupplier launch; - private final BlockingConcurrentHashMap> featureIdMap = new BlockingConcurrentHashMap<>(); + private final BlockingConcurrentHashMap>> featureIdMap = new BlockingConcurrentHashMap<>(); private final Map> scenarioIdMap = new ConcurrentHashMap<>(); private final Map> backgroundIdMap = new ConcurrentHashMap<>(); private final Map backgroundStatusMap = new ConcurrentHashMap<>(); @@ -162,7 +163,9 @@ protected StartTestItemRQ buildStartFeatureRq(@Nonnull FeatureRuntime fr) { @Override public boolean beforeFeature(FeatureRuntime fr) { - featureIdMap.computeIfAbsent(fr.featureCall.feature.getNameForReport(), f -> launch.get().startTestItem(buildStartFeatureRq(fr))); + featureIdMap.computeIfAbsent(fr.featureCall.feature.getNameForReport(), + f -> new MemoizingSupplier<>(() -> launch.get().startTestItem(buildStartFeatureRq(fr))) + ); return true; } @@ -179,13 +182,14 @@ protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureRuntime fr) { @Override public void afterFeature(FeatureRuntime fr) { - Maybe featureId = featureIdMap.remove(fr.featureCall.feature.getNameForReport()); - if (featureId == null) { + Optional> optionalId = ofNullable(featureIdMap.remove(fr.featureCall.feature.getNameForReport())).map(Supplier::get); + if (optionalId.isEmpty()) { LOGGER.error("ERROR: Trying to finish unspecified feature."); } - FinishTestItemRQ rq = buildFinishFeatureRq(fr); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(featureId, rq); + optionalId.ifPresent(featureId -> { + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(featureId, buildFinishFeatureRq(fr)); + }); } /** @@ -201,10 +205,15 @@ protected StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioRuntime sr) { @Override public boolean beforeScenario(ScenarioRuntime sr) { - Maybe featureId = featureIdMap.get(sr.featureRuntime.featureCall.feature.getNameForReport()); - StartTestItemRQ rq = buildStartScenarioRq(sr); - Maybe scenarioId = launch.get().startTestItem(featureId, rq); - scenarioIdMap.put(sr.scenario.getUniqueId(), scenarioId); + Optional> optionalId = ofNullable(featureIdMap.get(sr.featureRuntime.featureCall.feature.getNameForReport())).map(Supplier::get); + if (optionalId.isEmpty()) { + LOGGER.error("ERROR: Trying to post unspecified feature."); + } + optionalId.ifPresent(featureId -> { + StartTestItemRQ rq = buildStartScenarioRq(sr); + Maybe scenarioId = launch.get().startTestItem(featureId, rq); + scenarioIdMap.put(sr.scenario.getUniqueId(), scenarioId); + }); return true; } @@ -257,7 +266,6 @@ public Maybe startBackground(@Nonnull Step step, @Nonnull ScenarioRuntim @SuppressWarnings("unused") protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) { return buildFinishTestItemRq(Calendar.getInstance().getTime(), backgroundStatusMap.remove(sr.scenario.getUniqueId())); - } /** diff --git a/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java b/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java new file mode 100644 index 0000000..48e7b7d --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 2024 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 + * + * https://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.tags; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemStatus; +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.FinishTestItemRQ; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.Collections; +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.Mockito.*; + +public class SimpleTagInclusionTest { + private static final String[] TEST_FEATURES = new String[] { "classpath:feature/tags.feature", + "classpath:feature/http_request_tag.feature" }; + private final String launchUuid = CommonUtils.namedId("launch_"); + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, launchUuid, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_simple_all_passed(boolean report) { + List tagsToRun = Collections.singletonList("scope=smoke"); + Results results; + if (report) { + results = TestUtils.runAsReport(rp, tagsToRun, TEST_FEATURES); + } else { + results = TestUtils.runAsHook(rp, tagsToRun, TEST_FEATURES); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + ArgumentCaptor featureFinishCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(featureId), featureFinishCaptor.capture()); + ArgumentCaptor scenarioFinishCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(scenarioId), scenarioFinishCaptor.capture()); + List> stepFinishCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) + .limit(stepIds.size()) + .collect(Collectors.toList()); + IntStream.range(0, stepIds.size()) + .forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepFinishCaptors.get(i).capture())); + + FinishTestItemRQ featureRq = featureFinishCaptor.getValue(); + FinishTestItemRQ scenarioRq = scenarioFinishCaptor.getValue(); + + assertThat(featureRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(featureRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(featureRq.getEndTime(), notNullValue()); + + assertThat(scenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(scenarioRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(scenarioRq.getEndTime(), notNullValue()); + + stepFinishCaptors.forEach(stepFinishCaptor -> { + FinishTestItemRQ step = stepFinishCaptor.getValue(); + assertThat(step.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(step.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(step.getEndTime(), notNullValue()); + }); + } +} 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 520bacc..3e0e73f 100644 --- a/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java +++ b/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java @@ -65,12 +65,21 @@ public static ExecutorService testExecutor() { }); } + public static Results runAsReport(ReportPortal reportPortal, List tags, String... paths) { + return KarateReportPortalRunner.path(paths).withReportPortal(reportPortal).outputCucumberJson(false).tags(tags).parallel(1); + } + public static Results runAsReport(ReportPortal reportPortal, String... paths) { - return KarateReportPortalRunner.path(paths).withReportPortal(reportPortal).outputCucumberJson(false).parallel(1); + return runAsReport(reportPortal, Collections.emptyList(), paths); + } + + public static Results runAsHook(ReportPortal reportPortal, List tags, String... paths) { + Runner.Builder path = Runner.path(paths).hook(new ReportPortalHook(reportPortal)).outputCucumberJson(false); + return path.tags(tags).parallel(1); } public static Results runAsHook(ReportPortal reportPortal, String... paths) { - return Runner.path(paths).hook(new ReportPortalHook(reportPortal)).outputCucumberJson(false).parallel(1); + return runAsHook(reportPortal, Collections.emptyList(), paths); } public static ListenerParameters standardParameters() { diff --git a/src/test/resources/feature/http_request_tag.feature b/src/test/resources/feature/http_request_tag.feature new file mode 100644 index 0000000..d5c353f --- /dev/null +++ b/src/test/resources/feature/http_request_tag.feature @@ -0,0 +1,17 @@ +Feature: verify basic HTTP request + + @scope=regression + Scenario: Verify HTTP request + Given url 'https://example.com' + And header Content-Type = 'application/json' + And path 'api/test' + And request + """ + { + username: 'user', + password: 'password', + grant_type: 'password' + } + """ + When method post + Then status 404