diff --git a/pom.xml b/pom.xml index 3c305b1..72f61e5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.browserstack automate-client-java automate-client - 0.5 + 0.6 jar Java bindings for BrowserStack Automate REST API https://www.browserstack.com @@ -111,16 +111,12 @@ + + com.google.http-client - google-http-client - 1.21.0 - - - org.apache.httpcomponents - httpclient - - + google-http-client-apache-v2 + 1.38.0 diff --git a/src/main/java/com/browserstack/client/BrowserStackClient.java b/src/main/java/com/browserstack/client/BrowserStackClient.java index 46feed8..1da8817 100644 --- a/src/main/java/com/browserstack/client/BrowserStackClient.java +++ b/src/main/java/com/browserstack/client/BrowserStackClient.java @@ -15,15 +15,22 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.api.client.http.BasicAuthentication; import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpHeaders; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.http.apache.v2.ApacheHttpTransport; import com.google.api.client.util.ObjectParser; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; import javax.annotation.Nonnull; import java.io.IOException; @@ -37,536 +44,555 @@ import java.util.Map; public abstract class BrowserStackClient implements BrowserStackClientInterface { - private static final String BASE_URL = "https://www.browserstack.com"; - private static final String CACHE_KEY_PREFIX_BROWSERS = "browsers"; + private static final String BASE_URL = "https://www.browserstack.com"; + private static final String CACHE_KEY_PREFIX_BROWSERS = "browsers"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + private static final ObjectParser OBJECT_PARSER = new ObjectParser() { + public T parseAndClose(InputStream inputStream, Charset charset, Class aClass) + throws IOException { + return JSON_MAPPER.readValue(inputStream, aClass); + } - private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); - private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + public T parseAndClose(Reader reader, Class aClass) throws IOException { + return JSON_MAPPER.readValue(reader, aClass); + } - private static final ObjectParser OBJECT_PARSER = new ObjectParser() { - public T parseAndClose(InputStream inputStream, Charset charset, Class aClass) - throws IOException { - return JSON_MAPPER.readValue(inputStream, aClass); - } + public Object parseAndClose(InputStream inputStream, Charset charset, Type type) + throws IOException { + throw new IOException("Unsupported operation"); + } + + public Object parseAndClose(Reader reader, Type type) throws IOException { + throw new IOException("Unsupported operation"); + } + }; + private static HttpTransport HTTP_TRANSPORT = new ApacheHttpTransport(); + protected final BrowserStackCache cacheMap; + + private HttpRequestFactory requestFactory; + + private String baseUrl; - public T parseAndClose(Reader reader, Class aClass) throws IOException { - return JSON_MAPPER.readValue(reader, aClass); + private String username; + + private String accessKey; + + protected BrowserStackClient() { + this.cacheMap = new BrowserStackCache(); + this.requestFactory = newRequestFactory(); } - public Object parseAndClose(InputStream inputStream, Charset charset, Type type) - throws IOException { - throw new IOException("Unsupported operation"); + public BrowserStackClient(String baseUrl, String username, String accessKey) { + this(); + + if (baseUrl == null) { + throw new IllegalArgumentException("Invalid baseUrl"); + } + + if (username == null || username.trim().length() == 0) { + throw new IllegalArgumentException("Invalid username"); + } + + if (accessKey == null || accessKey.trim().length() == 0) { + throw new IllegalArgumentException("Invalid access key"); + } + + this.baseUrl = baseUrl; + this.username = username.trim(); + this.accessKey = accessKey.trim(); } - public Object parseAndClose(Reader reader, Type type) throws IOException { - throw new IOException("Unsupported operation"); + static HttpRequestFactory newRequestFactory() { + return HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() { + @Override + public void initialize(HttpRequest httpRequest) throws IOException { + httpRequest.setParser(OBJECT_PARSER); + } + }); } - }; - protected final BrowserStackCache cacheMap; + static HttpRequest newRequest(final HttpRequestFactory requestFactory, final Method method, final GenericUrl url) throws BrowserStackException { + if (method == null) { + throw new IllegalArgumentException("Invalid method"); + } + + final HttpRequest request; + + try { + switch (method) { + case GET: + request = requestFactory.buildGetRequest(url); + break; - private final HttpRequestFactory requestFactory; + case POST: + request = requestFactory.buildPostRequest(url, null); + break; - private String baseUrl; + case PUT: + request = requestFactory.buildPutRequest(url, null); + break; - private String username; + case DELETE: + request = requestFactory.buildDeleteRequest(url); + break; - private String accessKey; + default: + throw new IllegalArgumentException("Invalid method"); + } + } catch (IOException e) { + throw new BrowserStackException(e); + } + + return request; + } - private BasicAuthentication authentication; + /** + * Sets proxy configuration for requests + * + * @param proxyHost Host of the proxy + * @param proxyPort Port of the proxy + * @param proxyUsername Username of proxy + * @param proxyPassword password of the proxy + */ - protected BrowserStackClient() { - this.cacheMap = new BrowserStackCache(); - this.requestFactory = newRequestFactory(); - } + public void setProxy(final String proxyHost, final int proxyPort, final String proxyUsername, final String proxyPassword) { - public BrowserStackClient(String baseUrl, String username, String accessKey) { - this(); + if (proxyHost == null || proxyUsername == null || proxyPassword == null) { + return; + } - if (baseUrl == null) { - throw new IllegalArgumentException("Invalid baseUrl"); + final BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider(); + final AuthScope proxyAuthScope = new AuthScope(proxyHost, proxyPort); + UsernamePasswordCredentials proxyAuthentication = + new UsernamePasswordCredentials(proxyUsername, proxyPassword); + basicCredentialsProvider.setCredentials(proxyAuthScope, proxyAuthentication); + + final HttpHost proxy = new HttpHost(proxyHost, proxyPort); + final HttpClient client = HttpClientBuilder.create().setProxy(proxy).setDefaultCredentialsProvider(basicCredentialsProvider).build(); + final ApacheHttpTransport transport = new ApacheHttpTransport(client); + this.HTTP_TRANSPORT = transport; + this.requestFactory = newRequestFactory(); } - if (username == null || username.trim().length() == 0) { - throw new IllegalArgumentException("Invalid username"); + protected String getAccessKey() { + return accessKey; } - if (accessKey == null || accessKey.trim().length() == 0) { - throw new IllegalArgumentException("Invalid access key"); + protected synchronized void setAccessKey(final String accessKey) { + this.accessKey = accessKey; } - this.baseUrl = baseUrl; - this.username = username.trim(); - this.accessKey = accessKey.trim(); - this.authentication = new BasicAuthentication(this.username, this.accessKey); - } - - protected String getAccessKey() { - return accessKey; - } - - protected synchronized void setAccessKey(final String accessKey) { - this.accessKey = accessKey; - this.authentication = new BasicAuthentication(this.username, this.accessKey); - } - - static HttpRequestFactory newRequestFactory() { - return HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() { - public void initialize(HttpRequest httpRequest) throws IOException { - httpRequest.setParser(OBJECT_PARSER); - } - }); - } - - static HttpRequest newRequest(final HttpRequestFactory requestFactory, final Method method, - final GenericUrl url) throws BrowserStackException { - if (method == null) { - throw new IllegalArgumentException("Invalid method"); + private void checkAuthState() { + if (this.accessKey == null && this.username == null) { + throw new IllegalStateException("Missing API credentials"); + } } - final HttpRequest request; + protected BrowserListing getBrowsersForProduct(Product product) throws BrowserStackException { + return getBrowsersForProduct(product, true); + } - try { - switch (method) { - case GET: - request = requestFactory.buildGetRequest(url); - break; + @SuppressWarnings("unchecked") + protected BrowserListing getBrowsersForProduct(Product product, boolean cache) + throws BrowserStackException { + String productName = product.name().toLowerCase(); + String cacheKey = (CACHE_KEY_PREFIX_BROWSERS + productName).toLowerCase(); + + if (cache) { + if (cacheMap.containsKey(cacheKey)) { + BrowserListing browserListing = (BrowserListing) cacheMap.get(cacheKey); + if (browserListing != null) { + return browserListing; + } + } + } - case POST: - request = requestFactory.buildPostRequest(url, null); - break; + BrowserListing browserListing; - case PUT: - request = requestFactory.buildPutRequest(url, null); - break; + try { + GenericUrl url = + new GenericUrl(BASE_URL + "/list-of-browsers-and-platforms.json?product=" + productName); + HttpResponse response = newRequest(requestFactory, Method.GET, url).execute(); + browserListing = response.parseAs(BrowserListing.class); + } catch (IOException e) { + throw new BrowserStackException(e.getMessage(), 400); + } - case DELETE: - request = requestFactory.buildDeleteRequest(url); - break; + if (cache) { + cacheMap.put(cacheKey, browserListing); + } - default: - throw new IllegalArgumentException("Invalid method"); - } - } catch (IOException e) { - throw new BrowserStackException(e); + return browserListing; } - return request; - } + protected BrowserStackRequest newRequest(final Method method, final String path) + throws BrowserStackException { + return newRequest(method, path, true); + } - private void checkAuthState() { - if (authentication == null) { - throw new IllegalStateException("Missing API credentials"); + protected BrowserStackRequest newRequest(final Method method, final String path, + final boolean prependUrl) throws BrowserStackException { + String urlPath = (path == null) ? "" : path; + GenericUrl url = new GenericUrl(prependUrl ? this.baseUrl + urlPath : urlPath); + return signRequest(newRequest(requestFactory, method, url)); } - } - - protected BrowserListing getBrowsersForProduct(Product product) throws BrowserStackException { - return getBrowsersForProduct(product, true); - } - - @SuppressWarnings("unchecked") - protected BrowserListing getBrowsersForProduct(Product product, boolean cache) - throws BrowserStackException { - String productName = product.name().toLowerCase(); - String cacheKey = (CACHE_KEY_PREFIX_BROWSERS + productName).toLowerCase(); - - if (cache) { - if (cacheMap.containsKey(cacheKey)) { - BrowserListing browserListing = (BrowserListing) cacheMap.get(cacheKey); - if (browserListing != null) { - return browserListing; - } - } + + protected BrowserStackRequest newRequest(final Method method, final String path, + final Map data) throws BrowserStackException { + return newRequest(method, path, data, null); } - BrowserListing browserListing; + protected BrowserStackRequest newRequest(final Method method, final String path, + final Map data, final Map headers) + throws BrowserStackException { + BrowserStackRequest request = newRequest(method, path); + if (headers != null && headers.size() > 0) { + request.headers(headers); + } - try { - GenericUrl url = - new GenericUrl(BASE_URL + "/list-of-browsers-and-platforms.json?product=" + productName); - HttpResponse response = newRequest(requestFactory, Method.GET, url).execute(); - browserListing = response.parseAs(BrowserListing.class); - } catch (IOException e) { - throw new BrowserStackException(e.getMessage(), 400); - } + if (data != null && data.size() > 0 && request.canContainBody()) { + try { + request.header("Content-Type", "application/json") + .body(JSON_MAPPER.writeValueAsString(data)); + } catch (JsonProcessingException e) { + throw new BrowserStackException(e); + } + } - if (cache) { - cacheMap.put(cacheKey, browserListing); + return request; } - return browserListing; - } - - protected BrowserStackRequest newRequest(final Method method, final String path) - throws BrowserStackException { - return newRequest(method, path, true); - } - - protected BrowserStackRequest newRequest(final Method method, final String path, - final boolean prependUrl) throws BrowserStackException { - String urlPath = (path == null) ? "" : path; - GenericUrl url = new GenericUrl(prependUrl ? this.baseUrl + urlPath : urlPath); - return signRequest(newRequest(requestFactory, method, url)); - } - - protected BrowserStackRequest newRequest(final Method method, final String path, - final Map data) throws BrowserStackException { - return newRequest(method, path, data, null); - } - - protected BrowserStackRequest newRequest(final Method method, final String path, - final Map data, final Map headers) - throws BrowserStackException { - BrowserStackRequest request = newRequest(method, path); - if (headers != null && headers.size() > 0) { - request.headers(headers); + protected BrowserStackRequest signRequest(final HttpRequest request) { + checkAuthState(); + final HttpHeaders header = new HttpHeaders(); + final String combined = this.username + ":" + this.accessKey; + final String encoded = new String(Base64.encodeBase64(combined.getBytes())); + final String credential = "Basic " + encoded; + header.set("Authorization", credential); + request.setHeaders(header); + return new BrowserStackRequest(request); } - if (data != null && data.size() > 0 && request.canContainBody()) { - try { - request.header("Content-Type", "application/json") - .body(JSON_MAPPER.writeValueAsString(data)); - } catch (JsonProcessingException e) { - throw new BrowserStackException(e); - } - } + /** + * Gets the list of builds. + * + *

