From e220481aa2990330839f40041ec019edee5d187b Mon Sep 17 00:00:00 2001 From: Vadzim Hushchanskou Date: Tue, 16 Jan 2024 16:21:18 +0300 Subject: [PATCH] Release (#21) * Update CI build workflow * Update build scripts * Add the first integration test * Dependency update * The first Code Reference test, ReportPortal format apply, ignore target folder * Do not output Cucumber to avoid failures in CI * Revert last change * A try to fix tests * Add code reference for simple scenarios * Add code reference for Examples scenarios * Format fixes * Code reference generation: sort by example key to unify code reference * Add Test Case ID * Attribute handling * Fix tests * System attributes reporting add * Refactor item start method * Add more tests * Add scenario parameters reporting * Update property format * Add parameter handling for steps * Add parameter log message verification * Table parameters handling * Background steps handling * Test fixes * Fix typing * Background logic update * Another background test * Fix Table test * Fix Table test * Fix description * Add another test * Add Launch description test * Small fix * Small fix * Add test * Add junit-jupiter-params dependency * Description and item name tests and fixes * Fix test * Refactoring * Add parameter description to examples * Add examples description tests * Refactoring * Add test * Add test * Fix test * Update step logging * Add test * Add another test * Add ReportPortal runtime hook publisher * Refactoring, move common code to util class * Fix parameter reporting * Fix javadocs * ReportPortalHook: WIP * ReportPortalHook: WIP * ReportPortalHook: WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * ReportPortalHook: Tests WIP * Add timing test and javadocs * Add feature parameters tests * Bump version * Client version update * Client version update * Fix version number * Update copyrights * Update copyrights * Code format apply * Add README_TEMPLATE.md file * Update README_TEMPLATE.md file --- .github/workflows/ci.yml | 9 +- .gitignore | 1 + CHANGELOG.md | 3 +- README_TEMPLATE.md | 177 +++++ build-quality.gradle | 43 ++ build.gradle | 53 +- gradle.properties | 11 +- .../karate/KarateReportPortalRunner.java | 85 +- .../reportportal/karate/ReportPortalHook.java | 424 ++++++++++ .../karate/ReportPortalPublisher.java | 730 ++++++++++-------- .../karate/ReportPortalUtils.java | 426 ++++++++++ .../karate/enums/ItemLogLevelEnum.java | 18 - .../karate/enums/ItemStatusEnum.java | 21 - .../epam/reportportal/karate/KarateTest.java | 39 +- .../karate/ReportPortalPublisherTest.java | 119 +-- .../attributes/DifferentAttributesTest.java | 95 +++ .../attributes/LaunchAttributesTest.java | 89 +++ .../karate/attributes/NoAttributesTest.java | 80 ++ .../attributes/SystemAttributesTest.java | 85 ++ .../background/BackgroundExamplesTest.java | 120 +++ .../karate/background/BackgroundTest.java | 103 +++ .../background/BackgroundTwoStepsTest.java | 106 +++ .../karate/coderef/ExamplesCodeRefTest.java | 98 +++ .../karate/coderef/ScenarioCodeRefTest.java | 87 +++ .../CallWithParametersHookTest.java | 99 +++ .../CallWithParametersPublisherTest.java | 64 ++ .../description/DescriptionExamplesTest.java | 95 +++ .../description/LaunchDescriptionTest.java | 78 ++ .../NoDescriptionExamplesTest.java | 90 +++ .../karate/description/NoDescriptionTest.java | 82 ++ .../description/NoLaunchDescriptionTest.java | 84 ++ .../description/SimpleDescriptionTest.java | 98 +++ .../karate/id/ExamplesTestCaseIdTest.java | 86 +++ .../karate/id/ScenarioTestCaseIdTest.java | 77 ++ .../launch/LaunchRequiredFieldsTest.java | 76 ++ .../logging/HttpRequestLoggingTest.java | 87 +++ .../logging/SimpleFailureLoggingTest.java | 86 +++ .../karate/name/SimpleItemNameTest.java | 84 ++ .../ExamplesScenarioParametersTest.java | 95 +++ .../ExamplesStepParametersTest.java | 122 +++ .../karate/parameters/NoParametersTest.java | 82 ++ .../parameters/TableParametersTest.java | 91 +++ .../karate/status/SimpleAllPassedTest.java | 95 +++ .../status/SimpleOneStepFailedTest.java | 97 +++ .../karate/timing/SimpleTimingTest.java | 115 +++ .../karate/utils/ReflectUtils.java | 35 + .../reportportal/karate/utils/TestUtils.java | 219 ++++++ .../epam/reportportal/utils/ReflectUtils.java | 19 - src/test/resources/feature/Test.feature | 1 + src/test/resources/feature/background.feature | 8 + .../feature/background_examples.feature | 13 + .../feature/background_two_steps.feature | 8 + src/test/resources/feature/call.feature | 4 + src/test/resources/feature/called.feature | 7 + .../resources/feature/description.feature | 16 + .../feature/description_examples.feature | 13 + src/test/resources/feature/examples.feature | 10 + .../resources/feature/http_request.feature | 16 + src/test/resources/feature/simple.feature | 6 + .../resources/feature/simple_failed.feature | 6 + src/test/resources/feature/table.feature | 10 + src/test/resources/feature/tags.feature | 8 + src/test/resources/logback.xml | 23 +- src/test/resources/reportportal.properties | 9 +- 64 files changed, 4807 insertions(+), 529 deletions(-) create mode 100644 README_TEMPLATE.md create mode 100644 build-quality.gradle create mode 100644 src/main/java/com/epam/reportportal/karate/ReportPortalHook.java create mode 100644 src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java delete mode 100644 src/main/java/com/epam/reportportal/karate/enums/ItemLogLevelEnum.java delete mode 100644 src/main/java/com/epam/reportportal/karate/enums/ItemStatusEnum.java create mode 100644 src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/CallWithParametersHookTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/CallWithParametersPublisherTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java create mode 100644 src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java create mode 100644 src/test/java/com/epam/reportportal/karate/utils/TestUtils.java delete mode 100644 src/test/java/com/epam/reportportal/utils/ReflectUtils.java create mode 100644 src/test/resources/feature/background.feature create mode 100644 src/test/resources/feature/background_examples.feature create mode 100644 src/test/resources/feature/background_two_steps.feature create mode 100644 src/test/resources/feature/call.feature create mode 100644 src/test/resources/feature/called.feature create mode 100644 src/test/resources/feature/description.feature create mode 100644 src/test/resources/feature/description_examples.feature create mode 100644 src/test/resources/feature/examples.feature create mode 100644 src/test/resources/feature/http_request.feature create mode 100644 src/test/resources/feature/simple.feature create mode 100644 src/test/resources/feature/simple_failed.feature create mode 100644 src/test/resources/feature/table.feature create mode 100644 src/test/resources/feature/tags.feature diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3262a3..20f3334 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,9 @@ -# Copyright 2020 EPAM Systems +# Copyright 2022 EPAM Systems # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -17,7 +17,7 @@ on: push: branches: - '*' - - '!master' + - '!main' paths-ignore: - README.md - README_TEMPLATE.md @@ -25,8 +25,7 @@ on: pull_request: branches: - - master - - develop + - main jobs: build: diff --git a/.gitignore b/.gitignore index beed998..39b8c7c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ hs_err_pid* .gradle/ build/ test-output/ +target/ # IntelliJ Idea files .idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 222ffbd..13980a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog ## [Unreleased] -- Take items' startTime and endTime from Karate. +### Changed +- Refactored and implemented main ReportPortal agent features, by @HardNorth ## [1.0.6] ### Changed diff --git a/README_TEMPLATE.md b/README_TEMPLATE.md new file mode 100644 index 0000000..79ab35e --- /dev/null +++ b/README_TEMPLATE.md @@ -0,0 +1,177 @@ +# 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://slack.epmrpp.reportportal.io/badge.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: $LATEST_VERSION. 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 + agent-java-karate + $LATEST_VERSION + test + + + + +``` + +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:$LATEST_VERSION' +} +``` + +## 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/build-quality.gradle b/build-quality.gradle new file mode 100644 index 0000000..003f61f --- /dev/null +++ b/build-quality.gradle @@ -0,0 +1,43 @@ +/* + * 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. + */ +buildscript { + repositories { + maven { + url 'https://plugins.gradle.org/m2/' + } + } + dependencies { + classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:4.8.0' + } +} + +apply plugin: com.github.spotbugs.snom.SpotBugsPlugin + +spotbugs { + toolVersion = '3.1.12' + effort = 'max' + reportLevel = 'high' +} + +spotbugsMain { + sourceDirs = files(sourceSets.main.allSource.srcDirs) + classDirs = files(sourceSets.main.output) + auxClassPaths = files(sourceSets.main.compileClasspath) + reports { + html.enabled(true) + xml.enabled(false) + } +} diff --git a/build.gradle b/build.gradle index b0af09e..016f87b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ /* - * Copyright 2023 EPAM Systems + * 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -15,47 +15,58 @@ */ apply plugin: 'java-library' -apply plugin: 'maven-publish' -// Blocking issue for gradle version >=7.0:https://github.com/reportportal/gradle-scripts/issues/37 -//apply from: "${project.scripts_url}/${project.scripts_branch}/release-commons.gradle" -//apply from: "${project.scripts_url}/${project.scripts_branch}/build-quality.gradle" -//apply from: "${project.scripts_url}/${project.scripts_branch}/signing.gradle" +apply from: 'build-quality.gradle' +apply from: "${project.scripts_url}/${project.scripts_branch}/release-commons.gradle" +apply from: "${project.scripts_url}/${project.scripts_branch}/signing.gradle" +apply from: "${project.scripts_url}/${project.scripts_branch}/jacoco.gradle" +project.ext.limits = [ + 'instruction': 70, + 'branch' : 53, + 'line' : 75, + 'complexity' : 60, + 'method' : 65, + 'class' : 83 +] sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 + compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' repositories { + mavenLocal() mavenCentral() } dependencies { - api "com.epam.reportportal:client-java:${project.reportportal_client_java_version}" - api "com.epam.reportportal:logger-java-logback:${project.reportportal_logback_version}" + api 'com.epam.reportportal:client-java:5.2.0' api "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 "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}" testImplementation "org.mockito:mockito-core:${project.mockito_version}" testImplementation "org.mockito:mockito-junit-jupiter:${project.mockito_version}" -} - -tasks.withType(Test) { - jvmArgs += ['--add-opens', 'java.base/java.lang=ALL-UNNAMED', - '--add-opens', 'java.base/java.lang.reflect=ALL-UNNAMED', - '--add-opens', 'java.base/java.util=ALL-UNNAMED', - '--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED'] + testImplementation 'org.hamcrest:hamcrest-core:2.2' + testImplementation 'com.squareup.okhttp3:okhttp:4.12.0' } test { outputs.upToDateWhen { return false } - maxParallelForks(5) useJUnitPlatform() doFirst { def weaver = configurations.testRuntimeClasspath.find { it.name.contains("aspectjweaver") } jvmArgs += "-javaagent:$weaver" + jvmArgs += ['--add-opens', 'java.base/java.lang=ALL-UNNAMED', + '--add-opens', 'java.base/java.lang.reflect=ALL-UNNAMED', + '--add-opens', 'java.base/java.util=ALL-UNNAMED', + '--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED'] } environment "AGENT_NO_ANALYTICS", "1" testLogging { @@ -74,10 +85,4 @@ processResources { } } -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - } - } -} +build.dependsOn jacocoTestReport diff --git a/gradle.properties b/gradle.properties index 0b562d8..3a284cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,10 @@ name=agent-java-karate -version=1.0.6 -description=EPAM Report portal. Karate test framework [1.3.1, ) adapter +version=5.0.0-SNAPSHOT +description=EPAM ReportPortal. Karate test framework [1.3.1, ) adapter gradle_version=8.2 -reportportal_client_java_version=5.1.16 -reportportal_logback_version=5.1.3 karate_version=[1.3.1, ) -junit_version=5.10.0-M1 +junit_version=5.10.1 mockito_version=5.4.0 scripts_url=https://raw.githubusercontent.com/reportportal/gradle-scripts -scripts_branch=master \ No newline at end of file +scripts_branch=develop +excludeTests= diff --git a/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java b/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java index fb81065..19f97cc 100644 --- a/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java +++ b/src/main/java/com/epam/reportportal/karate/KarateReportPortalRunner.java @@ -1,35 +1,58 @@ +/* + * 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.*; -import com.intuit.karate.core.*; - -import java.util.*; -import java.util.stream.Collectors; - -public class KarateReportPortalRunner extends Suite { - - public static > Builder path(String... paths) { - Builder builder = new Builder<>(); - return builder.path(paths); - } - - public static class Builder> extends Runner.Builder { - ReportPortalPublisher reporter = new ReportPortalPublisher(); - - public Builder() { - super(); - } - - @Override - public Results parallel(int threadCount) { - reporter.startLaunch(); - Results results = super.parallel(threadCount); - List featureResults = results.getFeatureResults().collect(Collectors.toList()); - featureResults.forEach(f -> reporter.startFeature(f)); - featureResults.forEach(f -> reporter.finishFeature(f)); - reporter.finishLaunch(); - return results; - } - } +import com.epam.reportportal.service.ReportPortal; +import com.intuit.karate.Results; +import com.intuit.karate.Runner; + +public class KarateReportPortalRunner { + + public static > Builder path(String... paths) { + Builder builder = new Builder<>(); + return builder.path(paths); + } + + public static class Builder> extends Runner.Builder { + private ReportPortal rp; + + public Builder() { + super(); + } + + public Builder withReportPortal(ReportPortal reportPortal) { + rp = reportPortal; + return this; + } + + @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 new file mode 100644 index 0000000..1cc9530 --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalHook.java @@ -0,0 +1,424 @@ +/* + * 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.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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Calendar; +import java.util.Date; +import java.util.Map; +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.markdown.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 Map> featureIdMap = new ConcurrentHashMap<>(); + private final Map> scenarioIdMap = new ConcurrentHashMap<>(); + private final Map> backgroundIdMap = new ConcurrentHashMap<>(); + private final Map> stepIdMap = new ConcurrentHashMap<>(); + private final Map, Date> stepStartTimeMap = new ConcurrentHashMap<>(); + private volatile Thread shutDownHook; + + public ReportPortalHook(ReportPortal reportPortal) { + launch = new MemoizingSupplier<>(() -> { + ListenerParameters params = reportPortal.getParameters(); + StartLaunchRQ rq = buildStartLaunchRq(params); + Launch newLaunch = reportPortal.newLaunch(rq); + //noinspection ReactiveStreamsUnusedPublisher + newLaunch.start(); + shutDownHook = registerShutdownHook(this::finishLaunch); + return newLaunch; + }); + } + + public ReportPortalHook() { + this(ReportPortal.builder().build()); + } + + public ReportPortalHook(Supplier launchSupplier) { + launch = new MemoizingSupplier<>(launchSupplier); + shutDownHook = registerShutdownHook(this::finishLaunch); + } + + /** + * 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() { + Launch launchObject = launch.get(); + ListenerParameters parameters = launchObject.getParameters(); + FinishExecutionRQ rq = buildFinishLaunchRq(parameters); + LOGGER.info("Launch URL: {}/ui/#{}/launches/all/{}", + parameters.getBaseUrl(), + parameters.getProjectName(), + System.getProperty("rp.launch.id") + ); + launchObject.finish(rq); + if (Thread.currentThread() != shutDownHook) { + unregisterShutdownHook(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(String.format(MARKDOWN_DELIMITER_PATTERN, parameters, description)); + } else { + rq.setDescription(parameters); + } + }); + return rq; + } + + @Override + public boolean beforeFeature(FeatureRuntime fr) { + Maybe featureId = launch.get().startTestItem(buildStartFeatureRq(fr)); + Feature feature = fr.featureCall.feature; + featureIdMap.put(feature.getNameForReport(), featureId); + 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(Calendar.getInstance().getTime(), fr.result.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED); + } + + @Override + public void afterFeature(FeatureRuntime fr) { + Feature feature = fr.featureCall.feature; + Maybe featureId = featureIdMap.remove(feature.getNameForReport()); + if (featureId == null) { + LOGGER.error("ERROR: Trying to finish unspecified feature."); + } + FinishTestItemRQ rq = buildFinishFeatureRq(fr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(featureId, rq); + } + + /** + * 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) { + return ReportPortalUtils.buildStartScenarioRq(sr.scenario); + } + + @Override + public boolean beforeScenario(ScenarioRuntime sr) { + StartTestItemRQ rq = buildStartScenarioRq(sr); + + Maybe scenarioId = launch.get() + .startTestItem(featureIdMap.get(sr.featureRuntime.featureCall.feature.getNameForReport()), rq); + 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 buildFinishTestItemRq(Calendar.getInstance().getTime(), + sr.result.getFailureMessageForDisplay() == null ? ItemStatus.PASSED : ItemStatus.FAILED + ); + } + + /** + * 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 + */ + 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 step Karate's Step object instance + * @param sr Karate's ScenarioRuntime object instance + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable Step step, @Nonnull ScenarioRuntime sr) { + return buildFinishTestItemRq(Calendar.getInstance().getTime(), null); + + } + + /** + * Finish sending Scenario data to ReportPortal. + * + * @param step Karate's Step object instance + * @param sr Karate's ScenarioRuntime object instance + */ + public void finishBackground(@Nullable Step step, @Nonnull ScenarioRuntime sr) { + Maybe backgroundId = backgroundIdMap.remove(sr.scenario.getUniqueId()); + if (backgroundId != null) { + FinishTestItemRQ finishRq = buildFinishBackgroundRq(step, sr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(backgroundId, finishRq); + } + } + + @Override + public void afterScenario(ScenarioRuntime sr) { + Maybe scenarioId = scenarioIdMap.remove(sr.scenario.getUniqueId()); + if (scenarioId == null) { + LOGGER.error("ERROR: Trying to finish unspecified scenario."); + } + + FinishTestItemRQ rq = buildFinishScenarioRq(sr); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(scenarioId, rq); + finishBackground(null, sr); + } + + /** + * 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 stepId step ID. + * @return step new startTime in Date format. + */ + @Nonnull + private Date getStepStartTime(@Nullable Maybe stepId) { + Date currentStepStartTime = Calendar.getInstance().getTime(); + if (stepId == null || stepStartTimeMap.isEmpty()) { + return currentStepStartTime; + } + Date lastStepStartTime = stepStartTimeMap.get(stepId); + if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) { + currentStepStartTime.setTime(lastStepStartTime.getTime() + 1); + } + return currentStepStartTime; + } + + /** + * 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); + Maybe stepId = stepIdMap.get(sr.scenario.getUniqueId()); + Date startTime = getStepStartTime(stepId); + 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); + } else { + finishBackground(step, sr); + } + StartTestItemRQ stepRq = buildStartStepRq(step, sr); + + String scenarioId = sr.scenario.getUniqueId(); + Maybe stepId = launch.get().startTestItem(background ? backgroundId : scenarioIdMap.get(scenarioId), stepRq); + stepStartTimeMap.put(stepId, stepRq.getStartTime()); + 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(); + 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(Calendar.getInstance().getTime(), getStepStatus(stepResult.getResult().getStatus())); + } + + @Override + public void afterStep(StepResult stepResult, ScenarioRuntime sr) { + sendStepResults(stepResult, sr); + Maybe stepId = stepIdMap.get(sr.scenario.getUniqueId()); + if (stepId == null) { + LOGGER.error("ERROR: Trying to finish unspecified step."); + return; + } + + FinishTestItemRQ rq = buildFinishStepRq(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 index c0e0d1f..90d68e8 100644 --- a/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalPublisher.java @@ -1,8 +1,24 @@ +/* + * 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.enums.ItemStatusEnum; -import com.epam.reportportal.karate.enums.ItemLogLevelEnum; +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; @@ -10,351 +26,391 @@ 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.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.intuit.karate.core.*; import io.reactivex.Maybe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; -import static com.google.common.base.Strings.isNullOrEmpty; +import static com.epam.reportportal.karate.ReportPortalUtils.*; +import static com.epam.reportportal.utils.ParameterUtils.formatParametersAsTable; +import static com.epam.reportportal.utils.markdown.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); - - private static final ReportPortal REPORT_PORTAL = ReportPortal.builder().build(); - private final ConcurrentHashMap> featureIdMap = new ConcurrentHashMap<>(); - private final ConcurrentHashMap> scenarioIdMap = new ConcurrentHashMap<>(); - private final ConcurrentHashMap, Long> stepStartTimeMap = new ConcurrentHashMap<>(); - private Maybe stepId; - - private final MemoizingSupplier launch; - - private Thread shutDownHook; - - private static Thread getShutdownHook(final Supplier launch) { - return new Thread(() -> { - FinishExecutionRQ rq = new FinishExecutionRQ(); - rq.setEndTime(Calendar.getInstance().getTime()); - launch.get().finish(rq); - }); - } - - public ReportPortalPublisher() { - this.launch = new MemoizingSupplier<>(() -> { - ReportPortal rp = getReporter(); - ListenerParameters params = rp.getParameters(); - StartLaunchRQ rq = buildStartLaunchRq(params); - rq.setStartTime(Calendar.getInstance().getTime()); - Launch newLaunch = rp.newLaunch(rq); - shutDownHook = getShutdownHook(() -> newLaunch); - Runtime.getRuntime().addShutdownHook(shutDownHook); - return newLaunch; - }); - } - - public ReportPortalPublisher(Supplier launchSupplier) { - launch = new MemoizingSupplier<>(launchSupplier); - shutDownHook = getShutdownHook(launch); - Runtime.getRuntime().addShutdownHook(shutDownHook); - } - - /** - * Customize start launch event/request - * @param parameters Launch configuration parameters - * @return request to ReportPortal - */ - protected StartLaunchRQ buildStartLaunchRq(ListenerParameters parameters) { - StartLaunchRQ rq = new StartLaunchRQ(); - rq.setName(parameters.getLaunchName()); - rq.setStartTime(Calendar.getInstance().getTime()); - rq.setMode(parameters.getLaunchRunningMode()); - rq.setAttributes(new HashSet<>(parameters.getAttributes())); - if (!isNullOrEmpty(parameters.getDescription())) { - rq.setDescription(parameters.getDescription()); - } - rq.setStartTime(Calendar.getInstance().getTime()); - rq.setRerun(parameters.isRerun()); - if (isNotBlank(parameters.getRerunOf())) { - rq.setRerunOf(parameters.getRerunOf()); - } - return rq; - } - - /** - * Starts launch instance - */ - public void startLaunch() { - launch.get().start(); - } - - /** - * @return ReportPortal client instance - */ - protected ReportPortal getReporter() { - return REPORT_PORTAL; - } - - /** - * Finish launch - */ - public void finishLaunch() { - FinishExecutionRQ rq = new FinishExecutionRQ(); - rq.setEndTime(Calendar.getInstance().getTime()); - ListenerParameters parameters = launch.get().getParameters(); - LOGGER.info("LAUNCH URL: {}/ui/#{}/launches/all/{}", parameters.getBaseUrl(), parameters.getProjectName(), - System.getProperty("rp.launch.id")); - launch.get().finish(rq); - Runtime.getRuntime().removeShutdownHook(shutDownHook); - } - - /** - * Customize start test item event/request - * @param name item's name - * @param startTime item's start time in Date format - * @param type item's type (e.g. feature, scenario, step, etc.) - * @return request to ReportPortal - */ - protected StartTestItemRQ buildStartTestItemRq(@Nonnull String name, - @Nonnull Date startTime, - @Nonnull String type) { - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setName(name); - rq.setStartTime(startTime); - rq.setType(type); - return rq; - } - - /** - * Customize start test item event/request - * @param name item's name - * @param startTime item's start time - * @param type item's type (e.g. feature, scenario, step, etc.) - * @param hasStats enables nested items - * @return request to ReportPortal - */ - @SuppressWarnings("SameParameterValue") - protected StartTestItemRQ buildStartTestItemRq(@Nonnull String name, - @Nonnull Date startTime, - @Nonnull String type, - boolean hasStats) { - StartTestItemRQ rq = buildStartTestItemRq(name, startTime, type); - rq.setHasStats(hasStats); - return rq; - } - - /** - * Customize start test item event/request - * - * @param endTime item's end time - * @param status item's status - * @return request to ReportPortal - */ - protected FinishTestItemRQ buildFinishTestItemRq(@Nonnull Date endTime, - @Nonnull String status) { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setEndTime(endTime); - rq.setStatus(status); - return rq; - } - - /** - * Start sending feature data to ReportPortal - * - * @param featureResult feature result - */ - public void startFeature(FeatureResult featureResult) { - StartTestItemRQ rq = buildStartTestItemRq(String.valueOf(featureResult.toCucumberJson().get("name")), - Calendar.getInstance().getTime(), - "STORY"); - Maybe featureId = launch.get().startTestItem(rq); - featureIdMap.put(featureResult.getCallNameForReport(), featureId); - } - - /** - * 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); - } - - stepStartTimeMap.clear(); - finishScenario(scenarioResult); - } - - FinishTestItemRQ rq = buildFinishTestItemRq(Calendar.getInstance().getTime(), - featureResult.isFailed() ? ItemStatusEnum.FAILED.toString() : ItemStatusEnum.PASSED.toString()); - launch.get().finishTestItem(featureIdMap.remove(featureResult.getCallNameForReport()), rq); - } - - /** - * Start sending scenario data to ReportPortal - * - * @param scenarioResult scenario result - * @param featureResult feature result - */ - public void startScenario(ScenarioResult scenarioResult, FeatureResult featureResult) { - StartTestItemRQ rq = buildStartTestItemRq(scenarioResult.getScenario().getName(), - Calendar.getInstance().getTime(), - "STEP"); - Maybe scenarioId = launch.get().startTestItem(featureIdMap.get(featureResult.getCallNameForReport()), rq); - scenarioIdMap.put(scenarioResult.getScenario().getName(), scenarioId); - } - - /** - * 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 = buildFinishTestItemRq(Calendar.getInstance().getTime(), - scenarioResult.getFailureMessageForDisplay() == null ? ItemStatusEnum.PASSED.toString() : ItemStatusEnum.FAILED.toString()); - Maybe removedScenarioId = scenarioIdMap.remove(scenarioResult.getScenario().getName()); - launch.get().finishTestItem(removedScenarioId, rq); - } - - /** - * Start sending step data to ReportPortal - * - * @param stepResult step result - * @param scenarioResult scenario result - */ - public void startStep(StepResult stepResult, ScenarioResult scenarioResult) { - String stepName = stepResult.getStep().getPrefix() + " " + stepResult.getStep().getText(); - StartTestItemRQ rq = buildStartTestItemRq(stepName, getStepStartTime(stepStartTimeMap, stepId), "STEP", false); - stepId = launch.get().startTestItem(scenarioIdMap.get(scenarioResult.getScenario().getName()), rq); - stepStartTimeMap.put(stepId, rq.getStartTime().getTime()); - } - - /** - * Finish sending scenario data to ReportPortal - * - * @param stepResult step result - */ - public void finishStep(StepResult stepResult) { - if (stepId == null) { - LOGGER.error("ERROR: Trying to finish unspecified step."); - return; - } - - FinishTestItemRQ rq = buildFinishTestItemRq(Calendar.getInstance().getTime(), - getStepStatus(stepResult.getResult().getStatus())); - launch.get().finishTestItem(stepId, rq); - } - - - /** - * Send step execution results to ReportPortal - * - * @param stepResult step execution results - */ - public void sendStepResults(StepResult stepResult) { - Result result = stepResult.getResult(); - String logLevel = getLogLevel(result.getStatus()); - Step step = stepResult.getStep(); - - if (step.getDocString() != null) { - sendLog("\n-----------------DOC_STRING-----------------\n" + step.getDocString(), logLevel); - } - - if (stepResult.getStepLog() != null - && !stepResult.getStepLog().isEmpty() - && !stepResult.getStepLog().equals(" ")) { - sendLog(stepResult.getStepLog(), logLevel); - } - } - - /** - * Send step logs and/or execution results to ReportPortal - * - * @param message log message to send - * @param level log level - */ - public void sendLog(final String message, final String level) { - ReportPortal.emitLog(itemId -> { - SaveLogRQ rq = new SaveLogRQ(); - rq.setMessage(message); - rq.setItemUuid(itemId); - rq.setLevel(level); - rq.setLogTime(Calendar.getInstance().getTime()); - return rq; - }); - } - - private String getStepStatus(String status) { - switch (status) { - case "failed": - return ItemStatusEnum.FAILED.toString(); - case "passed": - return ItemStatusEnum.PASSED.toString(); - case "skipped": - return ItemStatusEnum.SKIPPED.toString(); - case "stopped": - return ItemStatusEnum.STOPPED.toString(); - case "interrupted": - return ItemStatusEnum.RESETED.toString(); - case "cancelled": - return ItemStatusEnum.CANCELLED.toString(); - default: - LOGGER.warn("Unknown step status received! Set it as SKIPPED"); - return ItemStatusEnum.SKIPPED.toString(); - } - } - - private String getLogLevel(String status) { - switch (status) { - case "failed": - return ItemLogLevelEnum.ERROR.toString(); - case "stopped": - case "interrupted": - case "cancelled": - return ItemLogLevelEnum.WARN.toString(); - default: - return ItemLogLevelEnum.INFO.toString(); - } - } - - /** - * 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 stepStartTimeMap ConcurrentHashMap of steps within a scenario. - * @param stepId step ID. - * @return step new startTime in Date format. - */ - private Date getStepStartTime(ConcurrentHashMap, Long> stepStartTimeMap, Maybe stepId) { - long currentStepStartTime = Calendar.getInstance().getTime().getTime(); - - if (!stepStartTimeMap.keySet().isEmpty()) { - long lastStepStartTime = stepStartTimeMap.get(stepId); - - if (lastStepStartTime >= currentStepStartTime) { - currentStepStartTime += (lastStepStartTime - currentStepStartTime) + 1; - } - } - - return new Date(currentStepStartTime); - } + 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, Long> stepStartTimeMap = new HashMap<>(); + private Maybe backgroundId; + 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); + shutDownHook = registerShutdownHook(this::finishLaunch); + } + + /** + * 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() { + Launch launchObject = launch.get(); + ListenerParameters parameters = launchObject.getParameters(); + FinishExecutionRQ rq = buildFinishLaunchRq(parameters); + LOGGER.info("Launch URL: {}/ui/#{}/launches/all/{}", + parameters.getBaseUrl(), + parameters.getProjectName(), + System.getProperty("rp.launch.id") + ); + launchObject.finish(rq); + if (Thread.currentThread() != shutDownHook) { + unregisterShutdownHook(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(Calendar.getInstance().getTime(), 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); + } + + stepStartTimeMap.clear(); + 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.getScenario()); + } + + /** + * 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 buildFinishTestItemRq(Calendar.getInstance().getTime(), + scenarioResult.getFailureMessageForDisplay() == null ? ItemStatus.PASSED : ItemStatus.FAILED + ); + + } + + /** + * 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()); + //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(Calendar.getInstance().getTime(), null); + + } + + /** + * Finish sending Scenario data to ReportPortal. + * + * @param stepResult step result + * @param scenarioResult scenario result + */ + public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioResult scenarioResult) { + ofNullable(backgroundId).ifPresent(id -> { + FinishTestItemRQ finishRq = buildFinishBackgroundRq(stepResult, scenarioResult); + //noinspection ReactiveStreamsUnusedPublisher + launch.get().finishTestItem(id, finishRq); + }); + backgroundId = null; + } + + /** + * 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 stepId step ID. + * @return step new startTime in Date format. + */ + private Date getStepStartTime(@Nonnull Maybe stepId) { + long currentStepStartTime = Calendar.getInstance().getTime().getTime(); + + if (!stepStartTimeMap.keySet().isEmpty()) { + long lastStepStartTime = stepStartTimeMap.get(stepId); + + if (lastStepStartTime >= currentStepStartTime) { + currentStepStartTime += (lastStepStartTime - currentStepStartTime) + 1; + } + } + return new Date(currentStepStartTime); + } + + /** + * 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()); + Date startTime = getStepStartTime(stepId); + 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(); + if (step.isBackground()) { + startBackground(stepResult, scenarioResult); + } else { + finishBackground(stepResult, scenarioResult); + } + StartTestItemRQ stepRq = buildStartStepRq(stepResult, scenarioResult); + stepId = launch.get() + .startTestItem(backgroundId != null ? backgroundId : scenarioIdMap.get(scenarioResult.getScenario().getName()), stepRq); + stepStartTimeMap.put(stepId, stepRq.getStartTime().getTime()); + 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(Calendar.getInstance().getTime(), 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) { + if (stepId == null) { + LOGGER.error("ERROR: Trying to finish unspecified step."); + return; + } + + FinishTestItemRQ rq = buildFinishStepRq(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); + } + + /** + * 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); + } + 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/ReportPortalUtils.java b/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java new file mode 100644 index 0000000..ed5da64 --- /dev/null +++ b/src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java @@ -0,0 +1,426 @@ +/* + * 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.ItemType; +import com.epam.reportportal.listeners.ListenerParameters; +import com.epam.reportportal.listeners.LogLevel; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.item.TestCaseIdEntry; +import com.epam.reportportal.utils.AttributeParser; +import com.epam.reportportal.utils.ParameterUtils; +import com.epam.reportportal.utils.TestCaseIdUtils; +import com.epam.reportportal.utils.properties.SystemAttributesExtractor; +import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; +import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import com.epam.ta.reportportal.ws.model.ParameterResource; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import com.intuit.karate.core.*; +import io.reactivex.Maybe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.epam.reportportal.utils.ParameterUtils.NULL_VALUE; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * Set of useful utils related to Karate -> ReportPortal integration + */ +public class ReportPortalUtils { + public static final String MARKDOWN_CODE_PATTERN = "```\n%s\n```"; + public static final String PARAMETERS_PATTERN = "Parameters:\n\n%s"; + public static final String VARIABLE_PATTERN = "(?:(?<=#\\()%1$s(?=\\)))|(?:(?<=[\\s=+-/*<>(]|^)%1$s(?=[\\s=+-/*<>)]|(?:\\r?\\n)|$))"; + public static final String AGENT_PROPERTIES_FILE = "agent.properties"; + public static final String SKIPPED_ISSUE_KEY = "skippedIssue"; + public static final String SCENARIO_CODE_REFERENCE_PATTERN = "%s/[SCENARIO:%s]"; + public static final String EXAMPLE_CODE_REFERENCE_PATTERN = "%s/[EXAMPLE:%s%s]"; + public static final String MARKDOWN_DELIMITER_PATTERN = "%s\n\n---\n\n%s"; + 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 ReportPortalUtils() { + throw new RuntimeException("No instances should exist for the class!"); + } + + /** + * Create a String from a parameter Map to be used as a test key and title + * + * @param example a map of parameters: name->value + * @return a formatted string of parameters + */ + public static String formatExampleKey(@Nonnull final Map example) { + return example.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .map(e -> e.getKey() + KEY_VALUE_SEPARATOR + e.getValue().toString()) + .collect(Collectors.joining(PARAMETER_ITEMS_DELIMITER, PARAMETER_ITEMS_START, PARAMETER_ITEMS_END)); + } + + /** + * Create a launch finish hook which will be called on JVM shutdown. Prevents from long unfinished launches for + * interrupted tests. + * + * @param actions Shutdown actions to perform + * @return a Thread which executes Launch finish and exits + */ + @Nonnull + public static Thread createShutdownHook(@Nonnull Runnable actions) { + return new Thread(actions); + } + + /** + * Create and register a launch finish hook which will be called on JVM shutdown. Prevents from long unfinished + * launches for interrupted tests. + * + * @param actions Shutdown actions to perform + * @return a Thread which executes Launch finish and exits + */ + @Nonnull + public static Thread registerShutdownHook(@Nonnull Runnable actions) { + Thread shutDownHook = createShutdownHook(actions); + Runtime.getRuntime().addShutdownHook(shutDownHook); + return shutDownHook; + } + + /** + * Remove a launch finish hook. Use it if the launch finished gracefully. + * + * @param hook a Thread which represents Launch finish hook + */ + public static void unregisterShutdownHook(@Nonnull Thread hook) { + Runtime.getRuntime().removeShutdownHook(hook); + } + + /** + * Build default start launch event/request + * + * @param parameters Launch configuration parameters + * @return request to ReportPortal + */ + @Nonnull + public static StartLaunchRQ buildStartLaunchRq(@Nonnull ListenerParameters parameters) { + StartLaunchRQ rq = new StartLaunchRQ(); + rq.setName(parameters.getLaunchName()); + rq.setStartTime(Calendar.getInstance().getTime()); + rq.setMode(parameters.getLaunchRunningMode()); + rq.setAttributes(new HashSet<>(parameters.getAttributes())); + if (isNotBlank(parameters.getDescription())) { + rq.setDescription(parameters.getDescription()); + } + rq.setRerun(parameters.isRerun()); + if (isNotBlank(parameters.getRerunOf())) { + rq.setRerunOf(parameters.getRerunOf()); + } + if (null != parameters.getSkippedAnIssue()) { + ItemAttributesRQ skippedIssueAttribute = new ItemAttributesRQ(); + skippedIssueAttribute.setKey(ReportPortalUtils.SKIPPED_ISSUE_KEY); + skippedIssueAttribute.setValue(parameters.getSkippedAnIssue().toString()); + skippedIssueAttribute.setSystem(true); + rq.getAttributes().add(skippedIssueAttribute); + } + rq.getAttributes().addAll(SystemAttributesExtractor.extract(AGENT_PROPERTIES_FILE, ReportPortalUtils.class.getClassLoader())); + return rq; + } + + /** + * Build default finish launch event/request + * + * @param parameters Launch configuration parameters + * @return request to ReportPortal + */ + @Nonnull + @SuppressWarnings("unused") + public static FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) { + FinishExecutionRQ rq = new FinishExecutionRQ(); + rq.setEndTime(Calendar.getInstance().getTime()); + return rq; + } + + /** + * Returns code reference for feature files by URI and Scenario reference + * + * @param scenario Karate's Scenario object instance + * @return a code reference + */ + @Nonnull + public static String getCodeRef(@Nonnull Scenario scenario) { + if (scenario.isOutlineExample()) { + return String.format(EXAMPLE_CODE_REFERENCE_PATTERN, + scenario.getFeature().getResource().getRelativePath(), + scenario.getName(), + ReportPortalUtils.formatExampleKey(scenario.getExampleData()) + ); + } else { + return String.format(SCENARIO_CODE_REFERENCE_PATTERN, + scenario.getFeature().getResource().getRelativePath(), + scenario.getName() + ); + } + } + + /** + * Build default start test item event/request + * + * @param name item's name + * @param startTime item's start time in Date format + * @param type item's type (e.g. feature, scenario, step, etc.) + * @return request to ReportPortal + */ + @Nonnull + public static StartTestItemRQ buildStartTestItemRq(@Nonnull String name, @Nonnull Date startTime, @Nonnull ItemType type) { + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setName(name); + rq.setStartTime(startTime); + rq.setType(type.name()); + return rq; + } + + /** + * Build default finish test item event/request + * + * @param endTime item's end time + * @param status item's status + * @return request to ReportPortal + */ + @Nonnull + public static FinishTestItemRQ buildFinishTestItemRq(@Nonnull Date endTime, @Nullable ItemStatus status) { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setEndTime(endTime); + rq.setStatus(ofNullable(status).map(Enum::name).orElse(null)); + return rq; + } + + @Nullable + public static Set toAttributes(@Nullable List tags) { + Set attributes = ofNullable(tags).orElse(Collections.emptyList()).stream().flatMap(tag -> { + if (tag.getValues().isEmpty()) { + return Stream.of(new ItemAttributesRQ(null, tag.getName())); + } + return AttributeParser.createItemAttributes(tag.getName(), tag.getValues().toArray(new String[0])).stream(); + }).collect(Collectors.toSet()); + return attributes.isEmpty() ? null : attributes; + } + + /** + * Build ReportPortal request for start Feature event. + * + * @param feature Karate's Feature object instance + * @return request to ReportPortal + */ + @Nonnull + public static StartTestItemRQ buildStartFeatureRq(@Nonnull Feature feature) { + StartTestItemRQ rq = buildStartTestItemRq(feature.getName(), Calendar.getInstance().getTime(), ItemType.STORY); + rq.setAttributes(toAttributes(feature.getTags())); + String featurePath = feature.getResource().getUri().toString(); + String description = feature.getDescription(); + if (isNotBlank(description)) { + rq.setDescription(String.format(MARKDOWN_DELIMITER_PATTERN, featurePath, description)); + } else { + rq.setDescription(featurePath); + } + return rq; + } + + /** + * Transform Map of parameters to ReportPortal parameter list. + * + * @param args argument Map + * @return parameters + */ + @Nonnull + public static List getParameters(@Nonnull Map args) { + return args.entrySet().stream().map(e -> { + ParameterResource parameterResource = new ParameterResource(); + parameterResource.setKey(e.getKey()); + parameterResource.setValue(ofNullable(e.getValue()).map(Object::toString).orElse(NULL_VALUE)); + return parameterResource; + }).collect(Collectors.toList()); + } + + /** + * Extract and transform ScenarioOutline parameters to ReportPortal parameter list. + * + * @param scenario Karate's Scenario object instance + * @return parameters + */ + @Nullable + public static List getParameters(@Nonnull Scenario scenario) { + if (!scenario.isOutlineExample()) { + return null; + } + return getParameters(scenario.getExampleData()); + } + + /** + * Return a Test Case ID for a Scenario in a Feature file + * + * @param scenario Karate's Scenario object instance + * @return Test Case ID entity or null if it's not possible to calculate + */ + @Nullable + public static TestCaseIdEntry getTestCaseId(@Nonnull Scenario scenario) { + return TestCaseIdUtils.getTestCaseId(getCodeRef(scenario), null); + } + + /** + * Build ReportPortal request for start Scenario event + * + * @param scenario Karate's Scenario object instance + * @return request to ReportPortal + */ + @Nonnull + public static StartTestItemRQ buildStartScenarioRq(@Nonnull Scenario scenario) { + StartTestItemRQ rq = buildStartTestItemRq(scenario.getName(), Calendar.getInstance().getTime(), ItemType.STEP); + rq.setCodeRef(getCodeRef(scenario)); + rq.setTestCaseId(ofNullable(getTestCaseId(scenario)).map(TestCaseIdEntry::getId).orElse(null)); + rq.setAttributes(toAttributes(scenario.getTags())); + List parameters = getParameters(scenario); + boolean hasParameters = ofNullable(parameters).filter(p -> !p.isEmpty()).isPresent(); + if (hasParameters) { + rq.setParameters(parameters); + } + + String description = scenario.getDescription(); + if (isNotBlank(description)) { + if (hasParameters) { + rq.setDescription(String.format(MARKDOWN_DELIMITER_PATTERN, + String.format(PARAMETERS_PATTERN, ParameterUtils.formatParametersAsTable(parameters)), + description + )); + } else { + rq.setDescription(description); + } + } else if (hasParameters) { + rq.setDescription(String.format(PARAMETERS_PATTERN, ParameterUtils.formatParametersAsTable(parameters))); + } + return rq; + } + + /** + * Build ReportPortal request for start Background event. + * + * @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, Calendar.getInstance().getTime(), ItemType.STEP); + rq.setHasStats(false); + return rq; + } + + /** + * Customize start step test item event/request + * + * @param step Karate's Step object instance + * @param scenario Karate's Scenario object instance + * @return request to ReportPortal + */ + @Nonnull + public static StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull Scenario scenario) { + String stepName = step.getPrefix() + " " + step.getText(); + StartTestItemRQ rq = buildStartTestItemRq(stepName, Calendar.getInstance().getTime(), ItemType.STEP); + rq.setHasStats(false); + if (step.isOutline()) { + List parameters = scenario.getExampleData() + .entrySet() + .stream() + .filter(e -> Pattern.compile(String.format(VARIABLE_PATTERN, e.getKey())).matcher(step.getText()).find()) + .map(e -> { + ParameterResource param = new ParameterResource(); + param.setKey(e.getKey()); + var value = ofNullable(e.getValue()).map(Object::toString).orElse(NULL_VALUE); + param.setValue(value); + return param; + }) + .collect(Collectors.toList()); + rq.setParameters(parameters); + } + return rq; + } + + /** + * Map Karate's item status to ReportPortal status object. + * + * @param status Karate item status + * @return ReportPortal status + */ + public static ItemStatus getStepStatus(String status) { + switch (status) { + case "failed": + return ItemStatus.FAILED; + case "passed": + return ItemStatus.PASSED; + case "skipped": + return ItemStatus.SKIPPED; + case "stopped": + return ItemStatus.STOPPED; + case "interrupted": + return ItemStatus.INTERRUPTED; + case "cancelled": + return ItemStatus.CANCELLED; + default: + LOGGER.warn("Unknown step status received! Set it as SKIPPED"); + return ItemStatus.SKIPPED; + } + } + + /** + * Send Step logs to ReportPortal. + * + * @param itemId item ID future + * @param message log message to send + * @param level log level + */ + public static void sendLog(Maybe itemId, String message, LogLevel level) { + ReportPortal.emitLog(itemId, id -> { + SaveLogRQ rq = new SaveLogRQ(); + rq.setMessage(message); + rq.setItemUuid(id); + rq.setLevel(level.name()); + rq.setLogTime(Calendar.getInstance().getTime()); + return rq; + }); + } + + /** + * Builds markdown representation of some code or script to be logged to ReportPortal + * + * @param code Code or Script + * @return Message to be sent to ReportPortal + */ + public static String asMarkdownCode(String code) { + return String.format(MARKDOWN_CODE_PATTERN, code); + } +} diff --git a/src/main/java/com/epam/reportportal/karate/enums/ItemLogLevelEnum.java b/src/main/java/com/epam/reportportal/karate/enums/ItemLogLevelEnum.java deleted file mode 100644 index f3f63df..0000000 --- a/src/main/java/com/epam/reportportal/karate/enums/ItemLogLevelEnum.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.epam.reportportal.karate.enums; - -public enum ItemLogLevelEnum { - INFO("INFO"), - WARN("WARN"), - ERROR("ERROR"); - - private final String name; - - ItemLogLevelEnum(String name) { - this.name = name; - } - - @Override - public String toString() { - return this.name; - } -} diff --git a/src/main/java/com/epam/reportportal/karate/enums/ItemStatusEnum.java b/src/main/java/com/epam/reportportal/karate/enums/ItemStatusEnum.java deleted file mode 100644 index 620e670..0000000 --- a/src/main/java/com/epam/reportportal/karate/enums/ItemStatusEnum.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.epam.reportportal.karate.enums; - -public enum ItemStatusEnum { - PASSED("PASSED"), - FAILED("FAILED"), - SKIPPED("SKIPPED"), - STOPPED("STOPPED"), - RESETED("RESETED"), - CANCELLED("CANCELLED"); - - private final String name; - - ItemStatusEnum(String name) { - this.name = name; - } - - @Override - public String toString() { - return this.name; - } -} diff --git a/src/test/java/com/epam/reportportal/karate/KarateTest.java b/src/test/java/com/epam/reportportal/karate/KarateTest.java index fd3e58a..dc64830 100644 --- a/src/test/java/com/epam/reportportal/karate/KarateTest.java +++ b/src/test/java/com/epam/reportportal/karate/KarateTest.java @@ -1,3 +1,19 @@ +/* + * 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; @@ -7,16 +23,15 @@ 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()); - } + @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 index dbe1a68..536bc9d 100644 --- a/src/test/java/com/epam/reportportal/karate/ReportPortalPublisherTest.java +++ b/src/test/java/com/epam/reportportal/karate/ReportPortalPublisherTest.java @@ -1,12 +1,30 @@ +/* + * 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.reportportal.utils.ReflectUtils; 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; @@ -14,62 +32,69 @@ 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 { - private ReportPortalPublisher reportPortalPublisher; - @Mock - Launch launchMock; + @Mock + Launch launchMock; + private ReportPortalPublisher reportPortalPublisher; - @BeforeEach - public void setUp() { - reportPortalPublisher = new ReportPortalPublisher(() -> launchMock); - } + @BeforeEach + public void setUp() { + reportPortalPublisher = new ReportPortalPublisher(() -> launchMock); + } - @Test - public void shouldStartLaunch() { - reportPortalPublisher.startLaunch(); - verify(launchMock, times(1)).start(); - } + @Test + public void shouldStartLaunch() { + reportPortalPublisher.startLaunch(); + verify(launchMock, times(1)).start(); + } - @Test - public void shouldFinishLaunch() { - when(launchMock.getParameters()).thenReturn(getListenerParameters()); - reportPortalPublisher.finishLaunch(); - verify(launchMock, times(1)).finish(any(FinishExecutionRQ.class)); - } + @Test + public void shouldFinishLaunch() { + when(launchMock.getParameters()).thenReturn(getListenerParameters()); + reportPortalPublisher.finishLaunch(); + verify(launchMock, times(1)).finish(any(FinishExecutionRQ.class)); + } - @SuppressWarnings("unchecked") - @Test - public void shouldStartFeature() { - FeatureResult featureResult = mock(FeatureResult.class); - when(featureResult.getCallNameForReport()).thenReturn("featureName"); - 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 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)); - } + @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; - } + 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 new file mode 100644 index 0000000..aa0573b --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/attributes/DifferentAttributesTest.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.attributes; + +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.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; +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.List; +import java.util.Set; +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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class DifferentAttributesTest { + private static final String TEST_FEATURE = "classpath:feature/tags.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_different_attributes(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), 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(3)).startTestItem(same(scenarioId), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(5)); + + StartTestItemRQ featureRq = items.get(0); + StartTestItemRQ scenarioRq = items.get(1); + + assertThat(featureRq.getAttributes(), hasSize(1)); + ItemAttributesRQ featureAttribute = featureRq.getAttributes().iterator().next(); + assertThat(featureAttribute.getKey(), nullValue()); + assertThat(featureAttribute.getValue(), equalTo("tag_test")); + + assertThat(scenarioRq.getAttributes(), hasSize(4)); + Set> scenarioAttributes = scenarioRq.getAttributes() + .stream() + .map(a -> Pair.of(a.getKey(), a.getValue())) + .collect(Collectors.toSet()); + assertThat(scenarioAttributes, hasItem(Pair.of(null, "math"))); + assertThat(scenarioAttributes, hasItem(Pair.of("scope", "smoke"))); + assertThat(scenarioAttributes, hasItem(Pair.of("environment", "dev"))); + assertThat(scenarioAttributes, hasItem(Pair.of("environment", "qa"))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java new file mode 100644 index 0000000..c419888 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/attributes/LaunchAttributesTest.java @@ -0,0 +1,89 @@ +/* + * 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.attributes; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ListenerParameters; +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.attribute.ItemAttributesRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +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.mock; +import static org.mockito.Mockito.verify; + +public class LaunchAttributesTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private ReportPortal rp; + + @BeforeEach + public void setupMock() { + ListenerParameters parameters = standardParameters(); + parameters.setAttributes(new HashSet<>(Arrays.asList(new ItemAttributesRQ("key", "value"), new ItemAttributesRQ(null, "value")))); + rp = ReportPortal.create(client, parameters, testExecutor()); + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void verify_start_launch_request_contains_launch_attributes(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(startCaptor.capture()); + + StartLaunchRQ launchStart = startCaptor.getValue(); + + Set attributes = launchStart.getAttributes(); + assertThat(attributes, allOf(notNullValue(), hasSize(greaterThan(0)))); + Set attributesStr = attributes.stream() + .filter(a -> !a.isSystem()) + .map(e -> e.getKey() + ":" + e.getValue()) + .collect(Collectors.toSet()); + assertThat(attributesStr, hasSize(2)); + assertThat(attributesStr, hasItem("key:value")); + assertThat(attributesStr, hasItem("null:value")); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java new file mode 100644 index 0000000..9ae4a8b --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/attributes/NoAttributesTest.java @@ -0,0 +1,80 @@ +/* + * 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.attributes; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class NoAttributesTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_different_attributes(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), 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(3)).startTestItem(same(scenarioId), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(5)); + + StartTestItemRQ featureRq = items.get(0); + StartTestItemRQ scenarioRq = items.get(1); + + assertThat(featureRq.getAttributes(), nullValue()); + assertThat(scenarioRq.getAttributes(), nullValue()); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java b/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java new file mode 100644 index 0000000..23664a9 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/attributes/SystemAttributesTest.java @@ -0,0 +1,85 @@ +/* + * 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.attributes; + +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.attribute.ItemAttributesRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.List; +import java.util.Set; +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.mock; +import static org.mockito.Mockito.verify; + +public class SystemAttributesTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void verify_start_launch_request_contains_system_attributes(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(startCaptor.capture()); + + StartLaunchRQ launchStart = startCaptor.getValue(); + + Set attributes = launchStart.getAttributes(); + assertThat(attributes, allOf(notNullValue(), hasSize(greaterThan(0)))); + Set attributesStr = attributes.stream() + .filter(ItemAttributesRQ::isSystem) + .map(e -> e.getKey() + ":" + e.getValue()) + .collect(Collectors.toSet()); + assertThat(attributesStr, hasSize(4)); + assertThat(attributesStr, hasItem("skippedIssue:true")); + assertThat(attributesStr, hasItem("agent:karate-test-agent|test-1.0")); + assertThat(attributesStr, hasItem(startsWith("os:"))); + assertThat(attributesStr, hasItem(startsWith("jvm:"))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java b/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java new file mode 100644 index 0000000..df30ea9 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundExamplesTest.java @@ -0,0 +1,120 @@ +/* + * 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.background; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +import com.intuit.karate.core.Background; +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.List; +import java.util.Set; +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.ArgumentMatchers.same; +import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.Mockito.*; + +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>> scenarioSteps = scenarioIds.stream() + .map(s -> Pair.of(s, Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()))) + .collect(Collectors.toList()); + private final List> nestedStepIds = scenarioSteps.stream() + .flatMap(s -> s.getValue().stream()) + .map(s -> Pair.of(s, CommonUtils.namedId("nested_step_"))) + .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, scenarioSteps); + mockNestedSteps(client, nestedStepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_background_steps(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(captor.capture()); + verify(client, times(2)).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor firstStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioIds.get(0)), firstStepCaptor.capture()); + ArgumentCaptor secondStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioIds.get(1)), secondStepCaptor.capture()); + ArgumentCaptor nestedStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(startsWith("step_"), nestedStepCaptor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(3)); + List firstSteps = firstStepCaptor.getAllValues(); + assertThat(firstSteps, hasSize(3)); + List secondSteps = secondStepCaptor.getAllValues(); + assertThat(firstSteps, hasSize(3)); + + List firstBackgroundSteps = firstSteps.stream() + .filter(s -> s.getName().startsWith(Background.KEYWORD)) + .collect(Collectors.toList()); + assertThat(firstBackgroundSteps, hasSize(1)); + List secondBackgroundSteps = secondSteps.stream() + .filter(s -> s.getName().startsWith(Background.KEYWORD)) + .collect(Collectors.toList()); + assertThat(secondBackgroundSteps, hasSize(1)); + + Stream.concat(firstBackgroundSteps.stream(), secondBackgroundSteps.stream()).forEach(backgroundStep -> { + assertThat(backgroundStep.getName(), equalTo(Background.KEYWORD)); // No name for Background in Karate + assertThat(backgroundStep.isHasStats(), equalTo(Boolean.FALSE)); + assertThat(backgroundStep.getStartTime(), notNullValue()); + assertThat(backgroundStep.getType(), equalTo(ItemType.STEP.name())); + }); + + List nestedSteps = nestedStepCaptor.getAllValues(); + assertThat(nestedSteps, hasSize(2)); + nestedSteps.forEach(step -> assertThat(step.isHasStats(), equalTo(Boolean.FALSE))); + Set nestedStepNames = nestedSteps.stream().map(StartTestItemRQ::getName).collect(Collectors.toSet()); + + assertThat(nestedStepNames, hasSize(1)); + assertThat(nestedStepNames, hasItem("Given def 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 new file mode 100644 index 0000000..6a6aaac --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundTest.java @@ -0,0 +1,103 @@ +/* + * 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.background; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +import com.intuit.karate.core.Background; +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.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.ArgumentMatchers.same; +import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.Mockito.*; + +public class BackgroundTest { + private static final String TEST_FEATURE = "classpath:feature/background.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + private final List> nestedStepIds = stepIds.stream() + .map(id -> Pair.of(id, CommonUtils.namedId("nested_step_"))) + .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, scenarioId, stepIds); + mockNestedSteps(client, nestedStepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_background_steps(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(captor.capture()); + verify(client).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + ArgumentCaptor nestedStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(startsWith("step_"), nestedStepCaptor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(2)); + List steps = stepCaptor.getAllValues(); + assertThat(steps, hasSize(3)); + + List backgroundSteps = steps.stream() + .filter(s -> s.getName().startsWith(Background.KEYWORD)) + .collect(Collectors.toList()); + assertThat(backgroundSteps, hasSize(1)); + StartTestItemRQ backgroundStep = backgroundSteps.get(0); + assertThat(backgroundStep.getName(), equalTo(Background.KEYWORD)); // No name for Background in Karate + assertThat(backgroundStep.isHasStats(), equalTo(Boolean.FALSE)); + assertThat(backgroundStep.getStartTime(), notNullValue()); + assertThat(backgroundStep.getType(), equalTo(ItemType.STEP.name())); + + List nestedSteps = nestedStepCaptor.getAllValues(); + assertThat(nestedSteps, hasSize(1)); + StartTestItemRQ nestedStep = nestedSteps.get(0); + assertThat(nestedStep.getName(), equalTo("Given def 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 new file mode 100644 index 0000000..67bd971 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/background/BackgroundTwoStepsTest.java @@ -0,0 +1,106 @@ +/* + * 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.background; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +import com.intuit.karate.core.Background; +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.List; +import java.util.Set; +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.ArgumentMatchers.same; +import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.Mockito.*; + +public class BackgroundTwoStepsTest { + private static final String TEST_FEATURE = "classpath:feature/background_two_steps.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(2).collect(Collectors.toList()); + private final List> nestedStepIds = Stream.concat( + stepIds.stream().map(id -> Pair.of(id, CommonUtils.namedId("nested_step_"))), + stepIds.stream().map(id -> Pair.of(id, CommonUtils.namedId("nested_step_"))) + ).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, scenarioId, stepIds); + mockNestedSteps(client, nestedStepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_background_steps(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(captor.capture()); + verify(client, times(1)).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(scenarioId), stepCaptor.capture()); + ArgumentCaptor nestedStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(startsWith("step_"), nestedStepCaptor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(2)); + List steps = stepCaptor.getAllValues(); + assertThat(steps, hasSize(2)); + + List backgroundSteps = steps.stream() + .filter(s -> s.getName().startsWith(Background.KEYWORD)) + .collect(Collectors.toList()); + assertThat(backgroundSteps, hasSize(1)); + StartTestItemRQ backgroundStep = backgroundSteps.get(0); + assertThat(backgroundStep.getName(), equalTo(Background.KEYWORD)); // No name for Background in Karate + assertThat(backgroundStep.isHasStats(), equalTo(Boolean.FALSE)); + assertThat(backgroundStep.getStartTime(), notNullValue()); + assertThat(backgroundStep.getType(), equalTo(ItemType.STEP.name())); + + List nestedSteps = nestedStepCaptor.getAllValues(); + assertThat(nestedSteps, hasSize(2)); + 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"))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java new file mode 100644 index 0000000..0975f38 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/coderef/ExamplesCodeRefTest.java @@ -0,0 +1,98 @@ +/* + * 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.coderef; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import 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.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class ExamplesCodeRefTest { + private static final String TEST_FEATURE = "classpath:feature/examples.feature"; + private static final String EXAMPLE_CODE_REFERENCE_PATTERN = "feature/examples.feature/[EXAMPLE:Verify different maths[%s]]"; + private static final String FIRST_EXAMPLE_CODE_REFERENCE = String.format(EXAMPLE_CODE_REFERENCE_PATTERN, "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>> 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); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_examples_code_reference(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor firstStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), firstStepCaptor.capture()); + ArgumentCaptor secondStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), secondStepCaptor.capture()); + + StartTestItemRQ featureRq = featureCaptor.getValue(); + assertThat(featureRq.getType(), allOf(notNullValue(), equalTo(ItemType.STORY.name()))); + + List scenarios = scenarioCaptor.getAllValues(); + StartTestItemRQ firstScenarioRq = scenarios.get(0); + assertThat(firstScenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(firstScenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_CODE_REFERENCE))); + + StartTestItemRQ secondScenarioRq = scenarios.get(1); + assertThat(secondScenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(secondScenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_CODE_REFERENCE))); + + Stream.concat(firstStepCaptor.getAllValues().stream(), secondStepCaptor.getAllValues().stream()).forEach(step -> { + assertThat(step.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(step.isHasStats(), equalTo(Boolean.FALSE)); + }); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java b/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java new file mode 100644 index 0000000..4285363 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/coderef/ScenarioCodeRefTest.java @@ -0,0 +1,87 @@ +/* + * 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.coderef; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ItemType; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class ScenarioCodeRefTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private static final String SIMPLE_CODE_REFERENCE = "feature/simple.feature/[SCENARIO:Verify math]"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_scenario_code_reference(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + StartTestItemRQ featureRq = featureCaptor.getValue(); + StartTestItemRQ scenarioRq = scenarioCaptor.getValue(); + + assertThat(featureRq.getType(), allOf(notNullValue(), equalTo(ItemType.STORY.name()))); + + assertThat(scenarioRq.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(scenarioRq.getCodeRef(), allOf(notNullValue(), equalTo(SIMPLE_CODE_REFERENCE))); + + stepCaptor.getAllValues().forEach(step -> { + assertThat(step.getType(), allOf(notNullValue(), equalTo(ItemType.STEP.name()))); + assertThat(step.isHasStats(), equalTo(Boolean.FALSE)); + }); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/CallWithParametersHookTest.java b/src/test/java/com/epam/reportportal/karate/description/CallWithParametersHookTest.java new file mode 100644 index 0000000..1fc96db --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/CallWithParametersHookTest.java @@ -0,0 +1,99 @@ +/* + * 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.description; + +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.reportportal.utils.markdown.MarkdownUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.intuit.karate.Results; +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.Collection; +import java.util.Collections; +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.endsWith; +import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.*; + +public class CallWithParametersHookTest { + private static final String TEST_FEATURE = "classpath:feature/call.feature"; + private static final String PARAMETERS_DESCRIPTION_PATTERN = + "Parameters:\n\n" + MarkdownUtils.TABLE_INDENT + "| vara | result |\n" + MarkdownUtils.TABLE_INDENT + "|------|--------|\n" + + MarkdownUtils.TABLE_INDENT + "|  2   |   4    |\n\n" + MarkdownUtils.TABLE_ROW_SEPARATOR; + private final List featureIds = Stream.generate(() -> CommonUtils.namedId("feature_")).limit(2).collect(Collectors.toList()); + private final List scenarioIds = Stream.generate(() -> CommonUtils.namedId("scenario_")).limit(2).collect(Collectors.toList()); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(4).collect(Collectors.toList()); + private final List>>>> features = Stream.of( + Pair.of(featureIds.get(0), + (Collection>>) Collections.singletonList(Pair.of( + scenarioIds.get(0), + Collections.singletonList(stepIds.get(0)) + )) + ), + Pair.of( + featureIds.get(1), + (Collection>>) Collections.singletonList(Pair.of( + scenarioIds.get(1), + stepIds.subList(1, stepIds.size()) + )) + ) + ).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); + mockFeatures(client, features); + mockBatchLogging(client); + } + + @Test + public void test_call_feature_with_parameters_hook_reporting() { + Results results = TestUtils.runAsHook(rp, TEST_FEATURE); + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureIds.get(0)), scenarioCaptor.capture()); + verify(client).startTestItem(same(featureIds.get(1)), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(scenarioIds.get(0)), stepCaptor.capture()); + verify(client, times(3)).startTestItem(same(scenarioIds.get(1)), stepCaptor.capture()); + + StartTestItemRQ calledFeature = featureCaptor.getAllValues() + .stream() + .filter(rq -> "a feature which is called with parameters".equals(rq.getName())) + .findAny() + .orElseThrow(); + + assertThat(calledFeature.getDescription(), allOf(endsWith("feature/called.feature"), startsWith(PARAMETERS_DESCRIPTION_PATTERN))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/CallWithParametersPublisherTest.java b/src/test/java/com/epam/reportportal/karate/description/CallWithParametersPublisherTest.java new file mode 100644 index 0000000..fdf1048 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/CallWithParametersPublisherTest.java @@ -0,0 +1,64 @@ +/* + * 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.description; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +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.equalTo; +import static org.mockito.Mockito.*; + +public class CallWithParametersPublisherTest { + private static final String TEST_FEATURE = "classpath:feature/call.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(1).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, scenarioId, stepIds); + mockBatchLogging(client); + } + + @Test + public void test_call_feature_with_parameters_publisher_reporting() { + Results results = TestUtils.runAsReport(rp, TEST_FEATURE); + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(captor.capture()); + verify(client).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(scenarioId), stepCaptor.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 new file mode 100644 index 0000000..d7ca77b --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/DescriptionExamplesTest.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.description; + +import com.epam.reportportal.karate.ReportPortalUtils; +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.StartTestItemRQ; +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.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class DescriptionExamplesTest { + public static final String FIRST_EXAMPLE_DESCRIPTION = String.format( + ReportPortalUtils.MARKDOWN_DELIMITER_PATTERN, + NoDescriptionExamplesTest.FIRST_EXAMPLE_DESCRIPTION, + SimpleDescriptionTest.SCENARIO_DESCRIPTION + ); + public static final String SECOND_EXAMPLE_DESCRIPTION = String.format( + ReportPortalUtils.MARKDOWN_DELIMITER_PATTERN, + NoDescriptionExamplesTest.SECOND_EXAMPLE_DESCRIPTION, + SimpleDescriptionTest.SCENARIO_DESCRIPTION + ); + 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>> 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); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_examples_description(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor firstStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), firstStepCaptor.capture()); + ArgumentCaptor secondStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), secondStepCaptor.capture()); + + List scenarios = scenarioCaptor.getAllValues(); + StartTestItemRQ firstScenarioRq = scenarios.get(0); + assertThat(firstScenarioRq.getDescription(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_DESCRIPTION))); + + StartTestItemRQ secondScenarioRq = scenarios.get(1); + assertThat(secondScenarioRq.getDescription(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_DESCRIPTION))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java new file mode 100644 index 0000000..b71479d --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/LaunchDescriptionTest.java @@ -0,0 +1,78 @@ +/* + * 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.description; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ListenerParameters; +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.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class LaunchDescriptionTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private static final String TEST_DESCRIPTION = "My test description"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private ReportPortal rp; + + @BeforeEach + public void setupMock() { + ListenerParameters parameters = standardParameters(); + parameters.setDescription(TEST_DESCRIPTION); + rp = ReportPortal.create(client, parameters, testExecutor()); + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void verify_start_launch_request_contains_launch_description(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(startCaptor.capture()); + + StartLaunchRQ launchStart = startCaptor.getValue(); + + assertThat(launchStart.getDescription(), equalTo(TEST_DESCRIPTION)); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java new file mode 100644 index 0000000..340d728 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionExamplesTest.java @@ -0,0 +1,90 @@ +/* + * 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.description; + +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.reportportal.utils.markdown.MarkdownUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +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.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class NoDescriptionExamplesTest { + private static final String TEST_FEATURE = "classpath:feature/examples.feature"; + 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   |   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>> 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); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_examples_no_description(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor firstStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), firstStepCaptor.capture()); + ArgumentCaptor secondStepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), secondStepCaptor.capture()); + + List scenarios = scenarioCaptor.getAllValues(); + StartTestItemRQ firstScenarioRq = scenarios.get(0); + assertThat(firstScenarioRq.getDescription(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_DESCRIPTION))); + + StartTestItemRQ secondScenarioRq = scenarios.get(1); + assertThat(secondScenarioRq.getDescription(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_DESCRIPTION))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java new file mode 100644 index 0000000..8128ee4 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/NoDescriptionTest.java @@ -0,0 +1,82 @@ +/* + * 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.description; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.endsWith; +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class NoDescriptionTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_description_for_all_possible_items(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + StartTestItemRQ featureStart = featureCaptor.getValue(); + assertThat(featureStart.getDescription(), endsWith("feature/simple.feature")); + + StartTestItemRQ scenarioStart = scenarioCaptor.getValue(); + assertThat(scenarioStart.getDescription(), nullValue()); + + stepCaptor.getAllValues().forEach(step -> assertThat(step.getDescription(), nullValue())); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java new file mode 100644 index 0000000..f54dab8 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/NoLaunchDescriptionTest.java @@ -0,0 +1,84 @@ +/* + * 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.description; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.ListenerParameters; +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.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +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.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class NoLaunchDescriptionTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + + public static Stream dataValues() { + List descriptions = Arrays.asList(null, "", " "); + return Stream.of(true, false).flatMap(b -> descriptions.stream().map(d -> Arguments.of(b, d))); + } + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @MethodSource("dataValues") + public void verify_start_launch_request_contains_no_launch_description(boolean report, String description) { + ListenerParameters parameters = standardParameters(); + parameters.setDescription(description); + ReportPortal rp = ReportPortal.create(client, parameters, testExecutor()); + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(startCaptor.capture()); + + StartLaunchRQ launchStart = startCaptor.getValue(); + + assertThat(launchStart.getDescription(), nullValue()); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java b/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java new file mode 100644 index 0000000..2e621e7 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/description/SimpleDescriptionTest.java @@ -0,0 +1,98 @@ +/* + * 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.description; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import com.intuit.karate.core.Background; +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.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.endsWith; +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class SimpleDescriptionTest { + public static final String SCENARIO_DESCRIPTION = "This is my Scenario description."; + private static final String TEST_FEATURE = "classpath:feature/description.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + private final List> nestedStepIds = stepIds.stream() + .map(id -> Pair.of(id, CommonUtils.namedId("nested_step_"))) + .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, scenarioId, stepIds); + mockNestedSteps(client, nestedStepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_description_for_all_possible_items(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + StartTestItemRQ featureStart = featureCaptor.getValue(); + assertThat(featureStart.getDescription(), endsWith("feature/description.feature\n\n---\n\nThis is my Feature description.")); + + StartTestItemRQ scenarioStart = scenarioCaptor.getValue(); + assertThat(scenarioStart.getDescription(), equalTo(SCENARIO_DESCRIPTION)); + + List backgroundSteps = stepCaptor.getAllValues() + .stream() + .filter(s -> s.getName().startsWith(Background.KEYWORD)) + .collect(Collectors.toList()); + assertThat(backgroundSteps, hasSize(1)); + StartTestItemRQ backgroundStep = backgroundSteps.get(0); + assertThat( + "No support of Background description in Karate yet. But this is a part of Gherkin standard.", + backgroundStep.getDescription(), + nullValue() + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java b/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java new file mode 100644 index 0000000..0da55a9 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/id/ExamplesTestCaseIdTest.java @@ -0,0 +1,86 @@ +/* + * 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.id; + +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.StartTestItemRQ; +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.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class ExamplesTestCaseIdTest { + private static final String TEST_FEATURE = "classpath:feature/examples.feature"; + private static final String EXAMPLE_TEST_CASE_ID_PATTERN = "feature/examples.feature/[EXAMPLE:Verify different maths[%s]]"; + 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>> 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); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_examples_test_case_id(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(captor.capture()); + verify(client, times(2)).startTestItem(same(featureId), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(7)); + + StartTestItemRQ firstScenarioRq = items.get(1); + assertThat(firstScenarioRq.getTestCaseId(), allOf(notNullValue(), equalTo(FIRST_EXAMPLE_TEST_CASE_ID))); + + StartTestItemRQ secondScenarioRq = items.get(2); + assertThat(secondScenarioRq.getTestCaseId(), allOf(notNullValue(), equalTo(SECOND_EXAMPLE_TEST_CASE_ID))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java b/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java new file mode 100644 index 0000000..9084271 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/id/ScenarioTestCaseIdTest.java @@ -0,0 +1,77 @@ +/* + * 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.id; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class ScenarioTestCaseIdTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private static final String SIMPLE_TEST_CASE_ID = "feature/simple.feature/[SCENARIO:Verify math]"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_test_case_id(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), 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(3)).startTestItem(same(scenarioId), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(5)); + + StartTestItemRQ scenarioRq = items.get(1); + assertThat(scenarioRq.getTestCaseId(), allOf(notNullValue(), equalTo(SIMPLE_TEST_CASE_ID))); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java b/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java new file mode 100644 index 0000000..52be11a --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/launch/LaunchRequiredFieldsTest.java @@ -0,0 +1,76 @@ +/* + * 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.launch; + +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.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.List; +import java.util.concurrent.TimeUnit; +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.mock; +import static org.mockito.Mockito.verify; + +public class LaunchRequiredFieldsTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void verify_start_launch_request_contains_required_fields(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor startCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(startCaptor.capture()); + + StartLaunchRQ launchStart = startCaptor.getValue(); + assertThat(launchStart.getName(), startsWith("My-test-launch")); + assertThat(launchStart.getStartTime(), notNullValue()); + assertThat(System.currentTimeMillis() - launchStart.getStartTime().getTime(), not(greaterThan(TimeUnit.SECONDS.toMillis(10)))); + + } +} diff --git a/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java b/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java new file mode 100644 index 0000000..7f2e67f --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/logging/HttpRequestLoggingTest.java @@ -0,0 +1,87 @@ +/* + * 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.logging; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.LogLevel; +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.log.SaveLogRQ; +import com.intuit.karate.Results; +import okhttp3.MultipartBody; +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.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 HttpRequestLoggingTest { + private static final String TEST_FEATURE = "classpath:feature/http_request.feature"; + private final String launchUuid = CommonUtils.namedId("launch_"); + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(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, scenarioId, stepIds); + 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(0)); + + ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); + verify(client, atLeastOnce()).log(logCaptor.capture()); + List logs = logCaptor.getAllValues() + .stream() + .flatMap(rq -> extractJsonParts((List) rq).stream()) + .filter(rq -> LogLevel.INFO.name().equals(rq.getLevel()) || LogLevel.DEBUG.name().equals(rq.getLevel())) + .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\"}") + ) + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java b/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java new file mode 100644 index 0000000..466d1df --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/logging/SimpleFailureLoggingTest.java @@ -0,0 +1,86 @@ +/* + * 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.logging; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.LogLevel; +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.log.SaveLogRQ; +import com.intuit.karate.Results; +import okhttp3.MultipartBody; +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.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 SimpleFailureLoggingTest { + 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 String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, launchUuid, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void test_simple_one_step_failed_error_log(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 logCaptor = ArgumentCaptor.forClass(List.class); + verify(client, atLeastOnce()).log(logCaptor.capture()); + List logs = logCaptor.getAllValues() + .stream() + .flatMap(rq -> extractJsonParts((List) rq).stream()) + .filter(rq -> LogLevel.ERROR.name().equals(rq.getLevel())) + .collect(Collectors.toList()); + + assertThat(logs, hasSize(greaterThan(0))); + SaveLogRQ log = logs.get(logs.size() - 1); + 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") + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java b/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java new file mode 100644 index 0000000..fe90e95 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/name/SimpleItemNameTest.java @@ -0,0 +1,84 @@ +/* + * 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.name; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +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 final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_item_names_simple(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + StartTestItemRQ featureRq = featureCaptor.getValue(); + StartTestItemRQ scenarioRq = scenarioCaptor.getValue(); + + assertThat(featureRq.getName(), allOf(notNullValue(), equalTo("the very basic test to run by Karate"))); + + assertThat(scenarioRq.getName(), allOf(notNullValue(), equalTo("Verify math"))); + + List stepNames = stepCaptor.getAllValues().stream().map(StartTestItemRQ::getName).collect(Collectors.toList()); + assertThat(stepNames, containsInAnyOrder(STEP_NAMES)); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.java new file mode 100644 index 0000000..9e779e1 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesScenarioParametersTest.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.parameters; + +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.ParameterResource; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +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.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +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>> 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); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_examples_scenario_parameters(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(captor.capture()); + verify(client, times(2)).startTestItem(same(featureId), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), captor.capture()); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(7)); + + StartTestItemRQ firstScenarioRq = items.get(1); + StartTestItemRQ secondScenarioRq = items.get(2); + List firstParameters = firstScenarioRq.getParameters(); + List secondParameters = secondScenarioRq.getParameters(); + assertThat(firstParameters, hasSize(3)); + assertThat(secondParameters, hasSize(3)); + + assertThat( + firstParameters.stream().map(p -> p.getKey() + ":" + p.getValue()).collect(Collectors.toSet()), + allOf(hasItem("vara:2"), hasItem("varb:2"), hasItem("result:4")) + ); + assertThat( + secondParameters.stream().map(p -> p.getKey() + ":" + p.getValue()).collect(Collectors.toSet()), + allOf(hasItem("vara:1"), hasItem("varb:2"), hasItem("result:3")) + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java new file mode 100644 index 0000000..929b136 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/parameters/ExamplesStepParametersTest.java @@ -0,0 +1,122 @@ +/* + * 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.parameters; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.LogLevel; +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.ParameterResource; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import com.intuit.karate.Results; +import okhttp3.MultipartBody; +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.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.epam.reportportal.karate.utils.TestUtils.*; +import static java.util.stream.Stream.ofNullable; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +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>> 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()); + + private static Set toParameterStringList(List parameters) { + return ofNullable(parameters).flatMap(Collection::stream).map(p -> p.getKey() + ":" + p.getValue()).collect(Collectors.toSet()); + } + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void test_examples_parameters_for_steps(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(captor.capture()); + verify(client, times(2)).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor firstExampleCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(0)), firstExampleCaptor.capture()); + ArgumentCaptor secondExampleCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(2)).startTestItem(same(exampleIds.get(1)), secondExampleCaptor.capture()); + + List firstSteps = firstExampleCaptor.getAllValues(); + Set parameterStrings = toParameterStringList(firstSteps.get(0).getParameters()); + assertThat(parameterStrings, hasSize(2)); + assertThat(parameterStrings, allOf(hasItem("vara:2"), hasItem("varb:2"))); + parameterStrings = toParameterStringList(firstSteps.get(1).getParameters()); + assertThat(parameterStrings, hasSize(1)); + assertThat(parameterStrings, hasItem("result:4")); + + List secondSteps = secondExampleCaptor.getAllValues(); + parameterStrings = toParameterStringList(secondSteps.get(0).getParameters()); + assertThat(parameterStrings, hasSize(2)); + assertThat(parameterStrings, allOf(hasItem("vara:1"), hasItem("varb:2"))); + parameterStrings = toParameterStringList(secondSteps.get(1).getParameters()); + assertThat(parameterStrings, hasSize(1)); + assertThat(parameterStrings, hasItem("result:3")); + + ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); + verify(client, atLeastOnce()).log(logCaptor.capture()); + Map logs = logCaptor.getAllValues() + .stream() + .flatMap(rq -> extractJsonParts((List) rq).stream()) + .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()); + assertThat(logs.keySet(), hasSize(stepIdList.size())); + stepIdList.forEach(id -> assertThat(logs, hasKey(id))); + assertThat(logs.values().stream().map(SaveLogRQ::getMessage).collect(Collectors.toList()), + everyItem(startsWith("Parameters:\n\n")) + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java new file mode 100644 index 0000000..715418b --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/parameters/NoParametersTest.java @@ -0,0 +1,82 @@ +/* + * 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.parameters; + +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.StartTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class NoParametersTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, null, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_no_parameters_reporting(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), 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(3)).startTestItem(same(scenarioId), captor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(5)); + + StartTestItemRQ featureRq = items.get(0); + StartTestItemRQ scenarioRq = items.get(1); + + assertThat(featureRq.getParameters(), nullValue()); + assertThat(scenarioRq.getParameters(), nullValue()); + + items.subList(2, items.size()).forEach(step -> assertThat(step.getParameters(), nullValue())); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java b/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java new file mode 100644 index 0000000..4784329 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/parameters/TableParametersTest.java @@ -0,0 +1,91 @@ +/* + * 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.parameters; + +import com.epam.reportportal.karate.utils.TestUtils; +import com.epam.reportportal.listeners.LogLevel; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import com.intuit.karate.Results; +import okhttp3.MultipartBody; +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.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.startsWith; +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +public class TableParametersTest { + private static final String TEST_FEATURE = "classpath:feature/table.feature"; + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(4).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, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void test_table_parameters_reporting(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(1)).startTestItem(captor.capture()); + verify(client, times(1)).startTestItem(same(featureId), captor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(4)).startTestItem(same(scenarioId), stepCaptor.capture()); + ArgumentCaptor logCaptor = ArgumentCaptor.forClass(List.class); + verify(client, atLeastOnce()).log(logCaptor.capture()); + + List items = captor.getAllValues(); + assertThat(items, hasSize(2)); + + List logs = logCaptor.getAllValues() + .stream() + .flatMap(rq -> extractJsonParts((List) rq).stream()) + .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_")); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java b/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.java new file mode 100644 index 0000000..0174ece --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/status/SimpleAllPassedTest.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.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.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static com.epam.reportportal.karate.utils.TestUtils.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.*; + +public class SimpleAllPassedTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String launchUuid = CommonUtils.namedId("launch_"); + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, launchUuid, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_simple_all_passed(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(featureId), featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(scenarioId), scenarioCaptor.capture()); + List> stepCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) + .limit(stepIds.size()) + .collect(Collectors.toList()); + IntStream.range(0, stepIds.size()).forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepCaptors.get(i).capture())); + + FinishTestItemRQ featureRq = featureCaptor.getValue(); + FinishTestItemRQ scenarioRq = scenarioCaptor.getValue(); + + assertThat(featureRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(featureRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(featureRq.getEndTime(), notNullValue()); + + assertThat(scenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(scenarioRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(scenarioRq.getEndTime(), notNullValue()); + + stepCaptors.forEach(stepCaptor -> { + FinishTestItemRQ step = stepCaptor.getValue(); + assertThat(step.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.PASSED.name()))); + assertThat(step.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(step.getEndTime(), notNullValue()); + }); + } +} \ No newline at end of file diff --git a/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java b/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java new file mode 100644 index 0000000..5b82026 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/status/SimpleOneStepFailedTest.java @@ -0,0 +1,97 @@ +/* + * 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.FinishExecutionRQ; +import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static com.epam.reportportal.karate.utils.TestUtils.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.*; + +public class SimpleOneStepFailedTest { + 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 String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, launchUuid, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_simple_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 scenarioCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(scenarioId), scenarioCaptor.capture()); + List> stepCaptors = Stream.generate(() -> ArgumentCaptor.forClass(FinishTestItemRQ.class)) + .limit(stepIds.size()) + .collect(Collectors.toList()); + IntStream.range(0, stepIds.size()).forEach(i -> verify(client).finishTestItem(same(stepIds.get(i)), stepCaptors.get(i).capture())); + + FinishTestItemRQ featureRq = featureCaptor.getValue(); + FinishTestItemRQ scenarioRq = scenarioCaptor.getValue(); + + assertThat(featureRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.FAILED.name()))); + assertThat(featureRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(featureRq.getEndTime(), notNullValue()); + + assertThat(scenarioRq.getStatus(), allOf(notNullValue(), equalTo(ItemStatus.FAILED.name()))); + assertThat(scenarioRq.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(scenarioRq.getEndTime(), notNullValue()); + + List steps = stepCaptors.stream().map(ArgumentCaptor::getValue).collect(Collectors.toList()); + steps.forEach(step -> { + assertThat(step.getLaunchUuid(), allOf(notNullValue(), equalTo(launchUuid))); + assertThat(step.getEndTime(), notNullValue()); + }); + List statuses = steps.stream().map(FinishExecutionRQ::getStatus).collect(Collectors.toList()); + assertThat(statuses, containsInAnyOrder("PASSED", "PASSED", "FAILED")); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java b/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java new file mode 100644 index 0000000..c71d24d --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/timing/SimpleTimingTest.java @@ -0,0 +1,115 @@ +/* + * 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.timing; + +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.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.intuit.karate.Results; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; + +import java.util.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 SimpleTimingTest { + private static final String TEST_FEATURE = "classpath:feature/simple.feature"; + private final String launchUuid = CommonUtils.namedId("launch_"); + private final String featureId = CommonUtils.namedId("feature_"); + private final String scenarioId = CommonUtils.namedId("scenario_"); + private final List stepIds = Stream.generate(() -> CommonUtils.namedId("step_")).limit(3).collect(Collectors.toList()); + + private final ReportPortalClient client = mock(ReportPortalClient.class); + private final ReportPortal rp = ReportPortal.create(client, standardParameters(), testExecutor()); + + @BeforeEach + public void setupMock() { + mockLaunch(client, launchUuid, featureId, scenarioId, stepIds); + mockBatchLogging(client); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + public void test_each_item_has_correct_start_date(boolean report) { + Results results; + if (report) { + results = TestUtils.runAsReport(rp, TEST_FEATURE); + } else { + results = TestUtils.runAsHook(rp, TEST_FEATURE); + } + assertThat(results.getFailCount(), equalTo(0)); + + ArgumentCaptor launchCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); + verify(client).startLaunch(launchCaptor.capture()); + ArgumentCaptor featureCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(featureCaptor.capture()); + ArgumentCaptor scenarioCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client).startTestItem(same(featureId), scenarioCaptor.capture()); + ArgumentCaptor stepCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); + verify(client, times(3)).startTestItem(same(scenarioId), stepCaptor.capture()); + + StartLaunchRQ launchRq = launchCaptor.getValue(); + StartTestItemRQ featureRq = featureCaptor.getValue(); + StartTestItemRQ scenarioRq = scenarioCaptor.getValue(); + + assertThat( + "Launch start time is greater than Feature start time.", + featureRq.getStartTime(), + greaterThanOrEqualTo(launchRq.getStartTime()) + ); + assertThat( + "Feature start time is greater than Scenario start time.", + scenarioRq.getStartTime(), + greaterThanOrEqualTo(featureRq.getStartTime()) + ); + + 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 thirdStep = steps.stream() + .filter(s -> "Then assert actualFour == four".equals(s.getName())) + .findAny() + .orElseThrow(); + + assertThat( + "Scenario start time is greater than Step start time.", + firstStep.getStartTime(), + greaterThanOrEqualTo(scenarioRq.getStartTime()) + ); + assertThat( + "First Step start time is greater or equal than Second Step start time.", + secondStep.getStartTime(), + greaterThan(firstStep.getStartTime()) + ); + assertThat( + "Second Step start time is greater or equal than Third Step start time.", + thirdStep.getStartTime(), + greaterThan(secondStep.getStartTime()) + ); + } +} diff --git a/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java b/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java new file mode 100644 index 0000000..bb61de3 --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/utils/ReflectUtils.java @@ -0,0 +1,35 @@ +/* + * 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 new file mode 100644 index 0000000..520bacc --- /dev/null +++ b/src/test/java/com/epam/reportportal/karate/utils/TestUtils.java @@ -0,0 +1,219 @@ +/* + * 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 com.epam.reportportal.karate.KarateReportPortalRunner; +import com.epam.reportportal.karate.ReportPortalHook; +import com.epam.reportportal.listeners.ListenerParameters; +import com.epam.reportportal.service.ReportPortal; +import com.epam.reportportal.service.ReportPortalClient; +import com.epam.reportportal.util.test.CommonUtils; +import com.epam.reportportal.utils.http.HttpRequestUtils; +import com.epam.ta.reportportal.ws.model.BatchSaveOperatingRS; +import com.epam.ta.reportportal.ws.model.Constants; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; +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.reactivex.Maybe; +import okhttp3.MultipartBody; +import okio.Buffer; +import org.apache.commons.lang3.tuple.Pair; +import org.mockito.stubbing.Answer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +import static com.epam.reportportal.util.test.CommonUtils.generateUniqueId; +import static java.util.Optional.ofNullable; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +public class TestUtils { + public static final String ROOT_SUITE_PREFIX = "root_"; + + private TestUtils() { + } + + public static ExecutorService testExecutor() { + return Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + }); + } + + public static Results runAsReport(ReportPortal reportPortal, String... paths) { + return KarateReportPortalRunner.path(paths).withReportPortal(reportPortal).outputCucumberJson(false).parallel(1); + } + + public static Results runAsHook(ReportPortal reportPortal, String... paths) { + return Runner.path(paths).hook(new ReportPortalHook(reportPortal)).outputCucumberJson(false).parallel(1); + } + + public static ListenerParameters standardParameters() { + ListenerParameters result = new ListenerParameters(); + result.setClientJoin(false); + result.setLaunchName("My-test-launch" + generateUniqueId()); + result.setProjectName("test-project"); + result.setEnable(true); + result.setCallbackReportingEnabled(true); + result.setBaseUrl("http://localhost:8080"); + return result; + } + + public static void mockLaunch(@Nonnull final ReportPortalClient client, @Nullable final String launchUuid, + @Nullable final String featureUuid, @Nonnull String scenarioUuid, @Nonnull String stepUuid) { + mockLaunch(client, launchUuid, featureUuid, scenarioUuid, Collections.singleton(stepUuid)); + } + + public static void mockLaunch(@Nonnull final ReportPortalClient client, @Nullable final String launchUuid, + @Nullable final String featureUuid, @Nonnull String scenarioUuid, @Nonnull Collection stepList) { + mockLaunch(client, launchUuid, featureUuid, Collections.singletonList(Pair.of(scenarioUuid, stepList))); + } + + public static > void mockLaunch(@Nonnull final ReportPortalClient client, + @Nullable final String launchUuid, @Nullable final String featureUuid, + @Nonnull final Collection> scenarioSteps) { + String launch = ofNullable(launchUuid).orElse(CommonUtils.namedId("launch_")); + when(client.startLaunch(any())).thenReturn(Maybe.just(new StartLaunchRS(launch, 1L))); + when(client.finishLaunch(eq(launch), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + + mockFeature(client, featureUuid, scenarioSteps); + } + + public static void mockLaunch(@Nonnull final ReportPortalClient client, @Nullable final String launchUuid) { + String launch = ofNullable(launchUuid).orElse(CommonUtils.namedId("launch_")); + when(client.startLaunch(any())).thenReturn(Maybe.just(new StartLaunchRS(launch, 1L))); + when(client.finishLaunch(eq(launch), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + } + + public static > void mockFeature(@Nonnull final ReportPortalClient client, + @Nullable final String featureUuid, @Nonnull final Collection> scenarioSteps) { + String rootItemId = ofNullable(featureUuid).orElseGet(() -> CommonUtils.namedId(ROOT_SUITE_PREFIX)); + mockFeatures(client, Collections.singletonList(Pair.of(rootItemId, scenarioSteps))); + } + + @SuppressWarnings("unchecked") + public static > void mockFeatures(@Nonnull final ReportPortalClient client, + @Nonnull final List>>> features) { + if (features.isEmpty()) { + return; + } + String firstFeature = features.get(0).getKey(); + Maybe first = Maybe.just(new ItemCreatedRS(firstFeature, firstFeature)); + Maybe[] other = (Maybe[]) features.subList(1, features.size()) + .stream() + .map(Pair::getKey) + .map(s -> Maybe.just(new ItemCreatedRS(s, s))) + .toArray(Maybe[]::new); + when(client.startTestItem(any())).thenReturn(first, other); + + features.forEach(i -> { + Maybe rootFinishMaybe = Maybe.just(new OperationCompletionRS()); + when(client.finishTestItem(same(i.getKey()), any())).thenReturn(rootFinishMaybe); + mockScenario(client, i.getKey(), i.getValue()); + }); + } + + @SuppressWarnings("unchecked") + public static > void mockScenario(@Nonnull final ReportPortalClient client, + @Nonnull final String featureUuid, @Nonnull final Collection> scenarioSteps) { + List> testResponses = scenarioSteps.stream() + .map(Pair::getKey) + .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) + .collect(Collectors.toList()); + + Maybe first = testResponses.get(0); + Maybe[] other = testResponses.subList(1, testResponses.size()).toArray(new Maybe[0]); + when(client.startTestItem(same(featureUuid), any())).thenReturn(first, other); + + scenarioSteps.forEach(test -> { + String scenarioUuid = test.getKey(); + List> stepResponses = test.getValue() + .stream() + .map(uuid -> Maybe.just(new ItemCreatedRS(uuid, uuid))) + .collect(Collectors.toList()); + when(client.finishTestItem(same(scenarioUuid), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + if (!stepResponses.isEmpty()) { + Maybe myFirst = stepResponses.get(0); + Maybe[] myOther = stepResponses.subList(1, stepResponses.size()).toArray(new Maybe[0]); + when(client.startTestItem(same(scenarioUuid), any())).thenReturn(myFirst, myOther); + new HashSet<>(test.getValue()).forEach(testMethodUuid -> when(client.finishTestItem(same(testMethodUuid), + any() + )).thenReturn(Maybe.just(new OperationCompletionRS()))); + } + }); + } + + @SuppressWarnings("unchecked") + public static void mockBatchLogging(final ReportPortalClient client) { + when(client.log(any(List.class))).thenReturn(Maybe.just(new BatchSaveOperatingRS())); + } + + @SuppressWarnings("unchecked") + public static void mockNestedSteps(final ReportPortalClient client, final List> parentNestedPairs) { + Map> 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()); + + Maybe first = responses.get(0); + Maybe[] other = responses.subList(1, responses.size()).toArray(new Maybe[0]); + when(client.startTestItem(eq(k), any())).thenReturn(first, other); + }); + parentNestedPairs.forEach(p -> when(client.finishTestItem(same(p.getValue()), + any() + )).thenAnswer((Answer>) invocation -> Maybe.just(new OperationCompletionRS()))); + } + + public static List extractJsonParts(List parts) { + return parts.stream() + .filter(p -> ofNullable(p.headers()).map(headers -> headers.get("Content-Disposition")) + .map(h -> h.contains(Constants.LOG_REQUEST_JSON_PART)) + .orElse(false)) + .map(MultipartBody.Part::body) + .map(b -> { + Buffer buf = new Buffer(); + try { + b.writeTo(buf); + } catch (IOException ignore) { + } + return buf.readByteArray(); + }) + .map(b -> { + try { + return HttpRequestUtils.MAPPER.readValue(b, new TypeReference<>() { + }); + } catch (IOException e) { + return Collections.emptyList(); + } + }) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/com/epam/reportportal/utils/ReflectUtils.java b/src/test/java/com/epam/reportportal/utils/ReflectUtils.java deleted file mode 100644 index f1d20cf..0000000 --- a/src/test/java/com/epam/reportportal/utils/ReflectUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.epam.reportportal.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); - } - } -} \ No newline at end of file diff --git a/src/test/resources/feature/Test.feature b/src/test/resources/feature/Test.feature index 28ecaf4..e3ff8c8 100644 --- a/src/test/resources/feature/Test.feature +++ b/src/test/resources/feature/Test.feature @@ -1,4 +1,5 @@ Feature: Quote generator + @To_run Scenario: Fetch random quote 1 Given url 'http://jsonplaceholder.typicode.com/posts' diff --git a/src/test/resources/feature/background.feature b/src/test/resources/feature/background.feature new file mode 100644 index 0000000..44b742d --- /dev/null +++ b/src/test/resources/feature/background.feature @@ -0,0 +1,8 @@ +Feature: test background reporting + + Background: Set variable + Given def four = 4 + + Scenario: Verify math + When def actualFour = 2 * 2 + Then assert actualFour == four diff --git a/src/test/resources/feature/background_examples.feature b/src/test/resources/feature/background_examples.feature new file mode 100644 index 0000000..b65a603 --- /dev/null +++ b/src/test/resources/feature/background_examples.feature @@ -0,0 +1,13 @@ +Feature: test background with Scenario Outline reporting + + Background: Set varb + Given def varb = 2 + + Scenario Outline: Verify different maths + Given def mathResult = vara + varb + Then assert mathResult == result + + Examples: + | vara! | result! | + | 2 | 4 | + | 1 | 3 | diff --git a/src/test/resources/feature/background_two_steps.feature b/src/test/resources/feature/background_two_steps.feature new file mode 100644 index 0000000..70c4f06 --- /dev/null +++ b/src/test/resources/feature/background_two_steps.feature @@ -0,0 +1,8 @@ +Feature: test background with two steps reporting + + Background: Set variable + Given def vara = 2 + And def varb = 2 + + Scenario: Verify math + Then assert vara * varb == 4 diff --git a/src/test/resources/feature/call.feature b/src/test/resources/feature/call.feature new file mode 100644 index 0000000..79546bb --- /dev/null +++ b/src/test/resources/feature/call.feature @@ -0,0 +1,4 @@ +Feature: calling another feature file + + Scenario: calling a feature with parameters + * def result = call read('called.feature') { vara: 2, result: 4 } diff --git a/src/test/resources/feature/called.feature b/src/test/resources/feature/called.feature new file mode 100644 index 0000000..12883cf --- /dev/null +++ b/src/test/resources/feature/called.feature @@ -0,0 +1,7 @@ +@ignore +Feature: a feature which is called with parameters + + Scenario: Verify different maths + Given def varb = 2 + Given def mathResult = vara + varb + Then assert mathResult == result diff --git a/src/test/resources/feature/description.feature b/src/test/resources/feature/description.feature new file mode 100644 index 0000000..818e8da --- /dev/null +++ b/src/test/resources/feature/description.feature @@ -0,0 +1,16 @@ +Feature: the test to show item description reporting + + This is my Feature description. + + Background: Set variable + + This is my Background description. + + Given def four = 4 + + Scenario: Verify math + + This is my Scenario description. + + When def actualFour = 2 * 2 + Then assert actualFour == four diff --git a/src/test/resources/feature/description_examples.feature b/src/test/resources/feature/description_examples.feature new file mode 100644 index 0000000..0915494 --- /dev/null +++ b/src/test/resources/feature/description_examples.feature @@ -0,0 +1,13 @@ +Feature: math tests with examples + + Scenario Outline: Verify different maths + + This is my Scenario description. + + Given def mathResult = vara + varb + Then assert mathResult == result + + Examples: + | vara! | varb! | result! | + | 2 | 2 | 4 | + | 1 | 2 | 3 | diff --git a/src/test/resources/feature/examples.feature b/src/test/resources/feature/examples.feature new file mode 100644 index 0000000..19617fc --- /dev/null +++ b/src/test/resources/feature/examples.feature @@ -0,0 +1,10 @@ +Feature: math tests with examples + + Scenario Outline: Verify different maths + Given def mathResult = vara + varb + Then assert mathResult == result + + Examples: + | vara! | varb! | result! | + | 2 | 2 | 4 | + | 1 | 2 | 3 | diff --git a/src/test/resources/feature/http_request.feature b/src/test/resources/feature/http_request.feature new file mode 100644 index 0000000..b958f45 --- /dev/null +++ b/src/test/resources/feature/http_request.feature @@ -0,0 +1,16 @@ +Feature: verify basic HTTP request + + Scenario: Verify HTTP request + Given url 'https://example.com' + And header Content-Type = 'application/json' + And path 'api/test' + And request + """ + { + username: 'user', + password: 'password', + grant_type: 'password' + } + """ + When method post + Then status 404 diff --git a/src/test/resources/feature/simple.feature b/src/test/resources/feature/simple.feature new file mode 100644 index 0000000..f177f74 --- /dev/null +++ b/src/test/resources/feature/simple.feature @@ -0,0 +1,6 @@ +Feature: the very basic test to run by Karate + + Scenario: Verify math + Given def four = 4 + When def actualFour = 2 * 2 + Then assert actualFour == four diff --git a/src/test/resources/feature/simple_failed.feature b/src/test/resources/feature/simple_failed.feature new file mode 100644 index 0000000..c72116d --- /dev/null +++ b/src/test/resources/feature/simple_failed.feature @@ -0,0 +1,6 @@ +Feature: the very basic test to run by Karate + + Scenario: Verify math + Given def four = 4 + When def actualFour = 2 * 2 + Then assert actualFour != four diff --git a/src/test/resources/feature/table.feature b/src/test/resources/feature/table.feature new file mode 100644 index 0000000..3a23ad3 --- /dev/null +++ b/src/test/resources/feature/table.feature @@ -0,0 +1,10 @@ +Feature: test with parameter table + + Scenario: Verify parameter table + Given def one = 'hello' + And def two = { baz: 'world' } + And table json + | foo | bar | + | one | { baz: 1 } | + | two.baz | ['baz', 'ban'] | + Then match json == [{ foo: 'hello', bar: { baz: 1 } }, { foo: 'world', bar: ['baz', 'ban'] }] diff --git a/src/test/resources/feature/tags.feature b/src/test/resources/feature/tags.feature new file mode 100644 index 0000000..4bf25f2 --- /dev/null +++ b/src/test/resources/feature/tags.feature @@ -0,0 +1,8 @@ +@tag_test +Feature: the very basic to test different tags + + @math @scope=smoke @environment=dev,qa + Scenario: Verify math + Given def four = 4 + When def actualFour = 2 * 2 + Then assert actualFour == four diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml index 6a3f276..231f74c 100644 --- a/src/test/resources/logback.xml +++ b/src/test/resources/logback.xml @@ -1,4 +1,20 @@ + + @@ -31,17 +47,18 @@ - + + - - + + diff --git a/src/test/resources/reportportal.properties b/src/test/resources/reportportal.properties index 2b4544b..4e3b746 100644 --- a/src/test/resources/reportportal.properties +++ b/src/test/resources/reportportal.properties @@ -1,8 +1,7 @@ -#rp.endpoint= -#rp.uuid= -#rp.launch= -#rp.project= - +# rp.endpoint= +# rp.api.key= +# rp.launch= +# rp.project= ## OPTIONAL PARAMETERS # rp.reporting.async=true # rp.reporting.callback=true