diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9c3aac..d5c7cc0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,8 +11,8 @@ on: env: GH_USER_NAME: github.actor - SCRIPTS_VERSION: 5.10.0 - BOM_VERSION: 5.11.0 + SCRIPTS_VERSION: 5.12.0 + BOM_VERSION: 5.12.1 jobs: release: diff --git a/build.gradle b/build.gradle index 6caca56..b84a51f 100644 --- a/build.gradle +++ b/build.gradle @@ -32,19 +32,20 @@ repositories { dependencyManagement { imports { - mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + getProperty('bom.version') : 'com.epam.reportportal:commons-bom:5.11.0') + mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + getProperty('bom.version') : 'com.epam.reportportal:commons-bom:5.12.1') } } dependencies { if (releaseMode) { + implementation 'com.epam.reportportal:commons-dao' implementation 'com.epam.reportportal:plugin-api' annotationProcessor 'com.epam.reportportal:plugin-api' } else { - implementation 'com.epam.reportportal:plugin-api' - annotationProcessor 'com.epam.reportportal:plugin-api' + implementation 'com.github.reportportal:commons-dao:acf1ec7' + implementation 'com.github.reportportal:plugin-api:188792e' + annotationProcessor 'com.github.reportportal:plugin-api:188792e' } - implementation 'com.saucelabs:saucerest:1.0.43' implementation 'org.hibernate:hibernate-core:5.6.15.Final' // TODO: 2.5.3+ switched to camel-case models. UI updates required diff --git a/gradle.properties b/gradle.properties index 516117e..2b0a52f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=5.11.2 +version=5.12.0 lombokVersion=1.18.34 diff --git a/src/main/java/com/epam/reportportal/saucelabs/AssetsCommand.java b/src/main/java/com/epam/reportportal/saucelabs/AssetsCommand.java index adfc452..4202dfc 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/AssetsCommand.java +++ b/src/main/java/com/epam/reportportal/saucelabs/AssetsCommand.java @@ -19,12 +19,16 @@ import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID; import com.epam.reportportal.extension.PluginCommand; +import com.epam.reportportal.rules.exception.ErrorType; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.epam.reportportal.saucelabs.client.RestClientBuilder; import com.epam.reportportal.saucelabs.model.SauceProperties; import com.epam.ta.reportportal.entity.integration.Integration; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.ErrorType; import com.fasterxml.jackson.databind.ObjectMapper; +import com.saucelabs.saucerest.MoshiSingleton; +import com.saucelabs.saucerest.model.jobs.JobAssets; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; import java.util.Map; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -40,54 +44,65 @@ @Slf4j public class AssetsCommand implements PluginCommand { - private final RestClientBuilder restClient; + private final RestClientBuilder restClient; - public AssetsCommand(RestClientBuilder restClient) { - this.restClient = restClient; - } - @SneakyThrows + public AssetsCommand(RestClientBuilder restClient) { + this.restClient = restClient; + } + + @SneakyThrows @Override - public Object executeCommand(Integration integration, Map params) { - ValidationUtils.validateParams(params); - ValidationUtils.validateIntegrationParams(integration.getParams()); + public Object executeCommand(Integration integration, Map params) { + ValidationUtils.validateParams(params); + ValidationUtils.validateIntegrationParams(integration.getParams()); SauceProperties sp = new SauceProperties(integration.getParams().getParams()); sp.setJobId((String) params.get(JOB_ID)); RestTemplate restTemplate = restClient.buildRestTemplate(sp); try { - String url = "/rest/v1/" + sp.getUsername() + "/jobs/" + sp.getJobId() + "/assets"; + String url = "/rest/v1/" + sp.getUsername() + "/jobs/" + sp.getJobId() + "/assets"; String jobAssets = restTemplate.getForObject(url, String.class); - JSONObject response = new JSONObject(jobAssets); + + JSONObject response = new JSONObject(jobAssets); response.put("assetsPrefix", sp.getDatacenter().apiServer + "rest/v1/" + sp.getUsername() + "/jobs/" + sp.getJobId() + "/assets"); - return new ObjectMapper().readValue(response.toString(), Object.class); + return new ObjectMapper().readValue(response.toString(), Object.class); } catch (HttpClientErrorException httpException) { if (httpException.getStatusCode().is4xxClientError()) { // TODO: handle RD endpoint in a separate plugin command. UI updates required - //String url = sp.getDatacenter().apiServer + "v1/rdc/jobs/" + sp.getJobId(); + //String url = sp.getDatacenter().apiServer + "v1/rdc/jobs/" + sp.getJobId(); //DeviceJob deviceJob = restTemplate.getForObject(url, DeviceJob.class); - JSONObject response = new JSONObject(); + JSONObject response = new JSONObject(); response.put("assetsPrefix", - String.format("%sv1/rdc/jobs/%s/", sp.getDatacenter().apiServer, sp.getJobId())); - response.put("screenshots", new JSONArray()); - response.put("sauce-log", - String.format("%sv1/rdc/jobs/%s/deviceLogs", sp.getDatacenter().apiServer, + String.format("%sv1/rdc/jobs/%s/", sp.getDatacenter().apiServer, sp.getJobId())); + response.put("screenshots", new JSONArray()); + response.put("sauce-log", + String.format("%sv1/rdc/jobs/%s/deviceLogs", sp.getDatacenter().apiServer, sp.getJobId())); return new ObjectMapper().readValue(response.toString(), Object.class); - } else { - throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, StringUtils.normalizeSpace("Failed to retrieve job assets")); + } else { + throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + StringUtils.normalizeSpace("Failed to retrieve job assets")); } - } - } + } + } + + @Override + public String getName() { + return "assets"; + } + + + public String toJson(JobAssets jobAssets) { + Moshi moshi = MoshiSingleton.getInstance(); - @Override - public String getName() { - return "assets"; - } + JsonAdapter jsonAdapter = moshi.adapter(JobAssets.class).nonNull(); + return jsonAdapter.toJson(jobAssets); + } } diff --git a/src/main/java/com/epam/reportportal/saucelabs/GenerateAuthTokenCommand.java b/src/main/java/com/epam/reportportal/saucelabs/GenerateAuthTokenCommand.java index a4989b6..998c6bf 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/GenerateAuthTokenCommand.java +++ b/src/main/java/com/epam/reportportal/saucelabs/GenerateAuthTokenCommand.java @@ -7,8 +7,8 @@ import static com.epam.reportportal.saucelabs.ValidationUtils.validateParams; import com.epam.reportportal.extension.PluginCommand; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.epam.ta.reportportal.entity.integration.Integration; -import com.epam.ta.reportportal.exception.ReportPortalException; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; @@ -22,38 +22,36 @@ */ public class GenerateAuthTokenCommand implements PluginCommand { - private final BasicTextEncryptor textEncryptor; + private final BasicTextEncryptor textEncryptor; - public GenerateAuthTokenCommand(BasicTextEncryptor textEncryptor) { - this.textEncryptor = textEncryptor; - } + public GenerateAuthTokenCommand(BasicTextEncryptor textEncryptor) { + this.textEncryptor = textEncryptor; + } - @Override - public Object executeCommand(Integration integration, Map params) { - try { - validateParams(params); + @Override + public Object executeCommand(Integration integration, Map params) { + try { + validateParams(params); validateIntegrationParams(integration.getParams()); - String username = USERNAME.getParam(integration.getParams()) - ; - String accessToken = textEncryptor.decrypt(ACCESS_TOKEN.getParam(integration.getParams()) - - ); - - SecretKeySpec keySpec = new SecretKeySpec((username + ":" + accessToken).getBytes(StandardCharsets.UTF_8), "HmacMD5"); - Mac mac = Mac.getInstance("HmacMD5"); - mac.init(keySpec); - return Collections.singletonMap( - "token", - Hex.encodeHexString(mac.doFinal(params.get(JOB_ID).toString().getBytes(StandardCharsets.UTF_8))) - ); - } catch (Exception e) { - throw new ReportPortalException(e.getMessage()); - } - } - - @Override - public String getName() { - return "token"; - } + String username = USERNAME.getParam(integration.getParams()); + String accessToken = textEncryptor.decrypt(ACCESS_TOKEN.getParam(integration.getParams())); + + SecretKeySpec keySpec = + new SecretKeySpec((username + ":" + accessToken).getBytes(StandardCharsets.UTF_8), + "HmacMD5" + ); + Mac mac = Mac.getInstance("HmacMD5"); + mac.init(keySpec); + return Collections.singletonMap("token", Hex.encodeHexString( + mac.doFinal(params.get(JOB_ID).toString().getBytes(StandardCharsets.UTF_8)))); + } catch (Exception e) { + throw new ReportPortalException(e.getMessage()); + } + } + + @Override + public String getName() { + return "token"; + } } diff --git a/src/main/java/com/epam/reportportal/saucelabs/GetLogsCommand.java b/src/main/java/com/epam/reportportal/saucelabs/GetLogsCommand.java index 71f9b6f..d1f89c4 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/GetLogsCommand.java +++ b/src/main/java/com/epam/reportportal/saucelabs/GetLogsCommand.java @@ -19,11 +19,11 @@ import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID; import com.epam.reportportal.extension.PluginCommand; +import com.epam.reportportal.rules.exception.ErrorType; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.epam.reportportal.saucelabs.client.RestClientBuilder; import com.epam.reportportal.saucelabs.model.SauceProperties; import com.epam.ta.reportportal.entity.integration.Integration; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.ErrorType; import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -46,15 +46,19 @@ public GetLogsCommand(RestClientBuilder restClient) { public Object executeCommand(Integration integration, Map params) { ValidationUtils.validateParams(params); ValidationUtils.validateIntegrationParams(integration.getParams()); + SauceProperties sp = new SauceProperties(integration.getParams().getParams()); sp.setJobId((String) params.get(JOB_ID)); + return getWebDriverLogs(restClient.buildRestTemplate(sp), sp); } + private Object getWebDriverLogs(RestTemplate restTemplate, SauceProperties sp) { try { String url = getJobAssetsUrl(sp) + "/log.json"; return restTemplate.getForObject(url, Object.class); + } catch (HttpClientErrorException httpException) { if (httpException.getStatusCode().is4xxClientError()) { @@ -67,6 +71,7 @@ private Object getWebDriverLogs(RestTemplate restTemplate, SauceProperties sp) { } } + // TODO: handle RD endpoint in a separate plugin command. UI updates required private Object getRealDeviceLogs(RestTemplate restTemplate, SauceProperties sp) { String url = "/v1/rdc/jobs/" + sp.getJobId() + "/deviceLogs"; @@ -87,4 +92,5 @@ private String getJobAssetsUrl(SauceProperties sp) { .append("/assets") .toString(); } + } diff --git a/src/main/java/com/epam/reportportal/saucelabs/JobInfoCommand.java b/src/main/java/com/epam/reportportal/saucelabs/JobInfoCommand.java index 677363f..0175e8a 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/JobInfoCommand.java +++ b/src/main/java/com/epam/reportportal/saucelabs/JobInfoCommand.java @@ -21,10 +21,10 @@ import static com.epam.reportportal.saucelabs.utils.OldDatacenterResolver.resolveDatacenterDeprecatedName; import com.epam.reportportal.extension.PluginCommand; +import com.epam.reportportal.rules.exception.ErrorType; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.epam.reportportal.saucelabs.utils.JsonUtils; import com.epam.ta.reportportal.entity.integration.Integration; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.ErrorType; import com.fasterxml.jackson.databind.ObjectMapper; import com.saucelabs.saucerest.SauceException; import com.saucelabs.saucerest.SauceREST; @@ -41,47 +41,49 @@ @Slf4j public class JobInfoCommand implements PluginCommand { - private final SauceRestClient sauceRestClient; + private final SauceRestClient sauceRestClient; - public JobInfoCommand(SauceRestClient sauceRestClient) { - this.sauceRestClient = sauceRestClient; - } + public JobInfoCommand(SauceRestClient sauceRestClient) { + this.sauceRestClient = sauceRestClient; + } + + @Override + public Object executeCommand(Integration integration, Map params) { + ValidationUtils.validateParams(params); + String datacenter = (String) params.get(DATA_CENTER.getName()); - @Override - public Object executeCommand(Integration integration, Map params) { - ValidationUtils.validateParams(params); - String datacenter = (String) params.get(DATA_CENTER.getName()); - SauceREST sauce = + SauceREST sauce = sauceRestClient.buildSauceClient(integration, resolveDatacenterDeprecatedName(datacenter)); - String jobId = (String) params.get(JOB_ID); - try { - return findJobById(sauce,jobId); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - StringUtils.normalizeSpace(e.getMessage())); + String jobId = (String) params.get(JOB_ID); + + try { + return findJobById(sauce, jobId); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + StringUtils.normalizeSpace(e.getMessage())); } } private Object findJobById(SauceREST sauce, String jobId) - throws IOException { + throws IOException { Object response; try { - // find job if exists - Job jobInfo = sauce.getJobsEndpoint().getJobDetails(jobId); + // find job if exists + Job jobInfo = sauce.getJobsEndpoint().getJobDetails(jobId); response = new ObjectMapper().readValue(jobInfo.toJson(), Object.class); - } catch (SauceException jobException) { + } catch (SauceException jobException) { // If job not exists find real device job // TODO: introduce separate plugin command. UI updates required DeviceJob dj = sauce.getRealDevicesEndpoint().getSpecificDeviceJob(jobId); JsonUtils.toJson(dj, DeviceJob.class); - response = new ObjectMapper() + response = new ObjectMapper() .readValue(JsonUtils.toJson(dj, DeviceJob.class), Object.class); } - return response; - } + return response; + } - @Override - public String getName() { - return "jobInfo"; - } + @Override + public String getName() { + return "jobInfo"; + } } diff --git a/src/main/java/com/epam/reportportal/saucelabs/SauceRestClient.java b/src/main/java/com/epam/reportportal/saucelabs/SauceRestClient.java index 23eb652..f9784c7 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/SauceRestClient.java +++ b/src/main/java/com/epam/reportportal/saucelabs/SauceRestClient.java @@ -20,12 +20,13 @@ import static com.epam.reportportal.saucelabs.SaucelabsProperties.USERNAME; import static java.util.Optional.ofNullable; +import com.epam.reportportal.rules.exception.ErrorType; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.integration.IntegrationParams; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.ErrorType; import com.saucelabs.saucerest.DataCenter; import com.saucelabs.saucerest.SauceREST; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jasypt.util.text.BasicTextEncryptor; @@ -36,27 +37,39 @@ @Slf4j public class SauceRestClient { - private final BasicTextEncryptor textEncryptor; + private final BasicTextEncryptor textEncryptor; - public SauceRestClient(BasicTextEncryptor textEncryptor) { - this.textEncryptor = textEncryptor; - } + public SauceRestClient(BasicTextEncryptor textEncryptor) { + this.textEncryptor = textEncryptor; + } - public SauceREST buildSauceClient(Integration system, DataCenter dataCenter) { - IntegrationParams params = ofNullable(system.getParams()).orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "Integration params are not specified." - )); + public SauceREST buildSauceClient(Integration system, DataCenter dataCenter) { + IntegrationParams params = ofNullable(system.getParams()) + .orElseThrow( + () -> new ReportPortalException( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Integration params are not specified." + )); - String username = USERNAME.getParam(params); - String accessToken = textEncryptor.decrypt(ACCESS_TOKEN.getParam(params)); + String username = Optional.ofNullable(USERNAME.getParam(params)) + .orElseThrow( + () -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Username is not specified." + )); + String accessToken = Optional.ofNullable(textEncryptor.decrypt(ACCESS_TOKEN.getParam(params))) + .orElseThrow( + () -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Access token is not specified." + )); - SauceREST sauceREST = new SauceREST(username, accessToken, dataCenter); + SauceREST sauceREST = new SauceREST(username, accessToken, dataCenter); - if (StringUtils.isEmpty(sauceREST.getUsername())) { - throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "Incorrect Username or Access token"); - } + if (StringUtils.isEmpty(sauceREST.getUsername())) { + throw new ReportPortalException( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "Incorrect Username or Access token"); + } - return sauceREST; - } + return sauceREST; + } } diff --git a/src/main/java/com/epam/reportportal/saucelabs/ValidationUtils.java b/src/main/java/com/epam/reportportal/saucelabs/ValidationUtils.java index 426b275..278e834 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/ValidationUtils.java +++ b/src/main/java/com/epam/reportportal/saucelabs/ValidationUtils.java @@ -16,15 +16,15 @@ package com.epam.reportportal.saucelabs; +import static com.epam.reportportal.rules.commons.validation.BusinessRule.expect; import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID; import static com.epam.reportportal.saucelabs.SaucelabsProperties.ACCESS_TOKEN; import static com.epam.reportportal.saucelabs.SaucelabsProperties.DATA_CENTER; import static com.epam.reportportal.saucelabs.SaucelabsProperties.USERNAME; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import com.epam.reportportal.rules.exception.ErrorType; import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.entity.integration.IntegrationParams; -import com.epam.ta.reportportal.ws.model.ErrorType; import java.util.Map; /** @@ -32,11 +32,12 @@ */ public class ValidationUtils { - public static final String IS_NOT_SPECIFIED = " is not specified.";public static void validateParams(Map params) { - expect(params.get(JOB_ID), Predicates.notNull()).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - JOB_ID + " parameter should be provided" - ); - } + public static final String IS_NOT_SPECIFIED = " is not specified."; + + public static void validateParams(Map params) { + expect(params.get(JOB_ID), Predicates.notNull()).verify( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, JOB_ID + " parameter should be provided"); + } public static void validateIntegrationParams(IntegrationParams integrationParams) { diff --git a/src/main/java/com/epam/reportportal/saucelabs/utils/OldDatacenterResolver.java b/src/main/java/com/epam/reportportal/saucelabs/utils/OldDatacenterResolver.java index 0725e72..861d410 100644 --- a/src/main/java/com/epam/reportportal/saucelabs/utils/OldDatacenterResolver.java +++ b/src/main/java/com/epam/reportportal/saucelabs/utils/OldDatacenterResolver.java @@ -16,9 +16,8 @@ package com.epam.reportportal.saucelabs.utils; - -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.reportportal.rules.exception.ErrorType; +import com.epam.reportportal.rules.exception.ReportPortalException; import com.saucelabs.saucerest.DataCenter; /**