diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0dbb13..204edf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,6 @@ jobs: build: uses: reportportal/.github/.github/workflows/agent-java-ci.yml@main with: - java-version: '17' + java-version: '21' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e7a14e..219908c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: release: uses: reportportal/.github/.github/workflows/agent-java-release.yml@main with: - java-version: '17' + java-version: '21' secrets: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index dc6a612..74cd032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,19 @@ # Changelog -### Changed -- Client version updated to [5.4.14](https://github.com/reportportal/client-java/releases/tag/5.4.14), by @HardNorth -- Karate dependency version updated to `1.5.2`, by @HardNorth -### Removed -- Java 11-16 support, by @HardNorth ## [Unreleased] +### Added +- Karate 2.x support, by @HardNorth +- Fancy HTTP logging, by @HardNorth +### Removed +- Java 17-20 support, by @HardNorth +- Karate 1.x support, by @HardNorth ## [5.4.0] ### Changed -- Client version updated to [5.4.13](https://github.com/reportportal/client-java/releases/tag/5.4.13), by @HardNorth +- Client version updated to [5.4.14](https://github.com/reportportal/client-java/releases/tag/5.4.14), by @HardNorth +- Karate dependency version updated to `1.5.2`, by @HardNorth +### Removed +- Java 11-16 support, by @HardNorth ## [5.3.7] ### Changed diff --git a/README.md b/README.md index ee9e06c..77edbbe 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ test results in this case, the test project should use by `ReportPortalHook` cla E.G.: ```java -import com.epam.reportportal.karate.ReportPortalHook; +import com.epam.reportportal.karate.ReportPortalResultListener; import com.intuit.karate.Results; import com.intuit.karate.Runner; import org.junit.jupiter.api.Assertions; diff --git a/README_TEMPLATE.md b/README_TEMPLATE.md index 13c4f66..e2840a3 100644 --- a/README_TEMPLATE.md +++ b/README_TEMPLATE.md @@ -1,4 +1,4 @@ -# ReportPortal runtime Hook for Karate tests +# ReportPortal Listeners for Karate tests Karate reporters which uploads the results to a ReportPortal server. @@ -98,29 +98,30 @@ dependencies { ### Runtime Runtime publisher uploads Karate tests on ReportPortal during the test execution, providing real-time monitoring capabilities. To publish -test results in this case, the test project should use by `ReportPortalHook` class, an instance of which you should pass to Karate runner. +test results in this case, the test project should use `ReportPortalRunListener` class, an instance of which you should pass to Karate +runner. E.G.: ```java -import com.epam.reportportal.karate.ReportPortalHook; -import com.intuit.karate.Results; -import com.intuit.karate.Runner; +import com.epam.reportportal.karate.ReportPortalRunListener; +import io.karatelabs.core.Runner; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class ScenarioRunnerTest { @Test void testParallel() { - ReportPortalHook karateRuntimeHook = new ReportPortalHook(); // Initialize ReportPortal runtime Karate hook - Results results = Runner // Regular Karate runner + ReportPortalRunListener karateRuntimeListener = new ReportPortalRunListener(); // Initialize ReportPortal runtime Karate listener + SuiteResult results = Runner // Regular Karate runner .path("classpath:features") // Path with feature files - .hook(karateRuntimeHook) // Add Karate hook + .listener(karateRuntimeListener) // Add Karate run listener .outputCucumberJson(true) // Generate cucumber report .tags("~@ignore") // Ignore tests marked with the tag .parallel(2); // Run in 2 Threads // Here you can additionally run tests, retries, etc. - karateRuntimeHook.finishLaunch(); // Finish execution on ReportPortal - Assertions.assertEquals(0, results.getFailCount(), "Non-zero fail count.\n Errors:\n" + results.getErrorMessages()); + karateRuntimeListener.finishLaunch(); // Finish execution on ReportPortal + Assertions.assertEquals(0, results.getFeatureFailedCount(), "Non-zero fail count.\n Errors:\n" + results.getErrors()); } } ``` @@ -129,12 +130,13 @@ class ScenarioRunnerTest { Post-running publisher uploads Karate tests on ReportPortal after the test execution. It uses Karate result object to get data about tests. It might be useful if your tests make heavy load both on ReportPortal server or on the running node. To publish test results in this case, -the test project should run by `KarateReportPortalRunner` instead of Karate runner. +the test project should add `ReportPortalResultListener` to Karate runner. E.G.: ```java -import com.epam.reportportal.karate.KarateReportPortalRunner; -import com.intuit.karate.Results; +import com.epam.reportportal.karate.ReportPortalResultListener; +import io.karatelabs.core.Runner; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -142,12 +144,15 @@ public class KarateRunnerTest { @Test public void testAll() { - Results results = KarateReportPortalRunner // Our runner with a Karate Publisher + ReportPortalResultListener resultListener = new ReportPortalResultListener(); // Initialize ReportPortal result listener + SuiteResult results = Runner // Regular Karate runner with ReportPortal result listener .path("classpath:features") // Path with feature files + .resultListener(resultListener) // Add Karate result listener .outputCucumberJson(true) // Generate cucumber report .tags("~@ignore") // Ignore tests marked with the tag .parallel(2); // Run in 2 Threads - Assertions.assertEquals(0, results.getFailCount(), "Non-zero fail count.\n Errors:\n" + results.getErrorMessages()); + resultListener.finishLaunch(); // Finish execution on ReportPortal + Assertions.assertEquals(0, results.getFeatureFailedCount(), "Non-zero fail count.\n Errors:\n" + results.getErrors()); } } ``` diff --git a/build.gradle b/build.gradle index 614fca9..e26b754 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,8 @@ project.ext.limits = [ 'class' : 83 ] -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' @@ -42,6 +42,7 @@ repositories { dependencies { api "com.epam.reportportal:client-java:${client_version}" + api 'com.epam.reportportal:utils-java-formatting:5.4.0' compileOnly "io.karatelabs:karate-core:${karate_version}" implementation "org.slf4j:slf4j-api:${slf4j_api_version}" implementation "org.apache.commons:commons-lang3:3.19.0" diff --git a/gradle.properties b/gradle.properties index 12c6018..a198ead 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ name=agent-java-karate -version=5.4.1-SNAPSHOT -description=EPAM ReportPortal. Karate test framework [1.3.1, 1.5.2] adapter +version=5.5.0-SNAPSHOT +description=EPAM ReportPortal. Karate test framework [2.0.0, ) adapter gradle_version=8.2 -karate_version=1.5.2 +karate_version=2.0.4 junit_version=5.10.1 mockito_version=5.4.0 test_utils_version=0.1.0 diff --git a/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java b/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java deleted file mode 100644 index 3a6f7a3..0000000 --- a/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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; - -import com.epam.reportportal.service.ReportPortal; -import com.intuit.karate.Results; -import com.intuit.karate.Runner; - -/** - * Karate runner with ReportPortal integration - */ -public class KarateReportPortalRunner { - - /** - * Create a new builder for the Karate runner with ReportPortal integration - * - * @param paths paths to feature files - * @param type of the builder - * @return a new builder - */ - public static > Builder path(String... paths) { - Builder builder = new Builder<>(); - return builder.path(paths); - } - - /** - * Builder for the Karate runner with ReportPortal integration - * - * @param type of the builder - */ - public static class Builder> extends Runner.Builder { - private ReportPortal rp; - - /** - * Create a new builder - */ - public Builder() { - super(); - } - - /** - * Set the ReportPortal instance to use - * - * @param reportPortal the ReportPortal instance - * @return the builder - */ - public Builder withReportPortal(ReportPortal reportPortal) { - rp = reportPortal; - return this; - } - - /** - * Run the tests in parallel - * - * @param threadCount number of threads to use - * @return the results of the tests - */ - @Override - public Results parallel(int threadCount) { - if (rp == null) { - rp = ReportPortal.builder().build(); - } - ReportPortalPublisher reporter = new ReportPortalPublisher(rp); - reporter.startLaunch(); - Results results = super.parallel(threadCount); - results.getFeatureResults().forEach(f -> { - reporter.startFeature(f); - reporter.finishFeature(f); - }); - reporter.finishLaunch(); - return results; - } - } -} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java deleted file mode 100644 index a269a45..0000000 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java +++ /dev/null @@ -1,518 +0,0 @@ -/* - * 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; - -import com.epam.reportportal.karate.utils.BlockingConcurrentHashMap; -import com.epam.reportportal.listeners.ItemStatus; -import com.epam.reportportal.listeners.ItemType; -import com.epam.reportportal.listeners.ListenerParameters; -import com.epam.reportportal.listeners.LogLevel; -import com.epam.reportportal.service.Launch; -import com.epam.reportportal.service.ReportPortal; -import com.epam.reportportal.utils.MemoizingSupplier; -import com.epam.reportportal.utils.StatusEvaluation; -import com.epam.reportportal.utils.formatting.MarkdownUtils; -import com.epam.reportportal.utils.reflect.Accessible; -import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; -import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.RuntimeHook; -import com.intuit.karate.Suite; -import com.intuit.karate.core.*; -import com.intuit.karate.http.HttpRequest; -import com.intuit.karate.http.Response; -import io.reactivex.Maybe; -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.Instant; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -import static com.epam.reportportal.karate.ReportPortalUtils.*; -import static com.epam.reportportal.utils.ParameterUtils.formatParametersAsTable; -import static com.epam.reportportal.utils.formatting.MarkdownUtils.formatDataTable; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -/** - * ReportPortal test results reporting hook for Karate. This class publish results in the process of test pass. - */ -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 Map> scenarioIdMap = new ConcurrentHashMap<>(); - private final Map> backgroundIdMap = new ConcurrentHashMap<>(); - private final Map backgroundStatusMap = new ConcurrentHashMap<>(); - private final Map> stepIdMap = new ConcurrentHashMap<>(); - private final Map stepStartTimeMap = new ConcurrentHashMap<>(); - private final Set> innerFeatures = Collections.newSetFromMap(new ConcurrentHashMap<>()); - private volatile Thread shutDownHook; - - /** - * Create a new instance of the ReportPortalHook with the specified ReportPortal instance. - * - * @param reportPortal the ReportPortal instance - */ - public ReportPortalHook(ReportPortal reportPortal) { - ListenerParameters params = reportPortal.getParameters(); - StartLaunchRQ rq = buildStartLaunchRq(params); - launch = new MemoizingSupplier<>(() -> { - Launch newLaunch = reportPortal.newLaunch(rq); - //noinspection ReactiveStreamsUnusedPublisher - newLaunch.start(); - shutDownHook = registerShutdownHook(this::finishLaunch); - return newLaunch; - }); - } - - /** - * Default constructor. Create a new instance of the ReportPortalHook with default ReportPortal instance. - */ - @SuppressWarnings("unused") - public ReportPortalHook() { - this(ReportPortal.builder().build()); - } - - @SuppressWarnings("unused") - public ReportPortalHook(Supplier launchSupplier) { - launch = new MemoizingSupplier<>(launchSupplier); - } - - /** - * Customize start launch event/request - * - * @param parameters Launch configuration parameters - * @return request to ReportPortal - */ - protected StartLaunchRQ buildStartLaunchRq(ListenerParameters parameters) { - return ReportPortalUtils.buildStartLaunchRq(parameters); - } - - /** - * Customize start Launch finish event/request. - * - * @param parameters Launch configuration parameters - * @return request to ReportPortal - */ - @Nonnull - protected FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) { - return ReportPortalUtils.buildFinishLaunchRq(parameters); - } - - /** - * Finish sending Launch data to ReportPortal. - */ - public void finishLaunch() { - ReportPortalUtils.doFinishLaunch(launch.get(), buildFinishLaunchRq(launch.get().getParameters()), shutDownHook); - } - - /** - * Build ReportPortal request for start Feature event. - * - * @param fr Karate's FeatureRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unchecked") - protected StartTestItemRQ buildStartFeatureRq(@Nonnull FeatureRuntime fr) { - StartTestItemRQ rq = ReportPortalUtils.buildStartFeatureRq(fr.featureCall.feature); - ofNullable(fr.caller).map(c -> c.arg) - .map(a -> (Map) a.getValue()) - .filter(args -> !args.isEmpty()) - .ifPresent(args -> { - // TODO: cover with tests - String parameters = String.format(PARAMETERS_PATTERN, formatParametersAsTable(getParameters(args))); - String description = rq.getDescription(); - if (isNotBlank(description)) { - rq.setDescription(MarkdownUtils.asTwoParts(parameters, description)); - } else { - rq.setDescription(parameters); - } - }); - return rq; - } - - private String getFeatureNameForReport(FeatureRuntime fr) { - int callDepth = ofNullable(fr.caller).map(c -> c.depth).orElse(0); - return callDepth + ":" + fr.featureCall.feature.getNameForReport(); - } - - @Override - public boolean beforeFeature(FeatureRuntime fr) { - StartTestItemRQ rq = buildStartFeatureRq(fr); - featureIdMap.computeIfAbsent( - getFeatureNameForReport(fr), f -> new MemoizingSupplier<>(() -> { - if (ofNullable(fr.caller).map(c -> c.depth).orElse(0) == 0) { - return launch.get().startTestItem(rq); - } else { - Maybe scenarioId = scenarioIdMap.get(fr.caller.parentRuntime.scenario.getUniqueId()); - if (scenarioId == null) { - LOGGER.error("ERROR: Trying to post unspecified scenario."); - return launch.get().startTestItem(rq); - } - rq.setType(ItemType.STEP.name()); - rq.setHasStats(false); - rq.setName(getInnerFeatureName(rq.getName())); - Maybe itemId = launch.get().startTestItem(scenarioId, rq); - innerFeatures.add(itemId); - if (StringUtils.isNotBlank(rq.getDescription())) { - ReportPortalUtils.sendLog(itemId, rq.getDescription(), LogLevel.INFO, (Instant) rq.getStartTime()); - } - return itemId; - } - }) - ); - return true; - } - - /** - * Build ReportPortal request for finish Feature event. - * - * @param fr Karate's FeatureRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureRuntime fr) { - return buildFinishTestItemRq(Instant.now(), fr.result.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED); - } - - @Override - public void afterFeature(FeatureRuntime fr) { - Optional> optionalId = ofNullable(featureIdMap.get(getFeatureNameForReport(fr))).map(Supplier::get); - if (optionalId.isEmpty()) { - LOGGER.error("ERROR: Trying to finish unspecified feature."); - } - optionalId.ifPresent(featureId -> { - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(featureId, buildFinishFeatureRq(fr)); - innerFeatures.remove(featureId); - }); - } - - /** - * Build ReportPortal request for start Scenario event. - * - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - protected StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioRuntime sr) { - StartTestItemRQ rq = ReportPortalUtils.buildStartScenarioRq(sr.result); - ofNullable(featureIdMap.get(getFeatureNameForReport(sr.featureRuntime))).map(Supplier::get) - .map(featureId -> innerFeatures.contains(featureId) ? featureId : null) - .ifPresent(featureId -> { - rq.setType(ItemType.STEP.name()); - rq.setHasStats(false); - rq.setName(getInnerScenarioName(rq.getName())); - }); - return rq; - } - - @Override - public boolean beforeScenario(ScenarioRuntime sr) { - StartTestItemRQ rq = buildStartScenarioRq(sr); - Optional> optionalId = ofNullable(featureIdMap.get(getFeatureNameForReport(sr.featureRuntime))).map(Supplier::get); - if (optionalId.isEmpty()) { - LOGGER.error("ERROR: Trying to post unspecified feature."); - } - ofNullable(scenarioIdMap.get(sr.scenario.getUniqueId())).map(Maybe::blockingGet).ifPresent(id -> { - rq.setRetry(true); - rq.setRetryOf(id); - }); - optionalId.ifPresent(featureId -> { - Maybe scenarioId = launch.get().startTestItem(featureId, rq); - if (innerFeatures.contains(featureId) && StringUtils.isNotBlank(rq.getDescription())) { - ReportPortalUtils.sendLog(scenarioId, rq.getDescription(), LogLevel.INFO); - } - scenarioIdMap.put(sr.scenario.getUniqueId(), scenarioId); - }); - return true; - } - - /** - * Build ReportPortal request for finish Scenario event. - * - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - protected FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioRuntime sr) { - return ReportPortalUtils.buildFinishScenarioRq(sr.result); - } - - /** - * Build ReportPortal request for start Background event. - * - * @param step Karate's Step object instance - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected StartTestItemRQ buildStartBackgroundRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { - return ReportPortalUtils.buildStartBackgroundRq(step, sr.scenario); - } - - /** - * Start sending Background data to ReportPortal. - * - * @param step Karate's Step object instance - * @param sr Karate's ScenarioRuntime object instance - * @return item ID Future - */ - public Maybe startBackground(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { - return backgroundIdMap.computeIfAbsent( - sr.scenario.getUniqueId(), k -> { - StartTestItemRQ backgroundRq = buildStartBackgroundRq(step, sr); - return launch.get().startTestItem(scenarioIdMap.get(sr.scenario.getUniqueId()), backgroundRq); - } - ); - } - - /** - * Build ReportPortal request for finish Background event. - * - * @param stepResult Karate's StepResult class instance - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) { - return buildFinishTestItemRq(Instant.now(), backgroundStatusMap.remove(sr.scenario.getUniqueId())); - } - - /** - * Finish sending Scenario data to ReportPortal. - * - * @param stepResult Karate's StepResult class instance - * @param sr Karate's ScenarioRuntime object instance - */ - public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) { - String uniqueId = sr.scenario.getUniqueId(); - Maybe backgroundId = backgroundIdMap.remove(uniqueId); - if (backgroundId != null) { - FinishTestItemRQ finishRq = buildFinishBackgroundRq(stepResult, sr); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(backgroundId, finishRq); - } - } - - /** - * Embed an attachment to ReportPortal. - * - * @param itemId item ID future - * @param embed Karate's Embed object - */ - protected void embedAttachment(@Nonnull Maybe itemId, @Nonnull Embed embed) { - ReportPortalUtils.embedAttachment(itemId, embed); - } - - /** - * Embed an attachment to ReportPortal. - * - * @param itemId item ID future - * @param embeddedEntities a list of Karate's Embed object - */ - protected void embedAttachments(@Nonnull Maybe itemId, @Nullable List embeddedEntities) { - ofNullable(embeddedEntities).ifPresent(embeds -> embeds.forEach(embed -> embedAttachment(itemId, embed))); - } - - @Override - public void afterScenario(ScenarioRuntime sr) { - Maybe scenarioId = scenarioIdMap.get(sr.scenario.getUniqueId()); - stepStartTimeMap.remove(sr.scenario.getUniqueId()); - finishBackground(null, sr); - - if (scenarioId == null) { - LOGGER.error("ERROR: Trying to finish unspecified scenario."); - return; - } - - try { - @SuppressWarnings("unchecked") - List embeddedEntities = (List) new Accessible(sr).field("embeds").getValue(); - embedAttachments(scenarioId, embeddedEntities); - } catch (Exception e) { - LOGGER.warn( - "Unable to retrieve scenario embeddings; attachments (such as screenshots or logs) will not be reported for this" // - + " scenario. Test execution and reporting will continue. Exception details:", e - ); - } - - FinishTestItemRQ rq = buildFinishScenarioRq(sr); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(scenarioId, rq); - } - - /** - * Get step start time. To keep the steps order in case previous step startTime == current step startTime or - * previous step startTime > current step startTime. - * - * @param scenarioUniqueId Karate's Scenario Unique ID - * @return step new startTime in Instant format. - */ - @Nonnull - private Instant getStepStartTime(@Nullable String scenarioUniqueId) { - return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, launch.get().useMicroseconds()); - } - - /** - * Customize start Step test item event/request. - * - * @param step Karate's Step object instance - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - protected StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { - StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(step, sr.scenario); - Instant startTime = getStepStartTime(sr.scenario.getUniqueId()); - rq.setStartTime(startTime); - return rq; - } - - /** - * Send Step logs to ReportPortal. - * - * @param itemId item ID future - * @param message log message to send - * @param level log level - */ - protected void sendLog(Maybe itemId, String message, LogLevel level) { - ReportPortalUtils.sendLog(itemId, message, level); - } - - @Override - public boolean beforeStep(Step step, ScenarioRuntime sr) { - boolean background = step.isBackground(); - Maybe backgroundId = null; - if (background) { - backgroundId = startBackground(step, sr); - } - StartTestItemRQ stepRq = buildStartStepRq(step, sr); - - String scenarioId = sr.scenario.getUniqueId(); - Maybe stepId = launch.get().startTestItem(background ? backgroundId : scenarioIdMap.get(scenarioId), stepRq); - stepIdMap.put(scenarioId, stepId); - ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty()) - .ifPresent(params -> sendLog(stepId, String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), LogLevel.INFO)); - ofNullable(step.getTable()).ifPresent(table -> sendLog(stepId, "Table:\n\n" + formatDataTable(table.getRows()), LogLevel.INFO)); - String docString = step.getDocString(); - if (isNotBlank(docString)) { - sendLog(stepId, "Docstring:\n\n" + asMarkdownCode(step.getDocString()), LogLevel.INFO); - } - return true; - } - - /** - * Send Step execution results to ReportPortal. - * - * @param stepResult step execution results - * @param sr Karate's ScenarioRuntime object instance - */ - public void sendStepResults(StepResult stepResult, ScenarioRuntime sr) { - Maybe stepId = stepIdMap.get(sr.scenario.getUniqueId()); - Step step = stepResult.getStep(); - Result result = stepResult.getResult(); - - ofNullable(stepResult.getEmbeds()).ifPresent(embeds -> embeds.forEach(embed -> embedAttachment(stepId, embed))); - - if (result.isFailed()) { - String fullErrorMessage = step.getPrefix() + " " + step.getText(); - String errorMessage = result.getErrorMessage(); - if (isNotBlank(errorMessage)) { - fullErrorMessage = fullErrorMessage + "\n" + errorMessage; - } - sendLog(stepId, fullErrorMessage, LogLevel.ERROR); - } - } - - /** - * Build ReportPortal request for finish Step event. - * - * @param stepResult Karate's StepResult class instance - * @param sr Karate's ScenarioRuntime object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) { - return buildFinishTestItemRq(Instant.now(), getStepStatus(stepResult.getResult().getStatus())); - } - - private void saveBackgroundStatus(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) { - backgroundStatusMap.put( - sr.scenario.getUniqueId(), - StatusEvaluation.evaluateStatus( - backgroundStatusMap.get(sr.scenario.getUniqueId()), - getStepStatus(stepResult.getResult().getStatus()) - ) - ); - } - - @Override - public void afterStep(StepResult stepResult, ScenarioRuntime sr) { - boolean background = stepResult.getStep().isBackground(); - if (!background) { - finishBackground(stepResult, sr); - } - - sendStepResults(stepResult, sr); - Maybe stepId = stepIdMap.remove(sr.scenario.getUniqueId()); - if (stepId == null) { - LOGGER.error("ERROR: Trying to finish unspecified step."); - return; - } - - FinishTestItemRQ rq = buildFinishStepRq(stepResult, sr); - if (background) { - saveBackgroundStatus(stepResult, sr); - } - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(stepId, rq); - } - - @Override - public void beforeHttpCall(HttpRequest request, ScenarioRuntime sr) { - // TODO: Implement better HTTP request logging later - RuntimeHook.super.beforeHttpCall(request, sr); - } - - @Override - public void afterHttpCall(HttpRequest request, Response response, ScenarioRuntime sr) { - // TODO: Implement better HTTP response logging later - RuntimeHook.super.afterHttpCall(request, response, sr); - } - - @Override - public void beforeSuite(Suite suite) { - // Omit Suite logic, since there is no Suite names in Karate - } - - @Override - public void afterSuite(Suite suite) { - // Omit Suite logic, since there is no Suite names in Karate - } -} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java b/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java deleted file mode 100644 index a623e43..0000000 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * 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; - -import com.epam.reportportal.listeners.ItemStatus; -import com.epam.reportportal.listeners.ListenerParameters; -import com.epam.reportportal.listeners.LogLevel; -import com.epam.reportportal.service.Launch; -import com.epam.reportportal.service.ReportPortal; -import com.epam.reportportal.utils.MemoizingSupplier; -import com.epam.reportportal.utils.StatusEvaluation; -import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; -import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.core.*; -import io.reactivex.Maybe; -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.Instant; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -import static com.epam.reportportal.karate.ReportPortalUtils.*; -import static com.epam.reportportal.utils.ParameterUtils.formatParametersAsTable; -import static com.epam.reportportal.utils.formatting.MarkdownUtils.formatDataTable; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -/** - * ReportPortal test results publisher for Karate. This class publish results after test pass. - */ -public class ReportPortalPublisher { - private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalPublisher.class); - protected final MemoizingSupplier launch; - private final Map> featureIdMap = new HashMap<>(); - private final Map> scenarioIdMap = new HashMap<>(); - private final Map stepStartTimeMap = new HashMap<>(); - private Maybe backgroundId; - private ItemStatus backgroundStatus; - private Maybe stepId; - private Thread shutDownHook; - - public ReportPortalPublisher(ReportPortal reportPortal) { - launch = new MemoizingSupplier<>(() -> { - ListenerParameters params = reportPortal.getParameters(); - StartLaunchRQ rq = buildStartLaunchRq(params); - Launch newLaunch = reportPortal.newLaunch(rq); - shutDownHook = registerShutdownHook(this::finishLaunch); - return newLaunch; - }); - } - - public ReportPortalPublisher(Supplier launchSupplier) { - launch = new MemoizingSupplier<>(launchSupplier); - } - - /** - * Customize start launch event/request - * - * @param parameters Launch configuration parameters - * @return request to ReportPortal - */ - protected StartLaunchRQ buildStartLaunchRq(ListenerParameters parameters) { - return ReportPortalUtils.buildStartLaunchRq(parameters); - } - - /** - * Start sending Launch data to ReportPortal. - */ - public void startLaunch() { - //noinspection ReactiveStreamsUnusedPublisher - launch.get().start(); - } - - /** - * Customize start Launch finish event/request. - * - * @param parameters Launch configuration parameters - * @return request to ReportPortal - */ - @Nonnull - protected FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) { - return ReportPortalUtils.buildFinishLaunchRq(parameters); - } - - /** - * Finish sending Launch data to ReportPortal. - */ - public void finishLaunch() { - ReportPortalUtils.doFinishLaunch(launch.get(), buildFinishLaunchRq(launch.get().getParameters()), shutDownHook); - } - - /** - * Build ReportPortal request for start Feature event. - * - * @param featureResult Karate's FeatureResult object instance - * @return request to ReportPortal - */ - @Nonnull - protected StartTestItemRQ buildStartFeatureRq(@Nonnull FeatureResult featureResult) { - return ReportPortalUtils.buildStartFeatureRq(featureResult.getFeature()); - } - - /** - * Start sending Feature data to ReportPortal. - * - * @param featureResult feature result - */ - public void startFeature(@Nonnull FeatureResult featureResult) { - StartTestItemRQ rq = buildStartFeatureRq(featureResult); - Maybe featureId = launch.get().startTestItem(rq); - featureIdMap.put(featureResult.getCallNameForReport(), featureId); - } - - /** - * Build ReportPortal request for finish Feature event. - * - * @param featureResult Karate's FeatureResult object instance - * @return request to ReportPortal - */ - @Nonnull - protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureResult featureResult) { - return buildFinishTestItemRq(Instant.now(), featureResult.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED); - } - - /** - * Finish sending Feature data to ReportPortal. - * - * @param featureResult feature result - */ - public void finishFeature(FeatureResult featureResult) { - if (!featureIdMap.containsKey(featureResult.getCallNameForReport())) { - LOGGER.error("ERROR: Trying to finish unspecified feature."); - } - - for (ScenarioResult scenarioResult : featureResult.getScenarioResults()) { - startScenario(scenarioResult, featureResult); - List stepResults = scenarioResult.getStepResults(); - - for (StepResult stepResult : stepResults) { - startStep(stepResult, scenarioResult); - sendStepResults(stepResult); - finishStep(stepResult, scenarioResult); - } - - finishScenario(scenarioResult); - } - - FinishTestItemRQ rq = buildFinishFeatureRq(featureResult); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(featureIdMap.remove(featureResult.getCallNameForReport()), rq); - } - - /** - * Build ReportPortal request for start Scenario event. - * - * @param scenarioResult Karate's ScenarioResult object instance - * @return request to ReportPortal - */ - @Nonnull - protected StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioResult scenarioResult) { - return ReportPortalUtils.buildStartScenarioRq(scenarioResult); - } - - /** - * Start sending Scenario data to ReportPortal. - * - * @param scenarioResult scenario result - * @param featureResult feature result - */ - public void startScenario(ScenarioResult scenarioResult, FeatureResult featureResult) { - StartTestItemRQ rq = buildStartScenarioRq(scenarioResult); - - Maybe scenarioId = launch.get().startTestItem(featureIdMap.get(featureResult.getCallNameForReport()), rq); - scenarioIdMap.put(scenarioResult.getScenario().getName(), scenarioId); - } - - /** - * Build ReportPortal request for finish Scenario event. - * - * @param scenarioResult Karate's ScenarioResult object instance - * @return request to ReportPortal - */ - @Nonnull - protected FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioResult scenarioResult) { - return ReportPortalUtils.buildFinishScenarioRq(scenarioResult); - } - - /** - * Finish sending Scenario data to ReportPortal. - * - * @param scenarioResult scenario result - */ - public void finishScenario(ScenarioResult scenarioResult) { - if (!scenarioIdMap.containsKey(scenarioResult.getScenario().getName())) { - LOGGER.error("ERROR: Trying to finish unspecified scenario."); - } - - FinishTestItemRQ rq = buildFinishScenarioRq(scenarioResult); - Maybe removedScenarioId = scenarioIdMap.remove(scenarioResult.getScenario().getName()); - stepStartTimeMap.remove(scenarioResult.getScenario().getUniqueId()); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(removedScenarioId, rq); - finishBackground(null, scenarioResult); - } - - /** - * Build ReportPortal request for start Background event. - * - * @param stepResult Karate's StepResult object instance - * @param scenarioResult Karate's ScenarioResult object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected StartTestItemRQ buildStartBackgroundRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - return ReportPortalUtils.buildStartBackgroundRq(stepResult.getStep(), scenarioResult.getScenario()); - } - - /** - * Start sending Background data to ReportPortal. - * - * @param stepResult Karate's StepResult object instance - * @param scenarioResult Karate's ScenarioResult object instance - */ - public void startBackground(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - backgroundId = ofNullable(backgroundId).orElseGet(() -> { - StartTestItemRQ backgroundRq = buildStartBackgroundRq(stepResult, scenarioResult); - return launch.get().startTestItem(scenarioIdMap.get(scenarioResult.getScenario().getName()), backgroundRq); - }); - } - - /** - * Build ReportPortal request for finish Background event. - * - * @param stepResult Karate's StepResult object instance - * @param scenarioResult Karate's ScenarioResult object instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - return buildFinishTestItemRq(Instant.now(), backgroundStatus); - - } - - /** - * Finish sending Scenario data to ReportPortal. - * - * @param stepResult step result - * @param scenarioResult scenario result - */ - public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - Maybe myBackgroundId = backgroundId; - backgroundId = null; - ofNullable(myBackgroundId).ifPresent(id -> { - FinishTestItemRQ finishRq = buildFinishBackgroundRq(stepResult, scenarioResult); - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(id, finishRq); - }); - } - - /** - * Get step start time. To keep the steps order in case previous step startTime == current step startTime or - * previous step startTime > current step startTime. - * - * @param scenarioUniqueId Karate's Scenario Unique ID - * @return step new startTime in Instant format. - */ - @Nonnull - private Instant getStepStartTime(@Nullable String scenarioUniqueId) { - return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, launch.get().useMicroseconds()); - } - - /** - * Customize start Step test item event/request. - * - * @param stepResult Karate's StepResult class instance - * @param scenarioResult Karate's ScenarioResult class instance - * @return request to ReportPortal - */ - @Nonnull - protected StartTestItemRQ buildStartStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(stepResult.getStep(), scenarioResult.getScenario()); - Instant startTime = getStepStartTime(scenarioResult.getScenario().getUniqueId()); - rq.setStartTime(startTime); - return rq; - } - - /** - * Start sending Step data to ReportPortal. - * - * @param stepResult step result - * @param scenarioResult scenario result - */ - public void startStep(StepResult stepResult, ScenarioResult scenarioResult) { - Step step = stepResult.getStep(); - boolean background = step.isBackground(); - if (background) { - startBackground(stepResult, scenarioResult); - } - - StartTestItemRQ stepRq = buildStartStepRq(stepResult, scenarioResult); - stepId = launch.get() - .startTestItem( - background && backgroundId != null ? backgroundId : scenarioIdMap.get(scenarioResult.getScenario().getName()), - stepRq - ); - ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty()) - .ifPresent(params -> sendLog(stepId, String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), LogLevel.INFO)); - ofNullable(step.getTable()).ifPresent(table -> sendLog(stepId, "Table:\n\n" + formatDataTable(table.getRows()), LogLevel.INFO)); - String docString = step.getDocString(); - if (isNotBlank(docString)) { - sendLog(stepId, "Docstring:\n\n" + asMarkdownCode(step.getDocString()), LogLevel.INFO); - } - } - - /** - * Build ReportPortal request for finish Step event. - * - * @param stepResult Karate's StepResult class instance - * @param scenarioResult Karate's ScenarioResult class instance - * @return request to ReportPortal - */ - @Nonnull - @SuppressWarnings("unused") - protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - return buildFinishTestItemRq(Instant.now(), getStepStatus(stepResult.getResult().getStatus())); - } - - @SuppressWarnings("unused") - private void saveBackgroundStatus(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { - backgroundStatus = StatusEvaluation.evaluateStatus(backgroundStatus, getStepStatus(stepResult.getResult().getStatus())); - } - - /** - * Finish sending Step data to ReportPortal. - * - * @param stepResult Karate's StepResult class instance - * @param scenarioResult Karate's ScenarioResult class instance - */ - public void finishStep(StepResult stepResult, ScenarioResult scenarioResult) { - Step step = stepResult.getStep(); - boolean background = step.isBackground(); - if (!background) { - finishBackground(stepResult, scenarioResult); - } - - if (stepId == null) { - LOGGER.error("ERROR: Trying to finish unspecified step."); - return; - } - - FinishTestItemRQ rq = buildFinishStepRq(stepResult, scenarioResult); - if (background) { - saveBackgroundStatus(stepResult, scenarioResult); - } - //noinspection ReactiveStreamsUnusedPublisher - launch.get().finishTestItem(stepId, rq); - } - - /** - * Send Step logs to ReportPortal. - * - * @param itemId item ID future - * @param message log message to send - * @param level log level - */ - protected void sendLog(Maybe itemId, String message, LogLevel level) { - ReportPortalUtils.sendLog(itemId, message, level); - } - - /** - * Embed an attachment to ReportPortal. - * - * @param itemId item ID future - * @param embed Karate's Embed object - */ - protected void embedAttachment(Maybe itemId, Embed embed) { - ReportPortalUtils.embedAttachment(itemId, embed); - } - - /** - * Embed an attachment to ReportPortal. - * - * @param itemId item ID future - * @param embeddedEntities a list of Karate's Embed object - */ - protected void embedAttachments(@Nonnull Maybe itemId, @Nullable List embeddedEntities) { - ofNullable(embeddedEntities).ifPresent(embeds -> embeds.forEach(embed -> embedAttachment(itemId, embed))); - } - - /** - * Send Step execution results to ReportPortal. - * - * @param stepResult step execution results - */ - public void sendStepResults(StepResult stepResult) { - Step step = stepResult.getStep(); - Result result = stepResult.getResult(); - String stepLog = stepResult.getStepLog(); - if (isNotBlank(stepLog)) { - sendLog(stepId, stepLog, LogLevel.DEBUG); - } - - embedAttachments(stepId, stepResult.getEmbeds()); - - if (result.isFailed()) { - String fullErrorMessage = step.getPrefix() + " " + step.getText(); - String errorMessage = result.getErrorMessage(); - if (isNotBlank(errorMessage)) { - fullErrorMessage = fullErrorMessage + "\n" + errorMessage; - - } - sendLog(stepId, fullErrorMessage, LogLevel.ERROR); - } - } -} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalResultListener.java b/src/main/java/com/epam/reportportal/karate/ReportPortalResultListener.java new file mode 100644 index 0000000..0ff7b79 --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalResultListener.java @@ -0,0 +1,571 @@ +/* + * Copyright 2026 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; + +import com.epam.reportportal.karate.utils.BlockingConcurrentHashMap; +import com.epam.reportportal.listeners.ItemStatus; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.listeners.ListenerParameters; +import com.epam.reportportal.listeners.LogLevel; +import com.epam.reportportal.service.Launch; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.utils.MemoizingSupplier; +import com.epam.reportportal.utils.StatusEvaluation; +import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; +import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import io.karatelabs.core.*; +import io.karatelabs.gherkin.Feature; +import io.karatelabs.gherkin.Scenario; +import io.karatelabs.gherkin.Step; +import io.karatelabs.output.ResultListener; +import io.reactivex.Maybe; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import static com.epam.reportportal.karate.ReportPortalUtils.*; +import static com.epam.reportportal.utils.ParameterUtils.formatParametersAsTable; +import static com.epam.reportportal.utils.formatting.MarkdownUtils.formatDataTable; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * ReportPortal result listener for Karate that reports completed execution output. + */ +public class ReportPortalResultListener implements ResultListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalResultListener.class); + /** + * Lazily initialized ReportPortal launch facade used for all item operations. + */ + protected final MemoizingSupplier launch; + private final BlockingConcurrentHashMap>> featureIdMap = new BlockingConcurrentHashMap<>(); + private final Map> scenarioIdMap = new ConcurrentHashMap<>(); + private final Map stepStartTimeMap = new HashMap<>(); + private final Map> backgroundIdMap = new ConcurrentHashMap<>(); + private final Map backgroundStatusMap = new ConcurrentHashMap<>(); + private final Map> stepIdMap = new ConcurrentHashMap<>(); + private final Set> innerFeatures = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final ThreadLocal> parentScenarios = ThreadLocal.withInitial(LinkedList::new); + private volatile Thread shutDownHook; + + /** + * Creates a listener instance backed by the provided ReportPortal client. + * + * @param reportPortal ReportPortal client instance + */ + public ReportPortalResultListener(ReportPortal reportPortal) { + ListenerParameters params = reportPortal.getParameters(); + StartLaunchRQ rq = buildStartLaunchRq(params); + launch = new MemoizingSupplier<>(() -> { + Launch newLaunch = reportPortal.newLaunch(rq); + //noinspection ReactiveStreamsUnusedPublisher + newLaunch.start(); + shutDownHook = registerShutdownHook(this::finishLaunch); + return newLaunch; + }); + } + + /** + * Creates a listener with a default ReportPortal client configuration. + */ + @SuppressWarnings("unused") + public ReportPortalResultListener() { + this(ReportPortal.builder().build()); + } + + /** + * Creates a listener with a preconfigured launch supplier. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + */ + @SuppressWarnings("unused") + public ReportPortalResultListener(Supplier launchSupplier) { + launch = new MemoizingSupplier<>(launchSupplier); + } + + /** + * Customize start launch event/request + * + * @param parameters Launch configuration parameters + * @return request to ReportPortal + */ + protected StartLaunchRQ buildStartLaunchRq(ListenerParameters parameters) { + return ReportPortalUtils.buildStartLaunchRq(parameters); + } + + /** + * Customizes the launch finish request. + * + * @param parameters launch configuration parameters + * @return request to ReportPortal + */ + @Nonnull + protected FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) { + return ReportPortalUtils.buildFinishLaunchRq(parameters); + } + + /** + * Finish sending Launch data to ReportPortal. + */ + public void finishLaunch() { + ReportPortalUtils.doFinishLaunch(launch.get(), buildFinishLaunchRq(launch.get().getParameters()), shutDownHook); + } + + /** + * Build ReportPortal request for start Feature event. + * + * @param fr Karate feature descriptor + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartFeatureRq(@Nonnull Feature fr) { + return ReportPortalUtils.buildStartFeatureRq(fr); + } + + /** + * Builds a unique feature key that includes parent scenario nesting depth. + * + * @param feature feature descriptor + * @return depth-qualified feature name + */ + private String getFeatureNameForReport(Feature feature) { + return parentScenarios.get().size() + ":" + feature.getNameForReport(); + } + + /** + * Starts a feature item in ReportPortal. + * + * @param feature feature descriptor + */ + @Override + public void onFeatureStart(Feature feature) { + Scenario parentScenario = parentScenarios.get().peekLast(); + StartTestItemRQ rq = buildStartFeatureRq(feature); + featureIdMap.computeIfAbsent( + getFeatureNameForReport(feature), f -> new MemoizingSupplier<>(() -> { + if (parentScenario == null) { + return launch.get().startTestItem(rq); + } else { + Maybe scenarioId = scenarioIdMap.get(parentScenario.getUniqueId()); + if (scenarioId == null) { + LOGGER.error("ERROR: Trying to post unspecified scenario."); + return launch.get().startTestItem(rq); + } + rq.setType(ItemType.STEP.name()); + rq.setHasStats(false); + rq.setName(getInnerFeatureName(rq.getName())); + Maybe itemId = launch.get().startTestItem(scenarioId, rq); + innerFeatures.add(itemId); + if (StringUtils.isNotBlank(rq.getDescription())) { + ReportPortalUtils.sendLog(itemId, rq.getDescription(), LogLevel.INFO, (Instant) rq.getStartTime()); + } + return itemId; + } + }) + ); + } + + /** + * Build ReportPortal request for finish Feature event. + * + * @param fr Karate feature result + * @return request to ReportPortal + */ + @Nonnull + protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureResult fr) { + return buildFinishTestItemRq(Instant.now(), fr.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED); + } + + /** + * Finishes a feature item in ReportPortal. + * + * @param fr feature result + */ + @Override + public void onFeatureEnd(FeatureResult fr) { + MemoizingSupplier> supplier = featureIdMap.get(getFeatureNameForReport(fr.getFeature())); + if (supplier == null || !supplier.isInitialized()) { + return; + } + Maybe featureId = supplier.get(); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(featureId, buildFinishFeatureRq(fr)); + innerFeatures.remove(featureId); + } + + /** + * Build ReportPortal request for start Scenario event. + * + * @param sr Karate scenario descriptor + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartScenarioRq(@Nonnull Scenario sr) { + StartTestItemRQ rq = ReportPortalUtils.buildStartScenarioRq(sr); + ofNullable(featureIdMap.get(getFeatureNameForReport(sr.getFeature()))).map(Supplier::get) + .map(featureId -> innerFeatures.contains(featureId) ? featureId : null) + .ifPresent(featureId -> { + rq.setType(ItemType.STEP.name()); + rq.setHasStats(false); + rq.setName(getInnerScenarioName(rq.getName())); + }); + return rq; + } + + /** + * Starts a scenario item in ReportPortal. + * + * @param scenario Karate scenario descriptor + */ + @Override + public void onScenarioStart(Scenario scenario) { + StartTestItemRQ rq = buildStartScenarioRq(scenario); + Optional> optionalId = ofNullable(featureIdMap.get(getFeatureNameForReport(scenario.getFeature()))).map(Supplier::get); + if (optionalId.isEmpty()) { + LOGGER.error("ERROR: Trying to post unspecified feature."); + } + ofNullable(scenarioIdMap.get(scenario.getUniqueId())).map(Maybe::blockingGet).ifPresent(id -> { + rq.setRetry(true); + rq.setRetryOf(id); + }); + optionalId.ifPresent(featureId -> { + Maybe scenarioId = launch.get().startTestItem(featureId, rq); + if (innerFeatures.contains(featureId) && StringUtils.isNotBlank(rq.getDescription())) { + ReportPortalUtils.sendLog(scenarioId, rq.getDescription(), LogLevel.INFO); + } + scenarioIdMap.put(scenario.getUniqueId(), scenarioId); + parentScenarios.get().add(scenario); + }); + } + + /** + * Build ReportPortal request for finish Scenario event. + * + * @param sr Karate scenario result + * @return request to ReportPortal + */ + @Nonnull + protected FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioResult sr) { + return ReportPortalUtils.buildFinishScenarioRq(sr); + } + + /** + * Build ReportPortal request for start Background event. + * + * @param startTime background start time + * @param step Karate step descriptor + * @param sr Karate scenario descriptor + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartBackgroundRq(Instant startTime, @Nonnull Step step, @Nonnull Scenario sr) { + return ReportPortalUtils.buildStartBackgroundRq(startTime, step, sr); + } + + /** + * Start sending Background data to ReportPortal. + * + * @param startTime background start time + * @param step Karate step descriptor + * @param sr Karate scenario descriptor + * @return item ID Future + */ + public Maybe startBackground(Instant startTime, @Nonnull Step step, @Nonnull Scenario sr) { + return backgroundIdMap.computeIfAbsent( + sr.getUniqueId(), k -> { + StartTestItemRQ backgroundRq = buildStartBackgroundRq(startTime, step, sr); + return launch.get().startTestItem(scenarioIdMap.get(sr.getUniqueId()), backgroundRq); + } + ); + } + + /** + * Build ReportPortal request for finish Background event. + * + * @param stepResult Karate step result + * @param sr Karate scenario result + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioResult sr) { + long duration = ofNullable(stepResult).map(StepResult::getDurationNanos).orElse(0L); + Instant startTime = ofNullable(stepResult).map(StepResult::getStartTime).map(Instant::ofEpochMilli).orElseGet(Instant::now); + Instant endTime = startTime.plusNanos(duration); + return buildFinishTestItemRq(endTime, backgroundStatusMap.remove(sr.getScenario().getUniqueId())); + } + + /** + * Finishes the background item for a scenario, if it was started. + * + * @param stepResult step result that completed the background flow + * @param sr scenario result + */ + public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioResult sr) { + String uniqueId = sr.getScenario().getUniqueId(); + Maybe backgroundId = backgroundIdMap.remove(uniqueId); + if (backgroundId != null) { + FinishTestItemRQ finishRq = buildFinishBackgroundRq(stepResult, sr); + + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(backgroundId, finishRq); + } + } + + /** + * Embed an attachment to ReportPortal. + * + * @param time log time + * @param itemId item ID future + * @param embed Karate's Embed object + */ + protected void embedAttachment(@Nonnull Instant time, @Nonnull Maybe itemId, @Nonnull StepResult.Embed embed) { + ReportPortalUtils.embedAttachment(time, itemId, embed); + } + + /** + * Replays collected step results and finishes the scenario in ReportPortal. + * + * @param sr scenario result + */ + @Override + public void onScenarioEnd(ScenarioResult sr) { + String scenarioUniqueId = sr.getScenario().getUniqueId(); + Maybe scenarioId = scenarioIdMap.get(scenarioUniqueId); + stepStartTimeMap.remove(scenarioUniqueId); + finishBackground(null, sr); + + if (scenarioId == null) { + LOGGER.error("ERROR: Trying to finish unspecified scenario."); + return; + } + + sr.getStepResults().forEach(stepResult -> { + beforeStep(stepResult, sr); + afterStep(stepResult, sr); + }); + + FinishTestItemRQ rq = buildFinishScenarioRq(sr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(scenarioId, rq); + parentScenarios.get().removeFirst(); + } + + /** + * Get step start time. To keep the steps order in case previous step startTime == current step startTime or + * previous step startTime > current step startTime. + * + * @param scenarioUniqueId Karate's Scenario Unique ID + * @return step new startTime in Instant format. + */ + @Nonnull + private Instant getStepStartTime(@Nullable String scenarioUniqueId, Instant stepStartTime) { + return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, stepStartTime, launch.get().useMicroseconds()); + } + + /** + * Customize start Step test item event/request. + * + * @param startTime step start time + * @param step Karate step descriptor + * @param sr Karate scenario descriptor + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartStepRq(Instant startTime, @Nonnull Step step, @Nonnull Scenario sr) { + StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(step, sr); + Instant newStartTime = getStepStartTime(sr.getUniqueId(), startTime); + rq.setStartTime(newStartTime); + return rq; + } + + /** + * Send Step logs to ReportPortal. + * + * @param time log time + * @param itemId item ID future + * @param message log message to send + * @param level log level + */ + protected void sendLog(Instant time, Maybe itemId, String message, LogLevel level) { + ReportPortalUtils.sendLog(itemId, message, level, time); + } + + /** + * Starts a step item and emits step input details. + * + * @param stepResult step execution result + * @param sr scenario result + */ + public void beforeStep(StepResult stepResult, ScenarioResult sr) { + Step step = stepResult.getStep(); + Scenario scenario = sr.getScenario(); + Instant startTime = Instant.ofEpochMilli(stepResult.getStartTime()); + + boolean background = step.isBackground(); + Maybe backgroundId = null; + if (background) { + backgroundId = startBackground(startTime, step, scenario); + } + StartTestItemRQ stepRq = buildStartStepRq(startTime, step, scenario); + + String scenarioId = scenario.getUniqueId(); + Maybe stepId = launch.get().startTestItem(background ? backgroundId : scenarioIdMap.get(scenarioId), stepRq); + stepIdMap.put(scenarioId, stepId); + ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty()) + .ifPresent(params -> sendLog( + startTime.plusMillis(1), + stepId, + String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), + LogLevel.INFO + )); + ofNullable(step.getTable()).ifPresent(table -> sendLog( + startTime.plusMillis(2), + stepId, + "Table:\n\n" + formatDataTable(table.getRows()), + LogLevel.INFO + )); + String docString = step.getDocString(); + if (isNotBlank(docString)) { + sendLog(startTime.plusMillis(3), stepId, "Docstring:\n\n" + asMarkdownCode(docString), LogLevel.INFO); + } + } + + /** + * Send Step execution results to ReportPortal. + * + * @param stepResult step execution results + * @param sr Karate scenario result + */ + public void sendStepResults(StepResult stepResult, ScenarioResult sr) { + List embeds = ofNullable(stepResult.getEmbeds()).orElse(Collections.emptyList()); + String log = ofNullable(stepResult.getLog()).filter(logs -> !logs.isBlank()).orElse(null); + + Instant itemTime = Instant.ofEpochMilli(stepResult.getStartTime()); + long stepDuration = stepResult.getDurationNanos(); + int numberOfArtefacts = embeds.size() + (log != null ? 1 : 0) + (stepResult.isFailed() ? 1 : 0); + int numberOfSteps = numberOfArtefacts + 1; // To always log a little bit after step start time + long duration = stepDuration / numberOfSteps; + + Maybe stepId = stepIdMap.get(sr.getScenario().getUniqueId()); + Step step = stepResult.getStep(); + for (var embed : embeds) { + itemTime = itemTime.plusNanos(duration); + embedAttachment(itemTime, stepId, embed); + } + + if (log != null) { + itemTime = itemTime.plusNanos(duration); + sendLog(itemTime, stepId, stripConsoleColors(log), LogLevel.INFO); + } + + if (stepResult.isFailed()) { + String fullErrorMessage = step.getPrefix() + " " + step.getText(); + String errorMessage = stepResult.getErrorMessage(); + if (isNotBlank(errorMessage)) { + fullErrorMessage = fullErrorMessage + "\n" + errorMessage; + } + itemTime = itemTime.plusNanos(duration); + sendLog(itemTime, stepId, fullErrorMessage, LogLevel.ERROR); + } + } + + /** + * Build ReportPortal request for finish Step event. + * + * @param stepResult Karate step result + * @param sr Karate scenario result + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult sr) { + Instant endTime = Instant.ofEpochMilli(stepResult.getStartTime()).plusNanos(stepResult.getDurationNanos()); + return buildFinishTestItemRq(endTime, getStepStatus(stepResult.getStatus())); + } + + /** + * Aggregates background status across background steps. + * + * @param stepResult background step result + * @param sr scenario result + */ + private void saveBackgroundStatus(@Nonnull StepResult stepResult, @Nonnull ScenarioResult sr) { + backgroundStatusMap.put( + sr.getScenario().getUniqueId(), + StatusEvaluation.evaluateStatus( + backgroundStatusMap.get(sr.getScenario().getUniqueId()), + getStepStatus(stepResult.getStatus()) + ) + ); + } + + /** + * Finishes a step item and sends corresponding step output. + * + * @param stepResult step execution result + * @param sr scenario result + */ + public void afterStep(StepResult stepResult, ScenarioResult sr) { + boolean background = stepResult.getStep().isBackground(); + if (!background) { + finishBackground(stepResult, sr); + } + sendStepResults(stepResult, sr); + Maybe stepId = stepIdMap.remove(sr.getScenario().getUniqueId()); + if (stepId == null) { + LOGGER.error("ERROR: Trying to finish unspecified step."); + return; + } + + FinishTestItemRQ rq = buildFinishStepRq(stepResult, sr); + if (background) { + saveBackgroundStatus(stepResult, sr); + } + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(stepId, rq); + } + + /** + * Initializes the launch at suite start. + * + * @param suite suite descriptor + */ + @Override + public void onSuiteStart(Suite suite) { + launch.get(); // Trigger launch start + } + + /** + * Karate suite callback after execution. + * + * @param suite suite result + */ + @Override + public void onSuiteEnd(SuiteResult suite) { + // Omit Suite logic, since there is no Suite names in Karate + } +} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalRunListener.java b/src/main/java/com/epam/reportportal/karate/ReportPortalRunListener.java new file mode 100644 index 0000000..bb37176 --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalRunListener.java @@ -0,0 +1,892 @@ +/* + * Copyright 2026 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; + +import com.epam.reportportal.formatting.AbstractHttpFormatter; +import com.epam.reportportal.formatting.http.converters.DefaultCookieConverter; +import com.epam.reportportal.formatting.http.converters.DefaultFormParamConverter; +import com.epam.reportportal.formatting.http.converters.DefaultHttpHeaderConverter; +import com.epam.reportportal.formatting.http.converters.DefaultUriConverter; +import com.epam.reportportal.formatting.http.entities.Cookie; +import com.epam.reportportal.formatting.http.entities.Header; +import com.epam.reportportal.formatting.http.entities.Param; +import com.epam.reportportal.karate.utils.BlockingConcurrentHashMap; +import com.epam.reportportal.karate.utils.HttpEntityFactory; +import com.epam.reportportal.listeners.ItemStatus; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.listeners.ListenerParameters; +import com.epam.reportportal.listeners.LogLevel; +import com.epam.reportportal.service.Launch; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.utils.MemoizingSupplier; +import com.epam.reportportal.utils.StatusEvaluation; +import com.epam.reportportal.utils.formatting.MarkdownUtils; +import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; +import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import io.karatelabs.core.*; +import io.karatelabs.gherkin.Scenario; +import io.karatelabs.gherkin.Step; +import io.karatelabs.http.HttpRequest; +import io.karatelabs.http.HttpResponse; +import io.reactivex.Maybe; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Supplier; + +import static com.epam.reportportal.karate.ReportPortalUtils.*; +import static com.epam.reportportal.utils.ParameterUtils.formatParametersAsTable; +import static com.epam.reportportal.utils.formatting.MarkdownUtils.formatDataTable; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * ReportPortal run listener for Karate that streams runtime events directly to ReportPortal. + */ +public class ReportPortalRunListener extends AbstractHttpFormatter implements RunListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalRunListener.class); + private static final String NULL_RESPONSE = "NULL response from Karate"; + /** + * Lazily initialized ReportPortal launch facade used for all item operations. + */ + protected final MemoizingSupplier launch; + /** + * Converter used to render Karate form parameters for HTTP logging. + */ + protected final Function paramConverter; + private final BlockingConcurrentHashMap>> featureIdMap = new BlockingConcurrentHashMap<>(); + private final Map> scenarioIdMap = new ConcurrentHashMap<>(); + private final Map> backgroundIdMap = new ConcurrentHashMap<>(); + private final Map backgroundStatusMap = new ConcurrentHashMap<>(); + private final Map> stepIdMap = new ConcurrentHashMap<>(); + private final Map stepStartTimeMap = new ConcurrentHashMap<>(); + private final Set> innerFeatures = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private volatile Thread shutDownHook; + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param reportPortal ReportPortal client instance + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + * @param uriConverterFunction the same as 'headerConvertFunction' param but for URI, default function returns + * URI "as is" + * @param paramConverter the same as 'headerConvertFunction' param but for Web Form Params, default function returns + * param.getName() + ": " + param.getValue() + */ + public ReportPortalRunListener(ReportPortal reportPortal, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction, @Nullable Function uriConverterFunction, + @Nullable Function paramConverter) { + super(defaultLogLevel, headerConvertFunction, partHeaderConvertFunction, cookieConvertFunction, uriConverterFunction); + this.paramConverter = paramConverter != null ? paramConverter : DefaultFormParamConverter.INSTANCE; + ListenerParameters params = reportPortal.getParameters(); + StartLaunchRQ rq = buildStartLaunchRq(params); + launch = new MemoizingSupplier<>(() -> { + Launch newLaunch = reportPortal.newLaunch(rq); + //noinspection ReactiveStreamsUnusedPublisher + newLaunch.start(); + shutDownHook = registerShutdownHook(this::finishLaunch); + return newLaunch; + }); + } + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param reportPortal ReportPortal client instance + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + * @param uriConverterFunction the same as 'headerConvertFunction' param but for URI, default function returns + * URI "as is" + */ + public ReportPortalRunListener(ReportPortal reportPortal, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction, @Nullable Function uriConverterFunction) { + this( + reportPortal, + defaultLogLevel, + headerConvertFunction, + partHeaderConvertFunction, + cookieConvertFunction, + uriConverterFunction, + DefaultFormParamConverter.INSTANCE + ); + } + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param reportPortal ReportPortal client instance + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + */ + public ReportPortalRunListener(ReportPortal reportPortal, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction) { + this( + reportPortal, + defaultLogLevel, + headerConvertFunction, + partHeaderConvertFunction, + cookieConvertFunction, + DefaultUriConverter.INSTANCE + ); + } + + /** + * Creates a Karate run listener with configurable header converters. + * + * @param reportPortal ReportPortal client instance + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + */ + public ReportPortalRunListener(ReportPortal reportPortal, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction) { + this(reportPortal, defaultLogLevel, headerConvertFunction, partHeaderConvertFunction, DefaultCookieConverter.INSTANCE); + } + + /** + * Creates a Karate run listener with the specified HTTP log level. + * + * @param reportPortal ReportPortal client instance + * @param httpLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + */ + public ReportPortalRunListener(ReportPortal reportPortal, @Nonnull LogLevel httpLogLevel) { + this(reportPortal, httpLogLevel, DefaultHttpHeaderConverter.INSTANCE, DefaultHttpHeaderConverter.INSTANCE); + } + + /** + * Creates a listener instance backed by the provided ReportPortal client. + * + * @param reportPortal ReportPortal client instance + */ + public ReportPortalRunListener(ReportPortal reportPortal) { + this(reportPortal, LogLevel.INFO); + } + + /** + * Creates a listener with a default ReportPortal client configuration. + */ + @SuppressWarnings("unused") + public ReportPortalRunListener() { + this(ReportPortal.builder().build()); + } + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + * @param uriConverterFunction the same as 'headerConvertFunction' param but for URI, default function returns + * URI "as is" + * @param paramConverter the same as 'headerConvertFunction' param but for Web Form Params, default function returns + * param.getName() + ": " + param.getValue() + */ + public ReportPortalRunListener(Supplier launchSupplier, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction, @Nullable Function uriConverterFunction, + @Nullable Function paramConverter) { + super(defaultLogLevel, headerConvertFunction, partHeaderConvertFunction, cookieConvertFunction, uriConverterFunction); + this.paramConverter = paramConverter != null ? paramConverter : DefaultFormParamConverter.INSTANCE; + launch = new MemoizingSupplier<>(launchSupplier); + } + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + * @param uriConverterFunction the same as 'headerConvertFunction' param but for URI, default function returns + * URI "as is" + */ + public ReportPortalRunListener(Supplier launchSupplier, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction, @Nullable Function uriConverterFunction) { + this( + launchSupplier, + defaultLogLevel, + headerConvertFunction, + partHeaderConvertFunction, + cookieConvertFunction, + uriConverterFunction, + DefaultFormParamConverter.INSTANCE + ); + } + + /** + * Creates a Karate run listener with configurable HTTP converters. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + * @param cookieConvertFunction the same as 'headerConvertFunction' param but for Cookies, default function + * formats Cookies with toString method + */ + public ReportPortalRunListener(Supplier launchSupplier, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction, + @Nullable Function cookieConvertFunction) { + this( + launchSupplier, + defaultLogLevel, + headerConvertFunction, + partHeaderConvertFunction, + cookieConvertFunction, + DefaultUriConverter.INSTANCE + ); + } + + /** + * Creates a Karate run listener with configurable header converters. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + * @param defaultLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + * @param headerConvertFunction if you want to preprocess your HTTP Headers before they appear on Report Portal + * provide this custom function for the class, default function formats it like + * that: header.getName() + ": " + header.getValue() + * @param partHeaderConvertFunction the same as for HTTP headers, but for parts in multipart requests + */ + public ReportPortalRunListener(Supplier launchSupplier, @Nonnull LogLevel defaultLogLevel, + @Nullable Function headerConvertFunction, @Nullable Function partHeaderConvertFunction) { + this(launchSupplier, defaultLogLevel, headerConvertFunction, partHeaderConvertFunction, DefaultCookieConverter.INSTANCE); + } + + /** + * Creates a Karate run listener with the specified HTTP log level. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + * @param httpLogLevel log level on which Karate HTTP requests/responses will appear in ReportPortal + */ + public ReportPortalRunListener(Supplier launchSupplier, @Nonnull LogLevel httpLogLevel) { + this(launchSupplier, httpLogLevel, DefaultHttpHeaderConverter.INSTANCE, DefaultHttpHeaderConverter.INSTANCE); + } + + /** + * Creates a listener with a preconfigured launch supplier. + * + * @param launchSupplier launch supplier used to lazily initialize launch interactions + */ + @SuppressWarnings("unused") + public ReportPortalRunListener(Supplier launchSupplier) { + this(launchSupplier, LogLevel.INFO); + } + + /** + * Customize start launch event/request + * + * @param parameters Launch configuration parameters + * @return request to ReportPortal + */ + protected StartLaunchRQ buildStartLaunchRq(ListenerParameters parameters) { + return ReportPortalUtils.buildStartLaunchRq(parameters); + } + + /** + * Customizes the launch finish request. + * + * @param parameters launch configuration parameters + * @return request to ReportPortal + */ + @Nonnull + protected FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) { + return ReportPortalUtils.buildFinishLaunchRq(parameters); + } + + /** + * Finish sending Launch data to ReportPortal. + */ + public void finishLaunch() { + ReportPortalUtils.doFinishLaunch(launch.get(), buildFinishLaunchRq(launch.get().getParameters()), shutDownHook); + } + + /** + * Build ReportPortal request for start Feature event. + * + * @param fr Karate's FeatureRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartFeatureRq(@Nonnull FeatureRuntime fr) { + StartTestItemRQ rq = ReportPortalUtils.buildStartFeatureRq(fr.getFeature()); + ofNullable(fr.getCallArg()).filter(args -> !args.isEmpty()).ifPresent(args -> { + String parameters = String.format(PARAMETERS_PATTERN, formatParametersAsTable(getParameters(args))); + String description = rq.getDescription(); + if (isNotBlank(description)) { + rq.setDescription(MarkdownUtils.asTwoParts(parameters, description)); + } else { + rq.setDescription(parameters); + } + }); + return rq; + } + + /** + * Calculates feature nesting depth for called features. + * + * @param fr feature runtime + * @return nesting depth where 0 means a top-level feature + */ + private int getDepth(FeatureRuntime fr) { + var caller = fr.getCallerScenario(); + if (caller == null) { + return 0; + } + int depth = 0; + while (caller != null) { + depth++; + FeatureRuntime myFr = caller.getFeatureRuntime(); + if (myFr == null) { + break; + } + caller = myFr.getCallerScenario(); + } + return depth; + } + + /** + * Builds a unique feature key that includes call depth. + * + * @param fr feature runtime + * @return depth-qualified feature name + */ + private String getFeatureNameForReport(FeatureRuntime fr) { + int callDepth = getDepth(fr); + return callDepth + ":" + fr.getFeature().getNameForReport(); + } + + /** + * Starts a feature item in ReportPortal. + * + * @param fr feature runtime + */ + public void beforeFeature(FeatureRuntime fr) { + StartTestItemRQ rq = buildStartFeatureRq(fr); + featureIdMap.computeIfAbsent( + getFeatureNameForReport(fr), f -> new MemoizingSupplier<>(() -> { + if (getDepth(fr) == 0) { + return launch.get().startTestItem(rq); + } else { + Maybe scenarioId = scenarioIdMap.get(fr.getCallerScenario().getScenario().getUniqueId()); + if (scenarioId == null) { + LOGGER.error("ERROR: Trying to post unspecified scenario."); + return launch.get().startTestItem(rq); + } + rq.setType(ItemType.STEP.name()); + rq.setHasStats(false); + rq.setName(getInnerFeatureName(rq.getName())); + Maybe itemId = launch.get().startTestItem(scenarioId, rq); + innerFeatures.add(itemId); + if (StringUtils.isNotBlank(rq.getDescription())) { + ReportPortalUtils.sendLog(itemId, rq.getDescription(), LogLevel.INFO, (Instant) rq.getStartTime()); + } + return itemId; + } + }) + ); + } + + /** + * Build ReportPortal request for finish Feature event. + * + * @param fr Karate's FeatureRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureRuntime fr) { + return buildFinishTestItemRq(Instant.now(), fr.getResult().isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED); + } + + /** + * Finishes a feature item in ReportPortal. + * + * @param fr feature runtime + */ + public void afterFeature(FeatureRuntime fr) { + MemoizingSupplier> supplier = featureIdMap.get(getFeatureNameForReport(fr)); + if (supplier == null || !supplier.isInitialized()) { + return; + } + Maybe featureId = supplier.get(); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(featureId, buildFinishFeatureRq(fr)); + innerFeatures.remove(featureId); + } + + /** + * Build ReportPortal request for start Scenario event. + * + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioRuntime sr) { + StartTestItemRQ rq = ReportPortalUtils.buildStartScenarioRq(sr.getScenario()); + ofNullable(featureIdMap.get(getFeatureNameForReport(sr.getFeatureRuntime()))).map(Supplier::get) + .map(featureId -> innerFeatures.contains(featureId) ? featureId : null) + .ifPresent(featureId -> { + rq.setType(ItemType.STEP.name()); + rq.setHasStats(false); + rq.setName(getInnerScenarioName(rq.getName())); + }); + return rq; + } + + /** + * Starts a scenario item in ReportPortal. + * + * @param sr scenario runtime + */ + public void beforeScenario(ScenarioRuntime sr) { + StartTestItemRQ rq = buildStartScenarioRq(sr); + Optional> optionalId = ofNullable(featureIdMap.get(getFeatureNameForReport(sr.getFeatureRuntime()))).map(Supplier::get); + if (optionalId.isEmpty()) { + LOGGER.error("ERROR: Trying to post unspecified feature."); + } + String uniqueId = sr.getScenario().getUniqueId(); + ofNullable(scenarioIdMap.get(uniqueId)).map(Maybe::blockingGet).ifPresent(id -> { + rq.setRetry(true); + rq.setRetryOf(id); + }); + optionalId.ifPresent(featureId -> { + Maybe scenarioId = launch.get().startTestItem(featureId, rq); + if (innerFeatures.contains(featureId) && StringUtils.isNotBlank(rq.getDescription())) { + ReportPortalUtils.sendLog(scenarioId, rq.getDescription(), LogLevel.INFO); + } + scenarioIdMap.put(uniqueId, scenarioId); + }); + } + + /** + * Build ReportPortal request for finish Scenario event. + * + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + protected FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioRuntime sr) { + return ReportPortalUtils.buildFinishScenarioRq(sr.getResult()); + } + + /** + * Build ReportPortal request for start Background event. + * + * @param step Karate's Step object instance + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected StartTestItemRQ buildStartBackgroundRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { + return ReportPortalUtils.buildStartBackgroundRq(Instant.now(), step, sr.getScenario()); + } + + /** + * Start sending Background data to ReportPortal. + * + * @param step Karate's Step object instance + * @param sr Karate's ScenarioRuntime object instance + * @return item ID Future + */ + public Maybe startBackground(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { + String uniqueId = sr.getScenario().getUniqueId(); + return backgroundIdMap.computeIfAbsent( + uniqueId, k -> { + StartTestItemRQ backgroundRq = buildStartBackgroundRq(step, sr); + return launch.get().startTestItem(scenarioIdMap.get(uniqueId), backgroundRq); + } + ); + } + + /** + * Build ReportPortal request for finish Background event. + * + * @param stepResult Karate's StepResult class instance + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) { + return buildFinishTestItemRq(Instant.now(), backgroundStatusMap.remove(sr.getScenario().getUniqueId())); + } + + /** + * Finishes the background item for a scenario, if it was started. + * + * @param stepResult step result that completed the background flow + * @param sr scenario runtime + */ + public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) { + String uniqueId = sr.getScenario().getUniqueId(); + Maybe backgroundId = backgroundIdMap.remove(uniqueId); + if (backgroundId != null) { + FinishTestItemRQ finishRq = buildFinishBackgroundRq(stepResult, sr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(backgroundId, finishRq); + } + } + + /** + * Embed an attachment to ReportPortal. + * + * @param itemId item ID future + * @param embed Karate's Embed object + */ + protected void embedAttachment(@Nonnull Maybe itemId, @Nonnull StepResult.Embed embed) { + ReportPortalUtils.embedAttachment(Instant.now(), itemId, embed); + } + + /** + * Finishes a scenario item in ReportPortal. + * + * @param sr scenario runtime + */ + public void afterScenario(ScenarioRuntime sr) { + String uniqueId = sr.getScenario().getUniqueId(); + Maybe scenarioId = scenarioIdMap.get(uniqueId); + stepStartTimeMap.remove(uniqueId); + finishBackground(null, sr); + + if (scenarioId == null) { + LOGGER.error("ERROR: Trying to finish unspecified scenario."); + return; + } + + FinishTestItemRQ rq = buildFinishScenarioRq(sr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(scenarioId, rq); + } + + /** + * Get step start time. To keep the steps order in case previous step startTime == current step startTime or + * previous step startTime > current step startTime. + * + * @param scenarioUniqueId Karate's Scenario Unique ID + * @return step new startTime in Instant format. + */ + @Nonnull + private Instant getStepStartTime(@Nullable String scenarioUniqueId) { + return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, launch.get().useMicroseconds()); + } + + /** + * Customize start Step test item event/request. + * + * @param step Karate's Step object instance + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + protected StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) { + StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(step, sr.getScenario()); + Instant startTime = getStepStartTime(sr.getScenario().getUniqueId()); + rq.setStartTime(startTime); + return rq; + } + + /** + * Send Step logs to ReportPortal. + * + * @param itemId item ID future + * @param message log message to send + * @param level log level + */ + protected void sendLog(Maybe itemId, String message, LogLevel level) { + ReportPortalUtils.sendLog(itemId, message, level); + } + + /** + * Starts a step item and emits step input details. + * + * @param step step definition + * @param sr scenario runtime + */ + public void beforeStep(Step step, ScenarioRuntime sr) { + boolean background = step.isBackground(); + Maybe backgroundId = null; + if (background) { + backgroundId = startBackground(step, sr); + } + StartTestItemRQ stepRq = buildStartStepRq(step, sr); + + String scenarioId = sr.getScenario().getUniqueId(); + Maybe stepId = launch.get().startTestItem(background ? backgroundId : scenarioIdMap.get(scenarioId), stepRq); + stepIdMap.put(scenarioId, stepId); + ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty()) + .ifPresent(params -> sendLog(stepId, String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), LogLevel.INFO)); + ofNullable(step.getTable()).ifPresent(table -> sendLog(stepId, "Table:\n\n" + formatDataTable(table.getRows()), LogLevel.INFO)); + String docString = step.getDocString(); + if (isNotBlank(docString)) { + sendLog(stepId, "Docstring:\n\n" + asMarkdownCode(step.getDocString()), LogLevel.INFO); + } + } + + /** + * Send Step execution results to ReportPortal. + * + * @param stepResult step execution results + * @param sr Karate's ScenarioRuntime object instance + */ + public void sendStepResults(StepResult stepResult, ScenarioRuntime sr) { + Maybe stepId = stepIdMap.get(sr.getScenario().getUniqueId()); + Step step = stepResult.getStep(); + ofNullable(stepResult.getEmbeds()).ifPresent(embeds -> embeds.forEach(embed -> embedAttachment(stepId, embed))); + + if (stepResult.isFailed()) { + String fullErrorMessage = step.getPrefix() + " " + step.getText(); + String errorMessage = stepResult.getErrorMessage(); + if (isNotBlank(errorMessage)) { + fullErrorMessage = fullErrorMessage + "\n" + errorMessage; + } + sendLog(stepId, fullErrorMessage, LogLevel.ERROR); + } + } + + /** + * Build ReportPortal request for finish Step event. + * + * @param stepResult Karate's StepResult class instance + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) { + return buildFinishTestItemRq(Instant.now(), getStepStatus(stepResult.getStatus())); + } + + /** + * Aggregates background status across background steps. + * + * @param stepResult background step result + * @param sr scenario runtime + */ + private void saveBackgroundStatus(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) { + String scenarioId = sr.getScenario().getUniqueId(); + backgroundStatusMap.put( + scenarioId, + StatusEvaluation.evaluateStatus(backgroundStatusMap.get(scenarioId), getStepStatus(stepResult.getStatus())) + ); + } + + /** + * Finishes a step item and sends corresponding step output. + * + * @param stepResult step execution result + * @param sr scenario runtime + */ + public void afterStep(StepResult stepResult, ScenarioRuntime sr) { + boolean background = stepResult.getStep().isBackground(); + if (!background) { + finishBackground(stepResult, sr); + } + + sendStepResults(stepResult, sr); + Maybe stepId = stepIdMap.remove(sr.getScenario().getUniqueId()); + if (stepId == null) { + LOGGER.error("ERROR: Trying to finish unspecified step."); + return; + } + + FinishTestItemRQ rq = buildFinishStepRq(stepResult, sr); + if (background) { + saveBackgroundStatus(stepResult, sr); + } + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(stepId, rq); + } + + /** + * Publishes an unexpected runtime error stack trace to ReportPortal. + * + * @param timestamp error timestamp + * @param error runtime error + * @param sr scenario runtime + */ + @SuppressWarnings("unused") + public void sendErrorResults(long timestamp, Throwable error, ScenarioRuntime sr) { + ReportPortal.sendStackTraceToRP(error); + } + + /** + * Karate HTTP callback executed before HTTP invocation. + * + * @param request HTTP request + * @param sr scenario runtime + */ + @SuppressWarnings("unused") + public void beforeHttpCall(HttpRequest request, ScenarioRuntime sr) { + if (request == null) { + return; + } + try { + emitLog(HttpEntityFactory.createHttpRequestFormatter( + request, + uriConverter, + headerConverter, + cookieConverter, + paramConverter, + getContentPrettifiers(), + partHeaderConverter, + getBodyTypeMap() + )); + } catch (Exception e) { + LOGGER.warn("Unable to log HTTP request for scenario '{}'", getScenarioUniqueId(sr), e); + } + } + + /** + * Karate HTTP callback executed after HTTP invocation. + * + * @param request HTTP request + * @param response HTTP response + * @param sr scenario runtime + */ + @SuppressWarnings("unused") + public void afterHttpCall(HttpRequest request, HttpResponse response, ScenarioRuntime sr) { + if (response == null) { + sendLog(stepIdMap.get(sr.getScenario().getUniqueId()), NULL_RESPONSE, LogLevel.WARN); + return; + } + try { + emitLog(HttpEntityFactory.createHttpResponseFormatter( + response, + headerConverter, + cookieConverter, + getContentPrettifiers(), + getBodyTypeMap() + )); + } catch (Exception e) { + LOGGER.warn("Unable to log HTTP response for scenario '{}'", getScenarioUniqueId(sr), e); + } + } + + @Nonnull + private String getScenarioUniqueId(@Nullable ScenarioRuntime sr) { + return ofNullable(sr).map(ScenarioRuntime::getScenario).map(Scenario::getUniqueId).orElse("unknown"); + } + + /** + * Karate suite callback before execution. + * + * @param suite suite descriptor + */ + @SuppressWarnings("unused") + public void beforeSuite(Suite suite) { + // Omit Suite logic, since there is no Suite names in Karate + } + + /** + * Karate suite callback after execution. + * + * @param suite suite result + */ + @SuppressWarnings("unused") + public void afterSuite(SuiteResult suite) { + // Omit Suite logic, since there is no Suite names in Karate + } + + /** + * Handles Karate runtime events and delegates to ReportPortal lifecycle methods. + * + * @param event Karate runtime event + * @return {@code true} to keep event processing active + */ + @Override + @SuppressWarnings("UnnecessaryDefault") + public boolean onEvent(RunEvent event) { + launch.get(); // Trigger launch start + switch (event.getType()) { + case SUITE_ENTER -> beforeSuite(((SuiteRunEvent) event).source()); + case SUITE_EXIT -> afterSuite(((SuiteRunEvent) event).result()); + case FEATURE_ENTER -> beforeFeature(((FeatureRunEvent) event).source()); + case FEATURE_EXIT -> afterFeature(((FeatureRunEvent) event).source()); + case SCENARIO_ENTER -> beforeScenario(((ScenarioRunEvent) event).source()); + case SCENARIO_EXIT -> afterScenario(((ScenarioRunEvent) event).source()); + case STEP_ENTER -> { + var stepEvent = ((StepRunEvent) event); + beforeStep(stepEvent.step(), stepEvent.scenarioRuntime()); + } + case STEP_EXIT -> { + var stepEvent = ((StepRunEvent) event); + afterStep(stepEvent.result(), stepEvent.scenarioRuntime()); + } + case HTTP_ENTER -> { + var httpEvent = ((HttpRunEvent) event); + beforeHttpCall(httpEvent.request(), httpEvent.scenarioRuntime()); + } + case HTTP_EXIT -> { + var httpEvent = ((HttpRunEvent) event); + afterHttpCall(httpEvent.request(), httpEvent.response(), httpEvent.scenarioRuntime()); + } + case ERROR -> { + var errorEvent = ((ErrorRunEvent) event); + sendErrorResults(errorEvent.timeStamp(), errorEvent.error(), errorEvent.scenarioRuntime()); + } + case PROGRESS -> { + // do we need it? + } + default -> LOGGER.warn("Unknown event type received: {}", event.getType().name()); + } + return true; + } +} diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java b/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java index 766efbb..fa92fbe 100644 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java @@ -35,7 +35,9 @@ import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.core.*; +import io.karatelabs.core.ScenarioResult; +import io.karatelabs.core.StepResult; +import io.karatelabs.gherkin.*; import io.reactivex.Maybe; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -54,25 +56,66 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; /** - * Set of useful utils related to Karate -> ReportPortal integration + * Utility methods for mapping Karate runtime entities to ReportPortal API requests. */ public class ReportPortalUtils { + /** + * Markdown template for rendering code blocks. + */ public static final String MARKDOWN_CODE_PATTERN = "```\n%s\n```"; + /** + * Markdown template for rendering parameter tables. + */ public static final String PARAMETERS_PATTERN = "Parameters:\n\n%s"; + /** + * Regex template used to match Karate outline variable placeholders in a step. + */ public static final String VARIABLE_PATTERN = "(?:(?<=#\\()%1$s(?=\\)))|(?:(?<=[\\s=+-/*<>(]|^)%1$s(?=[\\s=+-/*<>)]|(?:\\r?\\n)|$))"; + /** + * Agent properties file name used to enrich launch/system attributes. + */ public static final String AGENT_PROPERTIES_FILE = "agent.properties"; + /** + * System attribute key that controls skipped issue behavior in ReportPortal. + */ public static final String SKIPPED_ISSUE_KEY = "skippedIssue"; + /** + * Code reference template for a concrete scenario. + */ public static final String SCENARIO_CODE_REFERENCE_PATTERN = "%s/[SCENARIO:%s]"; + /** + * Code reference template for a scenario outline example. + */ public static final String EXAMPLE_CODE_REFERENCE_PATTERN = "%s/[EXAMPLE:%s%s]"; + /** + * Markdown delimiter used to join logical description sections. + */ public static final String MARKDOWN_DELIMITER = MarkdownUtils.LOGICAL_SEPARATOR; + /** + * Pattern for joining two text blocks with a markdown delimiter. + */ public static final String MARKDOWN_DELIMITER_PATTERN = "%s" + MARKDOWN_DELIMITER + "%s"; + /** + * Prefix used for naming called (inner) feature items. + */ public static final String FEATURE_TAG = "Feature: "; + /** + * Prefix used for naming called (inner) scenario items. + */ public static final String SCENARIO_TAG = "Scenario: "; private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalUtils.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 = ":"; + private static final Pattern CONSOLE_COLORS_PATTERN = Pattern.compile("\\u001B\\[[0-?]*[ -/]*[@-~]"); + + private static final List CODE_REF_PREFIXES_TO_REMOVE = List.of( + "build/resources/test/", + "build/resources/main/", + "target/test-classes/", + "target/classes/" + ); private ReportPortalUtils() { throw new RuntimeException("No instances should exist for the class!"); @@ -172,9 +215,21 @@ public static FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters return rq; } + /** + * Returns a feature file code reference. + * + * @param feature Karate feature + * @return feature-relative code reference + */ @Nonnull public static String getCodeRef(@Nonnull Feature feature) { - return feature.getResource().getRelativePath(); + String relativePath = feature.getResource().getRelativePath(); + for (String prefix : CODE_REF_PREFIXES_TO_REMOVE) { + if (relativePath.startsWith(prefix)) { + return relativePath.substring(prefix.length()); + } + } + return relativePath; } /** @@ -230,6 +285,12 @@ public static FinishTestItemRQ buildFinishTestItemRq(@Nonnull Instant endTime, @ return rq; } + /** + * Converts Karate tags to ReportPortal attributes. + * + * @param tags Karate tags + * @return ReportPortal attributes or {@code null} when there are no tags + */ @Nullable public static Set toAttributes(@Nullable List tags) { Set attributes = ofNullable(tags).orElse(Collections.emptyList()).stream().flatMap(tag -> { @@ -306,18 +367,17 @@ public static TestCaseIdEntry getTestCaseId(@Nonnull Scenario scenario) { /** * Build ReportPortal request for start Scenario event * - * @param result Karate's ScenarioResult object instance + * @param scenario Karate's Scenario object instance * @return request to ReportPortal */ @Nonnull - public static StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioResult result) { - Scenario scenario = result.getScenario(); + public static StartTestItemRQ buildStartScenarioRq(@Nonnull Scenario scenario) { StartTestItemRQ rq = buildStartTestItemRq(scenario.getName(), Instant.now(), ItemType.STEP); rq.setCodeRef(getCodeRef(scenario)); rq.setTestCaseId(ofNullable(getTestCaseId(scenario)).map(TestCaseIdEntry::getId).orElse(null)); rq.setAttributes(toAttributes(scenario.getTags())); rq.setParameters(getParameters(scenario)); - rq.setDescription(buildDescription(scenario, result.getErrorMessage(), getParameters(scenario))); + rq.setDescription(buildDescription(scenario, null, getParameters(scenario))); return rq; } @@ -334,10 +394,18 @@ public static FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioResult res Instant.now(), result.getFailureMessageForDisplay() == null ? ItemStatus.PASSED : ItemStatus.FAILED ); - rq.setDescription(buildDescription(scenario, result.getErrorMessage(), getParameters(scenario))); + rq.setDescription(buildDescription(scenario, result.getFailureMessageForDisplay(), getParameters(scenario))); return rq; } + /** + * Builds scenario description from parameters, scenario description and optional error details. + * + * @param scenario scenario descriptor + * @param errorMessage optional error message + * @param parameters optional outline parameters + * @return formatted Markdown description + */ @Nonnull private static String buildDescription(@Nonnull Scenario scenario, @Nullable String errorMessage, @Nullable List parameters) { @@ -356,6 +424,12 @@ private static String buildDescription(@Nonnull Scenario scenario, @Nullable Str return descriptionBuilder.toString(); } + /** + * Appends text using the configured Markdown delimiter when needed. + * + * @param builder destination description builder + * @param text text block to append + */ private static void appendWithDelimiter(StringBuilder builder, String text) { if (!builder.isEmpty()) { builder.append(MARKDOWN_DELIMITER); @@ -366,14 +440,15 @@ private static void appendWithDelimiter(StringBuilder builder, String text) { /** * Build ReportPortal request for start Background event. * - * @param step Karate's Step object instance - * @param scenario Karate's Scenario object instance + * @param startTime background start time + * @param step Karate's Step object instance + * @param scenario Karate's Scenario object instance * @return request to ReportPortal */ @Nonnull @SuppressWarnings("unused") - public static StartTestItemRQ buildStartBackgroundRq(@Nonnull Step step, @Nonnull Scenario scenario) { - StartTestItemRQ rq = buildStartTestItemRq(Background.KEYWORD, Instant.now(), ItemType.STEP); + public static StartTestItemRQ buildStartBackgroundRq(Instant startTime, @Nonnull Step step, @Nonnull Scenario scenario) { + StartTestItemRQ rq = buildStartTestItemRq(Background.KEYWORD, startTime, ItemType.STEP); rq.setHasStats(false); return rq; } @@ -414,14 +489,12 @@ public static StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull Scen * @param status Karate item status * @return ReportPortal status */ - public static ItemStatus getStepStatus(String status) { + @SuppressWarnings("UnnecessaryDefault") + public static ItemStatus getStepStatus(StepResult.Status status) { return switch (status) { - case "failed" -> ItemStatus.FAILED; - case "passed" -> ItemStatus.PASSED; - case "skipped" -> ItemStatus.SKIPPED; - case "stopped" -> ItemStatus.STOPPED; - case "interrupted" -> ItemStatus.INTERRUPTED; - case "cancelled" -> ItemStatus.CANCELLED; + case FAILED -> ItemStatus.FAILED; + case PASSED -> ItemStatus.PASSED; + case SKIPPED -> ItemStatus.SKIPPED; default -> { LOGGER.warn("Unknown step status received! Set it as SKIPPED"); yield ItemStatus.SKIPPED; @@ -464,22 +537,23 @@ public static void sendLog(Maybe itemId, String message, LogLevel level) /** * Embed an attachment to ReportPortal. * + * @param time log time * @param itemId item ID future * @param embed Karate's Embed object */ - public static void embedAttachment(@Nonnull Maybe itemId, @Nonnull Embed embed) { + public static void embedAttachment(@Nonnull Instant time, @Nonnull Maybe itemId, @Nonnull StepResult.Embed embed) { ReportPortal.emitLog( itemId, id -> { SaveLogRQ rq = new SaveLogRQ(); rq.setItemUuid(id); rq.setLevel(LogLevel.INFO.name()); - rq.setLogTime(Instant.now()); - rq.setMessage("Attachment: " + embed.getResourceType().contentType); + rq.setLogTime(time); + rq.setMessage("Attachment: " + embed.getMimeType()); SaveLogRQ.File file = new SaveLogRQ.File(); - file.setName(embed.getFile().getName()); - file.setContent(embed.getBytes()); - file.setContentType(embed.getResourceType().contentType); + file.setName(embed.getFileName()); + file.setContent(embed.getData()); + file.setContentType(embed.getMimeType()); rq.setFile(file); return rq; @@ -518,6 +592,20 @@ public static String asMarkdownCode(String code) { return String.format(MARKDOWN_CODE_PATTERN, code); } + /** + * Remove ANSI color/control escape codes from console output. + * + * @param text text potentially containing ANSI escape codes + * @return plain text without ANSI escape codes + */ + @Nullable + public static String stripConsoleColors(@Nullable String text) { + if (text == null) { + return null; + } + return CONSOLE_COLORS_PATTERN.matcher(text).replaceAll(""); + } + /** * Build name of inner scenario (called by another scenario). * @@ -542,14 +630,14 @@ public static String getInnerFeatureName(String name) { * Get step start time. To keep the steps order in case previous step startTime == current step startTime or * previous step startTime > current step startTime. * - * @param scenarioUniqueId Karate's Scenario Unique ID, a key for stepStartTimeMap - * @param stepStartTimeMap a holder for start times for every particular scenario - * @param useMicroseconds if server supports microseconds + * @param scenarioUniqueId Karate's Scenario Unique ID, a key for stepStartTimeMap + * @param stepStartTimeMap a holder for start times for every particular scenario + * @param currentStepStartTime scenario start time to use as baseline + * @param useMicroseconds if server supports microseconds * @return step new startTime in Instant format. */ public static Instant getStepStartTime(@Nullable String scenarioUniqueId, Map stepStartTimeMap, - boolean useMicroseconds) { - Instant currentStepStartTime = Instant.now().truncatedTo(ChronoUnit.MICROS); + Instant currentStepStartTime, boolean useMicroseconds) { if (scenarioUniqueId == null || stepStartTimeMap.isEmpty()) { stepStartTimeMap.put(scenarioUniqueId, currentStepStartTime); return currentStepStartTime; @@ -571,4 +659,19 @@ public static Instant getStepStartTime(@Nullable String scenarioUniqueId, Map stepStartTimeMap, + boolean useMicroseconds) { + Instant currentStepStartTime = Instant.now().truncatedTo(ChronoUnit.MICROS); + return getStepStartTime(scenarioUniqueId, stepStartTimeMap, currentStepStartTime, useMicroseconds); + } } diff --git a/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java b/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java index 20a31e9..094dd29 100644 --- a/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java +++ b/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java @@ -76,10 +76,28 @@ public T get(long timeout, TimeUnit unit) throws InterruptedException { private final Map> map = new ConcurrentHashMap<>(); + /** + * Creates an empty blocking concurrent map wrapper. + */ + public BlockingConcurrentHashMap() { + } + + /** + * Computes and stores a value for the key if it is absent. + * + * @param key map key + * @param mappingFunction function used to compute the value + */ public void computeIfAbsent(@Nonnull K key, Function mappingFunction) { map.computeIfAbsent(key, k -> new BlockingReference<>()).set(mappingFunction); } + /** + * Returns a value for the key, waiting until it is available or timeout expires. + * + * @param key map key + * @return stored value or {@code null} on timeout/interruption + */ @Nullable public V get(@Nonnull K key) { try { @@ -90,6 +108,12 @@ public V get(@Nonnull K key) { return null; } + /** + * Removes and returns a value for the key, waiting for pending computation if needed. + * + * @param key map key + * @return removed value or {@code null} on timeout/interruption + */ @Nullable public V remove(@Nonnull K key) { try { diff --git a/src/main/java/com/epam/reportportal/karate/utils/HttpEntityFactory.java b/src/main/java/com/epam/reportportal/karate/utils/HttpEntityFactory.java new file mode 100644 index 0000000..2910415 --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/utils/HttpEntityFactory.java @@ -0,0 +1,256 @@ +/* + * Copyright 2026 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.utils; + +import com.epam.reportportal.formatting.http.HttpFormatUtils; +import com.epam.reportportal.formatting.http.HttpPartFormatter; +import com.epam.reportportal.formatting.http.HttpRequestFormatter; +import com.epam.reportportal.formatting.http.HttpResponseFormatter; +import com.epam.reportportal.formatting.http.entities.BodyType; +import com.epam.reportportal.formatting.http.entities.Cookie; +import com.epam.reportportal.formatting.http.entities.Header; +import com.epam.reportportal.formatting.http.entities.Param; +import io.karatelabs.http.HttpRequest; +import io.karatelabs.http.HttpResponse; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.function.Function; + +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * Utility factory methods that convert Karate HTTP entities into ReportPortal formatters. + */ +public final class HttpEntityFactory { + + private HttpEntityFactory() { + throw new IllegalStateException("Utility class should not be instantiated"); + } + + /** + * Builds a request formatter from Karate {@link HttpRequest}. + * + * @param request Karate HTTP request + * @param uriConverter URI converter override + * @param headerConverter header converter override + * @param cookieConverter cookie converter override + * @param paramConverter form parameter converter override + * @param prettifiers payload prettifiers by MIME type + * @param partHeaderConverter multipart part header converter override + * @param bodyTypeMap body type mapping by MIME type + * @return populated request formatter + */ + @Nonnull + public static HttpRequestFormatter createHttpRequestFormatter(@Nonnull HttpRequest request, + @Nullable Function uriConverter, @Nullable Function headerConverter, + @Nullable Function cookieConverter, @Nullable Function paramConverter, + @Nullable Map> prettifiers, @Nullable Function partHeaderConverter, + @Nonnull Map bodyTypeMap) { + HttpRequestFormatter.Builder builder = new HttpRequestFormatter.Builder(request.getMethod(), request.getUrlAndPath()); + ofNullable(request.getHeaders()).ifPresent(headers -> headers.forEach((key, values) -> ofNullable(values).orElseGet(Collections::emptyList) + .forEach(value -> builder.addHeader(key, value)))); + ofNullable(request.getCookies()).orElseGet(Collections::emptyMap) + .forEach((key, value) -> builder.addCookie(key, value == null ? null : value.get("value"))); + builder.uriConverter(uriConverter) + .headerConverter(headerConverter) + .cookieConverter(cookieConverter) + .paramConverter(paramConverter) + .prettifiers(prettifiers); + + String contentType = request.getContentType(); + String mimeType = HttpFormatUtils.getMimeType(contentType); + BodyType bodyType = request.isMultiPart() ? BodyType.MULTIPART : HttpFormatUtils.getBodyType(contentType, bodyTypeMap); + byte[] body = request.getBody(); + if (body == null && !BodyType.MULTIPART.equals(bodyType)) { + return builder.build(); + } + switch (bodyType) { + case TEXT -> builder.bodyText(mimeType, ofNullable(request.getBodyDisplay()).orElseGet(request::getBodyString)); + case FORM -> builder.bodyParams(ofNullable(request.getBodyDisplay()).orElseGet(request::getBodyString)); + case MULTIPART -> toParts(request, bodyTypeMap, partHeaderConverter).forEach(builder::addBodyPart); + default -> builder.bodyBytes(mimeType, body); + } + return builder.build(); + } + + /** + * Builds a response formatter from Karate {@link HttpResponse}. + * + * @param response Karate HTTP response + * @param headerConverter header converter override + * @param cookieConverter cookie converter override + * @param prettifiers payload prettifiers by MIME type + * @param bodyTypeMap body type mapping by MIME type + * @return populated response formatter + */ + @Nonnull + public static HttpResponseFormatter createHttpResponseFormatter(@Nonnull HttpResponse response, + @Nullable Function headerConverter, @Nullable Function cookieConverter, + @Nullable Map> prettifiers, @Nonnull Map bodyTypeMap) { + HttpResponseFormatter.Builder builder = new HttpResponseFormatter.Builder(response.getStatus(), getStatusLine(response)); + ofNullable(response.getHeaders()).ifPresent(headers -> headers.forEach((key, values) -> ofNullable(values).orElseGet(Collections::emptyList) + .forEach(value -> builder.addHeader(key, value)))); + ofNullable(response.getCookies()).orElseGet(Collections::emptyMap).forEach((name, cookie) -> builder.addCookie( + name, + toStringValue(cookie.get("value")), + toStringValue(cookie.get("comment")), + toStringValue(cookie.get("path")), + toStringValue(cookie.get("domain")), + toLongValue(cookie.get("maxAge")), + toBooleanValue(cookie.get("secure")), + toBooleanValue(cookie.get("httpOnly")), + toInstantValue(cookie.get("expires")), + toIntegerValue(cookie.get("version")), + toStringValue(cookie.get("sameSite")) + )); + builder.headerConverter(headerConverter).cookieConverter(cookieConverter).prettifiers(prettifiers); + Object body = response.getBody(); + if (body == null) { + return builder.build(); + } + String contentType = response.getContentType(); + String mimeType = HttpFormatUtils.getMimeType(contentType); + BodyType bodyType = HttpFormatUtils.getBodyType(contentType, bodyTypeMap); + if (BodyType.TEXT == bodyType) { + builder.bodyText(mimeType, response.getBodyString()); + } else { + builder.bodyBytes(mimeType, response.getBodyBytes()); + } + return builder.build(); + } + + @Nonnull + private static List toParts(@Nonnull HttpRequest request, @Nonnull Map bodyTypeMap, + @Nullable Function partHeaderConverter) { + Map>> multipartMap = request.getMultiParts(); + if (multipartMap == null || multipartMap.isEmpty()) { + return Collections.emptyList(); + } + List parts = new ArrayList<>(); + multipartMap.values().stream().filter(Objects::nonNull).flatMap(List::stream).forEach(part -> { + String partMimeType = ofNullable(part.get("contentType")).map(Object::toString).orElse("application/octet-stream"); + Object value = part.get("value"); + BodyType partBodyType = HttpFormatUtils.getBodyType(partMimeType, bodyTypeMap); + HttpPartFormatter.PartType partType = + BodyType.TEXT == partBodyType ? HttpPartFormatter.PartType.TEXT : HttpPartFormatter.PartType.BINARY; + Object payload = partType == HttpPartFormatter.PartType.TEXT ? toTextValue(value) : toBinaryValue(value); + HttpPartFormatter.Builder partBuilder = new HttpPartFormatter.Builder(partType, partMimeType, payload); + partBuilder.controlName(ofNullable(part.get("name")).map(Object::toString).orElse(null)); + partBuilder.charset(ofNullable(part.get("charset")).map(Object::toString).orElse(null)); + partBuilder.fileName(ofNullable(part.get("filename")).map(Object::toString).orElse(null)); + partBuilder.headerConverter(partHeaderConverter); + parts.add(partBuilder.build()); + }); + return parts; + } + + @Nonnull + private static String getStatusLine(@Nonnull HttpResponse response) { + return isNotBlank(response.getStatusText()) ? + response.getStatus() + " " + response.getStatusText() : + Integer.toString(response.getStatus()); + } + + @Nonnull + private static String toTextValue(@Nullable Object value) { + if (value == null) { + return ""; + } + if (value instanceof byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } + return value.toString(); + } + + @Nonnull + private static byte[] toBinaryValue(@Nullable Object value) { + if (value == null) { + return new byte[0]; + } + if (value instanceof byte[] bytes) { + return bytes; + } + return value.toString().getBytes(StandardCharsets.UTF_8); + } + + @Nullable + private static String toStringValue(@Nullable Object value) { + return value == null ? null : value.toString(); + } + + @Nullable + private static Long toLongValue(@Nullable Object value) { + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.longValue(); + } + try { + return Long.parseLong(value.toString()); + } catch (NumberFormatException ignored) { + return null; + } + } + + @Nullable + private static Integer toIntegerValue(@Nullable Object value) { + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.intValue(); + } + try { + return Integer.parseInt(value.toString()); + } catch (NumberFormatException ignored) { + return null; + } + } + + @Nullable + private static Boolean toBooleanValue(@Nullable Object value) { + if (value == null) { + return null; + } + if (value instanceof Boolean b) { + return b; + } + return Boolean.parseBoolean(value.toString()); + } + + @Nullable + private static Instant toInstantValue(@Nullable Object value) { + if (value == null) { + return null; + } + if (value instanceof Instant instant) { + return instant; + } + try { + return Instant.parse(value.toString()); + } catch (DateTimeParseException ignored) { + return null; + } + } +} diff --git a/src/test/java/com/epam/reportportal/karate/KarateTest.java b/src/test/java/com/epam/reportportal/karate/KarateTest.java deleted file mode 100644 index dc64830..0000000 --- a/src/test/java/com/epam/reportportal/karate/KarateTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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; - -import com.intuit.karate.Results; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class KarateTest { - @Test - void testParallel() { - Results results = KarateReportPortalRunner.path("classpath:feature") - .outputCucumberJson(true) - .tags("~@ignore", "@To_run") - .parallel(2); - assertEquals(0, results.getFailCount()); - assertEquals(0, results.getErrors().size()); - assertTrue(results.getSuite().parallel); - assertEquals(2, results.getScenariosTotal()); - } -} \ No newline at end of file diff --git a/src/test/java/com/epam/reportportal/karate/ReportPortalPublisherTest.java b/src/test/java/com/epam/reportportal/karate/ReportPortalPublisherTest.java deleted file mode 100644 index 8054d95..0000000 --- a/src/test/java/com/epam/reportportal/karate/ReportPortalPublisherTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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; - -import com.epam.reportportal.karate.utils.ReflectUtils; -import com.epam.reportportal.listeners.ListenerParameters; -import com.epam.reportportal.service.Launch; -import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; -import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.core.Feature; -import com.intuit.karate.core.FeatureResult; -import com.intuit.karate.resource.Resource; -import io.reactivex.Maybe; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.concurrent.ConcurrentHashMap; - -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -public class ReportPortalPublisherTest { - @Mock - Launch launchMock; - private ReportPortalPublisher reportPortalPublisher; - - @BeforeEach - public void setUp() { - reportPortalPublisher = new ReportPortalPublisher(() -> launchMock); - } - - @Test - public void shouldStartLaunch() { - reportPortalPublisher.startLaunch(); - verify(launchMock, times(1)).start(); - } - - @Test - public void shouldFinishLaunch() { - when(launchMock.getParameters()).thenReturn(getListenerParameters()); - when(launchMock.getLaunch()).thenReturn(Maybe.just("launchUuid")); - reportPortalPublisher.finishLaunch(); - verify(launchMock, times(1)).finish(any(FinishExecutionRQ.class)); - } - - @SuppressWarnings("unchecked") - @Test - public void shouldStartFeature() throws URISyntaxException { - FeatureResult featureResult = mock(FeatureResult.class); - Feature feature = mock(Feature.class); - Resource resource = mock(Resource.class); - when(featureResult.getFeature()).thenReturn(feature); - when(featureResult.getCallNameForReport()).thenReturn("featureName"); - when(feature.getResource()).thenReturn(resource); - when(resource.getUri()).thenReturn(new URI("file:///feature/simple.feature")); - when(launchMock.startTestItem(any(StartTestItemRQ.class))).thenReturn(mock(Maybe.class)); - reportPortalPublisher.startFeature(featureResult); - verify(launchMock, times(1)).startTestItem(any(StartTestItemRQ.class)); - } - - @SuppressWarnings("unchecked") - @Test - public void shouldFinishFeature() throws NoSuchFieldException { - FeatureResult featureResult = mock(FeatureResult.class); - when(featureResult.getCallNameForReport()).thenReturn("featureName"); - ConcurrentHashMap> featureIdMap = new ConcurrentHashMap<>(); - featureIdMap.put("featureName", mock(Maybe.class)); - ReflectUtils.setField(reportPortalPublisher, ReportPortalPublisher.class.getDeclaredField("featureIdMap"), featureIdMap); - reportPortalPublisher.finishFeature(featureResult); - verify(launchMock, times(1)).finishTestItem(any(Maybe.class), any(FinishTestItemRQ.class)); - } - - private ListenerParameters getListenerParameters() { - ListenerParameters parameters = new ListenerParameters(); - parameters.setLaunchName("launch"); - parameters.setBaseUrl("url"); - parameters.setProjectName("project"); - System.setProperty("rp.launch.id", "launchId"); - return parameters; - } -} diff --git a/src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.java index aa0573b..e4fa796 100644 --- a/src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.java +++ b/src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -58,13 +58,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_different_attributes(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java index c419888..d52833a 100644 --- a/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java +++ b/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java @@ -23,7 +23,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -63,13 +63,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void verify_start_launch_request_contains_launch_attributes(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(startCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java index 9ae4a8b..1bd64f6 100644 --- a/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java +++ b/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -55,13 +55,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_different_attributes(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java index 23664a9..a8e8aeb 100644 --- a/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java +++ b/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -57,13 +57,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void verify_start_launch_request_contains_system_attributes(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(startCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java b/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java index df30ea9..9be0687 100644 --- a/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java @@ -22,8 +22,8 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; -import com.intuit.karate.core.Background; +import io.karatelabs.core.SuiteResult; +import io.karatelabs.gherkin.Background; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -45,7 +45,7 @@ public class BackgroundExamplesTest { private static final String TEST_FEATURE = "classpath:feature/background_examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List scenarioIds = Stream.generate(() -> CommonUtils.namedId("scenario_")).limit(2).collect(Collectors.toList()); + private final List scenarioIds = Stream.generate(() -> CommonUtils.namedId("scenario_")).limit(2).toList(); private final List>> scenarioSteps = scenarioIds.stream() .map(s -> Pair.of(s, Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()))) @@ -68,13 +68,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_background_steps(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(captor.capture()); @@ -115,6 +115,6 @@ public void test_background_steps(boolean report) { Set nestedStepNames = nestedSteps.stream().map(StartTestItemRQ::getName).collect(Collectors.toSet()); assertThat(nestedStepNames, hasSize(1)); - assertThat(nestedStepNames, hasItem("Given def varb = 2")); + assertThat(nestedStepNames, hasItem("Given varb = 2")); } } diff --git a/src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java b/src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java index 6a6aaac..b23f484 100644 --- a/src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java @@ -22,8 +22,8 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; -import com.intuit.karate.core.Background; +import io.karatelabs.core.SuiteResult; +import io.karatelabs.gherkin.Background; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -63,13 +63,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_background_steps(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(captor.capture()); @@ -88,7 +88,7 @@ public void test_background_steps(boolean report) { .filter(s -> s.getName().startsWith(Background.KEYWORD)) .collect(Collectors.toList()); assertThat(backgroundSteps, hasSize(1)); - StartTestItemRQ backgroundStep = backgroundSteps.get(0); + StartTestItemRQ backgroundStep = backgroundSteps.getFirst(); assertThat(backgroundStep.getName(), equalTo(Background.KEYWORD)); // No name for Background in Karate assertThat(backgroundStep.isHasStats(), equalTo(Boolean.FALSE)); assertThat(backgroundStep.getStartTime(), notNullValue()); @@ -96,8 +96,8 @@ public void test_background_steps(boolean report) { List nestedSteps = nestedStepCaptor.getAllValues(); assertThat(nestedSteps, hasSize(1)); - StartTestItemRQ nestedStep = nestedSteps.get(0); - assertThat(nestedStep.getName(), equalTo("Given def four = 4")); + StartTestItemRQ nestedStep = nestedSteps.getFirst(); + assertThat(nestedStep.getName(), equalTo("Given four = 4")); assertThat(nestedStep.isHasStats(), equalTo(Boolean.FALSE)); } } diff --git a/src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java b/src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java index 67bd971..4a2a8cf 100644 --- a/src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java @@ -22,8 +22,8 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; -import com.intuit.karate.core.Background; +import io.karatelabs.core.SuiteResult; +import io.karatelabs.gherkin.Background; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -65,13 +65,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_background_steps(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(captor.capture()); @@ -90,7 +90,7 @@ public void test_background_steps(boolean report) { .filter(s -> s.getName().startsWith(Background.KEYWORD)) .collect(Collectors.toList()); assertThat(backgroundSteps, hasSize(1)); - StartTestItemRQ backgroundStep = backgroundSteps.get(0); + StartTestItemRQ backgroundStep = backgroundSteps.getFirst(); assertThat(backgroundStep.getName(), equalTo(Background.KEYWORD)); // No name for Background in Karate assertThat(backgroundStep.isHasStats(), equalTo(Boolean.FALSE)); assertThat(backgroundStep.getStartTime(), notNullValue()); @@ -101,6 +101,6 @@ public void test_background_steps(boolean report) { nestedSteps.forEach(step -> assertThat(step.isHasStats(), equalTo(Boolean.FALSE))); Set nestedStepNames = nestedSteps.stream().map(StartTestItemRQ::getName).collect(Collectors.toSet()); - assertThat(nestedStepNames, allOf(hasItem("Given def vara = 2"), hasItem("And def varb = 2"))); + assertThat(nestedStepNames, allOf(hasItem("Given vara = 2"), hasItem("And varb = 2"))); } } diff --git a/src/test/java/com/epam/reportportal/karate/call/CallTheSameFeatureWithParametersHookTest.java b/src/test/java/com/epam/reportportal/karate/call/CallTheSameFeatureWithParametersHookTest.java index 220bce7..595c185 100644 --- a/src/test/java/com/epam/reportportal/karate/call/CallTheSameFeatureWithParametersHookTest.java +++ b/src/test/java/com/epam/reportportal/karate/call/CallTheSameFeatureWithParametersHookTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,7 +54,7 @@ public class CallTheSameFeatureWithParametersHookTest { private final String innerScenarioId = CommonUtils.namedId("scenario_step_"); private final List innerStepIds = Stream.generate(() -> CommonUtils.namedId("inner_step_")) .limit(4) - .collect(Collectors.toList()); + .toList(); private final List>>>> features = Stream.of(Pair.of( featureId, @@ -81,8 +81,8 @@ public void setupMock() { @Test @Timeout(value = 30, threadMode = Timeout.ThreadMode.SEPARATE_THREAD) public void test_call_feature_with_parameters_hook_reporting() { - Results results = TestUtils.runAsHook(rp, TEST_FEATURE); - assertThat(results.getFailCount(), equalTo(0)); + SuiteResult results = TestUtils.runAsEventListener(rp, TEST_FEATURE); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/call/CallWithParametersHookTest.java b/src/test/java/com/epam/reportportal/karate/call/CallWithParametersHookTest.java index 44975a6..ecee14f 100644 --- a/src/test/java/com/epam/reportportal/karate/call/CallWithParametersHookTest.java +++ b/src/test/java/com/epam/reportportal/karate/call/CallWithParametersHookTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,7 +56,7 @@ public class CallWithParametersHookTest { private final String innerScenarioId = CommonUtils.namedId("scenario_step_"); private final List innerStepIds = Stream.generate(() -> CommonUtils.namedId("inner_step_")) .limit(3) - .collect(Collectors.toList()); + .toList(); private final List>>>> features = Stream.of(Pair.of( featureId, @@ -82,8 +82,8 @@ public void setupMock() { @Test public void test_call_feature_with_parameters_hook_reporting() { - Results results = TestUtils.runAsHook(rp, TEST_FEATURE); - assertThat(results.getFailCount(), equalTo(0)); + SuiteResult results = TestUtils.runAsEventListener(rp, TEST_FEATURE); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); @@ -102,6 +102,6 @@ public void test_call_feature_with_parameters_hook_reporting() { .findAny() .orElseThrow(); - assertThat(calledFeature.getDescription(), allOf(endsWith("feature/called.feature"), startsWith(PARAMETERS_DESCRIPTION_PATTERN))); + assertThat(calledFeature.getDescription(), allOf(endsWith("build/resources/test/feature/called.feature"), startsWith(PARAMETERS_DESCRIPTION_PATTERN))); } } diff --git a/src/test/java/com/epam/reportportal/karate/call/CallWithParametersPublisherTest.java b/src/test/java/com/epam/reportportal/karate/call/CallWithParametersPublisherTest.java index 60ffd5b..64a70c7 100644 --- a/src/test/java/com/epam/reportportal/karate/call/CallWithParametersPublisherTest.java +++ b/src/test/java/com/epam/reportportal/karate/call/CallWithParametersPublisherTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -52,8 +52,8 @@ public void setupMock() { @Test public void test_call_feature_with_parameters_publisher_reporting() { - Results results = TestUtils.runAsReport(rp, TEST_FEATURE); - assertThat(results.getFailCount(), equalTo(0)); + SuiteResult results = TestUtils.runAsResultListener(rp, TEST_FEATURE); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java index 0975f38..6e8de8e 100644 --- a/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java +++ b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -45,7 +45,7 @@ public class ExamplesCodeRefTest { private static final String FIRST_EXAMPLE_CODE_REFERENCE = String.format(EXAMPLE_CODE_REFERENCE_PATTERN, "result:4;vara:2;varb:2"); private static final String SECOND_EXAMPLE_CODE_REFERENCE = String.format(EXAMPLE_CODE_REFERENCE_PATTERN, "result:3;vara:1;varb:2"); private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -61,13 +61,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_code_reference(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); @@ -82,7 +82,7 @@ public void test_examples_code_reference(boolean report) { assertThat(featureRq.getType(), allOf(notNullValue(), equalTo(ItemType.STORY.name()))); List scenarios = scenarioCaptor.getAllValues(); - StartTestItemRQ firstScenarioRq = scenarios.get(0); + StartTestItemRQ firstScenarioRq = scenarios.getFirst(); assertThat(firstScenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); assertThat(firstScenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_CODE_REFERENCE))); diff --git a/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java b/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java index 4285363..a37e20a 100644 --- a/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java +++ b/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -56,13 +56,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_scenario_code_reference(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.java b/src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.java index d7ca77b..e49a313 100644 --- a/src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -52,7 +52,7 @@ public class DescriptionExamplesTest { ); private static final String TEST_FEATURE = "classpath:feature/description_examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -68,13 +68,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java index b71479d..9fd0f0e 100644 --- a/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -60,13 +60,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void verify_start_launch_request_contains_launch_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(startCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java index 55cf9a7..e275aa7 100644 --- a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -47,7 +47,7 @@ public class NoDescriptionExamplesTest { public static final String FIRST_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  2   |  2   |   4    |"; public static final String SECOND_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  1   |  2   |   3    |"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -63,13 +63,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_no_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java index 6effb32..dd57aa6 100644 --- a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -56,13 +56,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_description_for_all_possible_items(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(featureCaptor.capture()); @@ -72,7 +72,7 @@ public void test_description_for_all_possible_items(boolean report) { verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); StartTestItemRQ featureStart = featureCaptor.getValue(); - assertThat(featureStart.getDescription(), endsWith("feature/simple.feature")); + assertThat(featureStart.getDescription(), endsWith("build/resources/test/feature/simple.feature")); StartTestItemRQ scenarioStart = scenarioCaptor.getValue(); assertThat(scenarioStart.getDescription(), emptyString()); diff --git a/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java index f54dab8..861bc6b 100644 --- a/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -66,13 +66,13 @@ public void verify_start_launch_request_contains_no_launch_description(boolean r ListenerParameters parameters = standardParameters(); parameters.setDescription(description); ReportPortal rp = ReportPortal.create(client, parameters, testExecutor()); - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(startCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogTest.java b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogTest.java index 13f9eff..16f7022 100644 --- a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogTest.java @@ -23,7 +23,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -37,14 +37,18 @@ import static com.epam.reportportal.karate.utils.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.*; public class ScenarioDescriptionErrorLogTest { - public static final String ERROR = "did not evaluate to 'true': actualFour != four\nclasspath:feature/simple_failed.feature:6"; - public static final String ERROR_MESSAGE = "Then assert actualFour != four\n" + ERROR; - public static final String DESCRIPTION_ERROR_LOG = "Error:\n" + ERROR; + public static final String ERROR = "/feature/simple_failed.feature:6 actualFour != four"; + public static final String ERROR_MESSAGE = """ + Then actualFour != four + assert failed: actualFour != four"""; + public static final String DESCRIPTION_ERROR_LOG = "Error:\n"; private static final String TEST_FEATURE = "classpath:feature/simple_failed.feature"; private final String launchUuid = CommonUtils.namedId("launch_"); private final String featureId = CommonUtils.namedId("feature_"); @@ -62,13 +66,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_error_log_in_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); @SuppressWarnings("unchecked") ArgumentCaptor> logCaptor = ArgumentCaptor.forClass(List.class); @@ -80,7 +84,7 @@ public void test_error_log_in_description(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThan(0))); - SaveLogRQ log = logs.get(logs.size() - 1); + SaveLogRQ log = logs.getLast(); assertThat(log.getItemUuid(), oneOf(stepIds.toArray(new String[0]))); assertThat(log.getLaunchUuid(), equalTo(launchUuid)); assertThat(log.getMessage(), equalTo(ERROR_MESSAGE)); @@ -89,7 +93,7 @@ public void test_error_log_in_description(boolean report) { verify(client, times(1)).finishTestItem(same(scenarioId), scenarioCaptorFinish.capture()); List scenarios = scenarioCaptorFinish.getAllValues(); - FinishTestItemRQ scenario = scenarios.get(0); - assertThat(scenario.getDescription(), allOf(notNullValue(), equalTo(DESCRIPTION_ERROR_LOG))); + FinishTestItemRQ scenario = scenarios.getFirst(); + assertThat(scenario.getDescription(), allOf(notNullValue(), startsWith(DESCRIPTION_ERROR_LOG), endsWith(ERROR))); } } diff --git a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionAndExamplesTest.java b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionAndExamplesTest.java index 189c7af..b27ceab 100644 --- a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionAndExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionAndExamplesTest.java @@ -25,7 +25,7 @@ import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; @@ -39,41 +39,31 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.epam.reportportal.karate.ReportPortalUtils.MARKDOWN_DELIMITER_PATTERN; import static com.epam.reportportal.karate.utils.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.*; public class ScenarioDescriptionErrorLogWithDescriptionAndExamplesTest { - public static final String MARKDOWN_DELIMITER_PATTERN_THREE_ARGS = "%s\n\n---\n\n%s\n\n---\n\n%s"; - public static final String ERROR = "did not evaluate to 'true': mathResult == 5\nclasspath:feature/simple_failed_description_examples.feature:8"; - public static final String ERROR_MESSAGE = "Then assert mathResult == 5\n" + ERROR; - public static final String DESCRIPTION_ERROR_LOG = "Error:\n" + ERROR; - public static final String DESCRIPTION = "This is my Scenario description."; + public static final String ERROR_END = "build/resources/test/feature/simple_failed_description_examples.feature:8 mathResult == 5"; + public static final String ERROR_MESSAGE = """ + Then mathResult == 5 + assert failed: mathResult == 5"""; + public static final String DESCRIPTION_STRING = "This is my Scenario description."; + public static final String ERROR = "Error:\n"; private static final String EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN = "Parameters:\n\n" + MarkdownUtils.TABLE_INDENT + "| vara | varb | result |\n" + MarkdownUtils.TABLE_INDENT + "|------|------|--------|\n" + MarkdownUtils.TABLE_INDENT; public static final String FIRST_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  2   |  2   |   4    |"; public static final String SECOND_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  1   |  2   |   5    |"; - public static final String FIRST_EXAMPLE_DESCRIPTION_WITHOUT_ERROR_LOG = String.format( - MARKDOWN_DELIMITER_PATTERN, - FIRST_EXAMPLE_DESCRIPTION, - DESCRIPTION - ); - public static final String SECOND_EXAMPLE_DESCRIPTION_WITH_ERROR_LOG = String.format( - MARKDOWN_DELIMITER_PATTERN_THREE_ARGS, - SECOND_EXAMPLE_DESCRIPTION, - DESCRIPTION, - DESCRIPTION_ERROR_LOG - ); - private static final String TEST_FEATURE = "classpath:feature/simple_failed_description_examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -90,15 +80,15 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_error_log_and_examples_in_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); @SuppressWarnings("unchecked") ArgumentCaptor> logCaptor = ArgumentCaptor.forClass(List.class); @@ -110,7 +100,7 @@ public void test_error_log_and_examples_in_description(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThan(0))); - SaveLogRQ log = logs.get(logs.size() - 1); + SaveLogRQ log = logs.getLast(); assertThat(log.getMessage(), equalTo(ERROR_MESSAGE)); ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); @@ -121,14 +111,26 @@ public void test_error_log_and_examples_in_description(boolean report) { stepIds.size(), ArgumentCaptor.forClass(FinishTestItemRQ.class) )); - stepIds.forEach(pair -> pair.getValue().forEach(id -> verify(client).finishTestItem(same(id), stepCaptors.get(0).capture()))); + stepIds.forEach(pair -> pair.getValue().forEach(id -> verify(client).finishTestItem(same(id), stepCaptors.getFirst().capture()))); - FinishTestItemRQ firstScenarioRq = scenarioCaptor.getAllValues().get(0); + FinishTestItemRQ firstScenarioRq = scenarioCaptor.getAllValues().getFirst(); assertThat(firstScenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); - assertThat(firstScenarioRq.getDescription(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_DESCRIPTION_WITHOUT_ERROR_LOG))); + assertThat( + firstScenarioRq.getDescription(), + allOf(notNullValue(), equalTo(MarkdownUtils.asTwoParts(FIRST_EXAMPLE_DESCRIPTION, DESCRIPTION_STRING))) + ); FinishTestItemRQ secondScenarioRq = scenarioCaptor.getAllValues().get(1); assertThat(secondScenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.FAILED.name()))); - assertThat(secondScenarioRq.getDescription(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_DESCRIPTION_WITH_ERROR_LOG))); + assertThat( + secondScenarioRq.getDescription(), allOf( + notNullValue(), + startsWith(MarkdownUtils.asTwoParts( + SECOND_EXAMPLE_DESCRIPTION, + MarkdownUtils.asTwoParts(DESCRIPTION_STRING, ERROR) + )), + endsWith(ERROR_END) + ) + ); } } diff --git a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionTest.java index 3b39320..f7827a2 100644 --- a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithDescriptionTest.java @@ -21,9 +21,10 @@ import com.epam.reportportal.service.ReportPortal; import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; +import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -34,24 +35,22 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.epam.reportportal.karate.ReportPortalUtils.MARKDOWN_DELIMITER_PATTERN; import static com.epam.reportportal.karate.utils.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.endsWith; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.*; public class ScenarioDescriptionErrorLogWithDescriptionTest { - public static final String ERROR = "did not evaluate to 'true': actualFour != four\nclasspath:feature/simple_failed_description.feature:9"; - public static final String ERROR_MESSAGE = "Then assert actualFour != four\n" + ERROR; - public static final String DESCRIPTION_ERROR_LOG = "Error:\n" + ERROR; + public static final String ERROR = "/feature/simple_failed_description.feature:9 actualFour != four"; + public static final String ERROR_MESSAGE = """ + Then actualFour != four + assert failed: actualFour != four"""; + public static final String DESCRIPTION_ERROR_LOG = "Error:\n"; public static final String DESCRIPTION = "This is my Scenario description."; - public static final String DESCRIPTION_ERROR_LOG_WITH_DESCRIPTION = String.format( - MARKDOWN_DELIMITER_PATTERN, - DESCRIPTION, - DESCRIPTION_ERROR_LOG - ); private static final String TEST_FEATURE = "classpath:feature/simple_failed_description.feature"; private final String launchUuid = CommonUtils.namedId("launch_"); private final String featureId = CommonUtils.namedId("feature_"); @@ -69,13 +68,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_error_log_and_description_in_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); @SuppressWarnings("unchecked") ArgumentCaptor> logCaptor = ArgumentCaptor.forClass(List.class); @@ -87,7 +86,7 @@ public void test_error_log_and_description_in_description(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThan(0))); - SaveLogRQ log = logs.get(logs.size() - 1); + SaveLogRQ log = logs.getLast(); assertThat(log.getItemUuid(), oneOf(stepIds.toArray(new String[0]))); assertThat(log.getLaunchUuid(), equalTo(launchUuid)); assertThat(log.getMessage(), equalTo(ERROR_MESSAGE)); @@ -96,8 +95,11 @@ public void test_error_log_and_description_in_description(boolean report) { verify(client, times(1)).finishTestItem(same(scenarioId), scenarioCaptorFinish.capture()); List scenarios = scenarioCaptorFinish.getAllValues(); - FinishTestItemRQ scenario = scenarios.get(0); + FinishTestItemRQ scenario = scenarios.getFirst(); - assertThat(scenario.getDescription(), allOf(notNullValue(), equalTo(DESCRIPTION_ERROR_LOG_WITH_DESCRIPTION))); + assertThat( + scenario.getDescription(), + allOf(notNullValue(), startsWith(MarkdownUtils.asTwoParts(DESCRIPTION, DESCRIPTION_ERROR_LOG)), endsWith(ERROR)) + ); } } diff --git a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithExamplesTest.java b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithExamplesTest.java index 8cd7503..22c0ba6 100644 --- a/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/ScenarioDescriptionErrorLogWithExamplesTest.java @@ -25,7 +25,7 @@ import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; @@ -39,33 +39,30 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.epam.reportportal.karate.ReportPortalUtils.MARKDOWN_DELIMITER_PATTERN; import static com.epam.reportportal.karate.utils.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.*; public class ScenarioDescriptionErrorLogWithExamplesTest { - public static final String ERROR = "did not evaluate to 'true': mathResult == 5\nclasspath:feature/simple_failed_examples.feature:5"; - public static final String ERROR_MESSAGE = "Then assert mathResult == 5\n" + ERROR; - public static final String DESCRIPTION_ERROR_LOG = "Error:\n" + ERROR; + public static final String ERROR = "/feature/simple_failed_examples.feature:5 mathResult == 5"; + public static final String ERROR_MESSAGE = """ + Then mathResult == 5 + assert failed: mathResult == 5"""; private static final String EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN = "Parameters:\n\n" + MarkdownUtils.TABLE_INDENT + "| vara | varb | result |\n" + MarkdownUtils.TABLE_INDENT + "|------|------|--------|\n" + MarkdownUtils.TABLE_INDENT; public static final String FIRST_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  2   |  2   |   4    |"; public static final String SECOND_EXAMPLE_DESCRIPTION = EXAMPLE_PARAMETERS_DESCRIPTION_PATTERN + "|  1   |  2   |   5    |"; - public static final String SECOND_EXAMPLE_DESCRIPTION_WITH_ERROR_LOG = String.format( - MARKDOWN_DELIMITER_PATTERN, - SECOND_EXAMPLE_DESCRIPTION, - DESCRIPTION_ERROR_LOG - ); - private static final String TEST_FEATURE = "classpath:feature/simple_failed_examples.feature"; + public static final String DESCRIPTION_ERROR_LOG = "Error:\n"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -82,15 +79,15 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_error_log_and_examples_in_description(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); @SuppressWarnings("unchecked") ArgumentCaptor> logCaptor = ArgumentCaptor.forClass(List.class); @@ -102,7 +99,7 @@ public void test_error_log_and_examples_in_description(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThan(0))); - SaveLogRQ log = logs.get(logs.size() - 1); + SaveLogRQ log = logs.getLast(); assertThat(log.getMessage(), equalTo(ERROR_MESSAGE)); ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); @@ -113,14 +110,20 @@ public void test_error_log_and_examples_in_description(boolean report) { stepIds.size(), ArgumentCaptor.forClass(FinishTestItemRQ.class) )); - stepIds.forEach(pair -> pair.getValue().forEach(id -> verify(client).finishTestItem(same(id), stepCaptors.get(0).capture()))); + stepIds.forEach(pair -> pair.getValue().forEach(id -> verify(client).finishTestItem(same(id), stepCaptors.getFirst().capture()))); - FinishTestItemRQ firstScenarioRq = scenarioCaptor.getAllValues().get(0); + FinishTestItemRQ firstScenarioRq = scenarioCaptor.getAllValues().getFirst(); assertThat(firstScenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); assertThat(firstScenarioRq.getDescription(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_DESCRIPTION))); FinishTestItemRQ secondScenarioRq = scenarioCaptor.getAllValues().get(1); assertThat(secondScenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.FAILED.name()))); - assertThat(secondScenarioRq.getDescription(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_DESCRIPTION_WITH_ERROR_LOG))); + assertThat( + secondScenarioRq.getDescription(), allOf( + notNullValue(), + startsWith(MarkdownUtils.asTwoParts(SECOND_EXAMPLE_DESCRIPTION, DESCRIPTION_ERROR_LOG)), + endsWith(ERROR) + ) + ); } } diff --git a/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java index f328579..002679c 100644 --- a/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java @@ -21,8 +21,8 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; -import com.intuit.karate.core.Background; +import io.karatelabs.core.SuiteResult; +import io.karatelabs.gherkin.Background; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -62,13 +62,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_description_for_all_possible_items(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(featureCaptor.capture()); @@ -78,7 +78,7 @@ public void test_description_for_all_possible_items(boolean report) { verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); StartTestItemRQ featureStart = featureCaptor.getValue(); - assertThat(featureStart.getDescription(), endsWith("feature/description.feature\n\n---\n\nThis is my Feature description.")); + assertThat(featureStart.getDescription(), endsWith("build/resources/test/feature/description.feature\n\n---\n\nThis is my Feature description.")); StartTestItemRQ scenarioStart = scenarioCaptor.getValue(); assertThat(scenarioStart.getDescription(), equalTo(SCENARIO_DESCRIPTION)); @@ -88,7 +88,7 @@ public void test_description_for_all_possible_items(boolean report) { .filter(s -> s.getName().startsWith(Background.KEYWORD)) .collect(Collectors.toList()); assertThat(backgroundSteps, hasSize(1)); - StartTestItemRQ backgroundStep = backgroundSteps.get(0); + StartTestItemRQ backgroundStep = backgroundSteps.getFirst(); assertThat( "No support of Background description in Karate yet. But this is a part of Gherkin standard.", backgroundStep.getDescription(), diff --git a/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java b/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java index 0da55a9..15c550f 100644 --- a/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java +++ b/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -44,7 +44,7 @@ public class ExamplesTestCaseIdTest { private static final String FIRST_EXAMPLE_TEST_CASE_ID = String.format(EXAMPLE_TEST_CASE_ID_PATTERN, "result:4;vara:2;varb:2"); private static final String SECOND_EXAMPLE_TEST_CASE_ID = String.format(EXAMPLE_TEST_CASE_ID_PATTERN, "result:3;vara:1;varb:2"); private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -60,13 +60,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_test_case_id(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java b/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java index 9084271..d9c85a7 100644 --- a/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java +++ b/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -55,13 +55,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_test_case_id(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java b/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java index 3e37dcb..806efe0 100644 --- a/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java +++ b/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -57,13 +57,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void verify_start_launch_request_contains_required_fields(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(startCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/logging/EmbedLoggingTest.java b/src/test/java/com/epam/reportportal/karate/logging/EmbedLoggingTest.java index bd2cb58..0a2f954 100644 --- a/src/test/java/com/epam/reportportal/karate/logging/EmbedLoggingTest.java +++ b/src/test/java/com/epam/reportportal/karate/logging/EmbedLoggingTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; @@ -37,7 +37,8 @@ import static com.epam.reportportal.karate.utils.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; public class EmbedLoggingTest { private static final String TEST_FEATURE = "classpath:feature/embed.feature"; @@ -59,13 +60,13 @@ public void setupMock() { @ValueSource(booleans = { true, false }) @SuppressWarnings({ "unchecked", "rawtypes" }) public void test_embed_image_attachment(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); verify(client).log(logCaptor.capture()); @@ -84,7 +85,7 @@ public void test_embed_image_attachment(boolean report) { assertThat("Should have one attachment log message", attachmentLogs, hasSize(1)); // Verify the attachment log properties - SaveLogRQ attachmentLog = attachmentLogs.get(0); + SaveLogRQ attachmentLog = attachmentLogs.getFirst(); assertThat("Attachment log should have INFO level", attachmentLog.getLevel(), equalTo(LogLevel.INFO.name())); assertThat("Attachment log should have item UUID", attachmentLog.getItemUuid(), notNullValue()); assertThat("Attachment log should have log time", attachmentLog.getLogTime(), notNullValue()); @@ -95,8 +96,8 @@ public void test_embed_image_attachment(boolean report) { .flatMap(rq -> extractBinaryParts((List) rq).stream()) .collect(Collectors.toList()); assertThat(attachments, hasSize(1)); - assertThat(attachments.get(0).getKey(), equalTo("image/png")); - assertThat(attachments.get(0).getValue().length, greaterThan(0)); + assertThat(attachments.getFirst().getKey(), equalTo("image/png")); + assertThat(attachments.getFirst().getValue().length, greaterThan(0)); } } diff --git a/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java b/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java index 7079575..4684488 100644 --- a/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java +++ b/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java @@ -22,11 +22,10 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.util.List; @@ -40,6 +39,16 @@ public class HttpRequestLoggingTest { private static final String TEST_FEATURE = "classpath:feature/http_request.feature"; + private static final String DOCSTRING_LOG_ENTRY = """ + Docstring: + + ``` + { + username: 'user', + password: 'password', + grant_type: 'password' + } + ```"""; private final String launchUuid = CommonUtils.namedId("launch_"); private final String featureId = CommonUtils.namedId("feature_"); private final String scenarioId = CommonUtils.namedId("scenario_"); @@ -54,18 +63,8 @@ public void setupMock() { mockBatchLogging(client); } - @ParameterizedTest - @ValueSource(booleans = { true, false }) @SuppressWarnings({ "unchecked", "rawtypes" }) - public void test_http_request_logging(boolean report) { - Results results; - if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); - } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); - } - assertThat(results.getFailCount(), equalTo(1)); - + private List extractMessages() { ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); verify(client, atLeastOnce()).log(logCaptor.capture()); List logs = logCaptor.getAllValues() @@ -75,13 +74,26 @@ public void test_http_request_logging(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThanOrEqualTo(2))); - List messages = logs.stream().map(SaveLogRQ::getMessage).collect(Collectors.toList()); - assertThat( - messages, hasItems( - equalTo("Docstring:\n\n```\n{\n" + " username: 'user',\n" + " password: 'password',\n" - + " grant_type: 'password'\n" + "}\n```"), - containsString("{\"username\":\"user\",\"password\":\"password\",\"grant_type\":\"password\"}") - ) - ); + return logs.stream().map(SaveLogRQ::getMessage).collect(Collectors.toList()); + } + + @Test + public void test_http_request_logging_result_listener() { + SuiteResult results = TestUtils.runAsResultListener(rp, TEST_FEATURE); + assertThat(results.getFeatureFailedCount(), equalTo(1)); + List messages = extractMessages(); + assertThat(messages, hasItem(equalTo(DOCSTRING_LOG_ENTRY))); + assertThat(messages, hasItem(containsString("{\"username\":\"user\",\"password\":\"password\",\"grant_type\":\"password\"}"))); + } + + @Test + public void test_http_request_logging_run_listener() { + SuiteResult results = TestUtils.runAsEventListener(rp, TEST_FEATURE); + assertThat(results.getFeatureFailedCount(), equalTo(1)); + List messages = extractMessages(); + assertThat(messages, hasItem(equalTo(DOCSTRING_LOG_ENTRY))); + assertThat(messages, hasItem(containsString("**>>> REQUEST**"))); + assertThat(messages, hasItem(containsString("**<<< RESPONSE**"))); + assertThat(messages, hasItem(containsString("\"username\" : \"user\""))); } } diff --git a/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java b/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java index 7699d95..0bbbdaf 100644 --- a/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java +++ b/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -58,13 +58,13 @@ public void setupMock() { @ValueSource(booleans = { true, false }) @SuppressWarnings({ "unchecked", "rawtypes" }) public void test_simple_one_step_failed_error_log(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); verify(client, atLeastOnce()).log(logCaptor.capture()); @@ -75,13 +75,13 @@ public void test_simple_one_step_failed_error_log(boolean report) { .collect(Collectors.toList()); assertThat(logs, hasSize(greaterThan(0))); - SaveLogRQ log = logs.get(logs.size() - 1); + SaveLogRQ log = logs.getLast(); assertThat(log.getItemUuid(), oneOf(stepIds.toArray(new String[0]))); assertThat(log.getLaunchUuid(), equalTo(launchUuid)); assertThat( - log.getMessage(), - equalTo("Then assert actualFour != four\n" + "did not evaluate to 'true': actualFour != four\n" - + "classpath:feature/simple_failed.feature:6") + log.getMessage(), equalTo(""" + Then actualFour != four + assert failed: actualFour != four""") ); } } diff --git a/src/test/java/com/epam/reportportal/karate/name/NoFeatureNameTest.java b/src/test/java/com/epam/reportportal/karate/name/NoFeatureNameTest.java index 71ead9c..a160cdb 100644 --- a/src/test/java/com/epam/reportportal/karate/name/NoFeatureNameTest.java +++ b/src/test/java/com/epam/reportportal/karate/name/NoFeatureNameTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -53,13 +53,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_item_names_simple(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_NO_NAME_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_NO_NAME_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_NO_NAME_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_NO_NAME_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java b/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java index fe90e95..09074a5 100644 --- a/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java +++ b/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -39,8 +39,7 @@ public class SimpleItemNameTest { private static final String TEST_FEATURE = "classpath:feature/simple.feature"; - private static final String[] STEP_NAMES = new String[] { "Given def four = 4", "When def actualFour = 2 * 2", - "Then assert actualFour == four" }; + private static final String[] STEP_NAMES = new String[] { "Given four = 4", "When actualFour = 2 * 2", "Then actualFour == four" }; 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()); @@ -56,13 +55,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_item_names_simple(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(featureCaptor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java index 9e779e1..821de51 100644 --- a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java +++ b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.ParameterResource; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -42,7 +42,7 @@ public class ExamplesScenarioParametersTest { private static final String TEST_FEATURE = "classpath:feature/examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -59,13 +59,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_scenario_parameters(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java index 030ee07..3f6d96c 100644 --- a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java +++ b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java @@ -24,7 +24,7 @@ import com.epam.ta.reportportal.ws.model.ParameterResource; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; @@ -50,7 +50,7 @@ public class ExamplesStepParametersTest { private static final String TEST_FEATURE = "classpath:feature/examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -72,13 +72,13 @@ public void setupMock() { @ValueSource(booleans = { true, false }) @SuppressWarnings({ "unchecked", "rawtypes" }) public void test_examples_parameters_for_steps(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(captor.capture()); @@ -89,7 +89,7 @@ public void test_examples_parameters_for_steps(boolean report) { verify(client, times(2)).startTestItem(same(exampleIds.get(1)), secondExampleCaptor.capture()); List firstSteps = firstExampleCaptor.getAllValues(); - Set parameterStrings = toParameterStringList(firstSteps.get(0).getParameters()); + Set parameterStrings = toParameterStringList(firstSteps.getFirst().getParameters()); assertThat(parameterStrings, hasSize(2)); assertThat(parameterStrings, allOf(hasItem("vara:2"), hasItem("varb:2"))); parameterStrings = toParameterStringList(firstSteps.get(1).getParameters()); @@ -97,7 +97,7 @@ public void test_examples_parameters_for_steps(boolean report) { assertThat(parameterStrings, hasItem("result:4")); List secondSteps = secondExampleCaptor.getAllValues(); - parameterStrings = toParameterStringList(secondSteps.get(0).getParameters()); + parameterStrings = toParameterStringList(secondSteps.getFirst().getParameters()); assertThat(parameterStrings, hasSize(2)); assertThat(parameterStrings, allOf(hasItem("vara:1"), hasItem("varb:2"))); parameterStrings = toParameterStringList(secondSteps.get(1).getParameters()); @@ -112,7 +112,7 @@ public void test_examples_parameters_for_steps(boolean report) { .filter(rq -> LogLevel.INFO.name().equals(rq.getLevel())) .collect(Collectors.toMap(SaveLogRQ::getItemUuid, v -> v)); - List stepIdList = stepIds.stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList()); + List stepIdList = stepIds.stream().flatMap(e -> e.getValue().stream()).toList(); assertThat(logs.keySet(), hasSize(stepIdList.size())); stepIdList.forEach(id -> assertThat(logs, hasKey(id))); assertThat( diff --git a/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java index 715418b..81b1588 100644 --- a/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java +++ b/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java @@ -21,7 +21,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -55,13 +55,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_no_parameters_reporting(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); diff --git a/src/test/java/com/epam/reportportal/karate/parameters/NullValueExamplesTest.java b/src/test/java/com/epam/reportportal/karate/parameters/NullValueExamplesTest.java index c535441..0125172 100644 --- a/src/test/java/com/epam/reportportal/karate/parameters/NullValueExamplesTest.java +++ b/src/test/java/com/epam/reportportal/karate/parameters/NullValueExamplesTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.ParameterResource; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -43,7 +43,7 @@ public class NullValueExamplesTest { private static final String TEST_FEATURE = "classpath:feature/null_examples.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(1).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(1).toList(); private final List>> stepIds = exampleIds.stream() .map(e -> Pair.of(e, Stream.generate(() -> CommonUtils.namedId("step_")).limit(1).collect(Collectors.toList()))) .collect(Collectors.toList()); @@ -60,18 +60,18 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_examples_null_value(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); verify(client, times(1)).startTestItem(same(featureId), captor.capture()); - verify(client, times(1)).startTestItem(same(exampleIds.get(0)), captor.capture()); + verify(client, times(1)).startTestItem(same(exampleIds.getFirst()), captor.capture()); List items = captor.getAllValues(); assertThat(items, hasSize(3)); diff --git a/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java index 47c32c3..0b08c5d 100644 --- a/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java +++ b/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java @@ -23,7 +23,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import okhttp3.MultipartBody; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -60,13 +60,13 @@ public void setupMock() { @ValueSource(booleans = { true, false }) @SuppressWarnings({ "unchecked", "rawtypes" }) public void test_table_parameters_reporting(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); @@ -85,7 +85,7 @@ public void test_table_parameters_reporting(boolean report) { .filter(rq -> LogLevel.INFO.name().equals(rq.getLevel())) .collect(Collectors.toList()); assertThat(logs, hasSize(1)); - assertThat(logs.get(0).getMessage(), startsWith("Table:\n\n")); - assertThat(logs.get(0).getItemUuid(), startsWith("step_")); + assertThat(logs.getFirst().getMessage(), startsWith("Table:\n\n")); + assertThat(logs.getFirst().getItemUuid(), startsWith("step_")); } } diff --git a/src/test/java/com/epam/reportportal/karate/retry/RetryFailedTest.java b/src/test/java/com/epam/reportportal/karate/retry/RetryFailedTest.java deleted file mode 100644 index 0ecfec6..0000000 --- a/src/test/java/com/epam/reportportal/karate/retry/RetryFailedTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.retry; - -import com.epam.reportportal.karate.utils.TestUtils; -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 com.intuit.karate.core.ScenarioResult; -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.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.*; -import static org.mockito.Mockito.any; - -public class RetryFailedTest { - private static final String TEST_FEATURE = "classpath:feature/simple_failed.feature"; - private final String launchUuid = CommonUtils.namedId("launch_"); - private final String featureId = CommonUtils.namedId("feature_"); - private final List scenarioIds = Stream.generate(() -> CommonUtils.namedId("scenario_")).limit(2).collect(Collectors.toList()); - private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(6).collect(Collectors.toList()); - - private final List>> scenarioSteps = Stream.of( - Pair.of(scenarioIds.get(0), stepIds.subList(0, 3)), - Pair.of(scenarioIds.get(1), stepIds.subList(3, 6)) - ) - .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, scenarioSteps); - mockBatchLogging(client); - } - - @Test - public void test_simple_one_step_failed_retry() { - Results results = TestUtils.runAsHook(rp, TEST_FEATURE); - assertThat(results.getFailCount(), equalTo(1)); - - List failedResults = results.getScenarioResults().filter(ScenarioResult::isFailed).collect(Collectors.toList()); - assertThat(failedResults, hasSize(1)); - - results.getSuite().retryScenario(failedResults.get(0).getScenario()); - - verify(client).startTestItem(any(StartTestItemRQ.class)); - ArgumentCaptor scenarioStartCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); - verify(client, times(2)).startTestItem(same(featureId), scenarioStartCaptor.capture()); - - verify(client).finishTestItem(same(featureId), any(FinishTestItemRQ.class)); - ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); - verify(client).finishTestItem(same(scenarioIds.get(0)), scenarioCaptor.capture()); - verify(client).finishTestItem(same(scenarioIds.get(1)), scenarioCaptor.capture()); - - assertThat(scenarioStartCaptor.getAllValues().get(0).isRetry(), anyOf(equalTo(false), nullValue())); - assertThat(scenarioStartCaptor.getAllValues().get(1).isRetry(), equalTo(true)); - assertThat(scenarioStartCaptor.getAllValues().get(1).getRetryOf(), equalTo(scenarioIds.get(0))); - } -} diff --git a/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java b/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java index 65c5c2b..73f094c 100644 --- a/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java +++ b/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -42,7 +42,7 @@ public class OneExampleFailedTest { private static final String TEST_FEATURE = "classpath:feature/examples_one_failed.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).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()); @@ -69,13 +69,13 @@ private static void verifyStatus(List rqs, ItemStatus... statu @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_simple_one_step_failed(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(featureId), featureCaptor.capture()); @@ -84,7 +84,7 @@ public void test_simple_one_step_failed(boolean report) { ArgumentCaptor secondExampleCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(exampleIds.get(1)), secondExampleCaptor.capture()); ArgumentCaptor firstExampleFirstStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); - verify(client).finishTestItem(same(stepIds.get(0).getValue().get(0)), firstExampleFirstStepCaptor.capture()); + verify(client).finishTestItem(same(stepIds.getFirst().getValue().getFirst()), firstExampleFirstStepCaptor.capture()); ArgumentCaptor firstExampleSecondStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(stepIds.get(0).getValue().get(1)), firstExampleSecondStepCaptor.capture()); ArgumentCaptor secondExampleFirstStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); diff --git a/src/test/java/com/epam/reportportal/karate/status/OneExampleWithBackgroundFailedTest.java b/src/test/java/com/epam/reportportal/karate/status/OneExampleWithBackgroundFailedTest.java index e066b6d..dc077dd 100644 --- a/src/test/java/com/epam/reportportal/karate/status/OneExampleWithBackgroundFailedTest.java +++ b/src/test/java/com/epam/reportportal/karate/status/OneExampleWithBackgroundFailedTest.java @@ -23,7 +23,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -45,13 +45,16 @@ public class OneExampleWithBackgroundFailedTest { private static final String TEST_FEATURE = "classpath:feature/examples_one_failed_with_background.feature"; private final String featureId = CommonUtils.namedId("feature_"); - private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).collect(Collectors.toList()); + private final List exampleIds = Stream.generate(() -> CommonUtils.namedId("example_")).limit(2).toList(); private final List>> stepIds = exampleIds.stream() .map(e -> Pair.of(e, Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()))) .collect(Collectors.toList()); private final List> nestedSteps = Arrays.asList( - Pair.of(stepIds.get(0).getValue().get(0), CommonUtils.namedId("nested_step_")), - Pair.of(stepIds.get(1).getValue().get(0), CommonUtils.namedId("nested_step_")) + Pair.of( + stepIds.getFirst().getValue().getFirst(), + CommonUtils.namedId("nested_step_") + ), + Pair.of(stepIds.get(1).getValue().getFirst(), CommonUtils.namedId("nested_step_")) ); private final ReportPortalClient client = mock(ReportPortalClient.class); @@ -66,7 +69,7 @@ public void setupMock() { private static void verifyStatus(List rqs, ItemStatus... statuses) { List actualStatuses = rqs.stream().map(FinishExecutionRQ::getStatus).collect(Collectors.toList()); - List expectedStatuses = Arrays.stream(statuses).map(ItemStatus::name).collect(Collectors.toList()); + List expectedStatuses = Arrays.stream(statuses).map(ItemStatus::name).toList(); assertThat("Failed verifying status number", actualStatuses, hasSize(rqs.size())); // Status for the last item may come in different order, that's OK. @@ -82,13 +85,13 @@ private static void verifyStatus(List rqs, ItemStatus... statu @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_simple_one_step_failed(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(featureId), featureCaptor.capture()); @@ -97,9 +100,9 @@ public void test_simple_one_step_failed(boolean report) { ArgumentCaptor secondExampleCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(exampleIds.get(1)), secondExampleCaptor.capture()); ArgumentCaptor firstExampleFirstStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); - verify(client).finishTestItem(same(stepIds.get(0).getValue().get(0)), firstExampleFirstStepCaptor.capture()); + verify(client).finishTestItem(same(stepIds.getFirst().getValue().get(0)), firstExampleFirstStepCaptor.capture()); ArgumentCaptor firstExampleSecondStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); - verify(client).finishTestItem(same(stepIds.get(0).getValue().get(1)), firstExampleSecondStepCaptor.capture()); + verify(client).finishTestItem(same(stepIds.getFirst().getValue().get(1)), firstExampleSecondStepCaptor.capture()); ArgumentCaptor firstExampleThirdStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(stepIds.get(0).getValue().get(2)), firstExampleThirdStepCaptor.capture()); ArgumentCaptor secondExampleFirstStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); diff --git a/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java b/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java index 0174ece..9eb4d16 100644 --- a/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java +++ b/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -57,13 +57,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_simple_all_passed(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(featureId), featureCaptor.capture()); @@ -71,7 +71,7 @@ public void test_simple_all_passed(boolean report) { verify(client).finishTestItem(same(scenarioId), scenarioCaptor.capture()); List> stepCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) .limit(stepIds.size()) - .collect(Collectors.toList()); + .toList(); IntStream.range(0, stepIds.size()).forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepCaptors.get(i).capture())); FinishTestItemRQ featureRq = featureCaptor.getValue(); diff --git a/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java b/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java index 5b82026..bebcf1f 100644 --- a/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java +++ b/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java @@ -23,7 +23,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -58,13 +58,13 @@ public void setupMock() { @ParameterizedTest @ValueSource(booleans = { true, false }) public void test_simple_one_step_failed(boolean report) { - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(1)); + assertThat(results.getFeatureFailedCount(), equalTo(1)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); verify(client).finishTestItem(same(featureId), featureCaptor.capture()); @@ -72,7 +72,7 @@ public void test_simple_one_step_failed(boolean report) { verify(client).finishTestItem(same(scenarioId), scenarioCaptor.capture()); List> stepCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) .limit(stepIds.size()) - .collect(Collectors.toList()); + .toList(); IntStream.range(0, stepIds.size()).forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepCaptors.get(i).capture())); FinishTestItemRQ featureRq = featureCaptor.getValue(); @@ -86,7 +86,7 @@ public void test_simple_one_step_failed(boolean report) { assertThat(scenarioRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); assertThat(scenarioRq.getEndTime(), notNullValue()); - List steps = stepCaptors.stream().map(ArgumentCaptor::getValue).collect(Collectors.toList()); + List steps = stepCaptors.stream().map(ArgumentCaptor::getValue).toList(); steps.forEach(step -> { assertThat(step.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); assertThat(step.getEndTime(), notNullValue()); diff --git a/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java b/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java index 48e7b7d..13928ec 100644 --- a/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java +++ b/src/test/java/com/epam/reportportal/karate/tags/SimpleTagInclusionTest.java @@ -23,7 +23,7 @@ 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 io.karatelabs.core.SuiteResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -61,13 +61,13 @@ public void setupMock() { @ValueSource(booleans = { true, false }) public void test_simple_all_passed(boolean report) { List tagsToRun = Collections.singletonList("scope=smoke"); - Results results; + SuiteResult results; if (report) { - results = TestUtils.runAsReport(rp, tagsToRun, TEST_FEATURES); + results = TestUtils.runAsResultListener(rp, tagsToRun, TEST_FEATURES); } else { - results = TestUtils.runAsHook(rp, tagsToRun, TEST_FEATURES); + results = TestUtils.runAsEventListener(rp, tagsToRun, TEST_FEATURES); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client).startTestItem(featureCaptor.capture()); @@ -82,7 +82,7 @@ public void test_simple_all_passed(boolean report) { verify(client).finishTestItem(same(scenarioId), scenarioFinishCaptor.capture()); List> stepFinishCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) .limit(stepIds.size()) - .collect(Collectors.toList()); + .toList(); IntStream.range(0, stepIds.size()) .forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepFinishCaptors.get(i).capture())); diff --git a/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java b/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java index c87e6d7..ed05471 100644 --- a/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java +++ b/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java @@ -22,7 +22,7 @@ import com.epam.reportportal.util.test.CommonUtils; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import com.intuit.karate.Results; +import io.karatelabs.core.SuiteResult; import io.reactivex.Maybe; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -68,19 +68,19 @@ public static Stream testCases() { @ParameterizedTest @MethodSource("testCases") public void test_each_item_has_correct_start_date(boolean report, boolean useMicroseconds) { - Results results; + SuiteResult results; if (report) { if (useMicroseconds) { when(client.getApiInfo()).thenReturn(Maybe.just(TestUtils.testApiInfo())); } - results = TestUtils.runAsReport(rp, TEST_FEATURE); + results = TestUtils.runAsResultListener(rp, TEST_FEATURE); } else { if (useMicroseconds) { when(client.getApiInfo()).thenReturn(Maybe.just(TestUtils.testApiInfo())); } - results = TestUtils.runAsHook(rp, TEST_FEATURE); + results = TestUtils.runAsEventListener(rp, TEST_FEATURE); } - assertThat(results.getFailCount(), equalTo(0)); + assertThat(results.getFeatureFailedCount(), equalTo(0)); ArgumentCaptor launchCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); verify(client).startLaunch(launchCaptor.capture()); @@ -107,10 +107,10 @@ public void test_each_item_has_correct_start_date(boolean report, boolean useMic ); List steps = stepCaptor.getAllValues(); - StartTestItemRQ firstStep = steps.stream().filter(s -> "Given def four = 4".equals(s.getName())).findAny().orElseThrow(); - StartTestItemRQ secondStep = steps.stream().filter(s -> "When def actualFour = 2 * 2".equals(s.getName())).findAny().orElseThrow(); + StartTestItemRQ firstStep = steps.stream().filter(s -> "Given four = 4".equals(s.getName())).findAny().orElseThrow(); + StartTestItemRQ secondStep = steps.stream().filter(s -> "When actualFour = 2 * 2".equals(s.getName())).findAny().orElseThrow(); StartTestItemRQ thirdStep = steps.stream() - .filter(s -> "Then assert actualFour == four".equals(s.getName())) + .filter(s -> "Then actualFour == four".equals(s.getName())) .findAny() .orElseThrow(); diff --git a/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java b/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java deleted file mode 100644 index bb61de3..0000000 --- a/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.utils; - -import java.lang.reflect.Field; - -public class ReflectUtils { - - private ReflectUtils() { - } - - public static void setField(Object object, Field fld, Object value) { - try { - fld.setAccessible(true); - fld.set(object, value); - } catch (IllegalAccessException e) { - String fieldName = fld.getName(); - throw new RuntimeException("Failed to set " + fieldName + " of object", e); - } - } -} 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 311d46c..34156e2 100644 --- a/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java +++ b/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java @@ -16,8 +16,8 @@ package com.epam.reportportal.karate.utils; -import com.epam.reportportal.karate.KarateReportPortalRunner; -import com.epam.reportportal.karate.ReportPortalHook; +import com.epam.reportportal.karate.ReportPortalResultListener; +import com.epam.reportportal.karate.ReportPortalRunListener; import com.epam.reportportal.listeners.ListenerParameters; import com.epam.reportportal.service.LaunchImpl; import com.epam.reportportal.service.ReportPortal; @@ -32,8 +32,8 @@ import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.fasterxml.jackson.core.type.TypeReference; -import com.intuit.karate.Results; -import com.intuit.karate.Runner; +import io.karatelabs.core.Runner; +import io.karatelabs.core.SuiteResult; import io.reactivex.Maybe; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -68,24 +68,28 @@ 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 SuiteResult runAsResultListener(ReportPortal reportPortal, List tags, String... paths) { + ReportPortalResultListener listener = new ReportPortalResultListener(reportPortal); + Runner.Builder path = Runner.path(paths).resultListener(listener).outputCucumberJson(false); + SuiteResult result = path.tags(tags.toArray(new String[0])).parallel(1); + listener.finishLaunch(); + return result; } - public static Results runAsReport(ReportPortal reportPortal, String... paths) { - return runAsReport(reportPortal, Collections.emptyList(), paths); + public static SuiteResult runAsResultListener(ReportPortal reportPortal, String... paths) { + return runAsResultListener(reportPortal, Collections.emptyList(), paths); } - public static Results runAsHook(ReportPortal reportPortal, List tags, String... paths) { - ReportPortalHook hook = new ReportPortalHook(reportPortal); - Runner.Builder path = Runner.path(paths).hook(hook).outputCucumberJson(false); - Results result = path.tags(tags).parallel(1); - hook.finishLaunch(); + public static SuiteResult runAsEventListener(ReportPortal reportPortal, List tags, String... paths) { + ReportPortalRunListener listener = new ReportPortalRunListener(reportPortal); + Runner.Builder path = Runner.path(paths).listener(listener).outputCucumberJson(false); + SuiteResult result = path.tags(tags.toArray(new String[0])).parallel(1); + listener.finishLaunch(); return result; } - public static Results runAsHook(ReportPortal reportPortal, String... paths) { - return runAsHook(reportPortal, Collections.emptyList(), paths); + public static SuiteResult runAsEventListener(ReportPortal reportPortal, String... paths) { + return runAsEventListener(reportPortal, Collections.emptyList(), paths); } public static ListenerParameters standardParameters() { @@ -137,7 +141,7 @@ public static > void mockFeatures(@Nonnull final Re if (features.isEmpty()) { return; } - String firstFeature = features.get(0).getKey(); + String firstFeature = features.getFirst().getKey(); Maybe first = Maybe.just(new ItemCreatedRS(firstFeature, firstFeature)); Maybe[] other = (Maybe[]) features.subList(1, features.size()) .stream() @@ -159,9 +163,9 @@ public static > void mockScenario(@Nonnull final Re List> testResponses = scenarioSteps.stream() .map(Pair::getKey) .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) - .collect(Collectors.toList()); + .toList(); - Maybe first = testResponses.get(0); + Maybe first = testResponses.getFirst(); Maybe[] other = testResponses.subList(1, testResponses.size()).toArray(new Maybe[0]); when(client.startTestItem(same(featureUuid), any())).thenReturn(first, other); @@ -170,10 +174,10 @@ public static > void mockScenario(@Nonnull final Re List> stepResponses = test.getValue() .stream() .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) - .collect(Collectors.toList()); + .toList(); when(client.finishTestItem(same(scenarioUuid), any())).thenReturn(Maybe.just(new OperationCompletionRS())); if (!stepResponses.isEmpty()) { - Maybe myFirst = stepResponses.get(0); + Maybe myFirst = stepResponses.getFirst(); Maybe[] myOther = stepResponses.subList(1, stepResponses.size()).toArray(new Maybe[0]); when(client.startTestItem(same(scenarioUuid), any())).thenReturn(myFirst, myOther); new HashSet<>(test.getValue()).forEach(testMethodUuid -> when(client.finishTestItem( @@ -194,11 +198,9 @@ public static void mockNestedSteps(final ReportPortalClient client, final List

> responseOrders = parentNestedPairs.stream() .collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList()))); responseOrders.forEach((k, v) -> { - List> responses = v.stream() - .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) - .collect(Collectors.toList()); + List> responses = v.stream().map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))).toList(); - Maybe first = responses.get(0); + Maybe first = responses.getFirst(); Maybe[] other = responses.subList(1, responses.size()).toArray(new Maybe[0]); when(client.startTestItem(eq(k), any())).thenReturn(first, other); }); diff --git a/src/test/resources/feature/call_same_feature.feature b/src/test/resources/feature/call_same_feature.feature index dc4524f..b7785de 100644 --- a/src/test/resources/feature/call_same_feature.feature +++ b/src/test/resources/feature/call_same_feature.feature @@ -10,4 +10,4 @@ Feature: the very basic test to run by Karate Scenario: Verify math * def expectedValue = 4 * def testValue = 2 - * call read('@execute-test') { expectedValue: #(expectedValue), testValue: #(testValue) } + * call read('@execute-test') { expectedValue: expectedValue, testValue: testValue }