Skip to content

Commit

Permalink
Epmrpp-93787 jpmc fix 24.1 (#29)
Browse files Browse the repository at this point in the history
* EPMRPP-93787 Update saucelabs client (#27)
  • Loading branch information
grabsefx authored Aug 20, 2024
1 parent 261f086 commit aec8737
Show file tree
Hide file tree
Showing 16 changed files with 434 additions and 172 deletions.
26 changes: 23 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ dependencies {
annotationProcessor 'com.epam.reportportal:plugin-api'
}
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
implementation 'com.saucelabs:saucerest:2.5.1'
implementation 'dev.failsafe:failsafe:3.3.2'
implementation 'org.awaitility:awaitility:4.2.2'
implementation 'org.hamcrest:hamcrest-core:2.2'
runtimeOnly 'com.squareup.moshi:moshi:1.15.1'

// add lombok support
compileOnly "org.projectlombok:lombok:${lombokVersion}"
annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"

}

generatePomFileForShadowPublication { pom.packaging = "jar" }
Expand All @@ -66,8 +81,13 @@ shadowJar {
archiveClassifier.set(null)
zip64 true
dependencies {
include(dependency('com.saucelabs:saucerest:1.0.43'))
include(dependency('org.json:json:20171018'))
include(dependency('com.saucelabs:saucerest:2.5.1'))
include(dependency('org.json:json:20240303'))
include(dependency('org.awaitility:awaitility:4.2.2'))
include(dependency('org.hamcrest:hamcrest:2.2'))
include(dependency('com.squareup.moshi:moshi:1.15.1'))
include(dependency('net.jodah:failsafe:2.4.4'))

}
}

Expand All @@ -93,4 +113,4 @@ task assemblePlugins(type: Copy) {

wrapper {
gradleVersion = '6.0'
}
}
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
version=5.11.1
version=5.11.1
lombokVersion=1.18.34
75 changes: 49 additions & 26 deletions src/main/java/com/epam/reportportal/saucelabs/AssetsCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,73 @@

package com.epam.reportportal.saucelabs;

import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID;

import com.epam.reportportal.extension.PluginCommand;
import com.epam.ta.reportportal.commons.validation.Suppliers;
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.SauceREST;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Map;

import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID;
import static com.epam.reportportal.saucelabs.SaucelabsProperties.DATA_CENTER;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

/**
* @author <a href="mailto:[email protected]">Pavel Bortnik</a>
*/
@Slf4j
public class AssetsCommand implements PluginCommand<Object> {

private final RestClient restClient;
private final RestClientBuilder restClient;

public AssetsCommand(RestClient restClient) {
public AssetsCommand(RestClientBuilder restClient) {
this.restClient = restClient;
}

@Override
@SneakyThrows
@Override
public Object executeCommand(Integration integration, Map<String, Object> params) {
ValidationUtils.validateParams(params);
SauceREST sauce = restClient.buildSauceClient(integration, (String) params.get(DATA_CENTER.getName()));
String jobId = (String) params.get(JOB_ID);
String assetsPrefix = sauce.getAppServer() + "rest/v1/" + sauce.getUsername() + "/jobs/" + jobId + "/assets/";
try {
String content = sauce.retrieveResults(sauce.getUsername() + "/jobs/" + jobId + "/assets");
if (StringUtils.isEmpty(content)) {
throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION,
Suppliers.formattedSupplier("Job '{}' not found.", jobId)
);
}
Map<String, String> result = new ObjectMapper().readValue(content, Map.class);
result.put("assetsPrefix", assetsPrefix);
return result;
} catch (IOException e) {
throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, e.getMessage());
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 jobAssets = restTemplate.getForObject(url, String.class);
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);

} 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();
//DeviceJob deviceJob = restTemplate.getForObject(url, DeviceJob.class);

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,
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"));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package com.epam.reportportal.saucelabs;

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.USERNAME;
import static com.epam.reportportal.saucelabs.ValidationUtils.validateIntegrationParams;
import static com.epam.reportportal.saucelabs.ValidationUtils.validateParams;

import com.epam.reportportal.extension.PluginCommand;
import com.epam.ta.reportportal.entity.integration.Integration;
import com.epam.ta.reportportal.exception.ReportPortalException;
import com.epam.ta.reportportal.ws.model.ErrorType;
import org.apache.commons.codec.binary.Hex;
import org.jasypt.util.text.BasicTextEncryptor;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;

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.USERNAME;
import static com.epam.reportportal.saucelabs.ValidationUtils.validateParams;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.jasypt.util.text.BasicTextEncryptor;

/**
* @author <a href="mailto:[email protected]">Pavel Bortnik</a>
Expand All @@ -33,13 +32,13 @@ public GenerateAuthTokenCommand(BasicTextEncryptor textEncryptor) {
public Object executeCommand(Integration integration, Map params) {
try {
validateParams(params);
validateIntegrationParams(integration.getParams());

String username = USERNAME.getParam(integration.getParams())
.orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "Username is not specified."));
;
String accessToken = textEncryptor.decrypt(ACCESS_TOKEN.getParam(integration.getParams())
.orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION,
"Access token is not specified."
)));

);

SecretKeySpec keySpec = new SecretKeySpec((username + ":" + accessToken).getBytes(StandardCharsets.UTF_8), "HmacMD5");
Mac mac = Mac.getInstance("HmacMD5");
Expand Down
91 changes: 57 additions & 34 deletions src/main/java/com/epam/reportportal/saucelabs/GetLogsCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,75 @@

package com.epam.reportportal.saucelabs;

import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID;

import com.epam.reportportal.extension.PluginCommand;
import com.epam.ta.reportportal.commons.validation.Suppliers;
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.SauceREST;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Map;

import static com.epam.reportportal.saucelabs.SaucelabsExtension.JOB_ID;
import static com.epam.reportportal.saucelabs.SaucelabsProperties.DATA_CENTER;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

/**
* @author <a href="mailto:[email protected]">Pavel Bortnik</a>
*/
@Slf4j
public class GetLogsCommand implements PluginCommand<Object> {

private final RestClient restClient;
private final RestClientBuilder restClient;

public GetLogsCommand(RestClientBuilder restClient) {
this.restClient = restClient;
}

@Override
public Object executeCommand(Integration integration, Map<String, Object> 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()) {
return getRealDeviceLogs(restTemplate, sp);

} else {
throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION,
StringUtils.normalizeSpace("Failed to retrieve job assets"));
}
}
}

public GetLogsCommand(RestClient restClient) {
this.restClient = restClient;
}
// 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";
return restTemplate.getForObject(url, Object.class);
}

@Override
public Object executeCommand(Integration system, Map<String, Object> params) {
ValidationUtils.validateParams(params);
SauceREST sauce = restClient.buildSauceClient(system, (String) params.get(DATA_CENTER.getName()));
try {
String jobId = (String) params.get(JOB_ID);
String content = sauce.retrieveResults(sauce.getUsername() + "/jobs/" + jobId + "/assets/log.json");
if (StringUtils.isEmpty(content)) {
throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION,
Suppliers.formattedSupplier("Job '{}' not found.", jobId)
);
}
return new ObjectMapper().readValue(content, Object.class);
} catch (IOException e) {
throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, e.getMessage());
}
}
@Override
public String getName() {
return "logs";
}

@Override
public String getName() {
return "logs";
}
private String getJobAssetsUrl(SauceProperties sp) {
return new StringBuilder()
.append("/rest/v1/")
.append(sp.getUsername())
.append("/jobs/")
.append(sp.getJobId())
.append("/assets")
.toString();
}
}
Loading

0 comments on commit aec8737

Please sign in to comment.