From f910d598dc4a3ceba7abb932557cc5afff148a9a Mon Sep 17 00:00:00 2001 From: Vadzim Hushchanskou Date: Thu, 14 Nov 2024 17:03:45 +0300 Subject: [PATCH] `rp.launch.uuid.creation.skip` configuration properties to control Launch start on provided UUID --- CHANGELOG.md | 2 + README.md | 9 +++ README_TEMPLATE.md | 58 +++++++++------ .../listeners/ListenerParameters.java | 74 +++++++++---------- .../epam/reportportal/service/LaunchImpl.java | 24 +++--- .../reportportal/service/ReportPortal.java | 45 ++++++----- .../utils/properties/ListenerProperty.java | 6 +- 7 files changed, 125 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a0193e..6a2f9e19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [Unreleased] +### Added +- `rp.launch.uuid.creation.skip` configuration properties to control Launch start on provided UUID, by @HardNorth ## [5.2.20] ### Fixed diff --git a/README.md b/README.md index 8013076b..418d4e43 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,15 @@ etc. | rp.truncation.item.name.limit | Integer | Default: `1024`
Maximum item names length before truncation. | | rp.truncation.attribute.limit | Integer | Default: `128`
Maximum attribute key and value limit (counts separately) | +### Bug Tracking System parameters + +| **Property name** | **Type** | **Description** | +|-------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| rp.bts.project | String | Bug Tracking System Project name to use along with `@ExternalIssue` annotation. Should be the same as in corresponding integration. | +| rp.bts.url | String | Bug Tracking System base URL. Should be the same as in corresponding integration. | +| rp.bts.issue.url | String | Bug Tracking System URL Pattern for Issues. Use {issue_id} and {bts_project} placeholders to mark a place where to put Issue ID and Bug Tracking System Project name. | +| rp.bts.issue.fail | Boolean | Default: `true`
Fail tests marked with `@Issue` annotation if they passed. Designed to not miss the moment when the issue got fixed but test is still marked by annotation. | + ## Proxy configuration ReportPortal supports 2 options for setting Proxy configuration: diff --git a/README_TEMPLATE.md b/README_TEMPLATE.md index 96806176..d6f92efd 100644 --- a/README_TEMPLATE.md +++ b/README_TEMPLATE.md @@ -84,30 +84,31 @@ value will be used. ### Common parameters -| **Property name** | **Type** | **Description** | **Required** | -|-----------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| -| rp.endpoint | String | URL of web service, where requests should be send | Yes | -| rp.api.key | String | Api token of user | Yes | -| rp.launch | String | A unique name of Launch (Run). Based on that name a history of runs will be created for particular name | Yes | -| rp.project | String | Project name to identify scope | Yes | -| rp.launch.uuid | String | A unique Launch UUID to which the whole test execution will be uploaded. No new launch will be created if the property specified. | No | -| rp.launch.uuid.print | Boolean | Enables printing Launch UUID on test run start. Default `False`. | No | -| rp.launch.uuid.print.output | Enum | Launch UUID print output. Default `stdout`. Possible values: `stderr`, `stdout`. | No | -| rp.enable | Boolean | Enable/Disable logging to ReportPortal: rp.enable=true - enable log to RP server. Any other value means 'false': rp.enable=false - disable log to RP server. If parameter is absent in properties file then automation project results will be posted on RP. | No | -| rp.description | String | Launch description | No | -| rp.attributes | String | Set of attributes for specifying additional meta information for current launch. Format: key:value;value;build:12345-6. Attributes should be separated by “;”, keys and values - “:”. | No | -| rp.reporting.async | Boolean | Enables asynchronous reporting. Available values - `true` (by default) or `false`. Supported only in 5+ version. | No | -| rp.reporting.callback | Boolean | Enables [callback reporting](https://github.com/reportportal/client-java/wiki/Callback-reporting-usefulness). Available values - `true` or `false`(by default). Supported only in 5+ vesion | No | -| rp.rerun | Boolean | Enables [rerun mode](https://github.com/reportportal/documentation/blob/master/src/md/src/DevGuides/rerun.md). Available values - `true` or `false`(by default). Supported only in 5+ version | No | -| rp.rerun.of | String | Specifies UUID of launch that has to be rerun. | No | -| rp.convertimage | Boolean | Colored log images can be converted to grayscale for reducing image size. Values: ‘true’ – will be converted. Any other value means ‘false’. | No | -| rp.mode | Enum | ReportPortal provides possibility to specify visibility of executing launch. Currently two modes are supported: DEFAULT - all users from project can see this launch; DEBUG - all users except of Customer role can see this launch (in debug sub tab). Note: for all java based clients (TestNG, Junit) mode will be set automatically to "DEFAULT" if it is not specified. | No | -| rp.skipped.issue | Boolean | ReportPortal provides feature to mark skipped tests as not 'To Investigate' items on WS side. Parameter could be equal boolean values:
  • `true` - skipped tests considered as issues and will be marked as 'To Investigate' on ReportPortal.
  • `false` - skipped tests will not be marked as 'To Investigate' on application. | No | -| rp.batch.size.logs | Integer | Put logs into batches of specified size in order to rise up performance and reduce number of requests to server. Default = 10 | No | -| rp.batch.payload.limit | Long | Limit batches by payload size to avoid request rejection due to server limitations. | No | -| rp.rx.buffer.size | Integer | Internal queue size for log processing, increase this value along with log batch size if you see not all your logs passing to server. Default = 128 | No | -| rp.keystore.resource | String | Put your JKS file into resources and specify path to it | No | -| rp.keystore.password | String | Access password for JKS (certificate storage) package, mentioned above
    | No | +| **Property name** | **Type** | **Description** | **Required** | +|-------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| +| rp.endpoint | String | URL of web service, where requests should be send | Yes | +| rp.api.key | String | Api token of user | Yes | +| rp.launch | String | A unique name of Launch (Run). Based on that name a history of runs will be created for particular name | Yes | +| rp.project | String | Project name to identify scope | Yes | +| rp.launch.uuid | String | A unique Launch UUID to which the whole test execution will be uploaded. | No | +| rp.launch.uuid.creation.skip | Boolean | Do not create new launch and report to predefined Launch provided by UUID above. Default `true`. | No | +| rp.launch.uuid.print | Boolean | Enables printing Launch UUID on test run start. Default `false`. | No | +| rp.launch.uuid.print.output | Enum | Launch UUID print output. Default `stdout`. Possible values: `stderr`, `stdout`. | No | +| rp.enable | Boolean | Enable/Disable logging to ReportPortal: rp.enable=true - enable log to RP server. Any other value means 'false': rp.enable=false - disable log to RP server. If parameter is absent in properties file then automation project results will be posted on RP. | No | +| rp.description | String | Launch description | No | +| rp.attributes | String | Set of attributes for specifying additional meta information for current launch. Format: key:value;value;build:12345-6. Attributes should be separated by “;”, keys and values - “:”. | No | +| rp.reporting.async | Boolean | Enables asynchronous reporting. Available values - `true` (by default) or `false`. Supported only in 5+ version. | No | +| rp.reporting.callback | Boolean | Enables [callback reporting](https://github.com/reportportal/client-java/wiki/Callback-reporting-usefulness). Available values - `true` or `false`(by default). Supported only in 5+ vesion | No | +| rp.rerun | Boolean | Enables [rerun mode](https://github.com/reportportal/documentation/blob/master/src/md/src/DevGuides/rerun.md). Available values - `true` or `false`(by default). Supported only in 5+ version | No | +| rp.rerun.of | String | Specifies UUID of launch that has to be rerun. | No | +| rp.convertimage | Boolean | Colored log images can be converted to grayscale for reducing image size. Values: ‘true’ – will be converted. Any other value means ‘false’. | No | +| rp.mode | Enum | ReportPortal provides possibility to specify visibility of executing launch. Currently two modes are supported: DEFAULT - all users from project can see this launch; DEBUG - all users except of Customer role can see this launch (in debug sub tab). Note: for all java based clients (TestNG, Junit) mode will be set automatically to "DEFAULT" if it is not specified. | No | +| rp.skipped.issue | Boolean | ReportPortal provides feature to mark skipped tests as not 'To Investigate' items on WS side. Parameter could be equal boolean values:
  • `true` - skipped tests considered as issues and will be marked as 'To Investigate' on ReportPortal.
  • `false` - skipped tests will not be marked as 'To Investigate' on application. | No | +| rp.batch.size.logs | Integer | Put logs into batches of specified size in order to rise up performance and reduce number of requests to server. Default = 10 | No | +| rp.batch.payload.limit | Long | Limit batches by payload size to avoid request rejection due to server limitations. | No | +| rp.rx.buffer.size | Integer | Internal queue size for log processing, increase this value along with log batch size if you see not all your logs passing to server. Default = 128 | No | +| rp.keystore.resource | String | Put your JKS file into resources and specify path to it | No | +| rp.keystore.password | String | Access password for JKS (certificate storage) package, mentioned above
    | No | Launch name sets once before first execution, because in common launch parts are fixed for a long time. By keeping the same launch name we will know a fixed list of suites behind it. That will allow us to have a history trend. On Report @@ -156,6 +157,15 @@ etc. | rp.truncation.item.name.limit | Integer | Default: `1024`
    Maximum item names length before truncation. | | rp.truncation.attribute.limit | Integer | Default: `128`
    Maximum attribute key and value limit (counts separately) | +### Bug Tracking System parameters + +| **Property name** | **Type** | **Description** | +|-------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| rp.bts.project | String | Bug Tracking System Project name to use along with `@ExternalIssue` annotation. Should be the same as in corresponding integration. | +| rp.bts.url | String | Bug Tracking System base URL. Should be the same as in corresponding integration. | +| rp.bts.issue.url | String | Bug Tracking System URL Pattern for Issues. Use {issue_id} and {bts_project} placeholders to mark a place where to put Issue ID and Bug Tracking System Project name. | +| rp.bts.issue.fail | Boolean | Default: `true`
    Fail tests marked with `@Issue` annotation if they passed. Designed to not miss the moment when the issue got fixed but test is still marked by annotation. | + ## Proxy configuration ReportPortal supports 2 options for setting Proxy configuration: diff --git a/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java b/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java index dedbdc1f..fb61be20 100644 --- a/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java +++ b/src/main/java/com/epam/reportportal/listeners/ListenerParameters.java @@ -71,6 +71,7 @@ public class ListenerParameters implements Cloneable { // Due to shortcoming of payload calculation mechanism this value is set to 65 million of bytes rather than 65 megabytes public static final long DEFAULT_BATCH_PAYLOAD_LIMIT = 65 * 1000 * 1000; + public static final boolean DEFAULT_LAUNCH_CREATION_SKIP = true; public static final boolean DEFAULT_LAUNCH_UUID_PRINT = false; public static final String DEFAULT_LAUNCH_UUID_OUTPUT = "stdout"; @@ -122,6 +123,7 @@ public class ListenerParameters implements Cloneable { private String truncateReplacement; private int attributeLengthLimit; + private boolean isLaunchUuidCreationSkip; private boolean printLaunchUuid; private PrintStream printLaunchUuidOutput; @@ -155,10 +157,12 @@ private static ChronoUnit toChronoUnit(@Nonnull TimeUnit t) { @Nullable private static Duration getDurationProperty(@Nonnull PropertiesLoader properties, @Nonnull ListenerProperty value, @Nonnull ListenerProperty unit) { - return ofNullable(properties.getProperty(value)).map(Long::parseLong).map(t -> Duration.of(t, - ofNullable(properties.getProperty(unit)).map(u -> toChronoUnit(TimeUnit.valueOf(u))) - .orElse(ChronoUnit.MILLIS) - )).orElse(null); + return ofNullable(properties.getProperty(value)).map(Long::parseLong) + .map(t -> Duration.of( + t, + ofNullable(properties.getProperty(unit)).map(u -> toChronoUnit(TimeUnit.valueOf(u))).orElse(ChronoUnit.MILLIS) + )) + .orElse(null); } /** @@ -200,8 +204,8 @@ public ListenerParameters() { this.attributeLengthLimit = DEFAULT_TRUNCATE_ATTRIBUTE_LIMIT; this.printLaunchUuid = DEFAULT_LAUNCH_UUID_PRINT; - this.printLaunchUuidOutput = - OutputTypes.valueOf(DEFAULT_LAUNCH_UUID_OUTPUT.toUpperCase(Locale.ROOT)).getOutput(); + this.printLaunchUuidOutput = OutputTypes.valueOf(DEFAULT_LAUNCH_UUID_OUTPUT.toUpperCase(Locale.ROOT)).getOutput(); + this.isLaunchUuidCreationSkip = DEFAULT_LAUNCH_CREATION_SKIP; this.btsIssueFail = DEFAULT_BTS_ISSUE_FAIL; } @@ -213,8 +217,7 @@ public ListenerParameters() { */ public ListenerParameters(PropertiesLoader properties) { this.description = properties.getProperty(DESCRIPTION); - this.apiKey = ofNullable(properties.getProperty(API_KEY, properties.getProperty(UUID))).map(String::trim) - .orElse(null); + this.apiKey = ofNullable(properties.getProperty(API_KEY, properties.getProperty(UUID))).map(String::trim).orElse(null); this.baseUrl = properties.getProperty(BASE_URL) != null ? properties.getProperty(BASE_URL).trim() : null; this.proxyUrl = properties.getProperty(HTTP_PROXY_URL); this.proxyUser = properties.getProperty(HTTP_PROXY_USER); @@ -222,19 +225,14 @@ public ListenerParameters(PropertiesLoader properties) { this.httpLogging = properties.getPropertyAsBoolean(HTTP_LOGGING, DEFAULT_HTTP_LOGGING); this.httpCallTimeout = getDurationProperty(properties, HTTP_CALL_TIMEOUT_VALUE, HTTP_CALL_TIMEOUT_UNIT); - this.httpConnectTimeout = getDurationProperty(properties, - HTTP_CONNECT_TIMEOUT_VALUE, - HTTP_CONNECT_TIMEOUT_UNIT - ); + this.httpConnectTimeout = getDurationProperty(properties, HTTP_CONNECT_TIMEOUT_VALUE, HTTP_CONNECT_TIMEOUT_UNIT); this.httpReadTimeout = getDurationProperty(properties, HTTP_READ_TIMEOUT_VALUE, HTTP_READ_TIMEOUT_UNIT); this.httpWriteTimeout = getDurationProperty(properties, HTTP_WRITE_TIMEOUT_VALUE, HTTP_WRITE_TIMEOUT_UNIT); - this.projectName = - properties.getProperty(PROJECT_NAME) != null ? properties.getProperty(PROJECT_NAME).trim() : null; + this.projectName = properties.getProperty(PROJECT_NAME) != null ? properties.getProperty(PROJECT_NAME).trim() : null; this.launchName = properties.getProperty(LAUNCH_NAME); this.launchUuid = properties.getProperty(LAUNCH_UUID); - this.attributes = Collections.unmodifiableSet(AttributeParser.parseAsSet(properties.getProperty( - LAUNCH_ATTRIBUTES))); + this.attributes = Collections.unmodifiableSet(AttributeParser.parseAsSet(properties.getProperty(LAUNCH_ATTRIBUTES))); this.launchRunningMode = parseLaunchMode(properties.getProperty(MODE)); this.enable = properties.getPropertyAsBoolean(ENABLE, DEFAULT_ENABLE); this.isSkippedAnIssue = properties.getPropertyAsBoolean(SKIPPED_AS_ISSUE, DEFAULT_SKIP_ISSUE); @@ -250,32 +248,25 @@ public ListenerParameters(PropertiesLoader properties) { this.rerunOf = properties.getProperty(RERUN_OF); this.asyncReporting = properties.getPropertyAsBoolean(ASYNC_REPORTING, DEFAULT_ASYNC_REPORTING); - this.callbackReportingEnabled = properties.getPropertyAsBoolean(CALLBACK_REPORTING_ENABLED, - DEFAULT_CALLBACK_REPORTING_ENABLED - ); + this.callbackReportingEnabled = properties.getPropertyAsBoolean(CALLBACK_REPORTING_ENABLED, DEFAULT_CALLBACK_REPORTING_ENABLED); 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 - )); + clientJoinMode = LaunchIdLockMode.valueOf(properties.getProperty(CLIENT_JOIN_MODE_VALUE, DEFAULT_CLIENT_JOIN_MODE)); 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); - clientJoinTimeout = ofNullable(properties.getProperty(CLIENT_JOIN_TIMEOUT_VALUE)) - .map(t -> TimeUnit.valueOf(properties.getProperty(CLIENT_JOIN_TIMEOUT_UNIT, + 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, + 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, + 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); @@ -283,19 +274,13 @@ public ListenerParameters(PropertiesLoader properties) { this.rxBufferSize = properties.getPropertyAsInt(RX_BUFFER_SIZE, DEFAULT_RX_BUFFER_SIZE); this.truncateFields = properties.getPropertyAsBoolean(TRUNCATE_FIELDS, DEFAULT_TRUNCATE); - this.truncateItemNamesLimit = properties.getPropertyAsInt(TRUNCATE_ITEM_NAME_LIMIT, - DEFAULT_TRUNCATE_ITEM_NAMES_LIMIT); + this.truncateItemNamesLimit = properties.getPropertyAsInt(TRUNCATE_ITEM_NAME_LIMIT, DEFAULT_TRUNCATE_ITEM_NAMES_LIMIT); this.truncateReplacement = properties.getProperty(TRUNCATE_REPLACEMENT, DEFAULT_TRUNCATE_REPLACEMENT); - this.attributeLengthLimit = properties.getPropertyAsInt(TRUNCATE_ATTRIBUTE_LIMIT, - DEFAULT_TRUNCATE_ATTRIBUTE_LIMIT); + this.attributeLengthLimit = properties.getPropertyAsInt(TRUNCATE_ATTRIBUTE_LIMIT, DEFAULT_TRUNCATE_ATTRIBUTE_LIMIT); this.printLaunchUuid = properties.getPropertyAsBoolean(LAUNCH_UUID_PRINT, DEFAULT_LAUNCH_UUID_PRINT); - this.printLaunchUuidOutput = - OutputTypes.valueOf( - properties - .getProperty(LAUNCH_UUID_PRINT_OUTPUT, DEFAULT_LAUNCH_UUID_OUTPUT) - .toUpperCase(Locale.ROOT) - ).getOutput(); + this.printLaunchUuidOutput = OutputTypes.valueOf(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); @@ -380,6 +365,14 @@ public void setLaunchUuid(@Nullable String launchUuid) { this.launchUuid = launchUuid; } + public boolean isLaunchUuidCreationSkip() { + return isLaunchUuidCreationSkip; + } + + public void setLaunchUuidCreationSkip(boolean launchUuidCreationSkip) { + isLaunchUuidCreationSkip = launchUuidCreationSkip; + } + public boolean isPrintLaunchUuid() { return printLaunchUuid; } @@ -590,9 +583,7 @@ public void setHttpLogging(boolean httpLogging) { } public int getRxBufferSize() { - return ofNullable(System.getProperty("rx2.buffer-size")).map(Integer::valueOf) - .map(s -> Math.max(1, s)) - .orElse(rxBufferSize); + return ofNullable(System.getProperty("rx2.buffer-size")).map(Integer::valueOf).map(s -> Math.max(1, s)).orElse(rxBufferSize); } public void setRxBufferSize(int size) { @@ -743,6 +734,7 @@ public String toString() { sb.append(", projectName='").append(projectName).append('\''); sb.append(", launchName='").append(launchName).append('\''); sb.append(", launchUuid='").append(launchUuid).append('\''); + sb.append(", launchUuidCreationSkip='").append(isLaunchUuidCreationSkip).append('\''); sb.append(", printLaunchUuid='").append(printLaunchUuid).append('\''); sb.append(", printLaunchUuidOutput='").append(printLaunchUuidOutput).append('\''); sb.append(", launchRunningMode=").append(launchRunningMode); diff --git a/src/main/java/com/epam/reportportal/service/LaunchImpl.java b/src/main/java/com/epam/reportportal/service/LaunchImpl.java index c9f4564d..e02f17a7 100644 --- a/src/main/java/com/epam/reportportal/service/LaunchImpl.java +++ b/src/main/java/com/epam/reportportal/service/LaunchImpl.java @@ -77,11 +77,13 @@ public class LaunchImpl extends Launch { && ErrorType.FINISH_ITEM_NOT_ALLOWED.equals(((ReportPortalException) throwable).getError().getErrorType())) || INTERNAL_CLIENT_EXCEPTION_PREDICATE.test(throwable); - private static final RetryWithDelay DEFAULT_REQUEST_RETRY = new RetryWithDelay(INTERNAL_CLIENT_EXCEPTION_PREDICATE, + private static final RetryWithDelay DEFAULT_REQUEST_RETRY = new RetryWithDelay( + INTERNAL_CLIENT_EXCEPTION_PREDICATE, DEFAULT_RETRY_COUNT, TimeUnit.SECONDS.toMillis(DEFAULT_RETRY_TIMEOUT) ); - private static final RetryWithDelay TEST_ITEM_FINISH_REQUEST_RETRY = new RetryWithDelay(TEST_ITEM_FINISH_RETRY_PREDICATE, + private static final RetryWithDelay TEST_ITEM_FINISH_REQUEST_RETRY = new RetryWithDelay( + TEST_ITEM_FINISH_RETRY_PREDICATE, ITEM_FINISH_MAX_RETRIES, TimeUnit.SECONDS.toMillis(ITEM_FINISH_RETRY_TIMEOUT) ); @@ -127,10 +129,12 @@ protected LaunchImpl(@Nonnull final ReportPortalClient reportPortalClient, @Nonn }).subscribeOn(getScheduler()).cache(); //noinspection ResultOfMethodCallIgnored - launchPromise.subscribe(rs -> emitter.onSuccess(rs.getId()), t -> { - LOG_ERROR.accept(t); - emitter.onComplete(); - }); + launchPromise.subscribe( + rs -> emitter.onSuccess(rs.getId()), t -> { + LOG_ERROR.accept(t); + emitter.onComplete(); + } + ); }).cache(); projectSettings = ofNullable(getClient().getProjectSettings()).map(settings -> settings.subscribeOn(getScheduler()).cache()) .orElse(Maybe.empty()); @@ -213,14 +217,16 @@ private Set truncateAttributes(@Nullable final Set limit && keyLength > replacement.length()) { - updated = new ItemAttributesRQ(updated.getKey().substring(0, limit - replacement.length()) + replacement, + updated = new ItemAttributesRQ( + updated.getKey().substring(0, limit - replacement.length()) + replacement, updated.getValue(), updated.isSystem() ); } int valueLength = ofNullable(updated.getValue()).map(String::length).orElse(0); if (valueLength > limit && valueLength > replacement.length()) { - updated = new ItemAttributesRQ(updated.getKey(), + updated = new ItemAttributesRQ( + updated.getKey(), updated.getValue().substring(0, limit - replacement.length()) + replacement, updated.isSystem() ); @@ -275,7 +281,7 @@ public Maybe start() { public void finish(final FinishExecutionRQ request) { QUEUE.getOrCompute(launch).addToQueue(LaunchLoggingContext.complete()); Completable finish = Completable.concat(QUEUE.getOrCompute(launch).getChildren()); - if (StringUtils.isBlank(getParameters().getLaunchUuid())) { + if (StringUtils.isBlank(getParameters().getLaunchUuid()) || !getParameters().isLaunchUuidCreationSkip()) { FinishExecutionRQ rq = clonePojo(request, FinishExecutionRQ.class); truncateAttributes(rq); finish = finish.andThen(launch.map(id -> getClient().finishLaunch(id, rq) diff --git a/src/main/java/com/epam/reportportal/service/ReportPortal.java b/src/main/java/com/epam/reportportal/service/ReportPortal.java index 684d736e..90467475 100644 --- a/src/main/java/com/epam/reportportal/service/ReportPortal.java +++ b/src/main/java/com/epam/reportportal/service/ReportPortal.java @@ -55,7 +55,10 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; @@ -118,34 +121,42 @@ public Launch newLaunch(@Nonnull StartLaunchRQ rq) { return Launch.NOOP_LAUNCH; } - if (StringUtils.isNotBlank(parameters.getLaunchUuid())) { - // a Launch UUID specified, use it and do not start a new Launch - return new LaunchImpl(rpClient, parameters, Maybe.just(parameters.getLaunchUuid()), executor); + StartLaunchRQ rqCopy = clonePojo(rq, StartLaunchRQ.class); + String launchUuid = parameters.getLaunchUuid(); + boolean launchUuidSet = StringUtils.isNotBlank(launchUuid); + if (launchUuidSet) { + if (parameters.isLaunchUuidCreationSkip()) { + // a Launch UUID specified, but we should skip its creation + return new LaunchImpl(rpClient, parameters, Maybe.just(launchUuid), executor); + } else { + // a Launch UUID specified, but we should create a new Launch with it + rqCopy.setUuid(launchUuid); + } } if (launchIdLock == null) { // do not use multi-client mode - return new LaunchImpl(rpClient, parameters, rq, executor); + return new LaunchImpl(rpClient, parameters, rqCopy, executor); } final String instanceUuid = UUID.randomUUID().toString(); final String uuid = launchIdLock.obtainLaunchUuid(instanceUuid); if (uuid == null) { // timeout locking on file or interrupted, anyway it should be logged already - // we continue to operate normally, since this flag is set by default and we shouldn't fail launches because of it - return new LaunchImpl(rpClient, parameters, rq, executor); + // we continue to operate normally, since this flag is set by default, and we shouldn't fail launches because of it + return new LaunchImpl(rpClient, parameters, rqCopy, executor); } if (instanceUuid.equals(uuid)) { - // We got our own UUID as launch UUID, that means we are primary launch. - StartLaunchRQ rqCopy = clonePojo(rq, StartLaunchRQ.class); - rqCopy.setUuid(uuid); + // We got our own instance UUID, that means we are primary launch. + if (!launchUuidSet) { + // If we got Launch UUID from parameters, we should use it, otherwise we should use instance UUID as Launch UUID + rqCopy.setUuid(instanceUuid); + } return new PrimaryLaunch(rpClient, parameters, rqCopy, executor, launchIdLock, instanceUuid); } else { - Maybe launch = Maybe.create(emitter -> { - emitter.onSuccess(uuid); - emitter.onComplete(); - }); + // If we got Launch UUID from parameters, we should use it, otherwise we should use obtained UUID as a Secondary Launch + Maybe launch = launchUuidSet ? Maybe.just(launchUuid) : Maybe.just(uuid); return new SecondaryLaunch(rpClient, parameters, launch, executor, launchIdLock, instanceUuid); } } @@ -495,12 +506,10 @@ protected Retrofit buildRestEndpoint(@Nonnull final ListenerParameters parameter builder.baseUrl(baseUrl); } catch (NoSuchMethodError e) { throw new InternalReportPortalClientException( - "Unable to initialize OkHttp client. " - + "ReportPortal client supports OkHttp version 3.11.0 as minimum.\n" + "Unable to initialize OkHttp client. ReportPortal client supports OkHttp version 3.11.0 as minimum.\n" + "Please update OkHttp dependency.\n" + "Besides this usually happens due to old selenium-java version (it overrides our dependency), " - + "please use selenium-java 3.141.0 as minimum.", - e + + "please use selenium-java 3.141.0 as minimum.", e ); } return builder.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.from(executor))) 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 522d661e..c482cc7a 100644 --- a/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java +++ b/src/main/java/com/epam/reportportal/utils/properties/ListenerProperty.java @@ -58,9 +58,13 @@ public enum ListenerProperty { PROJECT_NAME("rp.project", true), LAUNCH_NAME("rp.launch", true), /** - * Do not create new launch and use predefined Launch UUID. + * Use predefined Launch UUID. */ LAUNCH_UUID("rp.launch.uuid", false), + /** + * Do not create new launch and report to predefined Launch UUID. + */ + LAUNCH_UUID_CREATION_SKIP("rp.launch.uuid.creation.skip", false), /** * Print Launch UUID after start in a format: `ReportPortal Launch UUID: {UUID}`. */