diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cdfa07d..a306e0f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog ## [Unreleased] +### Added +- `rp.client.join.launch.timeout.value` and `rp.client.join.launch.timeout.unit` configuration properties to control SecondaryLaunch start timeout on client join, by @HardNorth +- `rp.bts.project`, `rp.bts.url`, `rp.bts.issue.url`, `rp.bts.issue.fail` configuration properties to control manual issue set by Agents, by @HardNorth +### Changed +- Disable Launch start wait for Secondary Launches if async reporting is enabled, by @HardNorth +- Disable Statistics for Secondary Launches, by @HardNorth + +## [5.2.15] +### Changed +- `commons-model` dependency version updated to `5.3.3`, by @HardNorth ## [5.2.14] ### Added diff --git a/README.md b/README.md index 2921f9df..89480c77 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -The latest version: 5.2.14. Please use `Maven Central` link above to get the client. +The latest version: 5.2.15. Please use `Maven Central` link above to get the client. ## JVM-based clients configuration diff --git a/build.gradle b/build.gradle index d2e7ddcd..c0c8783b 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'java-library' apply from: "${project.scripts_url}/${project.scripts_branch}/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}/signing.gradle" apply from: "${project.scripts_url}/${project.scripts_branch}/jacoco.gradle" project.ext.limits = [ @@ -36,13 +36,15 @@ compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' repositories { + mavenLocal() mavenCentral() maven { url 'https://jitpack.io' } } dependencies { - api ('com.github.reportportal:commons-reporting:24941f3') { + api ('com.epam.reportportal:commons-reporting:5.12.2') { exclude module: 'jackson-databind' + exclude module: 'guava' } api 'com.fasterxml.jackson.core:jackson-databind:2.12.7.1' // Access is needed by HTTP loggers to format JSON api 'io.reactivex.rxjava2:rxjava:2.2.10' @@ -77,7 +79,7 @@ dependencies { testImplementation 'org.hamcrest:hamcrest-core:2.2' testImplementation "org.mockito:mockito-core:${project.mockito_version}" testImplementation "org.mockito:mockito-junit-jupiter:${project.mockito_version}" - testImplementation 'ch.qos.logback:logback-classic:1.3.12' + testImplementation 'ch.qos.logback:logback-classic:1.3.14' testImplementation('org.awaitility:awaitility:4.0.2') { exclude group: 'org.hamcrest' } diff --git a/gradle.properties b/gradle.properties index c62306d8..c333bb9a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.2.15-SNAPSHOT +version=5.2.16-SNAPSHOT description=EPAM ReportPortal. Client retrofit_version=2.9.0 okhttp_version=4.12.0 diff --git a/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java b/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java index f6d69b77..f0bb8b2e 100644 --- a/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java +++ b/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java @@ -55,11 +55,13 @@ public class ListenerParameters implements Cloneable { private static final String DEFAULT_CLIENT_JOIN_MODE = "FILE"; private static final String DEFAULT_LOCK_FILE_NAME = "reportportal.lock"; private static final String DEFAULT_SYNC_FILE_NAME = "reportportal.sync"; - public static final long DEFAULT_FILE_WAIT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(1); + private static final int DEFAULT_CLIENT_JOIN_LOCK_PORT = 25464; + public static final long DEFAULT_FILE_WAIT_TIMEOUT = TimeUnit.MINUTES.toMillis(1); private static final long DEFAULT_CLIENT_JOIN_TIMEOUT = TimeUnit.MINUTES.toMillis(30); + private static final long DEFAULT_CLIENT_JOIN_LAUNCH_TIMEOUT = TimeUnit.MINUTES.toMillis(1); private static final String DEFAULT_CLIENT_JOIN_TIMEOUT_UNIT = "MILLISECONDS"; private static final String DEFAULT_CLIENT_JOIN_LOCK_TIMEOUT_UNIT = DEFAULT_CLIENT_JOIN_TIMEOUT_UNIT; - private static final int DEFAULT_CLIENT_JOIN_LOCK_PORT = 25464; + private static final String DEFAULT_CLIENT_JOIN_LAUNCH_TIMEOUT_UNIT = DEFAULT_CLIENT_JOIN_TIMEOUT_UNIT; private static final boolean DEFAULT_TRUNCATE = true; private static final int DEFAULT_TRUNCATE_ITEM_NAMES_LIMIT = 1024; @@ -72,6 +74,8 @@ public class ListenerParameters implements Cloneable { public static final boolean DEFAULT_LAUNCH_UUID_PRINT = false; public static final String DEFAULT_LAUNCH_UUID_OUTPUT = "stdout"; + public static final boolean DEFAULT_BTS_ISSUE_FAIL = true; + private String description; private String apiKey; private String baseUrl; @@ -106,9 +110,10 @@ public class ListenerParameters implements Cloneable { private LaunchIdLockMode clientJoinMode; private String lockFileName; private String syncFileName; + private int lockPortNumber; private long lockWaitTimeout; private long clientJoinTimeout; - private int lockPortNumber; + private long clientJoinLaunchTimeout; private int rxBufferSize; @@ -120,6 +125,11 @@ public class ListenerParameters implements Cloneable { private boolean printLaunchUuid; private PrintStream printLaunchUuidOutput; + private String btsProjectId; + private String btsUrl; + private String btsIssueUrl; + private boolean btsIssueFail; + @Nonnull private static ChronoUnit toChronoUnit(@Nonnull TimeUnit t) { switch (t) { @@ -175,11 +185,12 @@ public ListenerParameters() { this.clientJoin = DEFAULT_CLIENT_JOIN; this.clientJoinMode = LaunchIdLockMode.valueOf(DEFAULT_CLIENT_JOIN_MODE); - this.clientJoinTimeout = DEFAULT_CLIENT_JOIN_TIMEOUT; + this.lockPortNumber = DEFAULT_CLIENT_JOIN_LOCK_PORT; this.lockFileName = DEFAULT_LOCK_FILE_NAME; this.syncFileName = DEFAULT_SYNC_FILE_NAME; - this.lockWaitTimeout = DEFAULT_FILE_WAIT_TIMEOUT_MS; - this.lockPortNumber = DEFAULT_CLIENT_JOIN_LOCK_PORT; + this.lockWaitTimeout = DEFAULT_FILE_WAIT_TIMEOUT; + this.clientJoinTimeout = DEFAULT_CLIENT_JOIN_TIMEOUT; + this.clientJoinLaunchTimeout = DEFAULT_CLIENT_JOIN_LAUNCH_TIMEOUT; this.rxBufferSize = DEFAULT_RX_BUFFER_SIZE; @@ -191,6 +202,8 @@ public ListenerParameters() { this.printLaunchUuid = DEFAULT_LAUNCH_UUID_PRINT; this.printLaunchUuidOutput = OutputTypes.valueOf(DEFAULT_LAUNCH_UUID_OUTPUT.toUpperCase(Locale.ROOT)).getOutput(); + + this.btsIssueFail = DEFAULT_BTS_ISSUE_FAIL; } /** @@ -243,28 +256,29 @@ public ListenerParameters(PropertiesLoader properties) { this.ioPoolSize = properties.getPropertyAsInt(IO_POOL_SIZE, DEFAULT_IO_POOL_SIZE); + // client join parameters clientJoin = properties.getPropertyAsBoolean(CLIENT_JOIN_MODE, DEFAULT_CLIENT_JOIN); clientJoinMode = LaunchIdLockMode.valueOf(properties.getProperty(CLIENT_JOIN_MODE_VALUE, DEFAULT_CLIENT_JOIN_MODE )); - - clientJoinTimeout = ofNullable(properties.getProperty(CLIENT_JOIN_TIMEOUT_VALUE)).map(t -> TimeUnit.valueOf( - properties.getProperty(CLIENT_JOIN_TIMEOUT_UNIT, DEFAULT_CLIENT_JOIN_TIMEOUT_UNIT)) - .toMillis(Long.parseLong(t))).orElse(DEFAULT_CLIENT_JOIN_TIMEOUT); - + lockPortNumber = properties.getPropertyAsInt(CLIENT_JOIN_LOCK_PORT, DEFAULT_CLIENT_JOIN_LOCK_PORT); lockFileName = properties.getProperty(FILE_LOCK_NAME, DEFAULT_LOCK_FILE_NAME); syncFileName = properties.getProperty(FILE_SYNC_NAME, DEFAULT_SYNC_FILE_NAME); - - String waitTimeoutStr = properties.getProperty(CLIENT_JOIN_LOCK_TIMEOUT_VALUE); - if (waitTimeoutStr != null) { - TimeUnit waitTimeUnit = TimeUnit.valueOf(properties.getProperty(CLIENT_JOIN_LOCK_TIMEOUT_UNIT, - DEFAULT_CLIENT_JOIN_LOCK_TIMEOUT_UNIT - )); - lockWaitTimeout = waitTimeUnit.toMillis(Long.parseLong(waitTimeoutStr)); - } else { - lockWaitTimeout = DEFAULT_FILE_WAIT_TIMEOUT_MS; - } - lockPortNumber = properties.getPropertyAsInt(CLIENT_JOIN_LOCK_PORT, DEFAULT_CLIENT_JOIN_LOCK_PORT); + clientJoinTimeout = ofNullable(properties.getProperty(CLIENT_JOIN_TIMEOUT_VALUE)) + .map(t -> TimeUnit.valueOf(properties.getProperty(CLIENT_JOIN_TIMEOUT_UNIT, + DEFAULT_CLIENT_JOIN_TIMEOUT_UNIT + )).toMillis(Long.parseLong(t))) + .orElse(DEFAULT_CLIENT_JOIN_TIMEOUT); + lockWaitTimeout = ofNullable(properties.getProperty(CLIENT_JOIN_LOCK_TIMEOUT_VALUE)) + .map(t -> TimeUnit.valueOf(properties.getProperty(CLIENT_JOIN_LOCK_TIMEOUT_UNIT, + DEFAULT_CLIENT_JOIN_LOCK_TIMEOUT_UNIT + )).toMillis(Long.parseLong(t))) + .orElse(DEFAULT_FILE_WAIT_TIMEOUT); + clientJoinLaunchTimeout = ofNullable(properties.getProperty(CLIENT_JOIN_LAUNCH_TIMEOUT_VALUE)) + .map(t -> TimeUnit.valueOf(properties.getProperty(CLIENT_JOIN_LAUNCH_TIMEOUT_UNIT, + DEFAULT_CLIENT_JOIN_LAUNCH_TIMEOUT_UNIT + )).toMillis(Long.parseLong(t))) + .orElse(DEFAULT_CLIENT_JOIN_LAUNCH_TIMEOUT); this.rxBufferSize = properties.getPropertyAsInt(RX_BUFFER_SIZE, DEFAULT_RX_BUFFER_SIZE); @@ -282,6 +296,15 @@ public ListenerParameters(PropertiesLoader properties) { .getProperty(LAUNCH_UUID_PRINT_OUTPUT, DEFAULT_LAUNCH_UUID_OUTPUT) .toUpperCase(Locale.ROOT) ).getOutput(); + + this.btsProjectId = properties.getProperty(BTS_PROJECT); + this.btsUrl = properties.getProperty(BTS_URL); + this.btsIssueUrl = properties.getProperty(BTS_ISSUE_URL); + this.btsIssueFail = properties.getPropertyAsBoolean(BTS_ISSUE_FAIL, DEFAULT_BTS_ISSUE_FAIL); + } + + Mode parseLaunchMode(String mode) { + return Mode.isExists(mode) ? Mode.valueOf(mode.toUpperCase()) : Mode.DEFAULT; } public String getDescription() { @@ -510,6 +533,14 @@ public void setClientJoinMode(LaunchIdLockMode clientJoinMode) { this.clientJoinMode = clientJoinMode; } + public int getLockPortNumber() { + return lockPortNumber; + } + + public void setLockPortNumber(int lockPortNumber) { + this.lockPortNumber = lockPortNumber; + } + public String getLockFileName() { return lockFileName; } @@ -542,12 +573,12 @@ public void setLockWaitTimeout(long timeout) { this.lockWaitTimeout = timeout; } - public int getLockPortNumber() { - return lockPortNumber; + public long getClientJoinLaunchTimeout() { + return clientJoinLaunchTimeout; } - public void setLockPortNumber(int lockPortNumber) { - this.lockPortNumber = lockPortNumber; + public void setClientJoinLaunchTimeout(long clientJoinLaunchTimeout) { + this.clientJoinLaunchTimeout = clientJoinLaunchTimeout; } public boolean isHttpLogging() { @@ -636,8 +667,39 @@ public Duration getHttpWriteTimeout() { return httpWriteTimeout; } - Mode parseLaunchMode(String mode) { - return Mode.isExists(mode) ? Mode.valueOf(mode.toUpperCase()) : Mode.DEFAULT; + @Nullable + public String getBtsProjectId() { + return btsProjectId; + } + + public void setBtsProjectId(@Nullable String btsProjectId) { + this.btsProjectId = btsProjectId; + } + + @Nullable + public String getBtsUrl() { + return btsUrl; + } + + public void setBtsUrl(@Nullable String btsUrl) { + this.btsUrl = btsUrl; + } + + @Nullable + public String getBtsIssueUrl() { + return btsIssueUrl; + } + + public void setBtsIssueUrl(@Nullable String btsIssueUrl) { + this.btsIssueUrl = btsIssueUrl; + } + + public boolean isBtsIssueFail() { + return btsIssueFail; + } + + public void setBtsIssueFail(boolean btsIssueFail) { + this.btsIssueFail = btsIssueFail; } @Override @@ -700,11 +762,16 @@ public String toString() { sb.append(", clientJoin=").append(clientJoin); sb.append(", clientJoinMode=").append(ofNullable(clientJoinMode).map(Enum::name).orElse(null)); sb.append(", clientJoinTimeout=").append(clientJoinTimeout); + sb.append(", clientJoinLaunchTimeout=").append(clientJoinLaunchTimeout); sb.append(", lockFileName=").append(lockFileName); sb.append(", syncFileName=").append(syncFileName); sb.append(", lockWaitTimeout=").append(lockWaitTimeout); sb.append(", lockPortNumber=").append(lockPortNumber); sb.append(", rxBufferSize=").append(rxBufferSize); + sb.append(", btsProjectId=").append(btsProjectId); + sb.append(", btsUrl=").append(btsUrl); + sb.append(", btsIssueUrl=").append(btsIssueUrl); + sb.append(", btsIssueFail=").append(btsIssueFail); sb.append('}'); return sb.toString(); } diff --git a/src/main/java/com/epam/reportportal/service/Launch.java b/src/main/java/com/epam/reportportal/service/Launch.java index d0bc084d..8d19ea2a 100644 --- a/src/main/java/com/epam/reportportal/service/Launch.java +++ b/src/main/java/com/epam/reportportal/service/Launch.java @@ -31,7 +31,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.lang.reflect.Proxy; -import java.util.Set; import static java.util.Objects.requireNonNull; @@ -214,37 +213,5 @@ public Maybe getLaunch() { /** * An Issue to remove 'To Investigate' mark from a skipped/failed Test Item */ - public static final Issue NOT_ISSUE = new Issue() { - public static final String NOT_ISSUE = "NOT_ISSUE"; - - @Override - public String getIssueType() { - return NOT_ISSUE; - } - - @Override - public void setComment(String comment) { - throw new UnsupportedOperationException(); - } - - @Override - public void setIssueType(String type) { - throw new UnsupportedOperationException(); - } - - @Override - public void setAutoAnalyzed(boolean autoAnalyzed) { - throw new UnsupportedOperationException(); - } - - @Override - public void setIgnoreAnalyzer(boolean ignoreAnalyzer) { - throw new UnsupportedOperationException(); - } - - @Override - public void setExternalSystemIssues(Set externalSystemIssues) { - throw new UnsupportedOperationException(); - } - }; + public static final Issue NOT_ISSUE = StaticStructuresUtils.NOT_ISSUE; } diff --git a/src/main/java/com/epam/reportportal/service/LaunchImpl.java b/src/main/java/com/epam/reportportal/service/LaunchImpl.java index 4687142b..c6abe6a7 100644 --- a/src/main/java/com/epam/reportportal/service/LaunchImpl.java +++ b/src/main/java/com/epam/reportportal/service/LaunchImpl.java @@ -22,6 +22,7 @@ import com.epam.reportportal.listeners.ListenerParameters; import com.epam.reportportal.service.statistics.StatisticsService; import com.epam.reportportal.utils.RetryWithDelay; +import com.epam.reportportal.utils.StaticStructuresUtils; import com.epam.reportportal.utils.properties.DefaultProperties; import com.epam.ta.reportportal.ws.reporting.*; import io.reactivex.*; @@ -50,6 +51,7 @@ * A basic Launch object implementation which does straight requests to ReportPortal. */ public class LaunchImpl extends Launch { + public static final String DISABLE_PROPERTY = "AGENT_NO_ANALYTICS"; private static final Map SCHEDULERS = new ConcurrentHashMap<>(); @@ -236,20 +238,33 @@ private void truncateAttributes(@Nonnull final FinishExecutionRQ rq) { /** * Starts launch in ReportPortal. Does NOT start the same launch twice * + * @param statistics Send or not Launch statistics * @return Launch ID promise */ @Nonnull - public Maybe start() { + protected Maybe start(boolean statistics) { launch.subscribe(logMaybeResults("Launch start")); ListenerParameters params = getParameters(); if(params.isPrintLaunchUuid()) { launch.subscribe(printLaunch(params)); } LaunchLoggingContext.init(this.launch, getClient(), getScheduler(), getParameters()); - getStatisticsService().sendEvent(launch, startRq); + if(statistics) { + getStatisticsService().sendEvent(launch, startRq); + } return launch; } + /** + * Starts launch in ReportPortal. Does NOT start the same launch twice + * + * @return Launch ID promise + */ + @Nonnull + public Maybe start() { + return start(System.getenv(DISABLE_PROPERTY) == null); + } + /** * Finishes launch in ReportPortal. Blocks until all items are reported correctly * @@ -370,6 +385,38 @@ public Maybe startTestItem(final Maybe parentId, final StartTest return item; } + protected void completeBtsIssues(@Nullable Issue issue) { + if(!ofNullable(issue).map(Issue::getExternalSystemIssues).filter(issues -> !issues.isEmpty()).isPresent()) { + return; + } + ListenerParameters params = getParameters(); + Optional btsUrl = ofNullable(params.getBtsUrl()).filter(StringUtils::isNotBlank); + Optional btsProjectId = ofNullable(params.getBtsProjectId()).filter(StringUtils::isNotBlank); + Optional btsIssueUrl = ofNullable(params.getBtsIssueUrl()).filter(StringUtils::isNotBlank); + issue.getExternalSystemIssues().stream().filter(Objects::nonNull).forEach(externalIssue -> { + if(StringUtils.isBlank(externalIssue.getTicketId())) { + return; + } + if (btsUrl.isPresent() && StringUtils.isBlank(externalIssue.getBtsUrl())) { + externalIssue.setBtsUrl(btsUrl.get()); + } + if (btsProjectId.isPresent() && StringUtils.isBlank(externalIssue.getBtsProject())) { + externalIssue.setBtsProject(btsProjectId.get()); + } + if (btsIssueUrl.isPresent() && StringUtils.isBlank(externalIssue.getUrl())) { + externalIssue.setUrl(btsIssueUrl.get()); + } + if (StringUtils.isNotBlank(externalIssue.getUrl())) { + if (StringUtils.isNotBlank(externalIssue.getTicketId())) { + externalIssue.setUrl(externalIssue.getUrl().replace("{issue_id}", externalIssue.getTicketId())); + } + if (StringUtils.isNotBlank(externalIssue.getBtsProject())) { + externalIssue.setUrl(externalIssue.getUrl().replace("{bts_project}", externalIssue.getBtsProject())); + } + } + }); + } + /** * Finishes Test Item in ReportPortal. Non-blocking. Schedules finish after success of all child items * @@ -394,8 +441,14 @@ public Maybe finishTestItem(final Maybe item, fin getStepReporter().finishPreviousStep(ofNullable(rq.getStatus()).map(ItemStatus::valueOf).orElse(null)); - if (ItemStatus.SKIPPED.name().equals(rq.getStatus()) && !getParameters().getSkippedAnIssue()) { + ItemStatus status = ofNullable(rq.getStatus()).map(ItemStatus::valueOf).orElse(null); + if (status == ItemStatus.FAILED || (status == ItemStatus.SKIPPED && getParameters().getSkippedAnIssue())) { + completeBtsIssues(rq.getIssue()); + } else if (status == ItemStatus.SKIPPED && !getParameters().getSkippedAnIssue()) { rq.setIssue(Launch.NOT_ISSUE); + } else if (status == ItemStatus.PASSED && rq.getIssue() != null && getParameters().isBtsIssueFail()) { + rq.setStatus(ItemStatus.FAILED.name()); + rq.setIssue(StaticStructuresUtils.REDUNDANT_ISSUE); } QUEUE.getOrCompute(launch).addToQueue(LoggingContext.complete()); diff --git a/src/main/java/com/epam/reportportal/service/launch/SecondaryLaunch.java b/src/main/java/com/epam/reportportal/service/launch/SecondaryLaunch.java index 05112057..d490ab31 100644 --- a/src/main/java/com/epam/reportportal/service/launch/SecondaryLaunch.java +++ b/src/main/java/com/epam/reportportal/service/launch/SecondaryLaunch.java @@ -54,40 +54,46 @@ public SecondaryLaunch(ReportPortalClient rpClient, ListenerParameters parameter } private void waitForLaunchStart() { - new Waiter("Wait for Launch start").pollingEvery(1, TimeUnit.SECONDS).timeoutFail().till(new Callable() { - private volatile Boolean result = null; - private final Queue disposables = new ConcurrentLinkedQueue<>(); + new Waiter("Wait for Launch start").pollingEvery(1, TimeUnit.SECONDS) + .duration(getParameters().getClientJoinLaunchTimeout(), TimeUnit.MILLISECONDS) + .timeoutFail() + .till(new Callable() { + private volatile Boolean result = null; + private final Queue disposables = new ConcurrentLinkedQueue<>(); - @Override - public Boolean call() { - if (result == null) { - disposables.add(launch.subscribe(uuid -> { - Maybe maybeRs = client.getLaunchByUuid(uuid); - if (maybeRs != null) { - disposables.add(maybeRs.subscribe( - launchResource -> result = Boolean.TRUE, - throwable -> LOGGER.debug("Unable to get a Launch: " + throwable.getLocalizedMessage(), throwable) - )); + @Override + public Boolean call() { + if (result == null) { + disposables.add(launch.subscribe(uuid -> { + Maybe maybeRs = client.getLaunchByUuid(uuid); + if (maybeRs != null) { + disposables.add(maybeRs.subscribe(launchResource -> result = Boolean.TRUE, + throwable -> LOGGER.debug("Unable to get a Launch: " + throwable.getLocalizedMessage(), + throwable + ) + )); + } else { + LOGGER.debug("RP Client returned 'null' response on get Launch by UUID call"); + } + })); } else { - LOGGER.debug("RP Client returned 'null' response on get Launch by UUID call"); + Disposable disposable; + while ((disposable = disposables.poll()) != null) { + disposable.dispose(); + } } - })); - } else { - Disposable disposable; - while ((disposable = disposables.poll()) != null) { - disposable.dispose(); + return result; } - } - return result; - } - }); + }); } @Nonnull @Override public Maybe start() { - waitForLaunchStart(); - return super.start(); + if (!getParameters().isAsyncReporting()) { + waitForLaunchStart(); + } + return super.start(false); } @Override diff --git a/src/main/java/com/epam/reportportal/service/statistics/StatisticsService.java b/src/main/java/com/epam/reportportal/service/statistics/StatisticsService.java index 7c82a5d7..f0c3a8e1 100644 --- a/src/main/java/com/epam/reportportal/service/statistics/StatisticsService.java +++ b/src/main/java/com/epam/reportportal/service/statistics/StatisticsService.java @@ -55,7 +55,6 @@ public class StatisticsService implements Closeable { StandardCharsets.UTF_8 ).split(":"); - public static final String DISABLE_PROPERTY = "AGENT_NO_ANALYTICS"; private static final String CLIENT_PROPERTIES_FILE = "client.properties"; public static final String START_LAUNCH_EVENT_ACTION = "start_launch"; public static final String CLIENT_NAME_PARAM = "client_name"; @@ -88,10 +87,7 @@ public StatisticsService(ListenerParameters listenerParameters, Statistics clien public StatisticsService(ListenerParameters listenerParameters) { this(listenerParameters, - System.getenv(DISABLE_PROPERTY) != null ? - new DummyClient() : - new StatisticsClient(DECODED_CLIENT_INFO[0], DECODED_CLIENT_INFO[1], listenerParameters) - ); + new StatisticsClient(DECODED_CLIENT_INFO[0], DECODED_CLIENT_INFO[1], listenerParameters)); } protected Statistics getStatistics() { diff --git a/src/main/java/com/epam/reportportal/utils/StaticStructuresUtils.java b/src/main/java/com/epam/reportportal/utils/StaticStructuresUtils.java new file mode 100644 index 00000000..e40322c2 --- /dev/null +++ b/src/main/java/com/epam/reportportal/utils/StaticStructuresUtils.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.utils; + +import com.epam.ta.reportportal.ws.model.issue.Issue; + +import java.util.Set; + +public class StaticStructuresUtils { + + public static final Issue REDUNDANT_ISSUE = new Issue() { + public static final String AUTOMATION_BUG_ISSUE_TYPE = "ab001"; + public static final String ISSUE_NOT_REMOVED = "Invalid Issue parameter for Passed Test Item. " + + "Did you forgot to remove Issue mark? Ignore this message with \"rp.bts.issue.fail=false\" property."; + + @Override + public String getIssueType() { + return AUTOMATION_BUG_ISSUE_TYPE; + } + + @Override + public String getComment() { + return ISSUE_NOT_REMOVED; + } + + @Override + public void setComment(String comment) { + throw new UnsupportedOperationException(); + } + + @Override + public void setIssueType(String type) { + throw new UnsupportedOperationException(); + } + + @Override + public void setAutoAnalyzed(boolean autoAnalyzed) { + throw new UnsupportedOperationException(); + } + + @Override + public void setIgnoreAnalyzer(boolean ignoreAnalyzer) { + throw new UnsupportedOperationException(); + } + + @Override + public void setExternalSystemIssues(Set externalSystemIssues) { + throw new UnsupportedOperationException(); + } + }; + + public static final Issue NOT_ISSUE = new Issue() { + public static final String NOT_ISSUE = "NOT_ISSUE"; + + @Override + public String getIssueType() { + return NOT_ISSUE; + } + + @Override + public void setComment(String comment) { + throw new UnsupportedOperationException(); + } + + @Override + public void setIssueType(String type) { + throw new UnsupportedOperationException(); + } + + @Override + public void setAutoAnalyzed(boolean autoAnalyzed) { + throw new UnsupportedOperationException(); + } + + @Override + public void setIgnoreAnalyzer(boolean ignoreAnalyzer) { + throw new UnsupportedOperationException(); + } + + @Override + public void setExternalSystemIssues(Set externalSystemIssues) { + throw new UnsupportedOperationException(); + } + }; +} diff --git a/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java b/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java index 4708f36b..522d661e 100644 --- a/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java +++ b/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java @@ -111,6 +111,13 @@ public enum ListenerProperty { CLIENT_JOIN_LOCK_TIMEOUT_VALUE("rp.client.join.lock.timeout.value", false), CLIENT_JOIN_LOCK_TIMEOUT_UNIT("rp.client.join.lock.timeout.unit", false), + /** + * Timeout of waiting for the Primary launch to start. If the primary launch does not start within this timeout, the secondary launch + * will exit. + */ + CLIENT_JOIN_LAUNCH_TIMEOUT_VALUE("rp.client.join.launch.timeout.value", false), + CLIENT_JOIN_LAUNCH_TIMEOUT_UNIT("rp.client.join.launch.timeout.unit", false), + RX_BUFFER_SIZE("rp.rx.buffer.size", false), TRUNCATE_FIELDS("rp.truncation.field", false), diff --git a/src/test/java/com/epam/reportportal/listeners/ListenerParametersTest.java b/src/test/java/com/epam/reportportal/listeners/ListenerParametersTest.java index 51294fbd..7785f650 100644 --- a/src/test/java/com/epam/reportportal/listeners/ListenerParametersTest.java +++ b/src/test/java/com/epam/reportportal/listeners/ListenerParametersTest.java @@ -141,7 +141,7 @@ public void verify_lock_wait_timeout_property_set_if_it_not_present_in_property_ PropertiesLoader properties = PropertiesLoader.load("property-test/default-required.properties"); ListenerParameters listenerParameters = new ListenerParameters(properties); - assertEquals(ListenerParameters.DEFAULT_FILE_WAIT_TIMEOUT_MS, listenerParameters.getLockWaitTimeout()); + assertEquals(ListenerParameters.DEFAULT_FILE_WAIT_TIMEOUT, listenerParameters.getLockWaitTimeout()); } @Test diff --git a/src/test/java/com/epam/reportportal/service/LaunchTest.java b/src/test/java/com/epam/reportportal/service/LaunchTest.java index fc08b53a..e960641a 100644 --- a/src/test/java/com/epam/reportportal/service/LaunchTest.java +++ b/src/test/java/com/epam/reportportal/service/LaunchTest.java @@ -27,6 +27,7 @@ import com.epam.reportportal.service.statistics.StatisticsService; import com.epam.reportportal.service.step.StepReporter; import com.epam.reportportal.utils.ObjectUtils; +import com.epam.reportportal.utils.StaticStructuresUtils; import com.epam.reportportal.utils.properties.DefaultProperties; import com.epam.ta.reportportal.ws.reporting.FinishExecutionRQ; import com.epam.ta.reportportal.ws.reporting.FinishTestItemRQ; @@ -41,9 +42,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import javax.annotation.Nonnull; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; @@ -65,6 +69,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; +@SuppressWarnings({ "ReactiveStreamsUnusedPublisher", "ResultOfMethodCallIgnored" }) public class LaunchTest { private static final ErrorRS START_ERROR_RS; @@ -81,18 +86,10 @@ public class LaunchTest { "Finish time 'Thu Jan 01 00:00:00 UTC 1970' is earlier than start time 'Tue Aug 13 13:21:31 UTC 2019' for resource with ID '5d52b9899bd1160001b8f454'"); } - private static final ReportPortalException START_CLIENT_EXCEPTION = new ReportPortalException( - 400, - "Bad Request", - START_ERROR_RS - ); + private static final ReportPortalException START_CLIENT_EXCEPTION = new ReportPortalException(400, "Bad Request", START_ERROR_RS); // taken from: https://github.com/reportportal/client-java/issues/99 - private static final ReportPortalException FINISH_CLIENT_EXCEPTION = new ReportPortalException( - 406, - "Not Acceptable", - FINISH_ERROR_RS - ); + private static final ReportPortalException FINISH_CLIENT_EXCEPTION = new ReportPortalException(406, "Not Acceptable", FINISH_ERROR_RS); @Mock private ReportPortalClient rpClient; @@ -106,23 +103,37 @@ public void tearDown() { shutdownExecutorService(executor); } - @Test - public void launch_should_finish_all_items_even_if_one_of_finishes_failed() { - simulateStartLaunchResponse(rpClient); - simulateStartTestItemResponse(rpClient); - simulateStartChildTestItemResponse(rpClient); - - Launch launch = new LaunchImpl( - rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { + @Nonnull + private Launch createLaunch(@Nonnull StartLaunchRQ startRq, @Nonnull ListenerParameters parameters) { + return new LaunchImpl(rpClient, parameters, startRq, executor) { @Override StatisticsService getStatisticsService() { return statisticsService; } }; + } + + @Nonnull + private Launch createLaunch(@Nonnull StartLaunchRQ startRq) { + return createLaunch(startRq, standardParameters()); + } + + @Nonnull + private Launch createLaunch(@Nonnull ListenerParameters parameters) { + return createLaunch(standardLaunchRequest(parameters), parameters); + } + + @Nonnull + private Launch createLaunch() { + return createLaunch(standardLaunchRequest(STANDARD_PARAMETERS)); + } + + @Test + public void launch_should_finish_all_items_even_if_one_of_finishes_failed() { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateStartChildTestItemResponse(rpClient); + Launch launch = createLaunch(); Maybe launchUuid = launch.start(); Maybe suiteRs = launch.startTestItem(standardStartSuiteRequest()); @@ -130,18 +141,9 @@ StatisticsService getStatisticsService() { Maybe stepRs = launch.startTestItem(testRs, standardStartStepRequest()); when(rpClient.finishTestItem(eq(stepRs.blockingGet()), any())).thenThrow(FINISH_CLIENT_EXCEPTION); - when(rpClient.finishTestItem( - eq(testRs.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); - when(rpClient.finishTestItem( - eq(suiteRs.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); - when(rpClient.finishLaunch( - eq(launchUuid.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishTestItem(eq(testRs.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishTestItem(eq(suiteRs.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishLaunch(eq(launchUuid.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); launch.finishTestItem(stepRs, positiveFinishRequest()); launch.finishTestItem(testRs, positiveFinishRequest()); @@ -159,18 +161,7 @@ public void launch_should_finish_all_items_even_if_one_of_starts_failed() { simulateStartLaunchResponse(rpClient); simulateStartTestItemResponse(rpClient); simulateStartChildTestItemResponse(rpClient); - - Launch launch = new LaunchImpl( - rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(); Maybe launchUuid = launch.start(); Maybe suiteRs = launch.startTestItem(standardStartSuiteRequest()); @@ -179,18 +170,9 @@ StatisticsService getStatisticsService() { when(rpClient.startTestItem(eq(testRs.blockingGet()), any())).thenThrow(START_CLIENT_EXCEPTION); Maybe stepRs = launch.startTestItem(testRs, standardStartStepRequest()); - when(rpClient.finishTestItem( - eq(testRs.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); - when(rpClient.finishTestItem( - eq(suiteRs.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); - when(rpClient.finishLaunch( - eq(launchUuid.blockingGet()), - any() - )).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishTestItem(eq(testRs.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishTestItem(eq(suiteRs.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); + when(rpClient.finishLaunch(eq(launchUuid.blockingGet()), any())).thenReturn(Maybe.just(new OperationCompletionRS())); launch.finishTestItem(stepRs, positiveFinishRequest()); launch.finishTestItem(testRs, positiveFinishRequest()); @@ -210,16 +192,7 @@ public void launch_should_stick_to_every_thread_which_uses_it() throws Execution // Verify Launch set on creation ExecutorService launchCreateExecutor = Executors.newSingleThreadExecutor(); - Launch launchOnCreate = launchCreateExecutor.submit(() -> new LaunchImpl(rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }).get(); + Launch launchOnCreate = launchCreateExecutor.submit(() -> this.createLaunch()).get(); Launch launchGet = launchCreateExecutor.submit(Launch::currentLaunch).get(); assertThat(launchGet, sameInstance(launchOnCreate)); shutdownExecutorService(launchCreateExecutor); @@ -233,8 +206,7 @@ StatisticsService getStatisticsService() { // Verify Launch set on start root test item ExecutorService launchSuiteStartExecutor = Executors.newSingleThreadExecutor(); - Maybe parent = launchSuiteStartExecutor.submit(() -> launchOnCreate.startTestItem( - standardStartSuiteRequest())).get(); + Maybe parent = launchSuiteStartExecutor.submit(() -> launchOnCreate.startTestItem(standardStartSuiteRequest())).get(); launchGet = launchSuiteStartExecutor.submit(Launch::currentLaunch).get(); assertThat(launchGet, sameInstance(launchOnCreate)); shutdownExecutorService(launchSuiteStartExecutor); @@ -254,12 +226,7 @@ public void launch_should_send_analytics_events_if_created_with_request() { simulateFinishLaunchResponse(rpClient); StartLaunchRQ startRq = standardLaunchRequest(STANDARD_PARAMETERS); - Launch launch = new LaunchImpl(rpClient, STANDARD_PARAMETERS, startRq, executor) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(startRq); launch.start(); launch.finish(standardLaunchFinishRequest()); @@ -307,26 +274,14 @@ public void aFailureStep() { } @Test - public void launch_should_correctly_track_parent_items_for_annotation_based_nested_steps() - throws NoSuchMethodException { + public void launch_should_correctly_track_parent_items_for_annotation_based_nested_steps() throws NoSuchMethodException { simulateStartLaunchResponse(rpClient); simulateStartTestItemResponse(rpClient); simulateFinishTestItemResponse(rpClient); simulateStartChildTestItemResponse(rpClient); simulateFinishLaunchResponse(rpClient); simulateBatchLogResponse(rpClient); - - Launch launch = new LaunchImpl( - rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(); launch.start(); Maybe suiteRs = launch.startTestItem(standardStartSuiteRequest()); @@ -361,18 +316,7 @@ public void launch_should_truncate_long_item_names() { simulateStartLaunchResponse(rpClient); simulateStartTestItemResponse(rpClient); simulateStartChildTestItemResponse(rpClient); - - Launch launch = new LaunchImpl( - rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(); StartTestItemRQ suiteRq = standardStartSuiteRequest(); suiteRq.setName(suiteRq.getName() + RandomStringUtils.random(1025 - suiteRq.getName().length())); @@ -414,12 +358,7 @@ public void launch_should_truncate_long_attributes() { String longValue = RandomStringUtils.randomAlphanumeric(129); parameters.setAttributes(Collections.singleton(new ItemAttributesRQ(longKey, longValue))); - Launch launch = new LaunchImpl(rpClient, parameters, standardLaunchRequest(parameters), executor) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(parameters); StartTestItemRQ suiteStartRq = standardStartSuiteRequest(); suiteStartRq.setAttributes(Collections.singleton(new ItemAttributesRQ(longKey, longValue))); @@ -462,8 +401,7 @@ public void launch_should_not_throw_exceptions_or_hang_if_finished_and_started_a simulateStartTestItemResponse(rpClient); simulateFinishTestItemResponse(rpClient); - StartLaunchRQ startRq = standardLaunchRequest(STANDARD_PARAMETERS); - Launch launch = new LaunchImpl(rpClient, STANDARD_PARAMETERS, startRq, executor); + Launch launch = createLaunch(); launch.start(); Maybe id = launch.startTestItem(standardStartSuiteRequest()); launch.finishTestItem(id, positiveFinishRequest()); @@ -512,18 +450,7 @@ public void test_noop_launch_returns_valid_rp_client() { @Test public void verify_launch_get_response() { simulateStartLaunchResponse(rpClient); - - Launch launch = new LaunchImpl( - rpClient, - STANDARD_PARAMETERS, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(); Maybe launchUuid = launch.start(); assertThat(launchUuid, notNullValue()); @@ -542,18 +469,7 @@ public void verify_launch_print() throws UnsupportedEncodingException { ListenerParameters parameters = standardParameters(); parameters.setPrintLaunchUuid(true); parameters.setPrintLaunchUuidOutput(testStream); - - Launch launch = new LaunchImpl( - rpClient, - parameters, - standardLaunchRequest(STANDARD_PARAMETERS), - executor - ) { - @Override - StatisticsService getStatisticsService() { - return statisticsService; - } - }; + Launch launch = createLaunch(parameters); String launchUuid = launch.start().blockingGet(); Awaitility.await("Wait for Launch UUID output").atMost(Duration.ofSeconds(10)).until(() -> { @@ -563,4 +479,175 @@ StatisticsService getStatisticsService() { String result = baos.toString(StandardCharsets.UTF_8.name()); assertThat(result, endsWith(launchUuid + System.lineSeparator())); } + + @ParameterizedTest + @ValueSource(strings = { "FAILED", "SKIPPED" }) + public void verify_external_issue_filling_logic(String itemStatus) { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateFinishTestItemResponse(rpClient); + ListenerParameters parameters = standardParameters(); + parameters.setBtsUrl("https://example.com"); + parameters.setBtsProjectId("example_project"); + parameters.setBtsIssueUrl("https://example.com/{bts_project}/issue/{issue_id}"); + Launch launch = createLaunch(parameters); + + String launchUuid = launch.start().blockingGet(); + StartTestItemRQ itemRq = standardStartStepRequest(); + itemRq.setLaunchUuid(launchUuid); + Maybe itemId = launch.startTestItem(itemRq); + FinishTestItemRQ finishRq = positiveFinishRequest(); + finishRq.setStatus(itemStatus); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setComment("issue_comment"); + Issue.ExternalSystemIssue externalIssue = new Issue.ExternalSystemIssue(); + externalIssue.setTicketId("RP-001"); + issue.setExternalSystemIssues(Collections.singleton(externalIssue)); + finishRq.setIssue(issue); + launch.finishTestItem(itemId, finishRq).blockingGet(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(rpClient).finishTestItem(eq(itemId.blockingGet()), captor.capture()); + + FinishTestItemRQ resultFinishRq = captor.getValue(); + assertThat(resultFinishRq.getIssue().getExternalSystemIssues(), hasSize(1)); + Issue.ExternalSystemIssue resultExternalIssue = resultFinishRq.getIssue().getExternalSystemIssues().iterator().next(); + assertThat(resultExternalIssue.getTicketId(), equalTo("RP-001")); + assertThat(resultExternalIssue.getUrl(), equalTo("https://example.com/example_project/issue/RP-001")); + assertThat(resultExternalIssue.getBtsUrl(), equalTo("https://example.com")); + assertThat(resultExternalIssue.getBtsProject(), equalTo("example_project")); + } + + @Test + public void verify_failing_item_with_issue_on_passed_test() { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateFinishTestItemResponse(rpClient); + Launch launch = createLaunch(); + + String launchUuid = launch.start().blockingGet(); + StartTestItemRQ itemRq = standardStartStepRequest(); + itemRq.setLaunchUuid(launchUuid); + Maybe itemId = launch.startTestItem(itemRq); + FinishTestItemRQ finishRq = positiveFinishRequest(); + finishRq.setIssue(new Issue()); + launch.finishTestItem(itemId, finishRq).blockingGet(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(rpClient).finishTestItem(eq(itemId.blockingGet()), captor.capture()); + FinishTestItemRQ resultFinishRq = captor.getValue(); + + assertThat(resultFinishRq.getIssue(), notNullValue()); + assertThat(resultFinishRq.getStatus(), equalTo(ItemStatus.FAILED.name())); + Issue issue = resultFinishRq.getIssue(); + assertThat(issue.getIssueType(), equalTo(StaticStructuresUtils.REDUNDANT_ISSUE.getIssueType())); + assertThat(issue.getComment(), equalTo(StaticStructuresUtils.REDUNDANT_ISSUE.getComment())); + assertThat(issue.getExternalSystemIssues(), nullValue()); + } + + @Test + public void verify_not_failing_item_with_issue_on_passed_test_if_it_turned_off() { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateFinishTestItemResponse(rpClient); + ListenerParameters parameters = standardParameters(); + parameters.setBtsIssueFail(false); + Launch launch = createLaunch(parameters); + + String launchUuid = launch.start().blockingGet(); + StartTestItemRQ itemRq = standardStartStepRequest(); + itemRq.setLaunchUuid(launchUuid); + Maybe itemId = launch.startTestItem(itemRq); + FinishTestItemRQ finishRq = positiveFinishRequest(); + finishRq.setIssue(new Issue()); + launch.finishTestItem(itemId, finishRq).blockingGet(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(rpClient).finishTestItem(eq(itemId.blockingGet()), captor.capture()); + FinishTestItemRQ resultFinishRq = captor.getValue(); + + assertThat(resultFinishRq.getIssue(), notNullValue()); + Issue issue = resultFinishRq.getIssue(); + assertThat(issue.getIssueType(), nullValue()); + assertThat(issue.getComment(), nullValue()); + assertThat(issue.getExternalSystemIssues(), nullValue()); + } + + @Test + public void verify_external_issue_no_override_if_set() { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateFinishTestItemResponse(rpClient); + ListenerParameters parameters = standardParameters(); + parameters.setBtsUrl("https://example.com"); + parameters.setBtsProjectId("example_project"); + parameters.setBtsIssueUrl("https://example.com/{bts_project}/issue/{issue_id}"); + Launch launch = createLaunch(parameters); + + String launchUuid = launch.start().blockingGet(); + StartTestItemRQ itemRq = standardStartStepRequest(); + itemRq.setLaunchUuid(launchUuid); + Maybe itemId = launch.startTestItem(itemRq); + FinishTestItemRQ finishRq = positiveFinishRequest(); + finishRq.setStatus(ItemStatus.FAILED.name()); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setComment("issue_comment"); + Issue.ExternalSystemIssue externalIssue = new Issue.ExternalSystemIssue(); + externalIssue.setTicketId("RP-001"); + externalIssue.setBtsUrl("https://test.com"); + externalIssue.setUrl("https://test.com/test_project/issue/RP-002"); + externalIssue.setBtsProject("test_project"); + issue.setExternalSystemIssues(Collections.singleton(externalIssue)); + finishRq.setIssue(issue); + launch.finishTestItem(itemId, finishRq).blockingGet(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(rpClient).finishTestItem(eq(itemId.blockingGet()), captor.capture()); + + FinishTestItemRQ resultFinishRq = captor.getValue(); + assertThat(resultFinishRq.getIssue().getExternalSystemIssues(), hasSize(1)); + Issue.ExternalSystemIssue resultExternalIssue = resultFinishRq.getIssue().getExternalSystemIssues().iterator().next(); + assertThat(resultExternalIssue.getTicketId(), equalTo("RP-001")); + assertThat(resultExternalIssue.getUrl(), equalTo("https://test.com/test_project/issue/RP-002")); + assertThat(resultExternalIssue.getBtsUrl(), equalTo("https://test.com")); + assertThat(resultExternalIssue.getBtsProject(), equalTo("test_project")); + } + + @Test + public void verify_external_issue_url_is_used_for_project_and_ticket_ids() { + simulateStartLaunchResponse(rpClient); + simulateStartTestItemResponse(rpClient); + simulateFinishTestItemResponse(rpClient); + ListenerParameters parameters = standardParameters(); + parameters.setBtsUrl("https://example.com"); + parameters.setBtsProjectId("example_project"); + parameters.setBtsIssueUrl("https://example.com/{bts_project}/issue/{issue_id}"); + Launch launch = createLaunch(parameters); + + String launchUuid = launch.start().blockingGet(); + StartTestItemRQ itemRq = standardStartStepRequest(); + itemRq.setLaunchUuid(launchUuid); + Maybe itemId = launch.startTestItem(itemRq); + FinishTestItemRQ finishRq = positiveFinishRequest(); + finishRq.setStatus(ItemStatus.FAILED.name()); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setComment("issue_comment"); + Issue.ExternalSystemIssue externalIssue = new Issue.ExternalSystemIssue(); + externalIssue.setTicketId("RP-001"); + externalIssue.setUrl("https://test.com/{bts_project}/issue/{issue_id}"); + issue.setExternalSystemIssues(Collections.singleton(externalIssue)); + finishRq.setIssue(issue); + launch.finishTestItem(itemId, finishRq).blockingGet(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(rpClient).finishTestItem(eq(itemId.blockingGet()), captor.capture()); + + FinishTestItemRQ resultFinishRq = captor.getValue(); + assertThat(resultFinishRq.getIssue().getExternalSystemIssues(), hasSize(1)); + Issue.ExternalSystemIssue resultExternalIssue = resultFinishRq.getIssue().getExternalSystemIssues().iterator().next(); + assertThat(resultExternalIssue.getUrl(), equalTo("https://test.com/example_project/issue/RP-001")); + } } diff --git a/src/test/java/com/epam/reportportal/service/ReportPortalClientJoinTest.java b/src/test/java/com/epam/reportportal/service/ReportPortalClientJoinTest.java index 60895cd5..1e6af937 100644 --- a/src/test/java/com/epam/reportportal/service/ReportPortalClientJoinTest.java +++ b/src/test/java/com/epam/reportportal/service/ReportPortalClientJoinTest.java @@ -70,6 +70,7 @@ public class ReportPortalClientJoinTest { private final Supplier paramSupplier = () -> { ListenerParameters p = TestUtils.standardParameters(); p.setClientJoin(true); + p.setAsyncReporting(false); return p; }; @@ -346,10 +347,9 @@ public void test_secondary_launch_awaits_get_launch_by_uuid_correct_response_for } @Test - public void test_secondary_launch_awaits_get_launch_by_uuid_correct_response_for_v2() { + public void test_secondary_launch_does_not_await_get_launch_by_uuid_correct_response_for_v2() { int num = 2; simulateObtainLaunchUuidResponse(launchIdLock); - simulateGetLaunchByUuidResponse(rpClient); ListenerParameters p = paramSupplier.get(); p.setAsyncReporting(true); List launches = new ArrayList<>(num); @@ -360,7 +360,7 @@ public void test_secondary_launch_awaits_get_launch_by_uuid_correct_response_for launches.get(1).start(); verify(launchIdLock, timeout(WAIT_TIMEOUT).times(2)).obtainLaunchUuid(anyString()); - verify(rpClient, after(WAIT_TIMEOUT * 3).times(3)).getLaunchByUuid(anyString()); + verify(rpClient, after(WAIT_TIMEOUT * 3).times(0)).getLaunchByUuid(anyString()); } @Test diff --git a/src/test/java/com/epam/reportportal/service/StatisticsRunnable.java b/src/test/java/com/epam/reportportal/service/StatisticsRunnable.java new file mode 100644 index 00000000..acb5cbb8 --- /dev/null +++ b/src/test/java/com/epam/reportportal/service/StatisticsRunnable.java @@ -0,0 +1,59 @@ +/* + * 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 + * + * 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.service; + +import com.epam.reportportal.service.statistics.StatisticsClient; +import com.epam.reportportal.service.statistics.StatisticsService; +import com.epam.reportportal.service.statistics.item.StatisticsItem; +import static com.epam.reportportal.util.test.CommonUtils.shutdownExecutorService; +import com.epam.reportportal.test.TestUtils; +import io.reactivex.Maybe; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class StatisticsRunnable { + public static final long DELAY = 1000; + public static final StatisticsClient STATISTICS_CLIENT = mock(StatisticsClient.class); + public static final StatisticsService STATISTICS_SERVICE = + new StatisticsService(TestUtils.standardParameters(), STATISTICS_CLIENT); + public static final Maybe LAUNCH_ID = Maybe.just("launch_id"); + public static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + public static final ReportPortalClient CLIENT = mock(ReportPortalClient.class); + + public static class MyLaunch extends LaunchImpl { + public MyLaunch() { + super(CLIENT, TestUtils.standardParameters(), LAUNCH_ID, EXECUTOR_SERVICE); + } + + @Override + StatisticsService getStatisticsService() { + return STATISTICS_SERVICE; + } + } + + public static void main(String... args) { + MyLaunch launch = new MyLaunch(); + //noinspection ReactiveStreamsUnusedPublisher + launch.start(); + verify(STATISTICS_CLIENT, after(DELAY).times(Integer.parseInt(args[0]))).send(any(StatisticsItem.class)); + shutdownExecutorService(EXECUTOR_SERVICE); + } +} diff --git a/src/test/java/com/epam/reportportal/service/statistics/StatisticsRunnable.java b/src/test/java/com/epam/reportportal/service/statistics/StatisticsRunnable.java deleted file mode 100644 index 24479c38..00000000 --- a/src/test/java/com/epam/reportportal/service/statistics/StatisticsRunnable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.epam.reportportal.service.statistics; - -import com.epam.reportportal.test.TestUtils; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; - -public class StatisticsRunnable { - public static void main(String... args) throws ClassNotFoundException { - try(StatisticsService service = new StatisticsService(TestUtils.standardParameters())) { - assertThat(service.getStatistics(), instanceOf(Class.forName(args[0]))); - } - } -} diff --git a/src/test/java/com/epam/reportportal/service/statistics/StatisticsServiceOnOffTest.java b/src/test/java/com/epam/reportportal/service/statistics/StatisticsServiceOnOffTest.java index baec097e..87567818 100644 --- a/src/test/java/com/epam/reportportal/service/statistics/StatisticsServiceOnOffTest.java +++ b/src/test/java/com/epam/reportportal/service/statistics/StatisticsServiceOnOffTest.java @@ -16,6 +16,8 @@ package com.epam.reportportal.service.statistics; +import com.epam.reportportal.service.LaunchImpl; +import com.epam.reportportal.service.StatisticsRunnable; import com.epam.reportportal.util.test.ProcessUtils; import org.junit.jupiter.api.Test; @@ -31,15 +33,16 @@ public void test_statistics_property_off() throws IOException, InterruptedExcept Process process = ProcessUtils.buildProcess( true, StatisticsRunnable.class, - Collections.singletonMap(StatisticsService.DISABLE_PROPERTY, "1"), - DummyClient.class.getCanonicalName() + Collections.singletonMap(LaunchImpl.DISABLE_PROPERTY, "1"), + "0" ); assertThat("Exit code should be '0'", process.waitFor(), equalTo(0)); } @Test public void test_statistics_property_on() throws IOException, InterruptedException { - Process process = ProcessUtils.buildProcess(true, StatisticsRunnable.class, StatisticsClient.class.getCanonicalName()); + Process process = ProcessUtils.buildProcess(true, StatisticsRunnable.class, + "1"); assertThat("Exit code should be '0'", process.waitFor(), equalTo(0)); } }