diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 20f3334..60efaa5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -33,10 +33,10 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up JDK 11
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
@@ -45,4 +45,6 @@ jobs:
run: ./gradlew build
- name: Codecov upload
- run: bash <(curl -s https://codecov.io/bash)
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6b1aae4..1bb112b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -30,13 +30,16 @@ env:
CHANGE_LOG_FILE: CHANGELOG.md
CHANGE_LOG_TMP_FILE: CHANGELOG_updated.md
REPOSITORY_URL: 'https://maven.pkg.github.com/'
+ README_FILE: README.md
+ README_TEMPLATE_FILE: README_TEMPLATE.md
+ README_VERSION_PLACEHOLDER: $LATEST_VERSION
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Generate versions
uses: HardNorth/github-version-generate@v1
@@ -46,7 +49,7 @@ jobs:
version-file-extraction-pattern: ${{ env.VERSION_EXTRACT_PATTERN }}
- name: Set up JDK 11
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
@@ -66,6 +69,13 @@ jobs:
-PgithubUserName=${{ github.actor }} -PgithubToken=${{ secrets.GITHUB_TOKEN }} \
-PgpgPassphrase=${{ secrets.GPG_PASSPHRASE }} -PgpgPrivateKey="${{ secrets.GPG_PRIVATE_KEY }}"
+ - name: Update README.md
+ id: readmeUpdate
+ run: |
+ sed 's/${{ env.README_VERSION_PLACEHOLDER }}/${{ env.RELEASE_VERSION }}/g' ${{ env.README_TEMPLATE_FILE }} > ${{ env.README_FILE }}
+ git add ${{ env.README_FILE }}
+ git commit -m "Readme update"
+
- name: Update CHANGELOG.md
id: changelogUpdate
run: |
@@ -96,17 +106,17 @@ jobs:
body: ${{ steps.readChangelogEntry.outputs.changes }}
- name: Checkout develop branch
- if: ${{github.ref}} == 'master'
- uses: actions/checkout@v3
+ if: ${{github.ref}} == 'main'
+ uses: actions/checkout@v4
with:
ref: 'develop'
fetch-depth: 0
- name: Merge release branch into develop
id: mergeIntoDevelop
- if: ${{github.ref}} == 'master'
+ if: ${{github.ref}} == 'main'
run: |
- git merge -m 'Merge master branch into develop after a release' origin/master
+ git merge -m 'Merge main branch into develop after a release' origin/main
git status | (! grep -Fq 'both modified:') || git status | grep -F 'both modified:' \
- | { echo -e 'Unable to merge master into develop, merge conflicts:'; (! grep -Eo '[^ ]+$') }
+ | { echo -e 'Unable to merge main into develop, merge conflicts:'; (! grep -Eo '[^ ]+$') }
git push origin develop
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5fb72e1..013f86b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,15 @@
# Changelog
## [Unreleased]
+### Changed
+- Karate dependency marked as `compileOnly` to force users specify their own version of Karate, by @HardNorth
+- Client version updated on [5.2.5](https://github.com/reportportal/client-java/releases/tag/5.2.5), by @HardNorth
+### Fixed
+- Issue [#23](https://github.com/reportportal/agent-java-karate/issues/23) scenarios outside features in parallel execution, by @HardNorth
## [5.0.0]
+### Added
+- Basic Agent functionality, by @vrymar
### Changed
- Refactored and implemented main ReportPortal agent features, by @HardNorth
diff --git a/README.md b/README.md
index 5167357..978cc72 100644
--- a/README.md
+++ b/README.md
@@ -1,122 +1,177 @@
-# agent-java-karate
-
-- [Description](#description)
-- [Agent Configuration](#agent-configuration)
-- [Properties File Configuration](#properties-file-configuration)
-- [Execution](#execution)
-
-
-## Description
-ReportPortal Java agent for Karate testing tool.
-
-## Agent Configuration
-Until the agent-java-karate project is published to Maven repository,
-the following configuration can be used:
-
-* Add jitpack repository to get agent project from GitHub:
- * Maven pom.xml
- ```xml
-
-
- jitpack.io
- https://jitpack.io
-
-
- ```
-
- * Gradle build.gradle
- ```groovy
- repositories {
- maven { url 'https://jitpack.io' }
- }
- ```
-
-* Add dependency for the agent project:
- * Maven pom.xml
- ```xml
-
- com.github.vrymar
- agent-java-karate
- Tag_or_Version
-
- ```
-
- * Gradle build.gradle
- ```groovy
- implementation 'com.github.vrymar:agent-java-karate:Tag_or_Version'
- ```
-
-
-* Add reportportal `client-java` dependency:
- * Maven pom.xml
- ```xml
+# ReportPortal runtime Hook for Karate tests
+
+Karate reporters which uploads the results to a ReportPortal server.
+
+> **DISCLAIMER**: We use Google Analytics for sending anonymous usage information such as agent's and client's names, and their versions
+> after a successful launch start. This information might help us to improve both ReportPortal backend and client sides. It is used by the
+> ReportPortal team only and is not supposed for sharing with 3rd parties.
+
+[![Maven Central](https://img.shields.io/maven-central/v/com.epam.reportportal/agent-java-karate.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/com.epam.reportportal/agent-java-karate)
+[![CI Build](https://github.com/reportportal/agent-java-karate/actions/workflows/ci.yml/badge.svg)](https://github.com/reportportal/agent-java-karate/actions/workflows/ci.yml)
+[![codecov](https://codecov.io/github/reportportal/agent-java-karate/graph/badge.svg?token=wJr9F6hZln)](https://codecov.io/github/reportportal/agent-java-karate)
+[![Join Slack chat!](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://slack.epmrpp.reportportal.io/)
+[![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal)
+[![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat)
+
+The latest version: 5.0.0. Please use `Maven Central` link above to get the agent.
+
+## Overview: How to Add ReportPortal Logging to Your Project
+
+To start using ReportPortal with Karate framework please do the following steps:
+
+1. [Configuration](#configuration)
+ * Create/update the `reportportal.properties` configuration file
+ * Build system configuration
+ * Add Listener
+ * Runtime
+ * Post-running
+2. [Logging configuration](#logging)
+ * Loggers and their types
+3. [Running tests](#running-tests)
+ * Build system commands
+
+## Configuration
+
+### 'reportportal.properties' configuration file
+
+As the first step you need to create a file named `reportportal.properties` in your Java project in a source
+folder `src/main/resources` or `src/test/resources` (depending on where your tests are located):
+
+**reportportal.properties**
+
+```
+rp.endpoint = http://localhost:8080
+rp.api.key = test_YIvQraKKSquDZqrA6JLCWCX5qwmMZBk_7tTm_fkN44AHCi18Ze0RtYqxWNYKxk5p
+rp.launch = Karate Tests
+rp.project = default_personal
+```
+
+**Property description**
+
+* `rp.endpoint` - the URL for the ReportPortal server (actual link).
+* `rp.api.key` - an access token for ReportPortal which is used for user identification. It can be found on your report
+ portal user profile page.
+* `rp.project` - a project ID on which the agent will report test launches. Must be set to one of your assigned
+ projects.
+* `rp.launch` - a user-selected identifier of test launches.
+
+The full list of supported properties is located here in client-java library documentation (a common library for all
+Java agents): https://github.com/reportportal/client-java
+
+## Build system configuration
+
+### Maven
+
+If your project is Maven-based you need to add dependencies to `pom.xml` file:
+
+```xml
+
+
+
+
- com.epam.reportportal
- client-java
- Tag_or_Version
+ com.epam.reportportal
+ agent-java-karate
+ 5.0.0
+ test
- ```
- * Gradle build.gradle
- ```groovy
- implementation 'com.epam.reportportal:client-java:Tag_or_Version'
- ```
-
-
-**Note**: When the agent is approved by ReportPortal,
-the agent repository can be taken from `reportportal`. E.g.:
-* Maven pom.xml
- ```xml
-
- com.github.reportportal
- agent-java-karate
- Tag_or_Version
-
- ```
-
-* Gradle build.gradle
- ```groovy
- implementation 'com.github.reportportal:agent-java-karate:Tag_or_Version'
- ```
-
-## Properties File Configuration
-* Create `reportportal.properties` file in `src\main\resources` directory.
-* Add the following parameters:
+
+
+
```
-rp.endpoint =
-rp.uuid =
-rp.launch =
-rp.project =
-
-OPTIONAL PARAMETERS
-rp.reporting.async=true
-rp.reporting.callback=true
-rp.enable=true
-rp.description=My awesome launch
-rp.attributes=key:value;value
-rp.rerun=true
-rp.rerun.of=ae586912-841c-48de-9391-50720c35dd5a
-rp.convertimage=true
-rp.mode=DEFAULT
-rp.skipped.issue=true
-rp.batch.size.logs=20
-rp.keystore.resource=
-rp.keystore.password=
+
+You are free to use you own version of Karate, but not earlier than 1.0.0. If you leave just Agent dependency it will
+be still OK, it will use transitive Karate version.
+
+### Gradle
+
+For Gradle-based projects please update dependencies section in `build.gradle` file:
+
+```groovy
+dependencies {
+ testImplementation 'com.epam.reportportal:agent-java-karate:5.0.0'
+}
```
-## Execution
-To publish test results to ReportPortal, the test project should run by `KarateReportPortalRunner` instead of Karate runner.
-E.g.:
-
- ```java
- class scenarioRunnerTest {
-
- @Test
- void testParallel() {
- KarateReportPortalRunner
- .path("classpath:examples")
- .outputCucumberJson(true)
- .tags("~@ignore")
- .parallel(1);
- }
- }
- ```
+## Listener configuration
+
+### 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.
+E.G.:
+
+```java
+import com.epam.reportportal.karate.ReportPortalHook;
+import com.intuit.karate.Runner;
+
+class ScenarioRunnerTest {
+ @Test
+ void testParallel() {
+ return Runner
+ .path("classpath:examples")
+ .hook(new ReportPortalHook())
+ .outputCucumberJson(true)
+ .tags("~@ignore")
+ .parallel(1);
+ }
+}
+```
+
+### Post-running
+
+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.
+E.G.:
+
+```java
+import com.epam.reportportal.karate.KarateReportPortalRunner;
+
+class ScenarioRunnerTest {
+ @Test
+ void testParallel() {
+ KarateReportPortalRunner
+ .path("classpath:examples")
+ .outputCucumberJson(true)
+ .tags("~@ignore")
+ .parallel(1);
+ }
+}
+```
+
+## Logging
+
+Karate uses `slf4j` as Logging library, so you are free to choose any Logging Framework.
+
+ReportPortal provides its own logger implementations for major logging frameworks like *Log4j* and *Logback*. It also
+provides additional formatting features for popular client and test libraries like: *Selenide*, *Apache HttpComponents*,
+*Rest Assured*, etc.
+
+Here is the list of supported loggers and setup documentation links.
+
+**Logging frameworks:**
+
+| **Library name** | **Documentation link** |
+|------------------|-----------------------------------------------------|
+| Log4j | https://github.com/reportportal/logger-java-log4j |
+| Logback | https://github.com/reportportal/logger-java-logback |
+
+**HTTP clients:**
+
+| **Library name** | **Documentation link** |
+|-----------------------|------------------------------------------------------------|
+| OkHttp3 | https://github.com/reportportal/logger-java-okhttp3 |
+| Apache HttpComponents | https://github.com/reportportal/logger-java-httpcomponents |
+
+## Running tests
+
+We are set. To run tests we just need to execute corresponding command in our build system.
+
+#### Maven
+
+`mvn test` or `mvnw test` if you are using Maven wrapper
+
+#### Gradle
+
+`gradle test` or `gradlew test` if you are using Gradle wrapper
diff --git a/README_TEMPLATE.md b/README_TEMPLATE.md
index 79ab35e..40a15d9 100644
--- a/README_TEMPLATE.md
+++ b/README_TEMPLATE.md
@@ -9,7 +9,7 @@ Karate reporters which uploads the results to a ReportPortal server.
[![Maven Central](https://img.shields.io/maven-central/v/com.epam.reportportal/agent-java-karate.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/com.epam.reportportal/agent-java-karate)
[![CI Build](https://github.com/reportportal/agent-java-karate/actions/workflows/ci.yml/badge.svg)](https://github.com/reportportal/agent-java-karate/actions/workflows/ci.yml)
[![codecov](https://codecov.io/github/reportportal/agent-java-karate/graph/badge.svg?token=wJr9F6hZln)](https://codecov.io/github/reportportal/agent-java-karate)
-[![Join Slack chat!](https://slack.epmrpp.reportportal.io/badge.svg)](https://slack.epmrpp.reportportal.io/)
+[![Join Slack chat!](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://slack.epmrpp.reportportal.io/)
[![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal)
[![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat)
diff --git a/build.gradle b/build.gradle
index a90e645..3d18514 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,12 +42,14 @@ repositories {
}
dependencies {
- api 'com.epam.reportportal:client-java:5.2.0'
- api "com.intuit.karate:karate-core:${project.karate_version}"
+ api 'com.epam.reportportal:client-java:5.2.5'
+
+ compileOnly "com.intuit.karate:karate-core:${project.karate_version}"
implementation 'org.slf4j:slf4j-api:2.0.7'
- testImplementation 'com.epam.reportportal:logger-java-logback:5.2.0'
- testImplementation 'com.epam.reportportal:agent-java-test-utils:0.0.2'
+ testImplementation "com.intuit.karate:karate-core:${project.karate_version}"
+ testImplementation 'com.epam.reportportal:logger-java-logback:5.2.1'
+ testImplementation 'com.epam.reportportal:agent-java-test-utils:0.0.3'
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}"
testImplementation "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}"
testImplementation "org.junit.jupiter:junit-jupiter-params:${project.junit_version}"
diff --git a/gradle.properties b/gradle.properties
index deb8a02..206f8c7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,7 +2,7 @@ name=agent-java-karate
version=5.0.1-SNAPSHOT
description=EPAM ReportPortal. Karate test framework [1.3.1, ) adapter
gradle_version=8.2
-karate_version=[1.3.1, )
+karate_version=1.4.1
junit_version=5.10.1
mockito_version=5.4.0
scripts_url=https://raw.githubusercontent.com/reportportal/gradle-scripts
diff --git a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java
index 1cc9530..f90b20f 100644
--- a/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java
+++ b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java
@@ -16,6 +16,7 @@
package com.epam.reportportal.karate;
+import com.epam.reportportal.karate.utils.BlockingConcurrentHashMap;
import com.epam.reportportal.listeners.ItemStatus;
import com.epam.reportportal.listeners.ListenerParameters;
import com.epam.reportportal.listeners.LogLevel;
@@ -55,7 +56,7 @@
public class ReportPortalHook implements RuntimeHook {
private static final Logger LOGGER = LoggerFactory.getLogger(ReportPortalHook.class);
protected final MemoizingSupplier launch;
- private final Map> featureIdMap = new ConcurrentHashMap<>();
+ private final BlockingConcurrentHashMap> featureIdMap = new BlockingConcurrentHashMap<>();
private final Map> scenarioIdMap = new ConcurrentHashMap<>();
private final Map> backgroundIdMap = new ConcurrentHashMap<>();
private final Map> stepIdMap = new ConcurrentHashMap<>();
@@ -150,9 +151,7 @@ protected StartTestItemRQ buildStartFeatureRq(@Nonnull FeatureRuntime fr) {
@Override
public boolean beforeFeature(FeatureRuntime fr) {
- Maybe featureId = launch.get().startTestItem(buildStartFeatureRq(fr));
- Feature feature = fr.featureCall.feature;
- featureIdMap.put(feature.getNameForReport(), featureId);
+ featureIdMap.computeIfAbsent(fr.featureCall.feature.getNameForReport(), f -> launch.get().startTestItem(buildStartFeatureRq(fr)));
return true;
}
@@ -169,8 +168,7 @@ protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureRuntime fr) {
@Override
public void afterFeature(FeatureRuntime fr) {
- Feature feature = fr.featureCall.feature;
- Maybe featureId = featureIdMap.remove(feature.getNameForReport());
+ Maybe featureId = featureIdMap.remove(fr.featureCall.feature.getNameForReport());
if (featureId == null) {
LOGGER.error("ERROR: Trying to finish unspecified feature.");
}
@@ -192,10 +190,9 @@ protected StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioRuntime sr) {
@Override
public boolean beforeScenario(ScenarioRuntime sr) {
+ Maybe featureId = featureIdMap.get(sr.featureRuntime.featureCall.feature.getNameForReport());
StartTestItemRQ rq = buildStartScenarioRq(sr);
-
- Maybe scenarioId = launch.get()
- .startTestItem(featureIdMap.get(sr.featureRuntime.featureCall.feature.getNameForReport()), rq);
+ Maybe scenarioId = launch.get().startTestItem(featureId, rq);
scenarioIdMap.put(sr.scenario.getUniqueId(), scenarioId);
return true;
}
diff --git a/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java b/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java
new file mode 100644
index 0000000..7394261
--- /dev/null
+++ b/src/main/java/com/epam/reportportal/karate/utils/BlockingConcurrentHashMap.java
@@ -0,0 +1,95 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+public class BlockingConcurrentHashMap {
+ private static final Logger LOGGER = LoggerFactory.getLogger(BlockingConcurrentHashMap.class);
+
+ private static final class BlockingReference {
+ private final BlockingQueue lock = new ArrayBlockingQueue<>(1);
+ private volatile boolean set = false;
+ private volatile T value;
+
+ public void set(Function, T> supplier) {
+ lock.clear();
+ set = false;
+ try {
+ value = supplier.apply(null);
+ set = true;
+ try {
+ //noinspection StatementWithEmptyBody
+ while (lock.offer(value)) {
+ // Put while waiting Threads take values
+ }
+ } catch (IllegalStateException ignore) {
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Unable to get result value from passed supplier.", e);
+ throw e;
+ }
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException {
+ if (!set) {
+ return lock.poll(timeout, unit);
+ } else {
+ return value;
+ }
+ }
+ }
+
+ private static final int TIMEOUT = 1;
+ private static final TimeUnit TIMEOUT_UNIT = TimeUnit.MINUTES;
+
+ private final Map> map = new ConcurrentHashMap<>();
+
+ public void computeIfAbsent(@Nonnull K key, Function, V> mappingFunction) {
+ map.computeIfAbsent(key, k -> new BlockingReference<>()).set(mappingFunction);
+ }
+
+ @Nullable
+ public V get(@Nonnull K key) {
+ try {
+ return map.computeIfAbsent(key, k -> new BlockingReference<>()).get(TIMEOUT, TIMEOUT_UNIT);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Wait for value was interrupted", e);
+ }
+ return null;
+ }
+
+ @Nullable
+ public V remove(@Nonnull K key) {
+ try {
+ return map.remove(key).get(TIMEOUT, TIMEOUT_UNIT);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Wait for value was interrupted", e);
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java b/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java
new file mode 100644
index 0000000..8dacfd8
--- /dev/null
+++ b/src/test/java/com/epam/reportportal/karate/status/OneExampleFailedTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.status;
+
+import com.epam.reportportal.karate.utils.TestUtils;
+import com.epam.reportportal.listeners.ItemStatus;
+import com.epam.reportportal.service.ReportPortal;
+import com.epam.reportportal.service.ReportPortalClient;
+import com.epam.reportportal.util.test.CommonUtils;
+import com.epam.ta.reportportal.ws.model.FinishTestItemRQ;
+import com.intuit.karate.Results;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Arrays;
+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.*;
+
+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>> stepIds = exampleIds.stream()
+ .map(e -> Pair.of(e, Stream.generate(() -> CommonUtils.namedId("step_")).limit(2).collect(Collectors.toList())))
+ .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, null, featureId, stepIds);
+ mockBatchLogging(client);
+ }
+
+ private static void verifyStatus(List rqs, ItemStatus... statuses) {
+ for (int i = 0; i < rqs.size(); i++) {
+ ItemStatus statusTest = i >= statuses.length ? statuses[statuses.length - 1] : statuses[i];
+ assertThat(
+ "Failed verifying request number: " + (i + 1),
+ rqs.get(i).getStatus(),
+ allOf(notNullValue(), equalTo(statusTest.name()))
+ );
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = { true, false })
+ public void test_simple_one_step_failed(boolean report) {
+ Results results;
+ if (report) {
+ results = TestUtils.runAsReport(rp, TEST_FEATURE);
+ } else {
+ results = TestUtils.runAsHook(rp, TEST_FEATURE);
+ }
+ assertThat(results.getFailCount(), equalTo(1));
+
+ ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class);
+ verify(client).finishTestItem(same(featureId), featureCaptor.capture());
+ ArgumentCaptor firstExampleCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class);
+ verify(client).finishTestItem(same(exampleIds.get(0)), firstExampleCaptor.capture());
+ 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());
+ ArgumentCaptor firstExampleSecondStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class);
+ verify(client).finishTestItem(same(stepIds.get(0).getValue().get(1)), firstExampleSecondStepCaptor.capture());
+ ArgumentCaptor secondExampleFirstStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class);
+ verify(client).finishTestItem(same(stepIds.get(1).getValue().get(0)), secondExampleFirstStepCaptor.capture());
+ ArgumentCaptor secondExampleSecondStepCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class);
+ verify(client).finishTestItem(same(stepIds.get(1).getValue().get(1)), secondExampleSecondStepCaptor.capture());
+
+ FinishTestItemRQ featureRq = featureCaptor.getValue();
+ assertThat(featureRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.FAILED.name())));
+
+ verifyStatus(Arrays.asList(firstExampleCaptor.getValue(), secondExampleCaptor.getValue()), ItemStatus.PASSED, ItemStatus.FAILED);
+
+ List steps = Arrays.asList(firstExampleFirstStepCaptor.getValue(),
+ firstExampleSecondStepCaptor.getValue(),
+ secondExampleFirstStepCaptor.getValue(),
+ secondExampleSecondStepCaptor.getValue()
+ );
+
+ verifyStatus(steps, ItemStatus.PASSED, ItemStatus.PASSED, ItemStatus.PASSED, ItemStatus.FAILED);
+ }
+}
diff --git a/src/test/resources/feature/examples_one_failed.feature b/src/test/resources/feature/examples_one_failed.feature
new file mode 100644
index 0000000..76daf54
--- /dev/null
+++ b/src/test/resources/feature/examples_one_failed.feature
@@ -0,0 +1,10 @@
+Feature: math tests with examples
+
+ Scenario Outline: Verify different maths
+ Given def mathResult = vara + varb
+ Then assert mathResult == result
+
+ Examples:
+ | vara! | varb! | result! |
+ | 2 | 2 | 4 |
+ | 1 | 2 | 4 |