From e93f5d04f36443c1f5b74055b670553491a257d0 Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Sun, 22 Oct 2017 15:13:23 +0200 Subject: [PATCH 01/17] Batchify code coverage calculation to avoid "Request-URI Too Long" error --- .../codeCoverage/CodeCoverageComputer.java | 70 ++++++++++++------- .../codeCoverage/WebServiceInvoker.java | 7 +- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java index 8b9407d..b00f940 100644 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -72,7 +73,7 @@ public CodeCoverageComputer() { public ApexClassCodeCoverageBean[] calculateAggregatedCodeCoverageUsingToolingAPI() { PartnerConnection connection = ConnectionHandler.getConnectionHandlerInstance().getConnection(); - ApexClassCodeCoverageBean[] apexClassCodeCoverageBeans = null; + List apexClassCodeCoverageBeans = new ArrayList(); String[] classesAsArray = null; /* @@ -95,28 +96,47 @@ public ApexClassCodeCoverageBean[] calculateAggregatedCodeCoverageUsingToolingAP // Do not proceed if no class names are returned from both manifest // files and/or regexes if (classesAsArray != null && classesAsArray.length > 0) { - String classArrayAsStringForQuery = processClassArrayForQuery(classesAsArray); - String relativeServiceURL = "/services/data/v" + SUPPORTED_VERSION + "/tooling"; - // compute aggregated code coverage - String soqlcc = QueryConstructor.getAggregatedCodeCoverage(classArrayAsStringForQuery); - - JSONObject responseJsonObject = null; - responseJsonObject = WebServiceInvoker.doGet(relativeServiceURL, soqlcc, OAuthTokenGenerator.getOrgToken()); - LOG.debug("responseJsonObject says " + responseJsonObject + "\n relativeServiceURL is " + relativeServiceURL - + "\n soqlcc is " + soqlcc); - if (responseJsonObject != null) { - apexClassCodeCoverageBeans = processJSONResponseAndConstructCodeCoverageBeans(connection, - responseJsonObject); + List> listClassesAsArray = new ArrayList>(); + int N = classesAsArray.length; + List lclassesAsArray = Arrays.asList(classesAsArray); + for (int i = 0; i < N; i += 100) { + listClassesAsArray.add(lclassesAsArray.subList(i, Math.min(N, i + 100))); } - if (apexClassCodeCoverageBeans == null) { - ApexUnitUtils.shutDownWithErrMsg( - "Code coverage metrics not computed. Null object returned while processing the JSON response from the Tooling API"); + int T = listClassesAsArray.size(); + JSONObject[] responseJsonObjects = new JSONObject[T]; + for(int j=0;j lf = new ArrayList(); + for(int w=0;w < (listClassesAsArray.get(j)).size();w++){ + lf.add((listClassesAsArray.get(j)).get(w)); + } + String[] toProcess = new String[lf.size()];LOG.info(" ### LF = "+lf.toArray(toProcess)); + String classArrayAsStringForQuery = processClassArrayForQuery(lf.toArray(toProcess)); + String relativeServiceURL = "/services/data/v" + SUPPORTED_VERSION + "/tooling"; + // compute aggregated code coverage + String soqlcc = QueryConstructor.getAggregatedCodeCoverage(classArrayAsStringForQuery); + responseJsonObjects[j] = WebServiceInvoker.doGet(relativeServiceURL, soqlcc, OAuthTokenGenerator.getOrgToken()); + LOG.info("responseJsonObject says " + responseJsonObjects[j] + "\n relativeServiceURL is " + relativeServiceURL + + "\n soqlcc is " + soqlcc); + + if (responseJsonObjects[j] != null) { + ApexClassCodeCoverageBean[] results = processJSONResponseAndConstructCodeCoverageBeans(connection, responseJsonObjects[j]);LOG.info("### results = "+results); + if(results != null && results.length > 0){ + for(ApexClassCodeCoverageBean result:results){ + apexClassCodeCoverageBeans.add(result); + } + } + } + if (apexClassCodeCoverageBeans == null) { + ApexUnitUtils.shutDownWithErrMsg( + "Code coverage metrics not computed. Null object returned while processing the JSON response from the Tooling API"); + } } } else { ApexUnitUtils.shutDownWithErrMsg("No/Invalid Apex source classes mentioned in manifest file and/or " + "regex pattern for ApexSourceClassPrefix didn't return any Apex source class names from the org"); } - return apexClassCodeCoverageBeans; + int M = apexClassCodeCoverageBeans.size(); + return (ApexClassCodeCoverageBean[]) apexClassCodeCoverageBeans.toArray(new ApexClassCodeCoverageBean[M]); } /* @@ -305,16 +325,18 @@ public int getOrgWideCodeCoverage() { if (responseJsonObject != null) { String responseStr = responseJsonObject.toJSONString(); - LOG.debug("responseStr during org wide code coverage" + responseStr); + LOG.info("responseStr during org wide code coverage" + responseStr); JSONArray recordObject = (JSONArray) responseJsonObject.get("records"); - for (int i = 0; i < recordObject.size(); ++i) { + if(recordObject != null && recordObject.size() > 0) { + for (int i = 0; i < recordObject.size(); ++i) { - JSONObject rec = (JSONObject) recordObject.get(i); + JSONObject rec = (JSONObject) recordObject.get(i); - coverage = Integer.valueOf((String) rec.get("PercentCovered").toString()); - LOG.info( - "#################################### Org wide code coverage result #################################### "); - LOG.info("Org wide code coverage : " + coverage + "%"); + coverage = Integer.valueOf((String) rec.get("PercentCovered").toString()); + LOG.info( + "#################################### Org wide code coverage result #################################### "); + LOG.info("Org wide code coverage : " + coverage + "%"); + } } } else { ApexUnitUtils.shutDownWithErrMsg("Org wide code coverage not computed"); diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java index 225e085..fdacc8f 100644 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java @@ -32,6 +32,8 @@ import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.json.simple.JSONObject; +import org.json.simple.JSONArray; +import com.google.gson.Gson; import org.json.simple.JSONValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -152,8 +154,9 @@ public static JSONObject doGet(String relativeServiceURL, String accessToken) { try { instream = executeHTTPMethod(httpclient, get, authorizationServerURL); LOG.debug("done with get operation"); - - JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(instream)); + Object jarr = JSONValue.parse(new InputStreamReader(instream)); + Gson gson = new Gson(); + JSONObject json = (JSONObject)JSONValue.parse(gson.toJson(jarr)); LOG.debug("is json null? :" + json == null ? "true" : "false"); if (json != null) { if (LOG.isDebugEnabled()) { From c6a40f4c22559688576a21eefb2b014ed59d678c Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Sun, 22 Oct 2017 23:57:46 +0200 Subject: [PATCH 02/17] Merge with the simpler solution to the "Request-URI Too Long" error of robymathew : https://github.com/robymathew/ApexUnit/commit/12fc46cf63b8408cb493151f75bab1c898f3d9c4 --- .../codeCoverage/CodeCoverageComputer.java | 135 +++++++++------ .../codeCoverage/WebServiceInvoker.java | 7 +- .../client/testEngine/TestExecutor.java | 155 +++++++++--------- 3 files changed, 166 insertions(+), 131 deletions(-) mode change 100644 => 100755 src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java mode change 100644 => 100755 src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java mode change 100644 => 100755 src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestExecutor.java diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java old mode 100644 new mode 100755 index b00f940..c6b5cc4 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/CodeCoverageComputer.java @@ -16,7 +16,6 @@ import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -35,6 +34,7 @@ import com.sforce.cd.apexUnit.report.ApexClassCodeCoverageBean; import com.sforce.cd.apexUnit.report.ApexUnitCodeCoverageResults; import com.sforce.soap.partner.PartnerConnection; +import java.util.Arrays; public class CodeCoverageComputer { private static Logger LOG = LoggerFactory.getLogger(CodeCoverageComputer.class); @@ -73,9 +73,9 @@ public CodeCoverageComputer() { public ApexClassCodeCoverageBean[] calculateAggregatedCodeCoverageUsingToolingAPI() { PartnerConnection connection = ConnectionHandler.getConnectionHandlerInstance().getConnection(); - List apexClassCodeCoverageBeans = new ArrayList(); + ApexClassCodeCoverageBean[] apexClassCodeCoverageBeans = null; String[] classesAsArray = null; - + final int BATCH_SIZE = 100; /* * Builder design pattern construct the test class array by building the * final array using simple objects(arrays) viz. array from Manifest @@ -96,47 +96,84 @@ public ApexClassCodeCoverageBean[] calculateAggregatedCodeCoverageUsingToolingAP // Do not proceed if no class names are returned from both manifest // files and/or regexes if (classesAsArray != null && classesAsArray.length > 0) { - List> listClassesAsArray = new ArrayList>(); - int N = classesAsArray.length; - List lclassesAsArray = Arrays.asList(classesAsArray); - for (int i = 0; i < N; i += 100) { - listClassesAsArray.add(lclassesAsArray.subList(i, Math.min(N, i + 100))); + + if (classesAsArray.length > 100) { + int numOfBatches = 1; + int fromIndex = 0; + int toIndex = BATCH_SIZE; + JSONArray recordObject = new JSONArray(); + JSONObject responseJsonObject = null; + LOG.info ("Total number of classes: " + classesAsArray.length); + + if (classesAsArray.length % BATCH_SIZE == 0) { + numOfBatches = classesAsArray.length / BATCH_SIZE; + } else { + numOfBatches = classesAsArray.length / BATCH_SIZE + 1; + } + + for (int count = 0; count < numOfBatches; count++) { + String[] ClassesInBatch = Arrays.copyOfRange(classesAsArray, fromIndex, toIndex); + String classArrayAsStringForQuery = processClassArrayForQuery(ClassesInBatch); + LOG.debug("Classes i nthis query: " + classArrayAsStringForQuery); + LOG.info ("Total number of classes in this query: " + ClassesInBatch.length); + String relativeServiceURL = "/services/data/v" + SUPPORTED_VERSION + "/tooling"; + // compute aggregated code coverage + String soqlcc = QueryConstructor.getAggregatedCodeCoverage(classArrayAsStringForQuery); + + responseJsonObject = WebServiceInvoker.doGet(relativeServiceURL, soqlcc, OAuthTokenGenerator.getOrgToken()); + LOG.debug("responseJsonObject says " + responseJsonObject + "\n relativeServiceURL is " + relativeServiceURL + + "\n soqlcc is " + soqlcc); + String responseStr = responseJsonObject.toJSONString(); + LOG.debug(responseStr); + recordObject.addAll((JSONArray) responseJsonObject.get("records")); + LOG.debug("Total records so far : " + recordObject.size()); + + if (toIndex == classesAsArray.length) { + break; + } else { + fromIndex = fromIndex + BATCH_SIZE; + if ((toIndex + BATCH_SIZE) < (classesAsArray.length)) { + toIndex = toIndex + BATCH_SIZE; + } else { + toIndex = classesAsArray.length; + } + } + } + + if (recordObject.size() > 0) { + apexClassCodeCoverageBeans = processJSONResponseAndConstructCodeCoverageBeans(connection, recordObject); + } + if (apexClassCodeCoverageBeans == null) { + ApexUnitUtils.shutDownWithErrMsg("Code coverage metrics not computed. Null object returned while processing the JSON response from the Tooling API"); + } + + }else{ + String classArrayAsStringForQuery = processClassArrayForQuery(classesAsArray); + String relativeServiceURL = "/services/data/v" + SUPPORTED_VERSION + "/tooling"; + // compute aggregated code coverage + String soqlcc = QueryConstructor.getAggregatedCodeCoverage(classArrayAsStringForQuery); + + JSONObject responseJsonObject = null; + responseJsonObject = WebServiceInvoker.doGet(relativeServiceURL, soqlcc, OAuthTokenGenerator.getOrgToken()); + LOG.debug("responseJsonObject says " + responseJsonObject + "\n relativeServiceURL is " + relativeServiceURL + + "\n soqlcc is " + soqlcc); + String responseStr = responseJsonObject.toJSONString(); + LOG.debug(responseStr); + if (responseJsonObject != null) { + apexClassCodeCoverageBeans = processJSONResponseAndConstructCodeCoverageBeans(connection, + (JSONArray)responseJsonObject.get("records")); } - int T = listClassesAsArray.size(); - JSONObject[] responseJsonObjects = new JSONObject[T]; - for(int j=0;j lf = new ArrayList(); - for(int w=0;w < (listClassesAsArray.get(j)).size();w++){ - lf.add((listClassesAsArray.get(j)).get(w)); - } - String[] toProcess = new String[lf.size()];LOG.info(" ### LF = "+lf.toArray(toProcess)); - String classArrayAsStringForQuery = processClassArrayForQuery(lf.toArray(toProcess)); - String relativeServiceURL = "/services/data/v" + SUPPORTED_VERSION + "/tooling"; - // compute aggregated code coverage - String soqlcc = QueryConstructor.getAggregatedCodeCoverage(classArrayAsStringForQuery); - responseJsonObjects[j] = WebServiceInvoker.doGet(relativeServiceURL, soqlcc, OAuthTokenGenerator.getOrgToken()); - LOG.info("responseJsonObject says " + responseJsonObjects[j] + "\n relativeServiceURL is " + relativeServiceURL - + "\n soqlcc is " + soqlcc); - - if (responseJsonObjects[j] != null) { - ApexClassCodeCoverageBean[] results = processJSONResponseAndConstructCodeCoverageBeans(connection, responseJsonObjects[j]);LOG.info("### results = "+results); - if(results != null && results.length > 0){ - for(ApexClassCodeCoverageBean result:results){ - apexClassCodeCoverageBeans.add(result); - } - } - } - if (apexClassCodeCoverageBeans == null) { - ApexUnitUtils.shutDownWithErrMsg( - "Code coverage metrics not computed. Null object returned while processing the JSON response from the Tooling API"); - } + if (apexClassCodeCoverageBeans == null) { + ApexUnitUtils.shutDownWithErrMsg( + "Code coverage metrics not computed. Null object returned while processing the JSON response from the Tooling API"); } + } + } else { ApexUnitUtils.shutDownWithErrMsg("No/Invalid Apex source classes mentioned in manifest file and/or " + "regex pattern for ApexSourceClassPrefix didn't return any Apex source class names from the org"); } - int M = apexClassCodeCoverageBeans.size(); - return (ApexClassCodeCoverageBean[]) apexClassCodeCoverageBeans.toArray(new ApexClassCodeCoverageBean[M]); + return apexClassCodeCoverageBeans; } /* @@ -170,13 +207,11 @@ private String processClassArrayForQuery(String[] classesAsArray) { * @return code coverage result(beans) as array */ private ApexClassCodeCoverageBean[] processJSONResponseAndConstructCodeCoverageBeans(PartnerConnection connection, - JSONObject responseJsonObject) { + JSONArray aggregateRecordObject) { int classCounter = 0; int coveredLinesForTheTeam = 0; int unCoveredLinesForTheTeam = 0; - String responseStr = responseJsonObject.toJSONString(); - LOG.debug(responseStr); - JSONArray recordObject = (JSONArray) responseJsonObject.get("records"); + JSONArray recordObject = aggregateRecordObject; if (recordObject != null && recordObject.size() > 0) { ApexClassCodeCoverageBean[] apexClassCodeCoverageBeans = new ApexClassCodeCoverageBean[recordObject.size()]; for (int i = 0; i < recordObject.size(); ++i) { @@ -325,18 +360,16 @@ public int getOrgWideCodeCoverage() { if (responseJsonObject != null) { String responseStr = responseJsonObject.toJSONString(); - LOG.info("responseStr during org wide code coverage" + responseStr); + LOG.debug("responseStr during org wide code coverage" + responseStr); JSONArray recordObject = (JSONArray) responseJsonObject.get("records"); - if(recordObject != null && recordObject.size() > 0) { - for (int i = 0; i < recordObject.size(); ++i) { + for (int i = 0; i < recordObject.size(); ++i) { - JSONObject rec = (JSONObject) recordObject.get(i); + JSONObject rec = (JSONObject) recordObject.get(i); - coverage = Integer.valueOf((String) rec.get("PercentCovered").toString()); - LOG.info( - "#################################### Org wide code coverage result #################################### "); - LOG.info("Org wide code coverage : " + coverage + "%"); - } + coverage = Integer.valueOf((String) rec.get("PercentCovered").toString()); + LOG.info( + "#################################### Org wide code coverage result #################################### "); + LOG.info("Org wide code coverage : " + coverage + "%"); } } else { ApexUnitUtils.shutDownWithErrMsg("Org wide code coverage not computed"); diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java old mode 100644 new mode 100755 index fdacc8f..225e085 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java @@ -32,8 +32,6 @@ import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.json.simple.JSONObject; -import org.json.simple.JSONArray; -import com.google.gson.Gson; import org.json.simple.JSONValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -154,9 +152,8 @@ public static JSONObject doGet(String relativeServiceURL, String accessToken) { try { instream = executeHTTPMethod(httpclient, get, authorizationServerURL); LOG.debug("done with get operation"); - Object jarr = JSONValue.parse(new InputStreamReader(instream)); - Gson gson = new Gson(); - JSONObject json = (JSONObject)JSONValue.parse(gson.toJson(jarr)); + + JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(instream)); LOG.debug("is json null? :" + json == null ? "true" : "false"); if (json != null) { if (LOG.isDebugEnabled()) { diff --git a/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestExecutor.java b/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestExecutor.java old mode 100644 new mode 100755 index 0a66c8e..196249a --- a/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestExecutor.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestExecutor.java @@ -5,17 +5,12 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -/* + /* * Class for controlling the test execution flow in APexUnit * @author adarsh.ramakrishna@salesforce.com - */ - - + */ package com.sforce.cd.apexUnit.client.testEngine; -import java.util.ArrayList; -import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,76 +20,86 @@ import com.sforce.cd.apexUnit.client.utils.ApexClassFetcherUtils; import com.sforce.cd.apexUnit.report.ApexReportBean; import com.sforce.soap.partner.PartnerConnection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang.ArrayUtils; +import org.testng.collections.Lists; public class TestExecutor { - private static Logger LOG = LoggerFactory.getLogger(TestExecutor.class); - private static final int BATCH_SIZE = 200; - - public ApexReportBean[] testExecutionFlow() { - - ConnectionHandler connectionHandler = ConnectionHandler.getConnectionHandlerInstance(); - PartnerConnection conn = connectionHandler.getConnection(); - BulkConnection bulkConnection = null; - AsyncBulkApiHandler bulkApiHandler = null; - String[] testClassesInBatch = null; - String parentJobId; - ArrayList apexReportBean = null; - ApexReportBean[] apexReportBeanArray = null; - - - if (conn == null) { - ApexUnitUtils.shutDownWithErrMsg("Unable to establish Connection with the org. Suspending the run.."); - } - - String[] testClassesAsArray = ApexClassFetcherUtils.constructTestClassesArray(conn); - - if (LOG.isDebugEnabled()) { - ApexClassFetcherUtils.logTheFetchedApexClasses(testClassesAsArray); - } - - if (testClassesAsArray != null && testClassesAsArray.length > 0) { - - int numOfBatches = 0; - int fromIndex = 0; - int toIndex = 0; - apexReportBean = new ArrayList(); - bulkConnection = connectionHandler.getBulkConnection(); - bulkApiHandler = new AsyncBulkApiHandler(); - - int lastSetOfClasses = testClassesAsArray.length % BATCH_SIZE; - if (lastSetOfClasses == 0) { - numOfBatches = testClassesAsArray.length / BATCH_SIZE; - } else { - numOfBatches = testClassesAsArray.length / BATCH_SIZE + 1; - } - - for (int count = 0; count < numOfBatches; count++) { - - fromIndex = count * BATCH_SIZE; - toIndex = (lastSetOfClasses != 0 && count == numOfBatches - 1) ? (toIndex + lastSetOfClasses) - : (fromIndex + BATCH_SIZE); - - testClassesInBatch = Arrays.copyOfRange(testClassesAsArray, fromIndex, toIndex); - parentJobId = bulkApiHandler.handleBulkApiFlow(conn, bulkConnection, testClassesInBatch); - - LOG.info("#####Parent JOB ID #####"+parentJobId); - if (parentJobId != null) { - LOG.info("Parent job ID for the submission of the test classes to the Force.com platform is: " - + parentJobId); - TestStatusPollerAndResultHandler queryPollerAndResultHandler = new TestStatusPollerAndResultHandler(); - LOG.info( - "############################# Now executing - Apex tests.. #############################"); - apexReportBeanArray = queryPollerAndResultHandler.fetchResultsFromParentJobId(parentJobId, conn); - if(apexReportBeanArray != null){ - apexReportBean.addAll(Arrays.asList(apexReportBeanArray)); - } - - } - } - - } - return apexReportBean.toArray(new ApexReportBean[0]); - } + private static Logger LOG = LoggerFactory.getLogger(TestExecutor.class); + + public ApexReportBean[] testExecutionFlow() { + ConnectionHandler connectionHandler = ConnectionHandler.getConnectionHandlerInstance(); + PartnerConnection conn = connectionHandler.getConnection(); + final int BATCH_SIZE = 200; + String parentJobId; + List reportBean = new ArrayList(); + + if (conn == null) { + ApexUnitUtils.shutDownWithErrMsg("Unable to establish Connection with the org. Suspending the run.."); + } + String[] testClassesAsArray = ApexClassFetcherUtils.constructTestClassesArray(conn); + if (LOG.isDebugEnabled()) { + ApexClassFetcherUtils.logTheFetchedApexClasses(testClassesAsArray); + } + if (testClassesAsArray != null && testClassesAsArray.length > 0) { + LOG.info("Total number of classes: " + testClassesAsArray.length); + + if (testClassesAsArray.length > 200) { + int numOfBatches = 1; + int fromIndex = 0; + int toIndex = BATCH_SIZE; + + if (testClassesAsArray.length % BATCH_SIZE == 0) { + numOfBatches = testClassesAsArray.length / BATCH_SIZE; + } else { + numOfBatches = testClassesAsArray.length / BATCH_SIZE + 1; + } + + for (int count = 0; count < numOfBatches; count++) { + String[] testClassesInBatch = Arrays.copyOfRange(testClassesAsArray, fromIndex, toIndex); + BulkConnection bulkConnection = connectionHandler.getBulkConnection(); + AsyncBulkApiHandler bulkApiHandler = new AsyncBulkApiHandler(); + parentJobId = bulkApiHandler.handleBulkApiFlow(conn, bulkConnection, testClassesInBatch); + LOG.info("Running Batch of " + testClassesInBatch.length + " classes"); + if (parentJobId != null) { + LOG.info("Parent job ID for the submission of the test classes to the Force.com platform is: " + + parentJobId); + TestStatusPollerAndResultHandler queryPollerAndResultHandler = new TestStatusPollerAndResultHandler(); + LOG.info("############################# Now executing - Apex tests.. #############################"); + reportBean.addAll(Arrays.asList(queryPollerAndResultHandler.fetchResultsFromParentJobId(parentJobId, conn))); + } + + if (toIndex == testClassesAsArray.length) { + break; + } else { + fromIndex = fromIndex + BATCH_SIZE; + if ((toIndex + BATCH_SIZE) < (testClassesAsArray.length)) { + toIndex = toIndex + BATCH_SIZE; + } else { + toIndex = testClassesAsArray.length; + } + } + } + return reportBean.toArray(new ApexReportBean[reportBean.size()]); + } else { + BulkConnection bulkConnection = connectionHandler.getBulkConnection(); + AsyncBulkApiHandler bulkApiHandler = new AsyncBulkApiHandler(); + parentJobId = bulkApiHandler.handleBulkApiFlow(conn, bulkConnection, testClassesAsArray); + + if (parentJobId != null) { + LOG.info("Parent job ID for the submission of the test classes to the Force.com platform is: " + + parentJobId); + TestStatusPollerAndResultHandler queryPollerAndResultHandler = new TestStatusPollerAndResultHandler(); + LOG.info("############################# Now executing - Apex tests.. #############################"); + return queryPollerAndResultHandler.fetchResultsFromParentJobId(parentJobId, conn); + } + } + + } + return null; + } } From 00d04cf7abadebe9bed9c41f687bc891e6c2196c Mon Sep 17 00:00:00 2001 From: eSh3m4 Date: Mon, 23 Oct 2017 02:48:46 +0200 Subject: [PATCH 03/17] Group tests results reports files into a single report directory and append execution date --- .../com/sforce/cd/apexUnit/ApexUnitRunner.java | 9 +++++++-- .../report/ApexCodeCoverageReportGenerator.java | 15 ++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java index fba195b..75d2138 100644 --- a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java +++ b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java @@ -22,6 +22,8 @@ package com.sforce.cd.apexUnit; +import java.io.File; +import java.time.*; import java.util.Arrays; import java.util.List; @@ -101,16 +103,19 @@ public static void main(String[] args) { } Long end = System.currentTimeMillis(); LOG.debug("Total Time taken by ApexUnit tool in secs: " + (end - start) / 1000); + String reportDir = System.getProperty("user.dir") + System.getProperty("file.separator") + LocalDate.now() + "_Report"; + File dir = new File(reportDir); + dir.mkdirs(); if (apexReportBeans != null && apexReportBeans.length > 0) { LOG.info("Total test methods executed: " + apexReportBeans.length); - String reportFile = "ApexUnitReport.xml"; + String reportFile = reportDir + System.getProperty("file.separator") + "ApexUnitReport.xml"; ApexUnitTestReportGenerator.generateTestReport(apexReportBeans, reportFile); } else { ApexUnitUtils.shutDownWithErrMsg("Unable to generate test report. " + "Did not find any test results for the job id"); } if (!skipCodeCoverageComputation) { - ApexCodeCoverageReportGenerator.generateHTMLReport(apexClassCodeCoverageBeans); + ApexCodeCoverageReportGenerator.generateHTMLReport(apexClassCodeCoverageBeans, dir); // validating the code coverage metrics against the thresholds // provided by the user diff --git a/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java b/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java index 8d77dc5..0dc9f0d 100644 --- a/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java +++ b/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java @@ -29,7 +29,7 @@ public class ApexCodeCoverageReportGenerator { - public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeCoverageBeans) { + public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeCoverageBeans, File reportDir) { // Preparing the table: StringBuilder htmlBuilder = new StringBuilder(); htmlBuilder.append(""); @@ -112,7 +112,7 @@ public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeC // provide link to the test report appendTag(htmlBuilder, "header", "Apex Test Report: "); appendLineSpaces(htmlBuilder, 2); - String workingDir = System.getProperty("user.dir"); + String workingDir = reportDir.getPath(); String apexUnitTestReportPath = ""; if (!workingDir.contains("jenkins")) { apexUnitTestReportPath = workingDir + System.getProperty("file.separator") + "ApexUnitReport.xml"; @@ -122,7 +122,7 @@ public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeC apexUnitTestReportPath = "https://jenkins.internal.salesforce.com/job/" + jobName + "/lastCompletedBuild/testReport/"; } - appendTag(htmlBuilder, "a", "style=\"font-size:125%\"; href=" + apexUnitTestReportPath, "Detailed Test Report"); + appendTag(htmlBuilder, "a", "style=\"font-size:125%\"; href=\"" + apexUnitTestReportPath + "\"", "Detailed Test Report"); appendLineSpaces(htmlBuilder, 2); appendTag(htmlBuilder, "header", "Detailed code coverage report: "); @@ -216,17 +216,14 @@ public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeC htmlBuilder.append(""); htmlBuilder.append(""); - createHTMLReport(htmlBuilder.toString()); + createHTMLReport(htmlBuilder.toString(), reportDir); } - private static void createHTMLReport(String htmlBuffer) { + private static void createHTMLReport(String htmlBuffer, File reportDir) { File tmpFile = null; FileOutputStream tmpOut = null; - String workingDir = System.getProperty("user.dir") + System.getProperty("file.separator") + "Report"; - File dir = new File(workingDir); - dir.mkdirs(); - tmpFile = new File(dir, "ApexUnitReport.html"); + tmpFile = new File(reportDir, "ApexUnitReport.html"); byte[] reportAsBytes; try { tmpOut = new FileOutputStream(tmpFile); From 2c05d860cfb3a91d1b377d4c5815ca6c081316b6 Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Mon, 23 Oct 2017 07:51:46 +0200 Subject: [PATCH 04/17] add a relative path to the detailed results in the html report to ease file sharing --- .../cd/apexUnit/report/ApexCodeCoverageReportGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java b/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java index 0dc9f0d..700ba31 100644 --- a/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java +++ b/src/main/java/com/sforce/cd/apexUnit/report/ApexCodeCoverageReportGenerator.java @@ -115,7 +115,7 @@ public static void generateHTMLReport(ApexClassCodeCoverageBean[] apexClassCodeC String workingDir = reportDir.getPath(); String apexUnitTestReportPath = ""; if (!workingDir.contains("jenkins")) { - apexUnitTestReportPath = workingDir + System.getProperty("file.separator") + "ApexUnitReport.xml"; + apexUnitTestReportPath = "." + System.getProperty("file.separator") + "ApexUnitReport.xml"; } else { int lastIndexOfSlash = workingDir.lastIndexOf('/'); String jobName = workingDir.substring(lastIndexOfSlash + 1); From 4c175c42121743020cbf748c9f1c13a60a487f0c Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Wed, 25 Oct 2017 01:54:13 +0200 Subject: [PATCH 05/17] Incremented pom version from 2.3.6 to 2.3.8 to match the actual versioning state --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c354b0b..d255538 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ com.sforce.cd.ApexUnit ApexUnit-core - 2.3.6 + 2.3.8 ApexUnit Apex Unit v 2.0 with enhanced metrics and advanced features From db143162386f66f247c6b616e3130e02cedea362 Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Wed, 25 Oct 2017 17:04:23 +0200 Subject: [PATCH 06/17] Fix the issue with the number of test classes and methods in the html report when more than 200 tests --- .../client/testEngine/TestStatusPollerAndResultHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestStatusPollerAndResultHandler.java b/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestStatusPollerAndResultHandler.java index bb259ac..c4df6a8 100644 --- a/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestStatusPollerAndResultHandler.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/testEngine/TestStatusPollerAndResultHandler.java @@ -67,7 +67,7 @@ public ApexReportBean[] fetchResultsFromParentJobId(String parentJobId, PartnerC int index = 0; SObject[] sObjects = queryResult.getRecords(); if (sObjects != null) { - totalTestMethodsExecuted = sObjects.length; + totalTestMethodsExecuted += sObjects.length; LOG.info("Total test methods executed: " + TestStatusPollerAndResultHandler.totalTestMethodsExecuted); apexReportBeans = new ApexReportBean[sObjects.length]; for (SObject sobject : sObjects) { @@ -141,7 +141,7 @@ public boolean waitForTestsToComplete(String parentJobId, PartnerConnection conn if (sObjects != null) { String status = ""; int totalTests = sObjects.length; - totalTestClasses = totalTests; + totalTestClasses += totalTests; int remainingTests = totalTests; LOG.info("Total test classes to execute: " + totalTestClasses); String testId = ""; From 18a25ebf2f205212f83e2ba9f23b268bba57c7d9 Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Wed, 25 Oct 2017 19:41:21 +0200 Subject: [PATCH 07/17] Feature added : the parameter "-ignore.code.coverage.threshold" prevent build from failure when the code coverage thresholds are not met --- README.md | 1 + src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java | 4 ++-- .../sforce/cd/apexUnit/arguments/CommandLineArguments.java | 7 +++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1258332..86ded26 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Optional Parameters: - -max.test.execution.time.threshold : Maximum execution time(in minutes) for a test before it gets aborted - -proxy.host : Proxy host for external access - -proxy.port : Proxy port for external access +- -ignore.code.coverage.threshold : Build does not fail if the code coverage thresholds are not met - -help : Displays options available for running this application Note: You must provide either of the (-regex.for.selecting.source.classes.for.code.coverage.computation OR -manifest.files.with.source.class.names.for.code.coverage.computation) AND either of -(regex.for.selecting.test.classes.to.execute OR -manifest.files.with.test.class.names.to.execute) diff --git a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java index 75d2138..766e968 100644 --- a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java +++ b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java @@ -125,12 +125,12 @@ public static void main(String[] args) { if (ApexUnitCodeCoverageResults.teamCodeCoverage == -1) { LOG.warn("No source class names provided. Team Code coverage not computed "); } else { - teamCodeCoverageThresholdError = true; + teamCodeCoverageThresholdError = !CommandLineArguments.getSkipCoverageEnforcement(); } } if (ApexUnitCodeCoverageResults.orgWideCodeCoverage < CommandLineArguments .getOrgWideCodeCoverageThreshold()) { - orgWideCodeCoverageThresholdError = true; + orgWideCodeCoverageThresholdError = !CommandLineArguments.getSkipCoverageEnforcement(); } if (teamCodeCoverageThresholdError) { diff --git a/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java b/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java index 421e85b..473f305 100644 --- a/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java +++ b/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java @@ -35,6 +35,7 @@ public class CommandLineArguments { public static final String ORG_CLIENT_SECRET = "-org.client.secret"; public static final String PROXY_HOST = "-proxy.host"; public static final String PROXY_PORT = "-proxy.port"; + public static final String INGORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT = "-ignore.code.coverage.threshold"; public static final String HELP = "-help"; @@ -74,6 +75,8 @@ public class CommandLineArguments { static private String proxyHost; @Parameter(names = PROXY_PORT, description = "Proxy port if required for access.", validateWith = PositiveIntegerValidator.class, required = false) static private Integer proxyPort; + @Parameter(names = INGORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT, description = "Build does not fail if the code coverage thresholds are not met.", required = false) + static private boolean skipCoverageEnforcement = false; @Parameter(names = HELP, help = true, description = "Displays options available for running this application") static private boolean help; @@ -142,6 +145,10 @@ public static void setClientSecret(String clientSecret) { CommandLineArguments.clientSecret = clientSecret; } + public static boolean getSkipCoverageEnforcement() { + return skipCoverageEnforcement; + } + public static boolean isHelp() { return help; } From 9bd78d3d121d335a99e29f471ecdeca99667abdf Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Wed, 25 Oct 2017 22:43:28 +0200 Subject: [PATCH 08/17] Feature added : the parameter "-ignore.test.failure" prevent builds from failing when there are failing test methods --- README.md | 1 + .../java/com/sforce/cd/apexUnit/ApexUnitRunner.java | 2 +- .../cd/apexUnit/arguments/CommandLineArguments.java | 13 ++++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 86ded26..e4501d2 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Optional Parameters: - -proxy.host : Proxy host for external access - -proxy.port : Proxy port for external access - -ignore.code.coverage.threshold : Build does not fail if the code coverage thresholds are not met +- -ignore.test.failure : Build does not fail if there are tests failures - -help : Displays options available for running this application Note: You must provide either of the (-regex.for.selecting.source.classes.for.code.coverage.computation OR -manifest.files.with.source.class.names.for.code.coverage.computation) AND either of -(regex.for.selecting.test.classes.to.execute OR -manifest.files.with.test.class.names.to.execute) diff --git a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java index 766e968..af498ba 100644 --- a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java +++ b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java @@ -149,7 +149,7 @@ public static void main(String[] args) { } // if there are test failures, concatenate error messages - if (TestStatusPollerAndResultHandler.testFailures) { + if (TestStatusPollerAndResultHandler.testFailures && !CommandLineArguments.getIgnoreTestFailure()) { runTimeExceptionMessage += "Test failures amongst the Apex tests executed. "; if (TestStatusPollerAndResultHandler.failedTestMethods != null && TestStatusPollerAndResultHandler.failedTestMethods.size() > 0) { diff --git a/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java b/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java index 473f305..743faae 100644 --- a/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java +++ b/src/main/java/com/sforce/cd/apexUnit/arguments/CommandLineArguments.java @@ -35,8 +35,9 @@ public class CommandLineArguments { public static final String ORG_CLIENT_SECRET = "-org.client.secret"; public static final String PROXY_HOST = "-proxy.host"; public static final String PROXY_PORT = "-proxy.port"; - public static final String INGORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT = "-ignore.code.coverage.threshold"; - + public static final String IGNORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT = "-ignore.code.coverage.threshold"; + public static final String IGNORE_TEST_FAILURE = "-ignore.test.failure"; + public static final String HELP = "-help"; /* @@ -75,8 +76,10 @@ public class CommandLineArguments { static private String proxyHost; @Parameter(names = PROXY_PORT, description = "Proxy port if required for access.", validateWith = PositiveIntegerValidator.class, required = false) static private Integer proxyPort; - @Parameter(names = INGORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT, description = "Build does not fail if the code coverage thresholds are not met.", required = false) + @Parameter(names = IGNORE_CODE_COVERAGE_THRESHOLD_ENFORCEMENT, description = "Build does not fail if the code coverage thresholds are not met.", required = false) static private boolean skipCoverageEnforcement = false; + @Parameter(names = IGNORE_TEST_FAILURE, description = "Build does not fail if there are tests failures.", required = false) + static private boolean ignoreTestFailure = false; @Parameter(names = HELP, help = true, description = "Displays options available for running this application") static private boolean help; @@ -149,6 +152,10 @@ public static boolean getSkipCoverageEnforcement() { return skipCoverageEnforcement; } + public static boolean getIgnoreTestFailure() { + return ignoreTestFailure; + } + public static boolean isHelp() { return help; } From 65a3b3ef51c7a4dcad9df0fe73f2dc7fcf99eb9b Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Wed, 25 Oct 2017 23:13:38 +0200 Subject: [PATCH 09/17] Adjust the success messages to the added features "-ignore.test.failure" and "-ignore.code.coverage.threshold" --- src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java index af498ba..4101217 100644 --- a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java +++ b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java @@ -163,7 +163,10 @@ public static void main(String[] args) { if (!runTimeExceptionMessage.equals("")) { ApexUnitUtils.shutDownWithErrMsg(runTimeExceptionMessage); } else { - LOG.info("Success!! No test failures and all code coverage thresholds are met!! Exiting ApexUnit.. Good bye.."); + LOG.info("Build successful!!" + + +(TestStatusPollerAndResultHandler.testFailures?" There are tests failures :(":" No test failures!!") + + +((ApexUnitCodeCoverageResults.teamCodeCoverage < CommandLineArguments.getTeamCodeCoverageThreshold() && !(ApexUnitCodeCoverageResults.teamCodeCoverage == -1)) || (ApexUnitCodeCoverageResults.orgWideCodeCoverage < CommandLineArguments.getOrgWideCodeCoverageThreshold())?" and all code coverage thresholds are not met :(":" and all code coverage thresholds are met!!")+ + +" Exiting ApexUnit.. Good bye.."); } } From 028dfb3a3e5c13bd9dcbe3e93589f8aea9a310cc Mon Sep 17 00:00:00 2001 From: Eric Shema Date: Thu, 26 Oct 2017 00:12:44 +0200 Subject: [PATCH 10/17] Detailed build success message --- .../sforce/cd/apexUnit/ApexUnitRunner.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java index 4101217..0646f4f 100644 --- a/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java +++ b/src/main/java/com/sforce/cd/apexUnit/ApexUnitRunner.java @@ -114,33 +114,32 @@ public static void main(String[] args) { ApexUnitUtils.shutDownWithErrMsg("Unable to generate test report. " + "Did not find any test results for the job id"); } + boolean teamCodeCoverageThresholdError = false; + boolean orgWideCodeCoverageThresholdError = false; if (!skipCodeCoverageComputation) { ApexCodeCoverageReportGenerator.generateHTMLReport(apexClassCodeCoverageBeans, dir); // validating the code coverage metrics against the thresholds // provided by the user - boolean teamCodeCoverageThresholdError = false; - boolean orgWideCodeCoverageThresholdError = false; if (ApexUnitCodeCoverageResults.teamCodeCoverage < CommandLineArguments.getTeamCodeCoverageThreshold()) { if (ApexUnitCodeCoverageResults.teamCodeCoverage == -1) { LOG.warn("No source class names provided. Team Code coverage not computed "); } else { - teamCodeCoverageThresholdError = !CommandLineArguments.getSkipCoverageEnforcement(); + teamCodeCoverageThresholdError = true; } } - if (ApexUnitCodeCoverageResults.orgWideCodeCoverage < CommandLineArguments - .getOrgWideCodeCoverageThreshold()) { - orgWideCodeCoverageThresholdError = !CommandLineArguments.getSkipCoverageEnforcement(); + if (ApexUnitCodeCoverageResults.orgWideCodeCoverage < CommandLineArguments.getOrgWideCodeCoverageThreshold()) { + orgWideCodeCoverageThresholdError = true; } - if (teamCodeCoverageThresholdError) { + if (teamCodeCoverageThresholdError && !CommandLineArguments.getSkipCoverageEnforcement()) { runTimeExceptionMessage += "Failed to meet the Team code coverage threshold : " + CommandLineArguments.getTeamCodeCoverageThreshold() + " The team code coverage for the given classes is: " + ApexUnitCodeCoverageResults.teamCodeCoverage + "%\n" + "Calibrate your threshold values if you are happy with the current code coverage\n"; } - if (orgWideCodeCoverageThresholdError) { + if (orgWideCodeCoverageThresholdError && !CommandLineArguments.getSkipCoverageEnforcement()) { runTimeExceptionMessage += "Failed to meet the Org code coverage threshold : " + CommandLineArguments.getOrgWideCodeCoverageThreshold() + " The org code coverage for the org is: " + ApexUnitCodeCoverageResults.orgWideCodeCoverage @@ -163,10 +162,10 @@ public static void main(String[] args) { if (!runTimeExceptionMessage.equals("")) { ApexUnitUtils.shutDownWithErrMsg(runTimeExceptionMessage); } else { - LOG.info("Build successful!!" + - +(TestStatusPollerAndResultHandler.testFailures?" There are tests failures :(":" No test failures!!") + - +((ApexUnitCodeCoverageResults.teamCodeCoverage < CommandLineArguments.getTeamCodeCoverageThreshold() && !(ApexUnitCodeCoverageResults.teamCodeCoverage == -1)) || (ApexUnitCodeCoverageResults.orgWideCodeCoverage < CommandLineArguments.getOrgWideCodeCoverageThreshold())?" and all code coverage thresholds are not met :(":" and all code coverage thresholds are met!!")+ - +" Exiting ApexUnit.. Good bye.."); + LOG.info("Build successful!!" + +(TestStatusPollerAndResultHandler.testFailures ? " - But "+TestStatusPollerAndResultHandler.failedTestMethods.size()+" Test failure(s) amongst the Apex tests executed : "+TestStatusPollerAndResultHandler.failedTestMethods.toString():" - No test failures!!") + +(teamCodeCoverageThresholdError || orgWideCodeCoverageThresholdError ? (teamCodeCoverageThresholdError ? " - Failed to meet the Team code coverage threshold : "+ApexUnitCodeCoverageResults.teamCodeCoverage+"% < "+CommandLineArguments.getTeamCodeCoverageThreshold()+"%":"")+(orgWideCodeCoverageThresholdError ? " - Failed to meet the Org code coverage threshold : "+ApexUnitCodeCoverageResults.orgWideCodeCoverage+"% < "+CommandLineArguments.getOrgWideCodeCoverageThreshold()+"%":""):" - All code coverage thresholds are met!!") + +" - Exiting ApexUnit.. Good bye.."); } } From 2f5c51911b94d1c60d2c85955e1a80058faac80a Mon Sep 17 00:00:00 2001 From: Ashwin Reddy Vengareddy Date: Thu, 11 Jan 2018 22:49:14 +0530 Subject: [PATCH 11/17] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index eb6122f..93be8f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: java jdk: -- oraclejdk7 +- openjdk7 script: - mvn test -D-org.login.url="https://na14.salesforce.com" -D-org.username=$USERNAME -D-org.password=$PASSWORD -D-org.client.id=$CLIENT_ID -D-org.client.secret=$CLIENT_SECRET -D-org.wide.code.coverage.threshold=40 -D-team.code.coverage.threshold=40 -D-regex.for.selecting.source.classes.for.code.coverage.computation=HelloWorld -D-regex.for.selecting.test.classes.to.execute=HelloWord* -D-manifest.files.with.test.class.names.to.execute=ManifestFile_For_Unit_Test_Classes.txt -D-manifest.files.with.source.class.names.for.code.coverage.computation=ManifestFile.txt -D-max.test.execution.time.threshold=10 From b08ab58efefe6e552f9849ee50f2213fc9a0d30c Mon Sep 17 00:00:00 2001 From: foviedoITBA Date: Fri, 4 May 2018 15:00:48 -0300 Subject: [PATCH 12/17] Fix typo in escapeSingleQuote method documentation --- .../java/com/sforce/cd/apexUnit/client/QueryConstructor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sforce/cd/apexUnit/client/QueryConstructor.java b/src/main/java/com/sforce/cd/apexUnit/client/QueryConstructor.java index fc0240b..397ab1a 100644 --- a/src/main/java/com/sforce/cd/apexUnit/client/QueryConstructor.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/QueryConstructor.java @@ -292,7 +292,7 @@ private static String processRegexForSoqlQueries(String apexClassNameRegex) { } /* - * Escape single quotes in the user input during qyery execution + * Escape single quotes in the user input during query execution * * @param : userInput: String * From b92216cfce595cd2063ae222ecd034d1766d062c Mon Sep 17 00:00:00 2001 From: Vamshidhar Gandham Date: Wed, 26 Sep 2018 11:42:10 -0700 Subject: [PATCH 13/17] remove cla file --- SFDC_CLA.pdf | Bin 92431 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 SFDC_CLA.pdf diff --git a/SFDC_CLA.pdf b/SFDC_CLA.pdf deleted file mode 100644 index 45fb9f83ec9e3a7b01caa2c97b87cb9c35539647..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92431 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 From e6387e63f0a839eb02a1ed3a6902bedc7f5e70ee Mon Sep 17 00:00:00 2001 From: damiendurant Date: Tue, 4 Dec 2018 10:50:20 +0100 Subject: [PATCH 14/17] Set proxy configuration on WebServiceInvoker --- .../codeCoverage/WebServiceInvoker.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java index 8739aac..f71f1f8 100644 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; @@ -64,12 +65,23 @@ public HashMap doPost(String relativeServiceURL) { HttpClient httpclient = new HttpClient(); String requestString = ""; HashMap responseMap = new HashMap(); + try { // the client id and secret is applicable across all dev orgs requestString = generateRequestString(); String authorizationServerURL = CommandLineArguments.getOrgUrl() + relativeServiceURL; httpclient.getParams().setSoTimeout(0); + + // Set proxy if needed + if (CommandLineArguments.getProxyHost() != null && CommandLineArguments.getProxyPort() != null) { + LOG.debug("Setting proxy configuraiton to " + CommandLineArguments.getProxyHost() + " on port " + + CommandLineArguments.getProxyPort()); + HostConfiguration hostConfiguration = httpclient.getHostConfiguration(); + hostConfiguration.setProxy(CommandLineArguments.getProxyHost(),CommandLineArguments.getProxyPort()); + httpclient.setHostConfiguration(hostConfiguration); + } + post = new PostMethod(authorizationServerURL); post.addRequestHeader("Content-Type", "application/x-www-form-urlencoded"); post.addRequestHeader("X-PrettyPrint", "1"); @@ -140,6 +152,14 @@ public static JSONObject doGet(String relativeServiceURL, String accessToken) { LOG.debug("relativeServiceURL in doGet method:" + relativeServiceURL); HttpClient httpclient = new HttpClient(); + // Set proxy if needed + if (CommandLineArguments.getProxyHost() != null && CommandLineArguments.getProxyPort() != null) { + LOG.debug("Setting proxy configuraiton to " + CommandLineArguments.getProxyHost() + " on port " + + CommandLineArguments.getProxyPort()); + HostConfiguration hostConfiguration = httpclient.getHostConfiguration(); + hostConfiguration.setProxy(CommandLineArguments.getProxyHost(),CommandLineArguments.getProxyPort()); + httpclient.setHostConfiguration(hostConfiguration); + } GetMethod get = null; String authorizationServerURL = CommandLineArguments.getOrgUrl() + relativeServiceURL; From 04e21487b74a28dd8fd77dc9c8c2be6b0384c7fa Mon Sep 17 00:00:00 2001 From: Rutuja Chaudhari Date: Thu, 1 Aug 2019 15:00:05 +0530 Subject: [PATCH 15/17] changing version to 4.0.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c354b0b..0fb553e 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ com.sforce.cd.ApexUnit ApexUnit-core - 2.3.6 + 4.0.0 ApexUnit Apex Unit v 2.0 with enhanced metrics and advanced features From ad5b8707aa0458a6f9544bfbd82f60923537f510 Mon Sep 17 00:00:00 2001 From: eSh3m4 Date: Wed, 6 Nov 2019 01:49:27 +0100 Subject: [PATCH 16/17] Update .yml file to meet Travis CI build requirements --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93be8f9..aef1217 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: java jdk: -- openjdk7 +- openjdk8 script: - mvn test -D-org.login.url="https://na14.salesforce.com" -D-org.username=$USERNAME -D-org.password=$PASSWORD -D-org.client.id=$CLIENT_ID -D-org.client.secret=$CLIENT_SECRET -D-org.wide.code.coverage.threshold=40 -D-team.code.coverage.threshold=40 -D-regex.for.selecting.source.classes.for.code.coverage.computation=HelloWorld -D-regex.for.selecting.test.classes.to.execute=HelloWord* -D-manifest.files.with.test.class.names.to.execute=ManifestFile_For_Unit_Test_Classes.txt -D-manifest.files.with.source.class.names.for.code.coverage.computation=ManifestFile.txt -D-max.test.execution.time.threshold=10 From 1cf782fdcbe63dc6fd0ad845b81c27b3ac8abc43 Mon Sep 17 00:00:00 2001 From: eSh3m4 Date: Tue, 12 Nov 2019 10:13:26 +0100 Subject: [PATCH 17/17] solve Cookie domain rejected issue --- .../cd/apexUnit/client/codeCoverage/WebServiceInvoker.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java index f71f1f8..3d40b77 100755 --- a/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java +++ b/src/main/java/com/sforce/cd/apexUnit/client/codeCoverage/WebServiceInvoker.java @@ -29,9 +29,11 @@ import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; +import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.httpclient.params.HttpClientParams; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.slf4j.Logger; @@ -72,6 +74,8 @@ public HashMap doPost(String relativeServiceURL) { requestString = generateRequestString(); String authorizationServerURL = CommandLineArguments.getOrgUrl() + relativeServiceURL; httpclient.getParams().setSoTimeout(0); + //solve Cookie rejected: "$Version=0; BrowserId=Su_SOgNxEeqrrjGlvnCIuA; $Path=/; $Domain=.salesforce.com". Domain attribute ".salesforce.com" violates RFC 2109: host minus domain may not contain any dots + httpclient.getParams().setParameter(HttpClientParams.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); // Set proxy if needed if (CommandLineArguments.getProxyHost() != null && CommandLineArguments.getProxyPort() != null) { @@ -152,6 +156,8 @@ public static JSONObject doGet(String relativeServiceURL, String accessToken) { LOG.debug("relativeServiceURL in doGet method:" + relativeServiceURL); HttpClient httpclient = new HttpClient(); + //solve Cookie rejected: "$Version=0; BrowserId=Su_SOgNxEeqrrjGlvnCIuA; $Path=/; $Domain=.salesforce.com". Domain attribute ".salesforce.com" violates RFC 2109: host minus domain may not contain any dots + httpclient.getParams().setParameter(HttpClientParams.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); // Set proxy if needed if (CommandLineArguments.getProxyHost() != null && CommandLineArguments.getProxyPort() != null) { LOG.debug("Setting proxy configuraiton to " + CommandLineArguments.getProxyHost() + " on port "