+ * A build is an organizational structure for tests. + *

+ * + * @param status Return only builds that match the specified build status. + * @param limit Limit results to the specified count. + * @param buildName build name to be searched with. + * @return List of {@link Build} objects. + * @throws BrowserStackException + */ + public List getBuilds(final BuildStatus status, final int limit, final String buildName) + throws BrowserStackException { + BrowserStackRequest httpRequest; + try { + httpRequest = newRequest(Method.GET, "/builds.json"); + } catch (BrowserStackException e) { + throw new BrowserStackException(e); + } - return request; - } + if (limit > 0) { + httpRequest.queryString(Constants.Filter.LIMIT, limit); + } - protected BrowserStackRequest signRequest(final HttpRequest request) - throws BrowserStackException { - checkAuthState(); + if (status != null) { + httpRequest.queryString(Constants.Filter.FILTER, status.name().toLowerCase()); + } - try { - authentication.intercept(request); - } catch (IOException e) { - throw new BrowserStackException(e); - } + if (buildName != null && !buildName.isEmpty()) { + httpRequest.queryString(Constants.Filter.BUILD_NAME, buildName); + } - return new BrowserStackRequest(request); - } - - public enum Method { - GET, POST, PUT, DELETE - } - - public enum Product { - LIVE, AUTOMATE, SCREENSHOTS - } - - /** - * Gets the list of builds. - * - *

- * A build is an organizational structure for tests. - *

- * - * @param status Return only builds that match the specified build status. - * @param limit Limit results to the specified count. - * @param buildName build name to be searched with. - * @return List of {@link Build} objects. - * @throws BrowserStackException - */ - public List getBuilds(final BuildStatus status, final int limit, final String buildName) - throws BrowserStackException { - BrowserStackRequest httpRequest; - try { - httpRequest = newRequest(Method.GET, "/builds.json"); - } catch (BrowserStackException e) { - throw new BrowserStackException(e); - } + final List buildNodes; + try { + buildNodes = Arrays.asList(httpRequest.asObject(BuildNode[].class)); + } catch (BrowserStackException e) { + throw e; + } + + final List builds = new ArrayList(); + for (BuildNode buildNode : buildNodes) { + if (buildNode != null && buildNode.getBuild() != null) { + builds.add(buildNode.getBuild().setClient(this)); + } + } - if (limit > 0) { - httpRequest.queryString(Constants.Filter.LIMIT, limit); + return builds; } - if (status != null) { - httpRequest.queryString(Constants.Filter.FILTER, status.name().toLowerCase()); + /** + * Gets the list of builds via build status and the count required + * + *

+ * A build is an organizational structure for tests. + *

+ * + * @param status Return only builds that match the specified build status. + * @param limit Limit results to the specified count. + * @return List of {@link Build} objects. + * @throws BrowserStackException + */ + public List getBuilds(final BuildStatus status, final int limit) + throws BrowserStackException { + return getBuilds(status, limit, null); } - if (buildName != null && !buildName.isEmpty()) { - httpRequest.queryString(Constants.Filter.BUILD_NAME, buildName); + /** + * Gets the list of builds. + * + *

+ * A build is an organizational structure for tests. + *

+ * + * @return List of {@link Build} objects. + * @throws BrowserStackException + */ + public List getBuilds() throws BrowserStackException { + return getBuilds(null, 0); } - final List buildNodes; - try { - buildNodes = Arrays.asList(httpRequest.asObject(BuildNode[].class)); - } catch (BrowserStackException e) { - throw e; + /** + * Gets the list of builds. + * + *

+ * A build is an organizational structure for tests. + *

+ * + * @param limit Limit results to the specified count. + * @return List of {@link Build} objects. + * @throws BrowserStackException + */ + public List getBuilds(final int limit) throws BrowserStackException { + return getBuilds(null, limit); } - final List builds = new ArrayList(); - for (BuildNode buildNode : buildNodes) { - if (buildNode != null && buildNode.getBuild() != null) { - builds.add(buildNode.getBuild().setClient(this)); - } + /** + * Gets the list of builds. + * + *

+ * A build is an organizational structure for tests. + *

+ * + * @param status Include only builds that match the specified build status. + * @return List of {@link Build} objects. + * @throws BrowserStackException + */ + public List getBuilds(final BuildStatus status) throws BrowserStackException { + return getBuilds(status, 0); } - return builds; - } - - /** - * Gets the list of builds via build status and the count required - * - *

- * A build is an organizational structure for tests. - *

- * - * @param status Return only builds that match the specified build status. - * @param limit Limit results to the specified count. - * @return List of {@link Build} objects. - * @throws BrowserStackException - */ - public List getBuilds(final BuildStatus status, final int limit) - throws BrowserStackException { - return getBuilds(status, limit, null); - } - - /** - * Gets the list of builds. - * - *

- * A build is an organizational structure for tests. - *

- * - * @return List of {@link Build} objects. - * @throws BrowserStackException - */ - public List getBuilds() throws BrowserStackException { - return getBuilds(null, 0); - } - - /** - * Gets the list of builds. - * - *

- * A build is an organizational structure for tests. - *

- * - * @param limit Limit results to the specified count. - * @return List of {@link Build} objects. - * @throws BrowserStackException - */ - public List getBuilds(final int limit) throws BrowserStackException { - return getBuilds(null, limit); - } - - /** - * Gets the list of builds. - * - *

- * A build is an organizational structure for tests. - *

- * - * @param status Include only builds that match the specified build status. - * @return List of {@link Build} objects. - * @throws BrowserStackException - */ - public List getBuilds(final BuildStatus status) throws BrowserStackException { - return getBuilds(status, 0); - } - - /** - * Gets the build identified by the build identifier. - * - * @param buildId ID that uniquely identifies a build. - * @return List of {@link Build} objects. - * @throws BuildNotFound - * @throws BrowserStackException - */ - public Build getBuild(final String buildId) throws BuildNotFound, BrowserStackException { - try { - BuildNode buildNode = newRequest(Method.GET, "/builds/{buildId}.json") - .routeParam("buildId", buildId).asObject(BuildNode.class); - - if (buildNode == null) { - throw new BuildNotFound("Build not found: " + buildId); - } - - return buildNode.getBuild().setClient(this); - } catch (BrowserStackObjectNotFound e) { - throw new BuildNotFound("Build not found: " + buildId); - } catch (BrowserStackException e) { - throw e; + /** + * Gets the build identified by the build identifier. + * + * @param buildId ID that uniquely identifies a build. + * @return List of {@link Build} objects. + * @throws BuildNotFound + * @throws BrowserStackException + */ + public Build getBuild(final String buildId) throws BuildNotFound, BrowserStackException { + try { + BuildNode buildNode = newRequest(Method.GET, "/builds/{buildId}.json") + .routeParam("buildId", buildId).asObject(BuildNode.class); + + if (buildNode == null) { + throw new BuildNotFound("Build not found: " + buildId); + } + + return buildNode.getBuild().setClient(this); + } catch (BrowserStackObjectNotFound e) { + throw new BuildNotFound("Build not found: " + buildId); + } catch (BrowserStackException e) { + throw e; + } } - } - - /** - * Gets the build identified using the build name. - * - * @param buildName Name of the build which will be used for searching - * @return {@link Build} object - * @throws BuildNotFound - * @throws BrowserStackException - */ - public Build getBuildByName(@Nonnull final String buildName) throws BuildNotFound, BrowserStackException { - try { - final List build = getBuilds(null, 1, buildName); - if (build.size() == 1) { - return build.get(0); - } - throw new BuildNotFound("Build not found by name: " + buildName); - } catch (BrowserStackException e) { - throw e; + + /** + * Gets the build identified using the build name. + * + * @param buildName Name of the build which will be used for searching + * @return {@link Build} object + * @throws BuildNotFound + * @throws BrowserStackException + */ + public Build getBuildByName(@Nonnull final String buildName) throws BuildNotFound, BrowserStackException { + try { + final List build = getBuilds(null, 1, buildName); + if (build.size() == 1) { + return build.get(0); + } + throw new BuildNotFound("Build not found by name: " + buildName); + } catch (BrowserStackException e) { + throw e; + } } - } - - /** - * Delete the build identified by the build identifier. - * - * @param buildId ID that uniquely identifies a build. - * @return true or false based on successful deletion of the build. - * @throws BrowserStackException - */ - public boolean deleteBuild(final String buildId) throws BrowserStackException { - try { - ObjectNode result = newRequest(BrowserStackClient.Method.DELETE, "/builds/{buildId}.json") - .routeParam("buildId", buildId).asJsonObject(); - - String status = (result != null) ? result.path("status").asText() : null; - return (status != null && status.equals("ok")); - } catch (BrowserStackException e) { - throw e; + + /** + * Delete the build identified by the build identifier. + * + * @param buildId ID that uniquely identifies a build. + * @return true or false based on successful deletion of the build. + * @throws BrowserStackException + */ + public boolean deleteBuild(final String buildId) throws BrowserStackException { + try { + ObjectNode result = newRequest(BrowserStackClient.Method.DELETE, "/builds/{buildId}.json") + .routeParam("buildId", buildId).asJsonObject(); + + String status = (result != null) ? result.path("status").asText() : null; + return (status != null && status.equals("ok")); + } catch (BrowserStackException e) { + throw e; + } } - } - - /** - * Retrieves the list of sessions existing under a specific build. - * If no limit is specified, all the sessions will be fetched from that build - * - * @param buildId ID that uniquely identifies a build. - * @param status Include only builds that match the specified build status. - * @param limit Limit results to the specified count. - * @return List of {@link Session} objects containing test session information. - * @throws BuildNotFound - * @throws BrowserStackException - */ - public List getSessions(final String buildId, final BuildStatus status, final int limit) - throws BuildNotFound, BrowserStackException { - - // validation of the limit field. Default will be set to 1000 if 0 is provided - final int totalLimit = - (limit <= 0 || limit > Constants.Filter.MAX_SESSIONS) - ? Constants.Filter.MAX_SESSIONS - : limit; - int totalRequests = totalLimit/Constants.Filter.MAX_LIMIT; - - // An extra request to fetch the remainder sessions - if ((totalLimit % Constants.Filter.MAX_LIMIT) > 0) { - totalRequests++; + + /** + * Retrieves the list of sessions existing under a specific build. + * If no limit is specified, all the sessions will be fetched from that build + * + * @param buildId ID that uniquely identifies a build. + * @param status Include only builds that match the specified build status. + * @param limit Limit results to the specified count. + * @return List of {@link Session} objects containing test session information. + * @throws BuildNotFound + * @throws BrowserStackException + */ + public List getSessions(final String buildId, final BuildStatus status, final int limit) + throws BuildNotFound, BrowserStackException { + + // validation of the limit field. Default will be set to 1000 if 0 is provided + final int totalLimit = + (limit <= 0 || limit > Constants.Filter.MAX_SESSIONS) + ? Constants.Filter.MAX_SESSIONS + : limit; + int totalRequests = totalLimit / Constants.Filter.MAX_LIMIT; + + // An extra request to fetch the remainder sessions + if ((totalLimit % Constants.Filter.MAX_LIMIT) > 0) { + totalRequests++; + } + + final List sessions = new ArrayList(); + + // currReq will act as offset to fetch all* sessions from the build + for (int currReq = 0; currReq < totalRequests; currReq++) { + final List sessionNodes = getSessionNodes(buildId, status, totalLimit, currReq * Constants.Filter.MAX_LIMIT); + + for (SessionNode sessionNode : sessionNodes) { + if (sessionNode != null && sessionNode.getSession() != null) { + sessions.add(sessionNode.getSession().setClient(this)); + } + } + + // break the loop since there are no more sessions left to fetch + if (sessionNodes.size() < Constants.Filter.MAX_LIMIT) { + break; + } + } + + return sessions; } - final List sessions = new ArrayList(); + private List getSessionNodes(String buildId, BuildStatus status, int totalLimit, int offset) throws BrowserStackException { + BrowserStackRequest httpRequest; + try { + httpRequest = + newRequest(Method.GET, "/builds/{buildId}/sessions.json").routeParam("buildId", buildId); + } catch (BrowserStackException e) { + throw e; + } - // currReq will act as offset to fetch all* sessions from the build - for (int currReq = 0; currReq < totalRequests; currReq++) { - final List sessionNodes = getSessionNodes(buildId, status, totalLimit, currReq * Constants.Filter.MAX_LIMIT); + httpRequest.queryString(Constants.Filter.LIMIT, totalLimit); + httpRequest.queryString(Constants.Filter.OFFSET, offset); - for (SessionNode sessionNode : sessionNodes) { - if (sessionNode != null && sessionNode.getSession() != null) { - sessions.add(sessionNode.getSession().setClient(this)); + if (status != null) { + httpRequest.queryString(Constants.Filter.FILTER, status); } - } - // break the loop since there are no more sessions left to fetch - if (sessionNodes.size() < Constants.Filter.MAX_LIMIT) { - break; - } + final List sessionNodes; + try { + sessionNodes = Arrays.asList(httpRequest.asObject(SessionNode[].class)); + } catch (BrowserStackObjectNotFound e) { + throw new BuildNotFound("Build not found: " + buildId); + } catch (BrowserStackException e) { + throw e; + } + return sessionNodes; } - return sessions; - } + /** + * Retrieves the list of sessions existing under a specific build. + * + * @param buildId ID that uniquely identifies a build. + * @return List of {@link Session} objects containing test session information. + * @throws BuildNotFound + * @throws BrowserStackException + */ + public List getSessions(final String buildId) + throws BuildNotFound, BrowserStackException { + return getSessions(buildId, null, 0); + } - private List getSessionNodes(String buildId, BuildStatus status, int totalLimit, int offset) throws BrowserStackException { - BrowserStackRequest httpRequest; - try { - httpRequest = - newRequest(Method.GET, "/builds/{buildId}/sessions.json").routeParam("buildId", buildId); - } catch (BrowserStackException e) { - throw e; + /** + * Retrieves the list of sessions existing under a specific build. + * + * @param buildId ID that uniquely identifies a build. + * @param limit Limit results to the specified count. + * @return List of {@link Session} objects containing test session information. + * @throws BuildNotFound + * @throws BrowserStackException + */ + public List getSessions(final String buildId, final int limit) + throws BuildNotFound, BrowserStackException { + return getSessions(buildId, null, limit); } - httpRequest.queryString(Constants.Filter.LIMIT, totalLimit); - httpRequest.queryString(Constants.Filter.OFFSET, offset); + /** + * Retrieves the list of sessions existing under a specific build. + * + * @param buildId ID that uniquely identifies a build. + * @param status Include only builds that match the specified build status. + * @return List of {@link Session} objects containing test session information. + * @throws BuildNotFound + * @throws BrowserStackException + */ + public List getSessions(final String buildId, final BuildStatus status) + throws BuildNotFound, BrowserStackException { + return getSessions(buildId, status, 0); + } - if (status != null) { - httpRequest.queryString(Constants.Filter.FILTER, status); + /** + * Gets the session associated with the specified identifier. + * + * @param sessionId ID that uniquely identifies a session. + * @return {@link Session} objects containing test session information. + * @throws SessionNotFound, BrowserStackException + */ + public Session getSession(String sessionId) throws SessionNotFound, BrowserStackException { + try { + SessionNode sessionNode = newRequest(Method.GET, "/sessions/{sessionId}.json") + .routeParam("sessionId", sessionId).asObject(SessionNode.class); + + if (sessionNode.getSession() == null) { + throw new SessionNotFound("Session not found: " + sessionId); + } + + return sessionNode.getSession().setClient(this); + } catch (BrowserStackObjectNotFound e) { + throw new SessionNotFound("Session not found: " + sessionId); + } catch (BrowserStackException e) { + throw e; + } } - final List sessionNodes; - try { - sessionNodes = Arrays.asList(httpRequest.asObject(SessionNode[].class)); - } catch (BrowserStackObjectNotFound e) { - throw new BuildNotFound("Build not found: " + buildId); - } catch (BrowserStackException e) { - throw e; + public enum Method { + GET, POST, PUT, DELETE } - return sessionNodes; - } - - /** - * Retrieves the list of sessions existing under a specific build. - * - * @param buildId ID that uniquely identifies a build. - * @return List of {@link Session} objects containing test session information. - * @throws BuildNotFound - * @throws BrowserStackException - */ - public List getSessions(final String buildId) - throws BuildNotFound, BrowserStackException { - return getSessions(buildId, null, 0); - } - - /** - * Retrieves the list of sessions existing under a specific build. - * - * @param buildId ID that uniquely identifies a build. - * @param limit Limit results to the specified count. - * @return List of {@link Session} objects containing test session information. - * @throws BuildNotFound - * @throws BrowserStackException - */ - public List getSessions(final String buildId, final int limit) - throws BuildNotFound, BrowserStackException { - return getSessions(buildId, null, limit); - } - - /** - * Retrieves the list of sessions existing under a specific build. - * - * @param buildId ID that uniquely identifies a build. - * @param status Include only builds that match the specified build status. - * @return List of {@link Session} objects containing test session information. - * @throws BuildNotFound - * @throws BrowserStackException - */ - public List getSessions(final String buildId, final BuildStatus status) - throws BuildNotFound, BrowserStackException { - return getSessions(buildId, status, 0); - } - - /** - * Gets the session associated with the specified identifier. - * - * @param sessionId ID that uniquely identifies a session. - * @return {@link Session} objects containing test session information. - * @throws SessionNotFound, BrowserStackException - */ - public Session getSession(String sessionId) throws SessionNotFound, BrowserStackException { - try { - SessionNode sessionNode = newRequest(Method.GET, "/sessions/{sessionId}.json") - .routeParam("sessionId", sessionId).asObject(SessionNode.class); - - if (sessionNode.getSession() == null) { - throw new SessionNotFound("Session not found: " + sessionId); - } - - return sessionNode.getSession().setClient(this); - } catch (BrowserStackObjectNotFound e) { - throw new SessionNotFound("Session not found: " + sessionId); - } catch (BrowserStackException e) { - throw e; + + public enum Product { + LIVE, AUTOMATE, SCREENSHOTS } - } } diff --git a/src/main/java/com/browserstack/client/BrowserStackClientInterface.java b/src/main/java/com/browserstack/client/BrowserStackClientInterface.java index 75534fc..412561a 100644 --- a/src/main/java/com/browserstack/client/BrowserStackClientInterface.java +++ b/src/main/java/com/browserstack/client/BrowserStackClientInterface.java @@ -37,4 +37,7 @@ List getSessions(String buildId, BuildStatus status, int limit) List getSessions(String buildId, BuildStatus status) throws BuildNotFound, BrowserStackException; + + void setProxy(String proxyHost, int proxyPort, String proxyUsername, String proxyPassword); + }