Skip to content

fixed instability issues #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public ZephyrSyncService(Config config) {
zephyrService = new ZephyrService(config);
}

public void execute() throws IOException {
public void execute() throws IOException, InterruptedException {
authService.authenticateInJira();

MetaInfo metaInfo = metaInfoRetrievalService.retrieve();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import lv.ctco.zephyr.beans.zapi.ExecutionRequest;
import lv.ctco.zephyr.beans.zapi.ExecutionResponse;
import lv.ctco.zephyr.beans.zapi.ZapiTestStep;
import lv.ctco.zephyr.enums.TestStatus;
import lv.ctco.zephyr.util.ObjectTransformer;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URLEncoder;
Expand All @@ -34,15 +34,15 @@ public ZephyrService(Config config) {
this.config = config;
}

public Map<String, Execution> getAllExecutions(Config config) throws IOException {
private Map<String, Execution> getAllExecutions(Config config) throws IOException {
log("Fetching JIRA Test Executions for the project");
int skip = 0;
String search = "project='" + config.getValue(PROJECT_KEY) + "'%20and%20fixVersion='"
+ URLEncoder.encode(config.getValue(RELEASE_VERSION), "UTF-8") + "'%20and%20cycleName='" + config.getValue(TEST_CYCLE) + "'";

ExecutionResponse executionResponse = searchInZQL(search, skip);
if (executionResponse == null || executionResponse.getExecutions().isEmpty()) {
return new HashMap<String, Execution>();
return new HashMap<>();
}

List<Execution> executions = executionResponse.getExecutions();
Expand All @@ -58,23 +58,23 @@ public Map<String, Execution> getAllExecutions(Config config) throws IOException
executions.addAll(nextPageExecutions);
}
}
Map<String, Execution> result = new HashMap<String, Execution>(executions.size());
Map<String, Execution> result = new HashMap<>(executions.size());
for (Execution execution : executions) {
result.put(execution.getIssueKey(), execution);
}
log(format("Retrieved %s Test executions\n", executions.size()));
return result;
}

ExecutionResponse searchInZQL(String search, int skip) throws IOException {
private ExecutionResponse searchInZQL(String search, int skip) throws IOException {
String response = getAndReturnBody(config, "zapi/latest/zql/executeSearch?zqlQuery=" + search + "&offset=" + skip);
return ObjectTransformer.deserialize(response, ExecutionResponse.class);
}

public void linkExecutionsToTestCycle(MetaInfo metaInfo, List<TestCase> testCases) throws IOException {
public void linkExecutionsToTestCycle(MetaInfo metaInfo, List<TestCase> testCases) throws IOException, InterruptedException {
Map<String, Execution> executions = getAllExecutions(config);

List<String> keys = new ArrayList<String>();
List<String> keys = new ArrayList<>();

for (TestCase testCase : testCases) {
if (!executions.containsKey(testCase.getKey())) {
Expand All @@ -89,82 +89,102 @@ public void linkExecutionsToTestCycle(MetaInfo metaInfo, List<TestCase> testCase

}

void linkTestToCycle(MetaInfo metaInfo, List<String> keys) throws IOException {
log("Linking Test cases " + keys.toString() + " to Test Cycle");
private void linkTestToCycle(MetaInfo metaInfo, List<String> keys) throws IOException, InterruptedException {
log("INFO: Linking Test Cases to Test Cycle:" + keys.toString() + "");

Execution execution = new Execution();
execution.setProjectId(metaInfo.getProjectId());
execution.setVersionId(metaInfo.getVersionId());
execution.setCycleId(metaInfo.getCycleId());
execution.setMethod(1);
execution.setIssues(keys);
execution.setMethod(1);
execution.setProjectId(metaInfo.getProjectId());
execution.setVersionId(metaInfo.getVersionId());

HttpResponse response = post(config, "zapi/latest/execution/addTestsToCycle", execution);
ensureResponse(response, 200, "Could not link Test cases");
}

public void updateExecutionStatuses(List<TestCase> resultTestCases) throws IOException {
Map<String, Execution> executions = getAllExecutions(config);
/*
On first execution adding items to test cycle may take long time,
since that job is ran async, it may cause the situation when limited amount of tests will be returned by getAllExecutions()
in ZAPI version 2.3.0 Atlassian made addTestsToCycle to return jobProgressToken to check job status
prooflink1: https://marketplace.atlassian.com/plugins/com.thed.zephyr.zapi/versions
prooflink2: http://docs.getzephyr.apiary.io/#reference/executionresource/add-tests-to-cycle/add-test%27s-to-cycle
*/

Map<TestStatus, List<String>> statusMap = new HashMap<TestStatus, List<String>>();
// TODO: for ZAPI version 2.3.0 or higher implement handling of jobProgressToken
HttpResponse response = post(config, "zapi/latest/execution/addTestsToCycle/", execution);
ensureResponse(response, 200, "Could not link Test cases");

for (TestCase testCase : resultTestCases) {
TestStatus status = testCase.getStatus();
List<String> ids = statusMap.get(status);
if (ids == null) {
statusMap.put(status, new ArrayList<String>());
}
Execution execution = executions.get(testCase.getKey());
if (execution != null) {
statusMap.get(status).add(execution.getId().toString());
}
// waiting for addTestsToCycle() to finish it's job, workaround/hack/waiter for ZAPI version lover than 2.3.0
int iteration = 0;
while (!checkTestCycleIsInSync(keys) && iteration < 5) {
log("INFO: Test Cycle is not in sync. Giving Zephyr another chance.");
Thread.sleep(5000);
iteration++;
}
}

for (Map.Entry<TestStatus, List<String>> entry : statusMap.entrySet()) {
for (String id : entry.getValue()) {
updateExecutionStatus(entry.getKey(), id);
private boolean checkTestCycleIsInSync(List<String> keys) throws IOException {
Map<String, Execution> executions = getAllExecutions(config);
for (String testId : keys) {
if (!executions.containsKey(testId)) {
log("INFO: Test Case " + testId + " was not found in Test Cycle");
return false;
}
}
return true;
}

void updateExecutionStatus(TestStatus status, String id) throws IOException {
log("Setting status " + status.name() + " to " + id + " test case");
public void updateExecutionStatuses(List<TestCase> testCases) throws IOException {
Map<String, Execution> executions = getAllExecutions(config);

ExecutionRequest request = new ExecutionRequest();
request.setStatus(status.getId());
for (TestCase testCase : testCases) {
log("INFO: Setting status " + testCase.getStatus() + " for Test: " + testCase.getKey() + "");

Execution execution = executions.get(testCase.getKey());
if (execution == null) {
log("WARN: Test " + testCase.getKey() + " not found in Test Cycle " + config.getValue(TEST_CYCLE) + "");
continue;
}

HttpResponse response = put(config, "zapi/latest/execution/" + id + "/execute", request);
ensureResponse(response, 200, "Could not successfully update execution status");
ExecutionRequest request = new ExecutionRequest();
request.setStatus(testCase.getStatus().getId());
HttpResponse response = put(config, "zapi/latest/execution/" + execution.getId() + "/execute", request);
ensureResponse(response, 200, "Could not successfully update execution status");
}
}

public void addStepsToTestIssue(TestCase testCase) throws IOException {
log("Adding Test steps to Test issue: " + testCase.getKey());
log("INFO: Getting Test Steps for Test: " + testCase.getKey());
List<TestStep> testSteps = testCase.getSteps();
if (testSteps == null) {
log("INFO: No Test Steps found for Test: " + testCase.getKey());
return;
}

Map<Integer, TestStep> map = new HashMap<Integer, TestStep>();
prepareTestSteps(map, testSteps, 0, "", Boolean.valueOf(config.getValue(ORDERED_STEPS)));

Map<Integer, TestStep> map = prepareTestSteps(testSteps, 0, "", Boolean.valueOf(config.getValue(ORDERED_STEPS)));
log("INFO: Setting Test Steps for Test: " + testCase.getKey());
for (TestStep step : map.values()) {
HttpResponse response = post(config, "zapi/latest/teststep/" + testCase.getId(), new ZapiTestStep(step.getDescription()));
ensureResponse(response, 200, "Could not add Test Steps for Test Case: " + testCase.getId());
}
}

void prepareTestSteps(Map<Integer, TestStep> map, List<TestStep> testSteps, int level, String prefix, Boolean isOrdered) {
private Map<Integer, TestStep> prepareTestSteps(List<TestStep> testSteps, int level, String prefix, Boolean isOrdered) {
Map<Integer, TestStep> map = new HashMap<>();
for (int i = 1; i <= testSteps.size(); i++) {
TestStep testStep = testSteps.get(i - 1);
String description = testStep.getDescription();
testStep.setDescription(isOrdered ? format("%s %s", prefix + i + ".", description) : description);
map.put(map.size() + 1, testStep);

if (testStep.getSteps() != null && testStep.getSteps().size() > 0) {
prepareTestSteps(map, testStep.getSteps(), level + 1, prefix + i + ".", isOrdered);
map.putAll(prepareTestSteps(testStep.getSteps(), level + 1, prefix + i + ".", isOrdered));

}
}

return map;
}

public void mapTestCasesToIssues(List<TestCase> resultTestCases, List<Issue> issues) {
Map<String, Issue> uniqueKeyMap = new HashMap<String, Issue>(issues.size());
Map<String, Issue> uniqueKeyMap = new HashMap<>(issues.size());
for (Issue issue : issues) {
uniqueKeyMap.put(issue.getKey(), issue);
String testCaseUniqueId = issue.getFields().getTestCaseUniqueId();
Expand Down Expand Up @@ -193,7 +213,7 @@ public void mapTestCasesToIssues(List<TestCase> resultTestCases, List<Issue> iss
}
// if no exact match by id or by name, creating new one
if (testCaseKey != null) {
log(format("Key: %s, is not found, new Test Case should be created", testCaseKey));
log(format("INFO: Key %s not found, new Test Case will be created", testCaseKey));
testCase.setId(null);
testCase.setKey(null);
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,31 @@
public class ZephyrSyncMojo extends AbstractMojo implements Config.Loader{

@Parameter(required = true)
String username;
private String username;
@Parameter(required = true)
String password;
private String password;
@Parameter
String reportType;
private String reportType;
@Parameter(required = true)
String projectKey;
private String projectKey;
@Parameter(required = true)
String releaseVersion;
private String releaseVersion;
@Parameter
String testCycle;
private String testCycle;
@Parameter(required = true)
String jiraUrl;
private String jiraUrl;
@Parameter(required = true)
String reportPath;
private String reportPath;
@Parameter
Boolean orderedSteps;
private Boolean orderedSteps;
@Parameter
Boolean forceStoryLink;
private Boolean forceStoryLink;
@Parameter
String testCaseUniqueIdAttribute;
private String testCaseUniqueIdAttribute;
@Parameter
String severityAttribute;
private String severityAttribute;
@Parameter
Boolean autoCreateTestCycle;
private Boolean autoCreateTestCycle;


public void execute() throws MojoExecutionException, MojoFailureException {
Expand All @@ -52,6 +52,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
syncService.execute();
} catch (IOException e) {
throw new MojoExecutionException("Cannot sync test results into zephyr", e);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Expand Down