From 4048b98eb881ee3dbeaeaee9b406e38a4f9a0973 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Fri, 20 Jul 2018 10:43:45 +0530 Subject: [PATCH 01/22] Modify is_success field in the test_case table In current TG implementation, it stores the status of the test case as boolean (i.e. True or False). But when we consider integration test there could be some skipped test cases because of failure of a dependent test case. Hence storing the status of those test cases as Failure is incorrect. Therefore modified the data type of the field and according to that code source also modified. In the new implementation maintain status column as varchar. Further, 'SUCCESS', 'FAIL' and 'SKIP' statuses are maintained. --- .../parser/FunctionalTestResultParser.java | 9 +++- .../parser/TestNgResultsParser.java | 45 +++++++++++++++++-- .../executor/TestNgResultsParserTest.java | 15 ++++--- .../java/org/wso2/testgrid/common/Status.java | 7 ++- .../org/wso2/testgrid/common/TestCase.java | 19 ++++---- .../wso2/testgrid/core/TestPlanExecutor.java | 7 ++- .../testgrid/core/TestPlanExecutorTest.java | 6 +-- .../testgrid/reporting/TestReportEngine.java | 16 +++---- .../reporting/model/ReportElement.java | 16 +++++-- .../templates/report_element.mustache | 32 ++++++------- .../reporting/TestReportEngineTest.java | 6 +-- .../org/wso2/testgrid/web/api/APIUtil.java | 2 +- .../testgrid/web/api/TestPlanService.java | 12 ++--- .../org/wso2/testgrid/web/bean/TestCase.java | 18 ++++---- .../wso2/testgrid/web/bean/TestCaseEntry.java | 20 +++++---- 15 files changed, 150 insertions(+), 80 deletions(-) diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java index 3591142ca..a5f34d5a1 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.JTLResultParserException; import org.wso2.testgrid.automation.exception.ResultParserException; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -196,7 +197,13 @@ private TestCase buildTestCase(StartElement sampleElement) { if (TEST_NAME_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { testCase.setName(attribute.getValue()); } else if (TEST_SUCCESS_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { - testCase.setSuccess(Boolean.valueOf(attribute.getValue())); + if (Boolean.valueOf(attribute.getValue())) { + testCase.setSuccess(Status.SUCCESS); + } else if (!Boolean.valueOf(attribute.getValue())) { + testCase.setSuccess(Status.FAIL); + } else { + testCase.setSuccess(Status.SKIP); + } } } return testCase; diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java index 346338d9c..6d6b9e2cb 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.ResultParserException; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -147,7 +148,7 @@ public void parseResults() throws ResultParserException { } logger.info(String.format("Found total of %s test cases. %s test cases has failed.", testScenario .getTestCases().size(), - testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count())); + testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count())); } catch (IOException | XMLStreamException e) { logger.error("Error while parsing testng-results.xml at " + resultsFile + " for " + testScenario.getName(), e); @@ -216,6 +217,7 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event return testCases; } +<<<<<<< HEAD /** * Reads the text content data inside the element and builds the * error message. @@ -235,9 +237,47 @@ private String readFailureMessage(XMLEventReader eventReader) throws XMLStreamEx } } return builder.toString(); +======= + private TestCase readTestMethod(String classNameStr, StartElement element) { + final Iterator attrs = element.getAttributes(); + Status status = null; // null means 'SKIP' for now. true/false for PASS/FAIL. + String name = "unknown"; + String description = ""; + while (attrs.hasNext()) { + final Attribute attr = (Attribute) attrs.next(); + if ("status".equals(attr.getName().getLocalPart())) { + switch (attr.getValue()) { + case "PASS": + status = Status.SUCCESS; + break; + case "FAIL": + status = Status.FAIL; + break; + default: + status = Status.SKIP; //handle the skipped case + description += " :: " + attr.getValue(); + break; + } + } + if ("name".equals(attr.getName().getLocalPart())) { + name = attr.getValue(); + } + if ("description".equals(attr.getName().getLocalPart())) { + description = description.isEmpty() ? attr.getValue() : attr.getValue() + description; + } + } + if (status == null) { // it's a skipped test! + // TODO we need to properly handle Skipped test cases. + name = name + " :: SKIPPED!"; + status = Status.SKIP; + } + //todo capture failure message + return buildTestCase(classNameStr + "." + name, status, description); + +>>>>>>> Modify is_success field in the test_case table } - private TestCase buildTestCase(String className, boolean isSuccess, String failureMessage) { + private TestCase buildTestCase(String className, Status isSuccess, String failureMessage) { TestCase testCase = new TestCase(); testCase.setTestScenario(this.testScenario); testCase.setName(className); @@ -319,4 +359,3 @@ public void archiveResults() throws ResultParserException { } } - diff --git a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java index 8b0f45833..59e0341de 100644 --- a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java +++ b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java @@ -31,7 +31,7 @@ import org.wso2.testgrid.automation.parser.TestNgResultsParser; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; -import org.wso2.testgrid.common.TestCase; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; @@ -97,11 +97,13 @@ public void testTestNgResultsParser() throws ResultParserException, ParserInitia parser.get().parseResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long skipTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SKIP.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - + Assert.assertEquals(skipTestCases, 5, "skip test cases does not match."); } @Test @@ -119,11 +121,10 @@ public void testArchiveResults() throws Exception { parser.get().parseResults(); parser.get().archiveResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - } private void copyTestngResultsXml(Path outputLocation) throws IOException { diff --git a/common/src/main/java/org/wso2/testgrid/common/Status.java b/common/src/main/java/org/wso2/testgrid/common/Status.java index 77a3db704..ddf70977c 100644 --- a/common/src/main/java/org/wso2/testgrid/common/Status.java +++ b/common/src/main/java/org/wso2/testgrid/common/Status.java @@ -57,7 +57,12 @@ public enum Status { /** * Entity execution is incomplete. */ - INCOMPLETE("INCOMPLETE"); + INCOMPLETE("INCOMPLETE"), + + /** + * Entity execution is skipped. + */ + SKIP("SKIP"); private final String status; diff --git a/common/src/main/java/org/wso2/testgrid/common/TestCase.java b/common/src/main/java/org/wso2/testgrid/common/TestCase.java index 25086f70e..517f4b2ba 100644 --- a/common/src/main/java/org/wso2/testgrid/common/TestCase.java +++ b/common/src/main/java/org/wso2/testgrid/common/TestCase.java @@ -23,6 +23,8 @@ import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.ManyToOne; import javax.persistence.PrimaryKeyJoinColumn; @@ -46,7 +48,7 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { * Column names of the table. */ public static final String NAME_COLUMN = "name"; - public static final String IS_SUCCESS_COLUMN = "isSuccess"; + public static final String IS_SUCCESS_COLUMN = "status"; public static final String FAILURE_MESSAGE_COLUMN = "failureMessage"; public static final String TEST_SCENARIO_COLUMN = "testScenario"; @@ -55,8 +57,9 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { @Column(name = "test_name", nullable = false) private String name; - @Column(name = "is_success", nullable = false) - private boolean isSuccess; + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false, length = 50) + private Status status; @Column(name = "failure_message", length = 20000) private String failureMessage; @@ -88,8 +91,8 @@ public void setName(String name) { * * @return {@code true} if the test case is successful, {@code false} otherwise */ - public boolean isSuccess() { - return isSuccess; + public Status getStatus() { + return status; } /** @@ -97,8 +100,8 @@ public boolean isSuccess() { * * @param success whether the test is successful or failed */ - public void setSuccess(boolean success) { - isSuccess = success; + public void setSuccess(Status success) { + status = success; } /** @@ -143,7 +146,7 @@ public String toString() { return StringUtil.concatStrings("TestCase{", "id='", id, ", name='", name, "\'", - ", isSuccess='", isSuccess, "\'", + ", status='", status, "\'", ", failureMessage='", failureMessage, "\'", ", testScenario='", testScenario.getName(), "\'", '}'); diff --git a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java index 022962f05..4cff2a3a3 100644 --- a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java +++ b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java @@ -632,11 +632,11 @@ private void persistTestPlanStatus(TestPlan testPlan, Status status) { private void persistTestScenario(TestScenario testScenario) throws TestPlanExecutorException { //Persist test scenario try { - if (testScenario.getTestCases().size() == 0) { + if (testScenario.getTestCases().isEmpty()) { testScenario.setStatus(Status.ERROR); } else { for (TestCase testCase : testScenario.getTestCases()) { - if (!testCase.isSuccess()) { + if (Status.FAIL.equals(testCase.getStatus())) { testScenario.setStatus(Status.FAIL); break; } else { @@ -730,7 +730,7 @@ private static void printFailState(TestPlan testPlan) { .filter(ts -> ts.getStatus() != Status.SUCCESS) .map(TestScenario::getTestCases) .flatMap(Collection::stream) - .filter(tc -> !tc.isSuccess()) + .filter(tc -> Status.FAIL.equals(tc.getStatus())) .forEachOrdered( tc -> { failedTestCaseCount.incrementAndGet(); @@ -792,4 +792,3 @@ public String toString() { } } - diff --git a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java index 4f7730981..b76ce8fb4 100644 --- a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java +++ b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java @@ -74,21 +74,21 @@ public void testPrintSummary() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(true); + tc.setSuccess(Status.SUCCESS); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 6ee88cd8f..99117c5e4 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; @@ -278,7 +279,7 @@ private List processOverallResultForScenarioAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -321,7 +322,7 @@ private List processOverallResultForDeploymentAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -365,7 +366,7 @@ private List processOverallResultForInfrastructureAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -542,7 +543,7 @@ private Map> getGroupedReportElementsByColumn(AxisCo */ private List filterSuccessReportElements(List reportElements) { return reportElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); } @@ -704,14 +705,13 @@ private ReportElement createReportElement(DeploymentPattern deploymentPattern, T // Test case can be null if the infra fails. if (testCase != null) { reportElement.setTestCase(testCase.getName()); - reportElement.setTestSuccess(testCase.isSuccess()); - - if (!testCase.isSuccess()) { + reportElement.setTestSuccess(testCase.getStatus()); + if (Status.FAIL.equals(testCase.getStatus())) { reportElement.setTestCaseFailureMessage(testCase.getFailureMessage()); } } else { reportElement.setTestCase(""); - reportElement.setTestSuccess(false); + reportElement.setTestSuccess(Status.FAIL); } return reportElement; } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java index 8e3117f21..cb9931476 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java @@ -17,6 +17,7 @@ */ package org.wso2.testgrid.reporting.model; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.reporting.AxisColumn; /** @@ -34,7 +35,7 @@ public class ReportElement { private String scenarioDescription; private String testCase; private String testCaseFailureMessage; - private boolean isTestSuccess; + private Status isTestSuccess; /** * Constructs an instance of {@link ReportElement} for the given parameters. @@ -143,7 +144,16 @@ public void setTestCaseFailureMessage(String testCaseFailureMessage) { * @return {@code true} if the test case is successful, {@code false} otherwise */ public boolean isTestSuccess() { - return isTestSuccess; + return Status.SUCCESS.equals(isTestSuccess); + } + + /** + * Returns whether the test case is successful or not. + * + * @return {@code true} if the test case is successful, {@code false} otherwise + */ + public boolean isTestFail() { + return Status.FAIL.equals(isTestSuccess); } /** @@ -151,7 +161,7 @@ public boolean isTestSuccess() { * * @param testSuccess whether the test case is successful or not. */ - public void setTestSuccess(boolean testSuccess) { + public void setTestSuccess(Status testSuccess) { isTestSuccess = testSuccess; } diff --git a/reporting/src/main/resources/templates/report_element.mustache b/reporting/src/main/resources/templates/report_element.mustache index 0a198d77a..64a01f4bc 100644 --- a/reporting/src/main/resources/templates/report_element.mustache +++ b/reporting/src/main/resources/templates/report_element.mustache @@ -3,12 +3,12 @@
- {{#isTestSuccess}} + {{#status}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} - {{/isTestSuccess}} + {{/status}}
@@ -24,28 +24,28 @@ {{^isGroupByScenario}} - {{#isTestSuccess}} + {{#status}} {{scenarioDescription}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{scenarioDescription}} - {{/isTestSuccess}} + {{/status}} {{/isGroupByScenario}} - {{#isTestSuccess}} + {{#status}} {{testCase}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{testCase}} - {{/isTestSuccess}} + {{/status}} - {{#isTestSuccess}} + {{#status}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{testCaseFailureMessage}} - {{/isTestSuccess}} + {{/status}} {{/parsedReportElements}} \ No newline at end of file diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 9ab311641..8b13b1e7b 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -112,21 +112,21 @@ public void init() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(true); + tc.setSuccess(Status.SUCCESS); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java index aec97c625..e0e87562c 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java @@ -213,7 +213,7 @@ static TestCase getTestCaseBean(org.wso2.testgrid.common.TestCase testCase) { if (testCase != null) { testCaseBean.setId(testCase.getId()); testCaseBean.setName(testCase.getName()); - testCaseBean.setSuccess(testCase.isSuccess()); + testCaseBean.setStatus(testCase.getStatus()); testCaseBean.setModifiedTimestamp(testCase.getModifiedTimestamp()); testCaseBean.setCreatedTimestamp(testCase.getCreatedTimestamp()); testCaseBean.setErrorMsg(testCase.getFailureMessage()); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java index 0e90df7fa..8b1650aba 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java @@ -21,6 +21,7 @@ import org.apache.hc.core5.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; @@ -428,18 +429,19 @@ private TestExecutionSummary getTestExecutionSummary(TestPlan testPlan) { // TODO: change backend design to store these info within the db to reduce UI latency. // Create scenario summary - long totalSuccess = testCases.stream().filter(TestCase::isSuccess).count(); - long totalFailed = testCases.stream().filter(testCase -> !testCase.isSuccess()).count(); + long totalSuccess = testCases.stream().filter(testCase -> Status.SUCCESS.equals(testCase.getStatus())) + .count(); + long totalFailed = testCases.stream().filter(testCase -> Status.FAIL.equals(testCase.getStatus())).count(); ScenarioSummary scenarioSummary = new ScenarioSummary(testScenario.getDescription(), - testScenario.getConfigChangeSetName() , testScenario.getConfigChangeSetDescription(), totalSuccess, + testScenario.getConfigChangeSetName(), testScenario.getConfigChangeSetDescription(), totalSuccess, totalFailed, testScenario.getStatus(), testScenario.getName()); scenarioSummaries.add(scenarioSummary); // Create test case entries for failed tests List failedTestCaseEntries = testCases.stream() - .filter(testCase -> !testCase.isSuccess()) + .filter(testCase -> Status.FAIL.equals(testCase.getStatus())) .map(testCase -> new TestCaseEntry(testCase.getName(), testCase.getFailureMessage(), - testCase.isSuccess()) + testCase.getStatus()) ) .collect(Collectors.toList()); scenarioTestCaseEntries.add(new ScenarioTestCaseEntry( diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java index dd785acbd..6b1d253dc 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java @@ -18,6 +18,8 @@ package org.wso2.testgrid.web.bean; +import org.wso2.testgrid.common.Status; + import java.sql.Timestamp; import java.util.Date; @@ -31,7 +33,7 @@ public class TestCase { private String errorMsg; private Timestamp createdTimestamp; private Timestamp modifiedTimestamp; - private boolean isSuccess; + private Status status; /** * Returns the id of the test-case. @@ -112,21 +114,21 @@ public void setModifiedTimestamp(Timestamp modifiedTimestamp) { } /** - * Returns the isSuccess of the test-case. + * Returns the status of the test-case. * * @return {@code true} if the test is success, {@code false} otherwise */ - public boolean isSuccess() { - return isSuccess; + public Status getStatus() { + return status; } /** - * Sets the isSuccess of the test-case. + * Sets the status of the test-case. * - * @param success test-case isSuccess + * @param status test-case getStatus */ - public void setSuccess(boolean success) { - this.isSuccess = success; + public void setStatus(Status status) { + this.status = status; } /** diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java index 0ca6b52c7..fe48acf68 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java @@ -17,6 +17,8 @@ */ package org.wso2.testgrid.web.bean; +import org.wso2.testgrid.common.Status; + /** * Bean class for managing information related to test case. * @@ -26,19 +28,19 @@ public class TestCaseEntry { private final String testCase; private final String failureMessage; - private final boolean isTestSuccess; + private final Status status; /** * Constructs an instance of {@link TestCaseEntry} * * @param testCase test case name * @param failureMessage test case failure message - * @param isTestSuccess whether the test case is successful or not + * @param status whether the test case is successful or not */ - public TestCaseEntry(String testCase, String failureMessage, boolean isTestSuccess) { + public TestCaseEntry(String testCase, String failureMessage, Status status) { this.testCase = testCase; this.failureMessage = failureMessage; - this.isTestSuccess = isTestSuccess; + this.status = status; } /** @@ -60,12 +62,12 @@ public String getFailureMessage() { } /** - * Returns whether the test case is successful or not. + * Returns status of the test case. * - * @return {@code true} if the test case is success, {@code false} otherwise + * @return 'SUCCESS' if the test case is success,return 'FALSE' if the test case is failed,otherwise returns 'SKIP' */ - public boolean isTestSuccess() { - return isTestSuccess; + public Status getTestStatus() { + return status; } @Override @@ -73,7 +75,7 @@ public String toString() { return "TestCaseEntry{" + "testCase='" + testCase + '\'' + ", failureMessage='" + failureMessage + '\'' + - ", isTestSuccess='" + isTestSuccess + '\'' + + ", status='" + status + '\'' + '}'; } } From 75ab7048ba62f0cf355946a14101c2d627779641 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Fri, 20 Jul 2018 12:02:18 +0530 Subject: [PATCH 02/22] Fix merge conflicts --- .../parser/TestNgResultsParser.java | 64 ++++--------------- .../executor/TestNgResultsParserTest.java | 18 ++++-- 2 files changed, 22 insertions(+), 60 deletions(-) diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java index 6d6b9e2cb..bb3f9ed79 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java @@ -69,11 +69,9 @@ public class TestNgResultsParser extends ResultParser { public static final String RESULTS_TEST_SUITE_FILE = "TEST-TestSuite.xml"; private static final String[] ARCHIVABLE_FILES = new String[] { "surefire-reports", "automation.log" }; private static final Logger logger = LoggerFactory.getLogger(TestNgResultsParser.class); - private static final String TOTAL = "total"; - private static final String FAILED = "failed"; - private static final String PASSED = "passed"; + private static final String TEST_CASE = "testcase"; + private static final String FAILED = "failure"; private static final String SKIPPED = "skipped"; - private final XMLInputFactory factory = XMLInputFactory.newInstance(); /** * This constructor is used to create a {@link TestNgResultsParser} object with the @@ -193,23 +191,22 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event List testCases = new ArrayList<>(); while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); - if (event.getEventType() == XMLStreamConstants.END_ELEMENT && - event.asEndElement().getName().getLocalPart().equals("testcase")) { - TestCase testCase = buildTestCase(classNameStr, Boolean.TRUE, ""); + if (event.getEventType() == XMLStreamConstants.END_ELEMENT && TEST_CASE + .equals(event.asEndElement().getName().getLocalPart())) { + TestCase testCase = buildTestCase(classNameStr, Status.SUCCESS, ""); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && - event.asStartElement().getName().getLocalPart().equals("skipped")) { - //TODO add new state SKIPPED in the testcase/TestGrid and set to that state - TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, "Test Skipped"); + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && SKIPPED + .equals(event.asStartElement().getName().getLocalPart())) { + TestCase testCase = buildTestCase(classNameStr, Status.SKIP, "Test Skipped"); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && - event.asStartElement().getName().getLocalPart().equals("failure")) { + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && FAILED + .equals(event.asStartElement().getName().getLocalPart())) { String failureMessage = readFailureMessage(eventReader); - TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, failureMessage); + TestCase testCase = buildTestCase(classNameStr, Status.FAIL, failureMessage); testCases.add(testCase); break; } @@ -217,7 +214,6 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event return testCases; } -<<<<<<< HEAD /** * Reads the text content data inside the element and builds the * error message. @@ -237,44 +233,6 @@ private String readFailureMessage(XMLEventReader eventReader) throws XMLStreamEx } } return builder.toString(); -======= - private TestCase readTestMethod(String classNameStr, StartElement element) { - final Iterator attrs = element.getAttributes(); - Status status = null; // null means 'SKIP' for now. true/false for PASS/FAIL. - String name = "unknown"; - String description = ""; - while (attrs.hasNext()) { - final Attribute attr = (Attribute) attrs.next(); - if ("status".equals(attr.getName().getLocalPart())) { - switch (attr.getValue()) { - case "PASS": - status = Status.SUCCESS; - break; - case "FAIL": - status = Status.FAIL; - break; - default: - status = Status.SKIP; //handle the skipped case - description += " :: " + attr.getValue(); - break; - } - } - if ("name".equals(attr.getName().getLocalPart())) { - name = attr.getValue(); - } - if ("description".equals(attr.getName().getLocalPart())) { - description = description.isEmpty() ? attr.getValue() : attr.getValue() + description; - } - } - if (status == null) { // it's a skipped test! - // TODO we need to properly handle Skipped test cases. - name = name + " :: SKIPPED!"; - status = Status.SKIP; - } - //todo capture failure message - return buildTestCase(classNameStr + "." + name, status, description); - ->>>>>>> Modify is_success field in the test_case table } private TestCase buildTestCase(String className, Status isSuccess, String failureMessage) { diff --git a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java index 59e0341de..f2683f099 100644 --- a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java +++ b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java @@ -97,13 +97,15 @@ public void testTestNgResultsParser() throws ResultParserException, ParserInitia parser.get().parseResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); final long skipTestCases = testScenario.getTestCases().stream() .filter(tc -> Status.SKIP.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - Assert.assertEquals(skipTestCases, 5, "skip test cases does not match."); + Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); + Assert.assertEquals(skipTestCases, 1, "skip test cases does not match."); } @Test @@ -121,10 +123,12 @@ public void testArchiveResults() throws Exception { parser.get().parseResults(); parser.get().archiveResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); + Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); } private void copyTestngResultsXml(Path outputLocation) throws IOException { From a6c65642577b9b46c94e06175888894a11fc0fee Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Fri, 20 Jul 2018 10:43:45 +0530 Subject: [PATCH 03/22] Modify is_success field in the test_case table In current TG implementation, it stores the status of the test case as boolean (i.e. True or False). But when we consider integration test there could be some skipped test cases because of failure of a dependent test case. Hence storing the status of those test cases as Failure is incorrect. Therefore modified the data type of the field and according to that code source also modified. In the new implementation maintain status column as varchar. Further, 'SUCCESS', 'FAIL' and 'SKIP' statuses are maintained. --- .../parser/FunctionalTestResultParser.java | 9 +++- .../parser/TestNgResultsParser.java | 45 +++++++++++++++++-- .../executor/TestNgResultsParserTest.java | 15 ++++--- .../java/org/wso2/testgrid/common/Status.java | 7 ++- .../org/wso2/testgrid/common/TestCase.java | 19 ++++---- .../wso2/testgrid/core/TestPlanExecutor.java | 7 ++- .../testgrid/core/TestPlanExecutorTest.java | 6 +-- .../testgrid/reporting/TestReportEngine.java | 16 +++---- .../reporting/model/ReportElement.java | 16 +++++-- .../templates/report_element.mustache | 32 ++++++------- .../reporting/TestReportEngineTest.java | 6 +-- .../org/wso2/testgrid/web/api/APIUtil.java | 2 +- .../testgrid/web/api/TestPlanService.java | 12 ++--- .../org/wso2/testgrid/web/bean/TestCase.java | 18 ++++---- .../wso2/testgrid/web/bean/TestCaseEntry.java | 20 +++++---- 15 files changed, 150 insertions(+), 80 deletions(-) diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java index 3591142ca..a5f34d5a1 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.JTLResultParserException; import org.wso2.testgrid.automation.exception.ResultParserException; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -196,7 +197,13 @@ private TestCase buildTestCase(StartElement sampleElement) { if (TEST_NAME_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { testCase.setName(attribute.getValue()); } else if (TEST_SUCCESS_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { - testCase.setSuccess(Boolean.valueOf(attribute.getValue())); + if (Boolean.valueOf(attribute.getValue())) { + testCase.setSuccess(Status.SUCCESS); + } else if (!Boolean.valueOf(attribute.getValue())) { + testCase.setSuccess(Status.FAIL); + } else { + testCase.setSuccess(Status.SKIP); + } } } return testCase; diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java index 346338d9c..6d6b9e2cb 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.ResultParserException; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -147,7 +148,7 @@ public void parseResults() throws ResultParserException { } logger.info(String.format("Found total of %s test cases. %s test cases has failed.", testScenario .getTestCases().size(), - testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count())); + testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count())); } catch (IOException | XMLStreamException e) { logger.error("Error while parsing testng-results.xml at " + resultsFile + " for " + testScenario.getName(), e); @@ -216,6 +217,7 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event return testCases; } +<<<<<<< HEAD /** * Reads the text content data inside the element and builds the * error message. @@ -235,9 +237,47 @@ private String readFailureMessage(XMLEventReader eventReader) throws XMLStreamEx } } return builder.toString(); +======= + private TestCase readTestMethod(String classNameStr, StartElement element) { + final Iterator attrs = element.getAttributes(); + Status status = null; // null means 'SKIP' for now. true/false for PASS/FAIL. + String name = "unknown"; + String description = ""; + while (attrs.hasNext()) { + final Attribute attr = (Attribute) attrs.next(); + if ("status".equals(attr.getName().getLocalPart())) { + switch (attr.getValue()) { + case "PASS": + status = Status.SUCCESS; + break; + case "FAIL": + status = Status.FAIL; + break; + default: + status = Status.SKIP; //handle the skipped case + description += " :: " + attr.getValue(); + break; + } + } + if ("name".equals(attr.getName().getLocalPart())) { + name = attr.getValue(); + } + if ("description".equals(attr.getName().getLocalPart())) { + description = description.isEmpty() ? attr.getValue() : attr.getValue() + description; + } + } + if (status == null) { // it's a skipped test! + // TODO we need to properly handle Skipped test cases. + name = name + " :: SKIPPED!"; + status = Status.SKIP; + } + //todo capture failure message + return buildTestCase(classNameStr + "." + name, status, description); + +>>>>>>> Modify is_success field in the test_case table } - private TestCase buildTestCase(String className, boolean isSuccess, String failureMessage) { + private TestCase buildTestCase(String className, Status isSuccess, String failureMessage) { TestCase testCase = new TestCase(); testCase.setTestScenario(this.testScenario); testCase.setName(className); @@ -319,4 +359,3 @@ public void archiveResults() throws ResultParserException { } } - diff --git a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java index 8b0f45833..59e0341de 100644 --- a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java +++ b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java @@ -31,7 +31,7 @@ import org.wso2.testgrid.automation.parser.TestNgResultsParser; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; -import org.wso2.testgrid.common.TestCase; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; @@ -97,11 +97,13 @@ public void testTestNgResultsParser() throws ResultParserException, ParserInitia parser.get().parseResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long skipTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SKIP.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - + Assert.assertEquals(skipTestCases, 5, "skip test cases does not match."); } @Test @@ -119,11 +121,10 @@ public void testArchiveResults() throws Exception { parser.get().parseResults(); parser.get().archiveResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - } private void copyTestngResultsXml(Path outputLocation) throws IOException { diff --git a/common/src/main/java/org/wso2/testgrid/common/Status.java b/common/src/main/java/org/wso2/testgrid/common/Status.java index 77a3db704..ddf70977c 100644 --- a/common/src/main/java/org/wso2/testgrid/common/Status.java +++ b/common/src/main/java/org/wso2/testgrid/common/Status.java @@ -57,7 +57,12 @@ public enum Status { /** * Entity execution is incomplete. */ - INCOMPLETE("INCOMPLETE"); + INCOMPLETE("INCOMPLETE"), + + /** + * Entity execution is skipped. + */ + SKIP("SKIP"); private final String status; diff --git a/common/src/main/java/org/wso2/testgrid/common/TestCase.java b/common/src/main/java/org/wso2/testgrid/common/TestCase.java index 25086f70e..517f4b2ba 100644 --- a/common/src/main/java/org/wso2/testgrid/common/TestCase.java +++ b/common/src/main/java/org/wso2/testgrid/common/TestCase.java @@ -23,6 +23,8 @@ import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.ManyToOne; import javax.persistence.PrimaryKeyJoinColumn; @@ -46,7 +48,7 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { * Column names of the table. */ public static final String NAME_COLUMN = "name"; - public static final String IS_SUCCESS_COLUMN = "isSuccess"; + public static final String IS_SUCCESS_COLUMN = "status"; public static final String FAILURE_MESSAGE_COLUMN = "failureMessage"; public static final String TEST_SCENARIO_COLUMN = "testScenario"; @@ -55,8 +57,9 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { @Column(name = "test_name", nullable = false) private String name; - @Column(name = "is_success", nullable = false) - private boolean isSuccess; + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false, length = 50) + private Status status; @Column(name = "failure_message", length = 20000) private String failureMessage; @@ -88,8 +91,8 @@ public void setName(String name) { * * @return {@code true} if the test case is successful, {@code false} otherwise */ - public boolean isSuccess() { - return isSuccess; + public Status getStatus() { + return status; } /** @@ -97,8 +100,8 @@ public boolean isSuccess() { * * @param success whether the test is successful or failed */ - public void setSuccess(boolean success) { - isSuccess = success; + public void setSuccess(Status success) { + status = success; } /** @@ -143,7 +146,7 @@ public String toString() { return StringUtil.concatStrings("TestCase{", "id='", id, ", name='", name, "\'", - ", isSuccess='", isSuccess, "\'", + ", status='", status, "\'", ", failureMessage='", failureMessage, "\'", ", testScenario='", testScenario.getName(), "\'", '}'); diff --git a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java index 022962f05..4cff2a3a3 100644 --- a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java +++ b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java @@ -632,11 +632,11 @@ private void persistTestPlanStatus(TestPlan testPlan, Status status) { private void persistTestScenario(TestScenario testScenario) throws TestPlanExecutorException { //Persist test scenario try { - if (testScenario.getTestCases().size() == 0) { + if (testScenario.getTestCases().isEmpty()) { testScenario.setStatus(Status.ERROR); } else { for (TestCase testCase : testScenario.getTestCases()) { - if (!testCase.isSuccess()) { + if (Status.FAIL.equals(testCase.getStatus())) { testScenario.setStatus(Status.FAIL); break; } else { @@ -730,7 +730,7 @@ private static void printFailState(TestPlan testPlan) { .filter(ts -> ts.getStatus() != Status.SUCCESS) .map(TestScenario::getTestCases) .flatMap(Collection::stream) - .filter(tc -> !tc.isSuccess()) + .filter(tc -> Status.FAIL.equals(tc.getStatus())) .forEachOrdered( tc -> { failedTestCaseCount.incrementAndGet(); @@ -792,4 +792,3 @@ public String toString() { } } - diff --git a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java index 4f7730981..b76ce8fb4 100644 --- a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java +++ b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java @@ -74,21 +74,21 @@ public void testPrintSummary() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(true); + tc.setSuccess(Status.SUCCESS); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 6ee88cd8f..99117c5e4 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; @@ -278,7 +279,7 @@ private List processOverallResultForScenarioAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -321,7 +322,7 @@ private List processOverallResultForDeploymentAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -365,7 +366,7 @@ private List processOverallResultForInfrastructureAxis(List failList = distinctElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); // Success list @@ -542,7 +543,7 @@ private Map> getGroupedReportElementsByColumn(AxisCo */ private List filterSuccessReportElements(List reportElements) { return reportElements.stream() - .filter(reportElement -> !reportElement.isTestSuccess()) + .filter(ReportElement::isTestFail) .collect(Collectors.toList()); } @@ -704,14 +705,13 @@ private ReportElement createReportElement(DeploymentPattern deploymentPattern, T // Test case can be null if the infra fails. if (testCase != null) { reportElement.setTestCase(testCase.getName()); - reportElement.setTestSuccess(testCase.isSuccess()); - - if (!testCase.isSuccess()) { + reportElement.setTestSuccess(testCase.getStatus()); + if (Status.FAIL.equals(testCase.getStatus())) { reportElement.setTestCaseFailureMessage(testCase.getFailureMessage()); } } else { reportElement.setTestCase(""); - reportElement.setTestSuccess(false); + reportElement.setTestSuccess(Status.FAIL); } return reportElement; } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java index 8e3117f21..cb9931476 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java @@ -17,6 +17,7 @@ */ package org.wso2.testgrid.reporting.model; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.reporting.AxisColumn; /** @@ -34,7 +35,7 @@ public class ReportElement { private String scenarioDescription; private String testCase; private String testCaseFailureMessage; - private boolean isTestSuccess; + private Status isTestSuccess; /** * Constructs an instance of {@link ReportElement} for the given parameters. @@ -143,7 +144,16 @@ public void setTestCaseFailureMessage(String testCaseFailureMessage) { * @return {@code true} if the test case is successful, {@code false} otherwise */ public boolean isTestSuccess() { - return isTestSuccess; + return Status.SUCCESS.equals(isTestSuccess); + } + + /** + * Returns whether the test case is successful or not. + * + * @return {@code true} if the test case is successful, {@code false} otherwise + */ + public boolean isTestFail() { + return Status.FAIL.equals(isTestSuccess); } /** @@ -151,7 +161,7 @@ public boolean isTestSuccess() { * * @param testSuccess whether the test case is successful or not. */ - public void setTestSuccess(boolean testSuccess) { + public void setTestSuccess(Status testSuccess) { isTestSuccess = testSuccess; } diff --git a/reporting/src/main/resources/templates/report_element.mustache b/reporting/src/main/resources/templates/report_element.mustache index 0a198d77a..64a01f4bc 100644 --- a/reporting/src/main/resources/templates/report_element.mustache +++ b/reporting/src/main/resources/templates/report_element.mustache @@ -3,12 +3,12 @@
- {{#isTestSuccess}} + {{#status}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} - {{/isTestSuccess}} + {{/status}}
@@ -24,28 +24,28 @@ {{^isGroupByScenario}} - {{#isTestSuccess}} + {{#status}} {{scenarioDescription}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{scenarioDescription}} - {{/isTestSuccess}} + {{/status}} {{/isGroupByScenario}} - {{#isTestSuccess}} + {{#status}} {{testCase}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{testCase}} - {{/isTestSuccess}} + {{/status}} - {{#isTestSuccess}} + {{#status}} - {{/isTestSuccess}} - {{^isTestSuccess}} + {{/status}} + {{^status}} {{testCaseFailureMessage}} - {{/isTestSuccess}} + {{/status}} {{/parsedReportElements}} \ No newline at end of file diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 9ab311641..8b13b1e7b 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -112,21 +112,21 @@ public void init() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(true); + tc.setSuccess(Status.SUCCESS); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(false); + tc.setSuccess(Status.FAIL); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java index aec97c625..e0e87562c 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java @@ -213,7 +213,7 @@ static TestCase getTestCaseBean(org.wso2.testgrid.common.TestCase testCase) { if (testCase != null) { testCaseBean.setId(testCase.getId()); testCaseBean.setName(testCase.getName()); - testCaseBean.setSuccess(testCase.isSuccess()); + testCaseBean.setStatus(testCase.getStatus()); testCaseBean.setModifiedTimestamp(testCase.getModifiedTimestamp()); testCaseBean.setCreatedTimestamp(testCase.getCreatedTimestamp()); testCaseBean.setErrorMsg(testCase.getFailureMessage()); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java index 0e90df7fa..8b1650aba 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java @@ -21,6 +21,7 @@ import org.apache.hc.core5.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; @@ -428,18 +429,19 @@ private TestExecutionSummary getTestExecutionSummary(TestPlan testPlan) { // TODO: change backend design to store these info within the db to reduce UI latency. // Create scenario summary - long totalSuccess = testCases.stream().filter(TestCase::isSuccess).count(); - long totalFailed = testCases.stream().filter(testCase -> !testCase.isSuccess()).count(); + long totalSuccess = testCases.stream().filter(testCase -> Status.SUCCESS.equals(testCase.getStatus())) + .count(); + long totalFailed = testCases.stream().filter(testCase -> Status.FAIL.equals(testCase.getStatus())).count(); ScenarioSummary scenarioSummary = new ScenarioSummary(testScenario.getDescription(), - testScenario.getConfigChangeSetName() , testScenario.getConfigChangeSetDescription(), totalSuccess, + testScenario.getConfigChangeSetName(), testScenario.getConfigChangeSetDescription(), totalSuccess, totalFailed, testScenario.getStatus(), testScenario.getName()); scenarioSummaries.add(scenarioSummary); // Create test case entries for failed tests List failedTestCaseEntries = testCases.stream() - .filter(testCase -> !testCase.isSuccess()) + .filter(testCase -> Status.FAIL.equals(testCase.getStatus())) .map(testCase -> new TestCaseEntry(testCase.getName(), testCase.getFailureMessage(), - testCase.isSuccess()) + testCase.getStatus()) ) .collect(Collectors.toList()); scenarioTestCaseEntries.add(new ScenarioTestCaseEntry( diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java index dd785acbd..6b1d253dc 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java @@ -18,6 +18,8 @@ package org.wso2.testgrid.web.bean; +import org.wso2.testgrid.common.Status; + import java.sql.Timestamp; import java.util.Date; @@ -31,7 +33,7 @@ public class TestCase { private String errorMsg; private Timestamp createdTimestamp; private Timestamp modifiedTimestamp; - private boolean isSuccess; + private Status status; /** * Returns the id of the test-case. @@ -112,21 +114,21 @@ public void setModifiedTimestamp(Timestamp modifiedTimestamp) { } /** - * Returns the isSuccess of the test-case. + * Returns the status of the test-case. * * @return {@code true} if the test is success, {@code false} otherwise */ - public boolean isSuccess() { - return isSuccess; + public Status getStatus() { + return status; } /** - * Sets the isSuccess of the test-case. + * Sets the status of the test-case. * - * @param success test-case isSuccess + * @param status test-case getStatus */ - public void setSuccess(boolean success) { - this.isSuccess = success; + public void setStatus(Status status) { + this.status = status; } /** diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java index 0ca6b52c7..fe48acf68 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java @@ -17,6 +17,8 @@ */ package org.wso2.testgrid.web.bean; +import org.wso2.testgrid.common.Status; + /** * Bean class for managing information related to test case. * @@ -26,19 +28,19 @@ public class TestCaseEntry { private final String testCase; private final String failureMessage; - private final boolean isTestSuccess; + private final Status status; /** * Constructs an instance of {@link TestCaseEntry} * * @param testCase test case name * @param failureMessage test case failure message - * @param isTestSuccess whether the test case is successful or not + * @param status whether the test case is successful or not */ - public TestCaseEntry(String testCase, String failureMessage, boolean isTestSuccess) { + public TestCaseEntry(String testCase, String failureMessage, Status status) { this.testCase = testCase; this.failureMessage = failureMessage; - this.isTestSuccess = isTestSuccess; + this.status = status; } /** @@ -60,12 +62,12 @@ public String getFailureMessage() { } /** - * Returns whether the test case is successful or not. + * Returns status of the test case. * - * @return {@code true} if the test case is success, {@code false} otherwise + * @return 'SUCCESS' if the test case is success,return 'FALSE' if the test case is failed,otherwise returns 'SKIP' */ - public boolean isTestSuccess() { - return isTestSuccess; + public Status getTestStatus() { + return status; } @Override @@ -73,7 +75,7 @@ public String toString() { return "TestCaseEntry{" + "testCase='" + testCase + '\'' + ", failureMessage='" + failureMessage + '\'' + - ", isTestSuccess='" + isTestSuccess + '\'' + + ", status='" + status + '\'' + '}'; } } From bb8c7523e4ae6addd7b28e1f476af04e2a99d790 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Fri, 20 Jul 2018 12:02:18 +0530 Subject: [PATCH 04/22] Fix merge conflicts --- .../parser/TestNgResultsParser.java | 64 ++++--------------- .../executor/TestNgResultsParserTest.java | 18 ++++-- 2 files changed, 22 insertions(+), 60 deletions(-) diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java index 6d6b9e2cb..bb3f9ed79 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java @@ -69,11 +69,9 @@ public class TestNgResultsParser extends ResultParser { public static final String RESULTS_TEST_SUITE_FILE = "TEST-TestSuite.xml"; private static final String[] ARCHIVABLE_FILES = new String[] { "surefire-reports", "automation.log" }; private static final Logger logger = LoggerFactory.getLogger(TestNgResultsParser.class); - private static final String TOTAL = "total"; - private static final String FAILED = "failed"; - private static final String PASSED = "passed"; + private static final String TEST_CASE = "testcase"; + private static final String FAILED = "failure"; private static final String SKIPPED = "skipped"; - private final XMLInputFactory factory = XMLInputFactory.newInstance(); /** * This constructor is used to create a {@link TestNgResultsParser} object with the @@ -193,23 +191,22 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event List testCases = new ArrayList<>(); while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); - if (event.getEventType() == XMLStreamConstants.END_ELEMENT && - event.asEndElement().getName().getLocalPart().equals("testcase")) { - TestCase testCase = buildTestCase(classNameStr, Boolean.TRUE, ""); + if (event.getEventType() == XMLStreamConstants.END_ELEMENT && TEST_CASE + .equals(event.asEndElement().getName().getLocalPart())) { + TestCase testCase = buildTestCase(classNameStr, Status.SUCCESS, ""); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && - event.asStartElement().getName().getLocalPart().equals("skipped")) { - //TODO add new state SKIPPED in the testcase/TestGrid and set to that state - TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, "Test Skipped"); + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && SKIPPED + .equals(event.asStartElement().getName().getLocalPart())) { + TestCase testCase = buildTestCase(classNameStr, Status.SKIP, "Test Skipped"); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && - event.asStartElement().getName().getLocalPart().equals("failure")) { + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && FAILED + .equals(event.asStartElement().getName().getLocalPart())) { String failureMessage = readFailureMessage(eventReader); - TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, failureMessage); + TestCase testCase = buildTestCase(classNameStr, Status.FAIL, failureMessage); testCases.add(testCase); break; } @@ -217,7 +214,6 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event return testCases; } -<<<<<<< HEAD /** * Reads the text content data inside the element and builds the * error message. @@ -237,44 +233,6 @@ private String readFailureMessage(XMLEventReader eventReader) throws XMLStreamEx } } return builder.toString(); -======= - private TestCase readTestMethod(String classNameStr, StartElement element) { - final Iterator attrs = element.getAttributes(); - Status status = null; // null means 'SKIP' for now. true/false for PASS/FAIL. - String name = "unknown"; - String description = ""; - while (attrs.hasNext()) { - final Attribute attr = (Attribute) attrs.next(); - if ("status".equals(attr.getName().getLocalPart())) { - switch (attr.getValue()) { - case "PASS": - status = Status.SUCCESS; - break; - case "FAIL": - status = Status.FAIL; - break; - default: - status = Status.SKIP; //handle the skipped case - description += " :: " + attr.getValue(); - break; - } - } - if ("name".equals(attr.getName().getLocalPart())) { - name = attr.getValue(); - } - if ("description".equals(attr.getName().getLocalPart())) { - description = description.isEmpty() ? attr.getValue() : attr.getValue() + description; - } - } - if (status == null) { // it's a skipped test! - // TODO we need to properly handle Skipped test cases. - name = name + " :: SKIPPED!"; - status = Status.SKIP; - } - //todo capture failure message - return buildTestCase(classNameStr + "." + name, status, description); - ->>>>>>> Modify is_success field in the test_case table } private TestCase buildTestCase(String className, Status isSuccess, String failureMessage) { diff --git a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java index 59e0341de..f2683f099 100644 --- a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java +++ b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java @@ -97,13 +97,15 @@ public void testTestNgResultsParser() throws ResultParserException, ParserInitia parser.get().parseResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); final long skipTestCases = testScenario.getTestCases().stream() .filter(tc -> Status.SKIP.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); - Assert.assertEquals(skipTestCases, 5, "skip test cases does not match."); + Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); + Assert.assertEquals(skipTestCases, 1, "skip test cases does not match."); } @Test @@ -121,10 +123,12 @@ public void testArchiveResults() throws Exception { parser.get().parseResults(); parser.get().archiveResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream().filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); + final long failureTestCases = testScenario.getTestCases().stream() + .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); + Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); } private void copyTestngResultsXml(Path outputLocation) throws IOException { From 409ca2abdc479cebd2a594c83146a35260e210bd Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Mon, 23 Jul 2018 14:14:16 +0530 Subject: [PATCH 05/22] Add email graph data provider In order to create graphs for the generating email added new methods which return test failure summary and test execution summary for a given build. Build ids are read from the testgrid yaml files which are located under the current workspace. --- .../testgrid/common/InfraCombination.java | 55 +++++++++ .../wso2/testgrid/common/util/FileUtil.java | 94 +++++++++++++-- .../dao/dto/TestCaseFailureResultDTO.java | 69 +++++++++++ .../dao/repository/TestPlanRepository.java | 51 ++++++++ .../wso2/testgrid/dao/uow/TestPlanUOW.java | 23 ++++ reporting/pom.xml | 4 + .../testgrid/reporting/GraphDataProvider.java | 114 ++++++++++++++++++ .../testgrid/reporting/TestReportEngine.java | 50 +++----- .../model/email/TestExecutionSummary.java | 54 +++++++++ .../model/email/TestFailureSummary.java | 59 +++++++++ .../testgrid/reporting/util/FileUtil.java | 87 ------------- 11 files changed, 531 insertions(+), 129 deletions(-) create mode 100644 common/src/main/java/org/wso2/testgrid/common/InfraCombination.java create mode 100644 dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java delete mode 100755 reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java diff --git a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java new file mode 100644 index 000000000..9fd539895 --- /dev/null +++ b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.common; + +/** + * This defines the possible statuses of an entity. + * + * @since 1.0.0 + */ +public class InfraCombination { + private String os; + private String jdk; + private String dbEngine; + + public String getOs() { + return os; + } + + public void setOs(String os) { + this.os = os; + } + + public String getJdk() { + return jdk; + } + + public void setJdk(String jdk) { + this.jdk = jdk; + } + + public String getDbEngine() { + return dbEngine; + } + + public void setDbEngine(String dbEngine) { + this.dbEngine = dbEngine; + } + +} diff --git a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java index 748b899b6..ee0336c37 100644 --- a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java +++ b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java @@ -19,15 +19,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; import org.yaml.snakeyaml.Yaml; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; +import java.io.*; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; @@ -37,10 +33,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -162,4 +157,83 @@ public static void compress(String sourceDir, String destination) throws IOExcep } } + /** + * Writes a given string to a given file to persistent media. + * + * @param filePath absolute path of the file to be written + * @param string string to be written + * @throws TestGridException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} + */ + public static void writeToFile(String filePath, String string) throws TestGridException { + createFileIfNotExists(filePath); // Create file if not exists + try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { + writer.write(string); + } catch (FileNotFoundException e) { + throw new TestGridException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); + } catch (UnsupportedEncodingException e) { + throw new TestGridException( + String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); + } + } + + /** + * Creates a file with the given name. + * + * @param filePath absolute path of the file + * @throws TestGridException thrown when IO exception on creating a file + */ + private static void createFileIfNotExists(String filePath) throws TestGridException { + File file = new File(filePath); + if (!file.exists()) { + // Create directories if not exists + Path parent = Paths.get(filePath).getParent(); + + if (parent != null) { + boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); + + if (status) { + // Touch file + try { + new FileOutputStream(file).close(); + } catch (IOException e) { + throw new TestGridException(String.format(Locale.ENGLISH, + "IO Exception occurred when creating file %s", file), e); + } + } + } + } + } + + /** + * Get test plan ids by reading testgrid yaml files contains in the testgrid home. + * + * @param workspace path of the current workspace + * @throws TestGridException thrown when IO exception on reading testgrid yaml files. + */ + public static List getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException { + List testPlanIds = new ArrayList<>(); + Path source = Paths.get(workspace, "test-plans"); + if (!Files.exists(source)) { + logger.error("Test-plans dir does not exist: " + source); + return Collections.emptyList(); + } + try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { + List paths = stream.sorted().collect(Collectors.toList()); + for (Path path : paths) { + if (!path.toFile().exists()) { + throw new IOException( + "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); + } + logger.info("A test plan file found at " + path.toAbsolutePath().toString()); + TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil + .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); + testPlanIds.add(testPlanYaml.getId()); + } + return testPlanIds; + } catch (IOException e) { + throw new TestGridException("Error occurred while reading the test-plan yamls in workspace " + workspace, + e); + } + + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java new file mode 100644 index 000000000..3db6daad4 --- /dev/null +++ b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.dao.dto; + +import javax.persistence.ColumnResult; +import javax.persistence.ConstructorResult; +import javax.persistence.SqlResultSetMapping; + +/** + * Defines a model object of TestPlan with required attributes. + * + * @since 1.0.0 + */ +@SqlResultSetMapping(name = "TestCaseFailureResult", classes = { + @ConstructorResult(targetClass = TestCaseFailureResultDTO.class, columns = { @ColumnResult(name = "testName"), + @ColumnResult(name = "failureMessage"), + @ColumnResult(name = "infraParameters") }) }) +public class TestCaseFailureResultDTO { + + private String testName; + private String failureMessage; + private String infraParameters; + + public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) { + this.testName = testname; + this.failureMessage = failureMessage; + this.infraParameters = infraParameters; + } + + public String getTestName() { + return testName; + } + + public void setTestName(String testName) { + this.testName = testName; + } + + public String getFailureMessage() { + return failureMessage; + } + + public void setFailureMessage(String failureMessage) { + this.failureMessage = failureMessage; + } + + public String getInfraParameters() { + return infraParameters; + } + + public void setInfraParameters(String infraParameters) { + this.infraParameters = infraParameters; + } +} diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 7e8866400..f1ea6f904 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -24,6 +24,7 @@ import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.SortOrder; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import java.sql.Timestamp; import java.util.Collections; @@ -290,4 +291,54 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { .getResultList(); return EntityManagerHelper.refreshResultList(entityManager, resultList); } + + /** + * This method returns all the test plans that belongs to same infrastructure set,same deployment pattern + * and same product. + * + * @param testPlanIds testPlan being queried + * @return a List of {@link TestPlan} representing the history of that test plan + */ + public List getTestFailureSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " + + "testName, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " + + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;"); + Query query = entityManager.createNativeQuery(sql.toString(), "TestCaseFailureResult"); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List testCaseFailureResultDTO = (List) query + .getResultList(); + return testCaseFailureResultDTO; + } + + /** + * This method returns all the test plans that belongs to same infrastructure set,same deployment pattern + * and same product. + * + * @param testPlanIds testPlan being queried + * @return a List of {@link TestPlan} representing the history of that test plan + */ + public List getTestExecutionSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select status from test_plan where id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?):"); + Query query = entityManager.createNativeQuery(sql.toString()); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List statuses = (List) query.getResultList(); + return statuses; + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index 4d093382d..35b42f6e1 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -22,6 +22,7 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import org.wso2.testgrid.dao.repository.TestPlanRepository; import java.sql.Timestamp; @@ -180,4 +181,26 @@ public List getTestPlanHistory(TestPlan testPlan) { public List getTestPlansOlderThan(String duration, String timeUnit) { return testPlanRepository.getTestPlanOlderThan(duration, timeUnit); } + + + /** + * Returns the test plans older than a specified period of time. + * This will be used to resolve the statuses of testplans with erroneous statuses. + * + * @return a List of TestPlans corresponding to the query + */ + public List getTestExecutionSummary(List tpIds) { + return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); + } + + + /** + * Returns the test plans older than a specified period of time. + * This will be used to resolve the statuses of testplans with erroneous statuses. + * + * @return a List of TestPlans corresponding to the query + */ + public List getTestFailureSummary(List tpId) { + return testPlanRepository.getTestFailureSummaryByTPId(tpId); + } } diff --git a/reporting/pom.xml b/reporting/pom.xml index fe3377a33..520659ee3 100755 --- a/reporting/pom.xml +++ b/reporting/pom.xml @@ -100,5 +100,9 @@ org.jacoco.agent runtime + + com.google.code.gson + gson + \ No newline at end of file diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java new file mode 100644 index 000000000..7e0c5817c --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.wso2.testgrid.reporting; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.wso2.testgrid.common.InfraCombination; +import org.wso2.testgrid.common.Status; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; +import org.wso2.testgrid.common.util.StringUtil; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; +import org.wso2.testgrid.dao.uow.TestPlanUOW; +import org.wso2.testgrid.reporting.model.email.TestExecutionSummary; +import org.wso2.testgrid.reporting.model.email.TestFailureSummary; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; + +/** + * This class is responsible for providing required data in order to generate email graphs. + * + * @since 1.0.0 + */ +public class GraphDataProvider { + private TestPlanUOW testPlanUOW; + private int passedTestCases = 0; + private int failedTestCases = 0; + private int skippedTestCases = 0; + + public GraphDataProvider() { + this.testPlanUOW = new TestPlanUOW(); + } + + public List getTestFailureSummary(String workspace) throws TestGridException { + List testFailureSummary = testPlanUOW + .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + if (testFailureSummary.isEmpty()) { + throw new TestGridException("Couldn't find test case data for given test plan ids"); + } + return processTestFailureSummary(testFailureSummary); + } + + private List processTestFailureSummary(List testFailureSummary) { + TreeMap testFailureSummaryMap = new TreeMap<>(); + for (TestCaseFailureResultDTO testFailure : testFailureSummary) { + TestFailureSummary testFailureSummaryData = new TestFailureSummary(); + Gson gson = new GsonBuilder().create(); + InfraCombination infraCombination = new InfraCombination(); + String testName = testFailure.getTestName(); + JsonElement jelem = gson.fromJson(testFailure.getInfraParameters(), JsonElement.class); + JsonObject jobj = jelem.getAsJsonObject(); + infraCombination.setOs(StringUtil + .concatStrings(jobj.get("OS").getAsString(), " - ", jobj.get("OSVersion").getAsString())); + infraCombination.setJdk(jobj.get("JDK").getAsString()); + infraCombination.setDbEngine(StringUtil.concatStrings(jobj.get("DBEngine").getAsString(), " - ", + jobj.get("DBEngineVersion").getAsString())); + infraCombination.setOs(jobj.get("OS").getAsString()); + if (testFailureSummaryMap.containsKey(testName)) { + testFailureSummaryMap.get(testName).getInfraCombinations().add(infraCombination); + } else { + testFailureSummaryData.setTestCaseName(testName); + testFailureSummaryData.setTestCaseDescription(testFailure.getFailureMessage()); + testFailureSummaryData.setInfraCombinations(Collections.singletonList(infraCombination)); + testFailureSummaryMap.put(testName, testFailureSummaryData); + } + } + return new ArrayList<>(testFailureSummaryMap.values()); + } + + public TestExecutionSummary getTestExecutionSummary(String workspace) throws TestGridException { + List testExecutionSummary = testPlanUOW + .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + TestExecutionSummary testExecutionSummaryData = new TestExecutionSummary(); + if (testExecutionSummary.isEmpty()) { + throw new TestGridException("Couldn't find test plan status for given test plan ids"); + } + + for (String status : testExecutionSummary) { + if (Status.SUCCESS.toString().equals(status)) { + this.passedTestCases++; + } else if (Status.FAIL.toString().equals(status)) { + this.failedTestCases++; + } else if (Status.SKIP.toString().equals(status)) { + this.skippedTestCases++; + } + } + testExecutionSummaryData.setPassedTestCases(this.passedTestCases); + testExecutionSummaryData.setFailedTestCases(this.failedTestCases); + testExecutionSummaryData.setSkippedTestCase(this.skippedTestCases); + return testExecutionSummaryData; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 99117c5e4..ca10a8c3f 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -25,6 +25,8 @@ import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -37,7 +39,6 @@ import org.wso2.testgrid.reporting.model.performance.PerformanceReport; import org.wso2.testgrid.reporting.renderer.Renderable; import org.wso2.testgrid.reporting.renderer.RenderableFactory; -import org.wso2.testgrid.reporting.util.FileUtil; import java.io.IOException; import java.nio.file.Files; @@ -55,13 +56,12 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; +import static org.wso2.testgrid.common.util.FileUtil.writeToFile; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; -import static org.wso2.testgrid.reporting.util.FileUtil.writeToFile; /** * This class is responsible for generating the test reports. @@ -106,7 +106,8 @@ public TestReportEngine() { * @param groupBy columns to group by * @throws ReportingException thrown when error on generating test report */ - public void generateReport(Product product, boolean showSuccess, String groupBy) throws ReportingException { + public void generateReport(Product product, boolean showSuccess, String groupBy) + throws ReportingException, TestGridException { AxisColumn uniqueAxisColumn = getGroupByColumn(groupBy); // Construct report elements @@ -140,7 +141,7 @@ public void generateReport(Product product, boolean showSuccess, String groupBy) * @param testScenarios A List of TestScenarios included in the report */ public void generatePerformanceReport(PerformanceReport report, List testScenarios) - throws ReportingException { + throws ReportingException, TestGridException { try { Map parsedResultMap = new HashMap<>(); parsedResultMap.put(REPORT_TEMPLATE_KEY, report); @@ -723,7 +724,7 @@ private ReportElement createReportElement(DeploymentPattern deploymentPattern, T * @param htmlString HTML string to be written to the file * @throws ReportingException thrown when error on writing the HTML string to file */ - private void writeHTMLToFile(Path filePath, String htmlString) throws ReportingException { + private void writeHTMLToFile(Path filePath, String htmlString) throws TestGridException { logger.info("Writing test results to file: " + filePath.toString()); FileUtil.writeToFile(filePath.toAbsolutePath().toString(), htmlString); } @@ -735,45 +736,30 @@ private void writeHTMLToFile(Path filePath, String htmlString) throws ReportingE * @param product product needing the report. * @param workspace workspace containing the test-plan yamls */ - public Optional generateEmailReport(Product product, String workspace) throws ReportingException { + public Optional generateEmailReport(Product product, String workspace) + throws ReportingException, TestGridException { List testPlans = new ArrayList<>(); - Path source = Paths.get(workspace, "test-plans"); - if (!Files.exists(source)) { - logger.error("Test-plans dir does not exist: " + source); - return Optional.empty(); - } - try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { - List paths = stream.sorted().collect(Collectors.toList()); - for (Path path : paths) { - if (!path.toFile().exists()) { - throw new ReportingException( - "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); - } - logger.info("A test plan file found at " + path.toAbsolutePath().toString()); - TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil - .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); - Optional testPlanById = testPlanUOW.getTestPlanById(testPlanYaml.getId()); + List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); + try { + for (String testPlanId : testPlanIds) { + Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); if (testPlanById.isPresent()) { - logger.info("Derived test plan dir in email phase : " + - TestGridUtil.deriveTestPlanDirName(testPlanById.get())); + logger.info("Derived test plan dir in email phase : " + TestGridUtil + .deriveTestPlanDirName(testPlanById.get())); testPlans.add(testPlanById.get()); } else { logger.error(String.format( "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", - testPlanYaml.getId())); + + "Ignoring the test plan...", testPlanId)); } } - } catch (IOException e) { - throw new ReportingException("Error occurred while reading the test-plan yamls in workspace " - + workspace, e); } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); } //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { - logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + - "Hence skipping email-report generation.."); + logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + + "Hence skipping email-report generation.."); return Optional.empty(); } Renderable renderer = RenderableFactory.getRenderable(EMAIL_REPORT_MUSTACHE); diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java new file mode 100644 index 000000000..5e179d764 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +/** + * This defines the possible statuses of an entity. + * + * @since 1.0.0 + */ +public class TestExecutionSummary { + private int failedTestCases; + private int passedTestCases; + private int skippedTestCase; + + public int getFailedTestCases() { + return failedTestCases; + } + + public void setFailedTestCases(int failedTestCases) { + this.failedTestCases = failedTestCases; + } + + public int getPassedTestCases() { + return passedTestCases; + } + + public void setPassedTestCases(int passedTestCases) { + this.passedTestCases = passedTestCases; + } + + public int getSkippedTestCase() { + return skippedTestCase; + } + + public void setSkippedTestCase(int skippedTestCase) { + this.skippedTestCase = skippedTestCase; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java new file mode 100644 index 000000000..63bed444a --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +import org.wso2.testgrid.common.InfraCombination; + +import java.util.ArrayList; +import java.util.List; + +/** + * This defines the possible statuses of an entity. + * + * @since 1.0.0 + */ +public class TestFailureSummary { + private String testCaseName; + private String testCaseDescription; + private List infraCombinations = new ArrayList<>(); + + public String getTestCaseName() { + return testCaseName; + } + + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } + + public String getTestCaseDescription() { + return testCaseDescription; + } + + public void setTestCaseDescription(String testCaseDescription) { + this.testCaseDescription = testCaseDescription; + } + + public List getInfraCombinations() { + return infraCombinations; + } + + public void setInfraCombinations(List infraCombinations) { + this.infraCombinations = infraCombinations; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java b/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java deleted file mode 100755 index 32b40cff7..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.wso2.testgrid.reporting.util; - -import org.wso2.testgrid.reporting.ReportingException; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Locale; - -/** - * This class is responsible for handling file operations. - * - * @since 1.0.0 - */ -public class FileUtil { - - /** - * Writes a given string to a given file to persistent media. - * - * @param filePath absolute path of the file to be written - * @param string string to be written - * @throws ReportingException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} - */ - public static void writeToFile(String filePath, String string) throws ReportingException { - createFileIfNotExists(filePath); // Create file if not exists - try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { - writer.write(string); - writer.close(); - } catch (FileNotFoundException e) { - throw new ReportingException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); - } catch (UnsupportedEncodingException e) { - throw new ReportingException( - String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); - } - } - - /** - * Creates a file with the given name. - * - * @param filePath absolute path of the file - * @throws ReportingException thrown when IO exception on creating a file - */ - private static void createFileIfNotExists(String filePath) throws ReportingException { - File file = new File(filePath); - if (!file.exists()) { - // Create directories if not exists - Path parent = Paths.get(filePath).getParent(); - - if (parent != null) { - boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); - - if (status) { - // Touch file - try { - new FileOutputStream(file).close(); - } catch (IOException e) { - throw new ReportingException(String.format(Locale.ENGLISH, - "IO Exception occurred when creating file %s", file), e); - } - } - } - } - } -} From 5f3ab79c591fdf4d05d33e672d6eb134080a4ff3 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Mon, 23 Jul 2018 14:17:33 +0530 Subject: [PATCH 06/22] Add support for chart generation --- .../testgrid/reporting/ChartGenerator.java | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java new file mode 100644 index 000000000..3c1fc7371 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -0,0 +1,171 @@ +package org.wso2.testgrid.reporting; + +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.embed.swing.JFXPanel; +import javafx.embed.swing.SwingFXUtils; +import javafx.scene.Scene; +import javafx.scene.chart.CategoryAxis; +import javafx.scene.chart.Chart; +import javafx.scene.chart.NumberAxis; +import javafx.scene.chart.PieChart; +import javafx.scene.chart.StackedBarChart; +import javafx.scene.chart.XYChart; +import javafx.scene.image.WritableImage; +import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.TestGridConstants; + +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Map; +import javax.imageio.ImageIO; + +/** + * This class is responsib;e generating the necessary charts fot the email report. + */ +public class ChartGenerator { + + private static final Logger logger = LoggerFactory.getLogger(ChartGenerator.class); + private static String chartGenLocation = System.getenv(TestGridConstants.TESTGRID_HOME_ENV); + private static String summaryChartFileName = "summary.png"; + private static String historyChartFileName = "history.png"; + + public ChartGenerator(String chartGenLocation) { + + new JFXPanel(); + this.chartGenLocation = chartGenLocation; + } + + /** + * Generatees a pie chart with the summary test results of the current build. + * + * @param passedCount passed test count + * @param failedCount failed test count + * @param skippedCount skipped test count + * @throws IOException if the chart cannot be written into a file + */ + public void generateSummaryChart(int passedCount, int failedCount, int skippedCount) throws IOException { + + ObservableList pieChartData = + FXCollections.observableArrayList( + new PieChart.Data("Failed", failedCount), + new PieChart.Data("Skipped", skippedCount), + new PieChart.Data("Passed", passedCount)); + final PieChart chart = new PieChart(pieChartData); + chart.setTitle("Test Failure Summary"); + genChart(chart, 500, 500, summaryChartFileName); + } + + /** + * Generates the history chart with the summary of test executions. + * + * @param dataSet input data-set for the chart + */ + public void generateResultHistoryChart(Map dataSet) { + + final CategoryAxis xAxis = new CategoryAxis(); + final NumberAxis yAxis = new NumberAxis(); + final StackedBarChart stackedBarChart = new StackedBarChart<>(xAxis, yAxis); + // This represents the series of values e.g: Failed, skipped, Passed + final XYChart.Series[] seriesSet = new XYChart.Series[]{new XYChart.Series<>(), + new XYChart.Series<>(), new XYChart.Series<>()}; + + // Set Axis Names + xAxis.setLabel("Build Number"); + yAxis.setLabel("Number of Infra Combinations"); + + // Setting series names + seriesSet[0].setName("Build Failed Combinations"); + seriesSet[1].setName("Build Passed Combinations"); + seriesSet[2].setName("Infra Failed Combinations"); + + // Setting space between the bars + stackedBarChart.setCategoryGap(50); + + //Setting the title of the bar chart. + stackedBarChart.setTitle("History of test execution summary"); + + dataSet.forEach((key, value) -> { + String[] resultSet = value.split(","); + if (resultSet.length != seriesSet.length) { + logger.error("Input value set didn't match the series count!! Total number of series " + + "expected : " + seriesSet.length + " Total number of series received " + + resultSet.length); + } + int i = 0; + for (XYChart.Series series : seriesSet) { + series.getData().add(new XYChart.Data<>(key, Integer.parseInt(resultSet[i]))); + i++; + } + }); + + // Adding the series to the chart + for (XYChart.Series series : seriesSet) { + stackedBarChart.getData().add(series); + } + genChart(stackedBarChart, 800, 800, historyChartFileName); + } + + /** + * Generate the test failure summary table for failed test cases. + * + * @return a html table with contents. + */ + public String generaeSummaryTable() { + + // Color pallet is used to inject colors to differentiate the testcase rows. + String[] colorPallette = new String[]{"#b2ad7f", "#a2b9bc", "#d6cbd3", "#bdcebe", "#e3eaa7", "#e6e2d3", + "#dac292", "#c6bcb6", "#b7d7e8", "#b8a9c9", "#f2ae72"}; + + StringBuilder tableContent = new StringBuilder(); + tableContent.append(""); + tableContent.append(""); + tableContent.append(""); + tableContent.append(""); + tableContent.append(""); + tableContent.append(""); + tableContent.append(""); + // loop the content +// for testcase +// for OS +// for JDK +// for DB + tableContent.append("
Failing Test CaseOSJDKDB
"); + return null; + } + + /** + * Returns the chart generation location. + * + * @return chart generation dir + */ + public static String getChartGenLocation() { + return chartGenLocation; + } + + private static void genChart(Chart chart, int width, int height, String fileName) { + Platform.runLater(() -> { + Stage stage = new Stage(); + Scene scene = new Scene(chart, width, height); + stage.setScene(scene); + WritableImage img = new WritableImage(width, height); + scene.snapshot(img); + writeImage(img, fileName); + }); + } + + private static void writeImage(WritableImage image, String fileName) { + + File file = new File(Paths.get(chartGenLocation, fileName).toString()); + try { + ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file); + } catch (IOException e) { + logger.error("Error occured while writing the chart image", e); + } + } +} \ No newline at end of file From c8ec4c141659f65cb75caafc1ef38591611b6ef0 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Mon, 23 Jul 2018 14:30:12 +0530 Subject: [PATCH 07/22] Fix compilation issues --- .../testgrid/reporting/ChartGenerator.java | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java index 3c1fc7371..8ca9bbfb0 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -16,9 +16,7 @@ import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.wso2.testgrid.common.TestGridConstants; -import java.awt.*; import java.io.File; import java.io.IOException; import java.nio.file.Paths; @@ -31,12 +29,11 @@ public class ChartGenerator { private static final Logger logger = LoggerFactory.getLogger(ChartGenerator.class); - private static String chartGenLocation = System.getenv(TestGridConstants.TESTGRID_HOME_ENV); - private static String summaryChartFileName = "summary.png"; - private static String historyChartFileName = "history.png"; + private static final String summaryChartFileName = "summary.png"; + private static final String historyChartFileName = "history.png"; + private String chartGenLocation; public ChartGenerator(String chartGenLocation) { - new JFXPanel(); this.chartGenLocation = chartGenLocation; } @@ -111,44 +108,44 @@ public void generateResultHistoryChart(Map dataSet) { genChart(stackedBarChart, 800, 800, historyChartFileName); } - /** - * Generate the test failure summary table for failed test cases. - * - * @return a html table with contents. - */ - public String generaeSummaryTable() { - - // Color pallet is used to inject colors to differentiate the testcase rows. - String[] colorPallette = new String[]{"#b2ad7f", "#a2b9bc", "#d6cbd3", "#bdcebe", "#e3eaa7", "#e6e2d3", - "#dac292", "#c6bcb6", "#b7d7e8", "#b8a9c9", "#f2ae72"}; - - StringBuilder tableContent = new StringBuilder(); - tableContent.append(""); - tableContent.append(""); - tableContent.append(""); - tableContent.append(""); - tableContent.append(""); - tableContent.append(""); - tableContent.append(""); - // loop the content -// for testcase -// for OS -// for JDK -// for DB - tableContent.append("
Failing Test CaseOSJDKDB
"); - return null; - } +// /** +// * Generate the test failure summary table for failed test cases. +// * +// * @return a html table with contents. +// */ +// public String generaeSummaryTable() { +// +// // Color pallet is used to inject colors to differentiate the testcase rows. +// String[] colorPallette = new String[]{"#b2ad7f", "#a2b9bc", "#d6cbd3", "#bdcebe", "#e3eaa7", "#e6e2d3", +// "#dac292", "#c6bcb6", "#b7d7e8", "#b8a9c9", "#f2ae72"}; +// +// StringBuilder tableContent = new StringBuilder(); +// tableContent.append(""); +// tableContent.append(""); +// tableContent.append(""); +// tableContent.append(""); +// tableContent.append(""); +// tableContent.append(""); +// tableContent.append(""); +// // loop the content +//// for testcase +//// for OS +//// for JDK +//// for DB +// tableContent.append("
Failing Test CaseOSJDKDB
"); +// return null; +// } /** * Returns the chart generation location. * * @return chart generation dir */ - public static String getChartGenLocation() { + public String getChartGenLocation() { return chartGenLocation; } - private static void genChart(Chart chart, int width, int height, String fileName) { + private void genChart(Chart chart, int width, int height, String fileName) { Platform.runLater(() -> { Stage stage = new Stage(); Scene scene = new Scene(chart, width, height); @@ -159,7 +156,7 @@ private static void genChart(Chart chart, int width, int height, String fileName }); } - private static void writeImage(WritableImage image, String fileName) { + private void writeImage(WritableImage image, String fileName) { File file = new File(Paths.get(chartGenLocation, fileName).toString()); try { @@ -168,4 +165,4 @@ private static void writeImage(WritableImage image, String fileName) { logger.error("Error occured while writing the chart image", e); } } -} \ No newline at end of file +} From e942a898116fa58be044a6e2ef5dfa37718569ce Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Mon, 23 Jul 2018 14:14:16 +0530 Subject: [PATCH 08/22] Add email graph data provider In order to create graphs for the generating email added new methods which return test failure summary and test execution summary for a given build. Build ids are read from the testgrid yaml files which are located under the current workspace. --- .../testgrid/common/InfraCombination.java | 85 +++++++++++ .../wso2/testgrid/common/util/FileUtil.java | 87 +++++++++++ .../dao/dto/TestCaseFailureResultDTO.java | 69 +++++++++ .../dao/repository/TestPlanRepository.java | 49 +++++++ .../wso2/testgrid/dao/uow/TestPlanUOW.java | 22 +++ reporting/pom.xml | 4 + .../testgrid/reporting/GraphDataProvider.java | 135 ++++++++++++++++++ .../testgrid/reporting/TestReportEngine.java | 54 +++---- .../model/email/BuildExecutionSummary.java | 54 +++++++ .../model/email/BuildFailureSummary.java | 59 ++++++++ .../testgrid/reporting/util/FileUtil.java | 87 ----------- .../reporting/TestReportEngineTest.java | 3 +- 12 files changed, 588 insertions(+), 120 deletions(-) create mode 100644 common/src/main/java/org/wso2/testgrid/common/InfraCombination.java create mode 100644 dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java delete mode 100755 reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java diff --git a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java new file mode 100644 index 000000000..207ddefbe --- /dev/null +++ b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.common; + +/** + * This defines s single infra combination. + * + * @since 1.0.0 + */ +public class InfraCombination { + private String os; + private String jdk; + private String dbEngine; + + /** + * Returns name of the operating system. + * + * @return OS name + OS version + */ + public String getOs() { + return os; + } + + /** + * Sets name of the operating system. + * + * @param os OS name + OS version + */ + public void setOs(String os) { + this.os = os; + } + + /** + * Returns jdk name. + * + * @return JDK name + */ + public String getJdk() { + return jdk; + } + + /** + * Sets jdk name. + * + * @param jdk JDK name + */ + public void setJdk(String jdk) { + this.jdk = jdk; + } + + /** + * Returns database engine name. + * + * @return DB engine name + DB engine version + */ + public String getDbEngine() { + return dbEngine; + } + + /** + * Sets database engine name. + * + * @param dbEngine DB engine name + DB engine version + */ + public void setDbEngine(String dbEngine) { + this.dbEngine = dbEngine; + } + +} diff --git a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java index 748b899b6..60c02c352 100644 --- a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java +++ b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java @@ -19,15 +19,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; @@ -38,9 +42,13 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -162,4 +170,83 @@ public static void compress(String sourceDir, String destination) throws IOExcep } } + /** + * Writes a given string to a given file to persistent media. + * + * @param filePath absolute path of the file to be written + * @param string string to be written + * @throws TestGridException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} + */ + public static void writeToFile(String filePath, String string) throws TestGridException { + createFileIfNotExists(filePath); // Create file if not exists + try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { + writer.write(string); + } catch (FileNotFoundException e) { + throw new TestGridException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); + } catch (UnsupportedEncodingException e) { + throw new TestGridException( + String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); + } + } + + /** + * Creates a file with the given name. + * + * @param filePath absolute path of the file + * @throws TestGridException thrown when IO exception on creating a file + */ + private static void createFileIfNotExists(String filePath) throws TestGridException { + File file = new File(filePath); + if (!file.exists()) { + // Create directories if not exists + Path parent = Paths.get(filePath).getParent(); + + if (parent != null) { + boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); + + if (status) { + // Touch file + try { + new FileOutputStream(file).close(); + } catch (IOException e) { + throw new TestGridException(String.format(Locale.ENGLISH, + "IO Exception occurred when creating file %s", file), e); + } + } + } + } + } + + /** + * Get test plan ids by reading testgrid yaml files contains in the testgrid home. + * + * @param workspace path of the current workspace + * @throws TestGridException thrown when IO exception on reading testgrid yaml files. + */ + public static List getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException { + List testPlanIds = new ArrayList<>(); + Path source = Paths.get(workspace, "test-plans"); + if (!Files.exists(source)) { + logger.error("Test-plans dir does not exist: " + source); + return Collections.emptyList(); + } + try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { + List paths = stream.sorted().collect(Collectors.toList()); + for (Path path : paths) { + if (!path.toFile().exists()) { + throw new IOException( + "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); + } + logger.info("A test plan file found at " + path.toAbsolutePath().toString()); + TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil + .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); + testPlanIds.add(testPlanYaml.getId()); + } + return testPlanIds; + } catch (IOException e) { + throw new TestGridException("Error occurred while reading the test-plan yamls in workspace " + workspace, + e); + } + + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java new file mode 100644 index 000000000..057339e60 --- /dev/null +++ b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.dao.dto; + +import javax.persistence.ColumnResult; +import javax.persistence.ConstructorResult; +import javax.persistence.SqlResultSetMapping; + +/** + * Defines a model object of test case failure results. + * + * @since 1.0.0 + */ +@SqlResultSetMapping(name = "TestCaseFailureResult", classes = { + @ConstructorResult(targetClass = TestCaseFailureResultDTO.class, columns = { @ColumnResult(name = "testName"), + @ColumnResult(name = "failureMessage"), + @ColumnResult(name = "infraParameters") }) }) +public class TestCaseFailureResultDTO { + + private String testName; + private String failureMessage; + private String infraParameters; + + public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) { + this.testName = testname; + this.failureMessage = failureMessage; + this.infraParameters = infraParameters; + } + + public String getTestName() { + return testName; + } + + public void setTestName(String testName) { + this.testName = testName; + } + + public String getFailureMessage() { + return failureMessage; + } + + public void setFailureMessage(String failureMessage) { + this.failureMessage = failureMessage; + } + + public String getInfraParameters() { + return infraParameters; + } + + public void setInfraParameters(String infraParameters) { + this.infraParameters = infraParameters; + } +} diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 7e8866400..961d051c7 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -24,6 +24,7 @@ import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.SortOrder; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import java.sql.Timestamp; import java.util.Collections; @@ -290,4 +291,52 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { .getResultList(); return EntityManagerHelper.refreshResultList(entityManager, resultList); } + + /** + * This method returns test failure summary for given test plan ids. (i.e for a given build job). + * + * @param testPlanIds test plan ids + * @return a List of {@link TestCaseFailureResultDTO} representing the test case failure results for a given build + */ + public List getTestFailureSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " + + "testName, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " + + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;"); + Query query = entityManager.createNativeQuery(sql.toString(), "TestCaseFailureResult"); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List testCaseFailureResultDTO = (List) query + .getResultList(); + return testCaseFailureResultDTO; + } + + /** + * This method returns the test execution summary for given test plan ids(i.e for a given build job). + * + * @param testPlanIds test plan ids of a specific build job + * @return a List of {@link String} representing statuses of given test plans + */ + public List getTestExecutionSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select status from test_plan where id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?):"); + Query query = entityManager.createNativeQuery(sql.toString()); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List statuses = (List) query.getResultList(); + return statuses; + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index 4d093382d..e59b98214 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -22,6 +22,7 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import org.wso2.testgrid.dao.repository.TestPlanRepository; import java.sql.Timestamp; @@ -180,4 +181,25 @@ public List getTestPlanHistory(TestPlan testPlan) { public List getTestPlansOlderThan(String duration, String timeUnit) { return testPlanRepository.getTestPlanOlderThan(duration, timeUnit); } + + + /** + * Returns the test plan statuses for given test plan ids. + * + * @return a List of Test Plan statuses. + */ + public List getTestExecutionSummary(List tpIds) { + return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); + } + + + /** + * Returns the representation of failed test cases with test case name, description and infra combination for given + * test plan ids. (I.e for a given build job) + * + * @return a List of TestCaseFailureResultDTO which represent test cases failure for given test plan ids. + */ + public List getTestFailureSummary(List tpIds) { + return testPlanRepository.getTestFailureSummaryByTPId(tpIds); + } } diff --git a/reporting/pom.xml b/reporting/pom.xml index fe3377a33..520659ee3 100755 --- a/reporting/pom.xml +++ b/reporting/pom.xml @@ -100,5 +100,9 @@ org.jacoco.agent runtime + + com.google.code.gson + gson + \ No newline at end of file diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java new file mode 100644 index 000000000..21ea375d7 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.wso2.testgrid.reporting; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.wso2.testgrid.common.InfraCombination; +import org.wso2.testgrid.common.Status; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; +import org.wso2.testgrid.common.util.StringUtil; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; +import org.wso2.testgrid.dao.uow.TestPlanUOW; +import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; +import org.wso2.testgrid.reporting.model.email.BuildFailureSummary; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; + +/** + * This class is responsible for providing required data in order to generate email graphs. + * + * @since 1.0.0 + */ +public class GraphDataProvider { + private TestPlanUOW testPlanUOW; + private int passedTestPlans = 0; + private int failedTestPlans = 0; + private int skippedTestPlans = 0; + + public GraphDataProvider() { + this.testPlanUOW = new TestPlanUOW(); + } + + /** + * Provides the test failure summary for a given build job. Test Plan ids of the build job is retrieved by reading + * testgrid yaml files which contains in the current workspace. + * + * @param workspace current workspace + * @throws TestGridException thrown when getting test plan ids by reading test plan yaml files + */ + public List getTestFailureSummary(String workspace) throws TestGridException { + List testFailureSummary = testPlanUOW + .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + if (testFailureSummary.isEmpty()) { + return Collections.emptyList(); + } + return processTestFailureSummary(testFailureSummary); + } + + /** + * Process the test failure summary which is retrieved by reading database and construct the list of + * {@link BuildFailureSummary} to draw test failure summary chart. + * + * @param testFailureSummary list of {@link TestCaseFailureResultDTO} which are retrieved by quering the databse. + */ + private List processTestFailureSummary(List testFailureSummary) { + TreeMap testFailureSummaryMap = new TreeMap<>(); + for (TestCaseFailureResultDTO testFailure : testFailureSummary) { + BuildFailureSummary buildFailureSummaryData = new BuildFailureSummary(); + Gson gson = new GsonBuilder().create(); + InfraCombination infraCombination = new InfraCombination(); + String testName = testFailure.getTestName(); + JsonElement jelem = gson.fromJson(testFailure.getInfraParameters(), JsonElement.class); + JsonObject jobj = jelem.getAsJsonObject(); + infraCombination.setOs(StringUtil + .concatStrings(jobj.get("OS").getAsString(), " - ", jobj.get("OSVersion").getAsString())); + infraCombination.setJdk(jobj.get("JDK").getAsString()); + infraCombination.setDbEngine(StringUtil.concatStrings(jobj.get("DBEngine").getAsString(), " - ", + jobj.get("DBEngineVersion").getAsString())); + if (testFailureSummaryMap.containsKey(testName)) { + testFailureSummaryMap.get(testName).getInfraCombinations().add(infraCombination); + } else { + List infraCombinations = new ArrayList<>(); + buildFailureSummaryData.setTestCaseName(testName); + buildFailureSummaryData.setTestCaseDescription(testFailure.getFailureMessage()); + infraCombinations.add(infraCombination); + buildFailureSummaryData.setInfraCombinations(infraCombinations); + testFailureSummaryMap.put(testName, buildFailureSummaryData); + } + } + return new ArrayList<>(testFailureSummaryMap.values()); + } + + /** + * Provide test execution summary for a given build job.. + * + * @param workspace current workspace + * @throws TestGridException thrown when error on getting test plan ids by reading testgrid yaml files located + * in the current workspace. + */ + public BuildExecutionSummary getTestExecutionSummary(String workspace) throws TestGridException { + List testExecutionSummary = testPlanUOW + .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + BuildExecutionSummary testExecutionSummaryData = new BuildExecutionSummary(); + if (testExecutionSummary.isEmpty()) { + throw new TestGridException("Couldn't find test plan status for given test plan ids"); + } + + for (String status : testExecutionSummary) { + if (Status.SUCCESS.toString().equals(status)) { + this.passedTestPlans++; + } else if (Status.FAIL.toString().equals(status)) { + this.failedTestPlans++; + } else { + this.skippedTestPlans++; + } + } + testExecutionSummaryData.setPassedTestPlans(this.passedTestPlans); + testExecutionSummaryData.setFailedTestPlans(this.failedTestPlans); + testExecutionSummaryData.setSkippedTestPlans(this.skippedTestPlans); + return testExecutionSummaryData; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 99117c5e4..39e0d14a1 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -25,6 +25,8 @@ import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -37,7 +39,6 @@ import org.wso2.testgrid.reporting.model.performance.PerformanceReport; import org.wso2.testgrid.reporting.renderer.Renderable; import org.wso2.testgrid.reporting.renderer.RenderableFactory; -import org.wso2.testgrid.reporting.util.FileUtil; import java.io.IOException; import java.nio.file.Files; @@ -55,13 +56,11 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; -import static org.wso2.testgrid.reporting.util.FileUtil.writeToFile; /** * This class is responsible for generating the test reports. @@ -106,7 +105,8 @@ public TestReportEngine() { * @param groupBy columns to group by * @throws ReportingException thrown when error on generating test report */ - public void generateReport(Product product, boolean showSuccess, String groupBy) throws ReportingException { + public void generateReport(Product product, boolean showSuccess, String groupBy) + throws ReportingException { AxisColumn uniqueAxisColumn = getGroupByColumn(groupBy); // Construct report elements @@ -166,7 +166,6 @@ public void generatePerformanceReport(PerformanceReport report, List generateEmailReport(Product product, String workspace) throws ReportingException { List testPlans = new ArrayList<>(); - Path source = Paths.get(workspace, "test-plans"); - if (!Files.exists(source)) { - logger.error("Test-plans dir does not exist: " + source); - return Optional.empty(); - } - try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { - List paths = stream.sorted().collect(Collectors.toList()); - for (Path path : paths) { - if (!path.toFile().exists()) { - throw new ReportingException( - "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); - } - logger.info("A test plan file found at " + path.toAbsolutePath().toString()); - TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil - .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); - Optional testPlanById = testPlanUOW.getTestPlanById(testPlanYaml.getId()); + try { + List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); + for (String testPlanId : testPlanIds) { + Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); if (testPlanById.isPresent()) { - logger.info("Derived test plan dir in email phase : " + - TestGridUtil.deriveTestPlanDirName(testPlanById.get())); + logger.info("Derived test plan dir in email phase : " + TestGridUtil + .deriveTestPlanDirName(testPlanById.get())); testPlans.add(testPlanById.get()); } else { logger.error(String.format( "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", - testPlanYaml.getId())); + + "Ignoring the test plan...", testPlanId)); } } - } catch (IOException e) { - throw new ReportingException("Error occurred while reading the test-plan yamls in workspace " - + workspace, e); } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); + } catch (TestGridException e) { + throw new ReportingException( + "Error occurred while getting the test plan id by reading test grid yaml files ", e); } //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { - logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + - "Hence skipping email-report generation.."); + logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + + "Hence skipping email-report generation.."); return Optional.empty(); } Renderable renderer = RenderableFactory.getRenderable(EMAIL_REPORT_MUSTACHE); @@ -790,7 +780,7 @@ public Optional generateEmailReport(Product product, String workspace) thr String relativeFilePath = TestGridUtil.deriveTestGridLogFilePath(product.getName(), TESTGRID_EMAIL_REPORT_NAME); String testGridHome = TestGridUtil.getTestGridHomePath(); Path reportPath = Paths.get(testGridHome, relativeFilePath); - writeToFile(reportPath.toString(), htmlString); + writeHTMLToFile(reportPath, htmlString); return Optional.of(reportPath); } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java new file mode 100644 index 000000000..4f0e7d947 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +/** + * This defines the build execution summary for a build. + * + * @since 1.0.0 + */ +public class BuildExecutionSummary { + private int failedTestPlans; + private int passedTestPlans; + private int skippedTestPlans; + + public int getFailedTestPlans() { + return failedTestPlans; + } + + public void setFailedTestPlans(int failedTestPlans) { + this.failedTestPlans = failedTestPlans; + } + + public int getPassedTestPlans() { + return passedTestPlans; + } + + public void setPassedTestPlans(int passedTestPlans) { + this.passedTestPlans = passedTestPlans; + } + + public int getSkippedTestPlans() { + return skippedTestPlans; + } + + public void setSkippedTestPlans(int skippedTestPlans) { + this.skippedTestPlans = skippedTestPlans; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java new file mode 100644 index 000000000..7afdbfb2e --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +import org.wso2.testgrid.common.InfraCombination; + +import java.util.ArrayList; +import java.util.List; + +/** + * This defines the build failure summary for a specifc test case. + * + * @since 1.0.0 + */ +public class BuildFailureSummary { + private String testCaseName; + private String testCaseDescription; + private List infraCombinations = new ArrayList<>(); + + public String getTestCaseName() { + return testCaseName; + } + + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } + + public String getTestCaseDescription() { + return testCaseDescription; + } + + public void setTestCaseDescription(String testCaseDescription) { + this.testCaseDescription = testCaseDescription; + } + + public List getInfraCombinations() { + return infraCombinations; + } + + public void setInfraCombinations(List infraCombinations) { + this.infraCombinations = infraCombinations; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java b/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java deleted file mode 100755 index 32b40cff7..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.wso2.testgrid.reporting.util; - -import org.wso2.testgrid.reporting.ReportingException; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Locale; - -/** - * This class is responsible for handling file operations. - * - * @since 1.0.0 - */ -public class FileUtil { - - /** - * Writes a given string to a given file to persistent media. - * - * @param filePath absolute path of the file to be written - * @param string string to be written - * @throws ReportingException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} - */ - public static void writeToFile(String filePath, String string) throws ReportingException { - createFileIfNotExists(filePath); // Create file if not exists - try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { - writer.write(string); - writer.close(); - } catch (FileNotFoundException e) { - throw new ReportingException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); - } catch (UnsupportedEncodingException e) { - throw new ReportingException( - String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); - } - } - - /** - * Creates a file with the given name. - * - * @param filePath absolute path of the file - * @throws ReportingException thrown when IO exception on creating a file - */ - private static void createFileIfNotExists(String filePath) throws ReportingException { - File file = new File(filePath); - if (!file.exists()) { - // Create directories if not exists - Path parent = Paths.get(filePath).getParent(); - - if (parent != null) { - boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); - - if (status) { - // Touch file - try { - new FileOutputStream(file).close(); - } catch (IOException e) { - throw new ReportingException(String.format(Locale.ENGLISH, - "IO Exception occurred when creating file %s", file), e); - } - } - } - } - } -} diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 8b13b1e7b..c3ee2efff 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -36,6 +36,7 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; import org.wso2.testgrid.common.config.InfrastructureConfig; +import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -150,7 +151,7 @@ public void init() throws Exception { } @Test - public void generateEmailReport() throws TestGridDAOException, ReportingException { + public void generateEmailReport() throws TestGridDAOException, ReportingException, TestGridException { when(testPlanUOW.getLatestTestPlans(Matchers.any(Product.class))) .thenReturn(Collections.singletonList(testPlan)); when(testPlanUOW.getTestPlanById("abc")).thenReturn(Optional.of(testPlan)); From b7b095168d0b991a8995cca8f9eb351cf9b2808c Mon Sep 17 00:00:00 2001 From: Yasassri Ratnayake Date: Wed, 25 Jul 2018 10:58:02 +0530 Subject: [PATCH 09/22] Revert "merging with graph data provider" --- .../parser/FunctionalTestResultParser.java | 9 +- .../parser/TestNgResultsParser.java | 31 ++--- .../executor/TestNgResultsParserTest.java | 23 ++-- .../testgrid/common/InfraCombination.java | 55 --------- .../java/org/wso2/testgrid/common/Status.java | 7 +- .../org/wso2/testgrid/common/TestCase.java | 19 ++- .../wso2/testgrid/common/util/FileUtil.java | 94 ++------------- .../wso2/testgrid/core/TestPlanExecutor.java | 7 +- .../testgrid/core/TestPlanExecutorTest.java | 6 +- .../dao/dto/TestCaseFailureResultDTO.java | 69 ----------- .../dao/repository/TestPlanRepository.java | 51 -------- .../wso2/testgrid/dao/uow/TestPlanUOW.java | 23 ---- reporting/pom.xml | 4 - .../testgrid/reporting/GraphDataProvider.java | 114 ------------------ .../testgrid/reporting/TestReportEngine.java | 66 ++++++---- .../reporting/model/ReportElement.java | 16 +-- .../model/email/TestExecutionSummary.java | 54 --------- .../model/email/TestFailureSummary.java | 59 --------- .../testgrid/reporting/util/FileUtil.java | 87 +++++++++++++ .../templates/report_element.mustache | 32 ++--- .../reporting/TestReportEngineTest.java | 6 +- .../org/wso2/testgrid/web/api/APIUtil.java | 2 +- .../testgrid/web/api/TestPlanService.java | 12 +- .../org/wso2/testgrid/web/bean/TestCase.java | 18 ++- .../wso2/testgrid/web/bean/TestCaseEntry.java | 20 ++- 25 files changed, 225 insertions(+), 659 deletions(-) delete mode 100644 common/src/main/java/org/wso2/testgrid/common/InfraCombination.java delete mode 100644 dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java delete mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java delete mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java delete mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java create mode 100755 reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java index a5f34d5a1..3591142ca 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/FunctionalTestResultParser.java @@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.JTLResultParserException; import org.wso2.testgrid.automation.exception.ResultParserException; -import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -197,13 +196,7 @@ private TestCase buildTestCase(StartElement sampleElement) { if (TEST_NAME_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { testCase.setName(attribute.getValue()); } else if (TEST_SUCCESS_ATTRIBUTE.equals(attribute.getName().getLocalPart())) { - if (Boolean.valueOf(attribute.getValue())) { - testCase.setSuccess(Status.SUCCESS); - } else if (!Boolean.valueOf(attribute.getValue())) { - testCase.setSuccess(Status.FAIL); - } else { - testCase.setSuccess(Status.SKIP); - } + testCase.setSuccess(Boolean.valueOf(attribute.getValue())); } } return testCase; diff --git a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java index bb3f9ed79..346338d9c 100644 --- a/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java +++ b/automation/src/main/java/org/wso2/testgrid/automation/parser/TestNgResultsParser.java @@ -21,7 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.testgrid.automation.exception.ResultParserException; -import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestScenario; @@ -69,9 +68,11 @@ public class TestNgResultsParser extends ResultParser { public static final String RESULTS_TEST_SUITE_FILE = "TEST-TestSuite.xml"; private static final String[] ARCHIVABLE_FILES = new String[] { "surefire-reports", "automation.log" }; private static final Logger logger = LoggerFactory.getLogger(TestNgResultsParser.class); - private static final String TEST_CASE = "testcase"; - private static final String FAILED = "failure"; + private static final String TOTAL = "total"; + private static final String FAILED = "failed"; + private static final String PASSED = "passed"; private static final String SKIPPED = "skipped"; + private final XMLInputFactory factory = XMLInputFactory.newInstance(); /** * This constructor is used to create a {@link TestNgResultsParser} object with the @@ -146,7 +147,7 @@ public void parseResults() throws ResultParserException { } logger.info(String.format("Found total of %s test cases. %s test cases has failed.", testScenario .getTestCases().size(), - testScenario.getTestCases().stream().filter(tc -> Status.FAIL.equals(tc.getStatus())).count())); + testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count())); } catch (IOException | XMLStreamException e) { logger.error("Error while parsing testng-results.xml at " + resultsFile + " for " + testScenario.getName(), e); @@ -191,22 +192,23 @@ private List getTestCasesFor(String classNameStr, XMLEventReader event List testCases = new ArrayList<>(); while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); - if (event.getEventType() == XMLStreamConstants.END_ELEMENT && TEST_CASE - .equals(event.asEndElement().getName().getLocalPart())) { - TestCase testCase = buildTestCase(classNameStr, Status.SUCCESS, ""); + if (event.getEventType() == XMLStreamConstants.END_ELEMENT && + event.asEndElement().getName().getLocalPart().equals("testcase")) { + TestCase testCase = buildTestCase(classNameStr, Boolean.TRUE, ""); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && SKIPPED - .equals(event.asStartElement().getName().getLocalPart())) { - TestCase testCase = buildTestCase(classNameStr, Status.SKIP, "Test Skipped"); + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && + event.asStartElement().getName().getLocalPart().equals("skipped")) { + //TODO add new state SKIPPED in the testcase/TestGrid and set to that state + TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, "Test Skipped"); testCases.add(testCase); break; } - if (event.getEventType() == XMLStreamConstants.START_ELEMENT && FAILED - .equals(event.asStartElement().getName().getLocalPart())) { + if (event.getEventType() == XMLStreamConstants.START_ELEMENT && + event.asStartElement().getName().getLocalPart().equals("failure")) { String failureMessage = readFailureMessage(eventReader); - TestCase testCase = buildTestCase(classNameStr, Status.FAIL, failureMessage); + TestCase testCase = buildTestCase(classNameStr, Boolean.FALSE, failureMessage); testCases.add(testCase); break; } @@ -235,7 +237,7 @@ private String readFailureMessage(XMLEventReader eventReader) throws XMLStreamEx return builder.toString(); } - private TestCase buildTestCase(String className, Status isSuccess, String failureMessage) { + private TestCase buildTestCase(String className, boolean isSuccess, String failureMessage) { TestCase testCase = new TestCase(); testCase.setTestScenario(this.testScenario); testCase.setName(className); @@ -317,3 +319,4 @@ public void archiveResults() throws ResultParserException { } } + diff --git a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java index f2683f099..8b0f45833 100644 --- a/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java +++ b/automation/src/test/java/org/wso2/testgrid/automation/executor/TestNgResultsParserTest.java @@ -31,7 +31,7 @@ import org.wso2.testgrid.automation.parser.TestNgResultsParser; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; -import org.wso2.testgrid.common.Status; +import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; @@ -97,15 +97,11 @@ public void testTestNgResultsParser() throws ResultParserException, ParserInitia parser.get().parseResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream() - .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream() - .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); - final long skipTestCases = testScenario.getTestCases().stream() - .filter(tc -> Status.SKIP.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); - Assert.assertEquals(skipTestCases, 1, "skip test cases does not match."); + Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); + } @Test @@ -123,12 +119,11 @@ public void testArchiveResults() throws Exception { parser.get().parseResults(); parser.get().archiveResults(); Assert.assertEquals(testScenario.getTestCases().size(), 9, "generated test cases does not match."); - final long successTestCases = testScenario.getTestCases().stream() - .filter(tc -> Status.SUCCESS.equals(tc.getStatus())).count(); - final long failureTestCases = testScenario.getTestCases().stream() - .filter(tc -> Status.FAIL.equals(tc.getStatus())).count(); + final long successTestCases = testScenario.getTestCases().stream().filter(TestCase::isSuccess).count(); + final long failureTestCases = testScenario.getTestCases().stream().filter(tc -> !tc.isSuccess()).count(); Assert.assertEquals(successTestCases, 6, "success test cases does not match."); - Assert.assertEquals(failureTestCases, 2, "failure test cases does not match."); + Assert.assertEquals(failureTestCases, 3, "failure test cases does not match."); + } private void copyTestngResultsXml(Path outputLocation) throws IOException { diff --git a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java deleted file mode 100644 index 9fd539895..000000000 --- a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.testgrid.common; - -/** - * This defines the possible statuses of an entity. - * - * @since 1.0.0 - */ -public class InfraCombination { - private String os; - private String jdk; - private String dbEngine; - - public String getOs() { - return os; - } - - public void setOs(String os) { - this.os = os; - } - - public String getJdk() { - return jdk; - } - - public void setJdk(String jdk) { - this.jdk = jdk; - } - - public String getDbEngine() { - return dbEngine; - } - - public void setDbEngine(String dbEngine) { - this.dbEngine = dbEngine; - } - -} diff --git a/common/src/main/java/org/wso2/testgrid/common/Status.java b/common/src/main/java/org/wso2/testgrid/common/Status.java index ddf70977c..77a3db704 100644 --- a/common/src/main/java/org/wso2/testgrid/common/Status.java +++ b/common/src/main/java/org/wso2/testgrid/common/Status.java @@ -57,12 +57,7 @@ public enum Status { /** * Entity execution is incomplete. */ - INCOMPLETE("INCOMPLETE"), - - /** - * Entity execution is skipped. - */ - SKIP("SKIP"); + INCOMPLETE("INCOMPLETE"); private final String status; diff --git a/common/src/main/java/org/wso2/testgrid/common/TestCase.java b/common/src/main/java/org/wso2/testgrid/common/TestCase.java index 517f4b2ba..25086f70e 100644 --- a/common/src/main/java/org/wso2/testgrid/common/TestCase.java +++ b/common/src/main/java/org/wso2/testgrid/common/TestCase.java @@ -23,8 +23,6 @@ import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.ManyToOne; import javax.persistence.PrimaryKeyJoinColumn; @@ -48,7 +46,7 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { * Column names of the table. */ public static final String NAME_COLUMN = "name"; - public static final String IS_SUCCESS_COLUMN = "status"; + public static final String IS_SUCCESS_COLUMN = "isSuccess"; public static final String FAILURE_MESSAGE_COLUMN = "failureMessage"; public static final String TEST_SCENARIO_COLUMN = "testScenario"; @@ -57,9 +55,8 @@ public class TestCase extends AbstractUUIDEntity implements Serializable { @Column(name = "test_name", nullable = false) private String name; - @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false, length = 50) - private Status status; + @Column(name = "is_success", nullable = false) + private boolean isSuccess; @Column(name = "failure_message", length = 20000) private String failureMessage; @@ -91,8 +88,8 @@ public void setName(String name) { * * @return {@code true} if the test case is successful, {@code false} otherwise */ - public Status getStatus() { - return status; + public boolean isSuccess() { + return isSuccess; } /** @@ -100,8 +97,8 @@ public Status getStatus() { * * @param success whether the test is successful or failed */ - public void setSuccess(Status success) { - status = success; + public void setSuccess(boolean success) { + isSuccess = success; } /** @@ -146,7 +143,7 @@ public String toString() { return StringUtil.concatStrings("TestCase{", "id='", id, ", name='", name, "\'", - ", status='", status, "\'", + ", isSuccess='", isSuccess, "\'", ", failureMessage='", failureMessage, "\'", ", testScenario='", testScenario.getName(), "\'", '}'); diff --git a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java index ee0336c37..748b899b6 100644 --- a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java +++ b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java @@ -19,11 +19,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; import org.yaml.snakeyaml.Yaml; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; @@ -33,9 +37,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -157,83 +162,4 @@ public static void compress(String sourceDir, String destination) throws IOExcep } } - /** - * Writes a given string to a given file to persistent media. - * - * @param filePath absolute path of the file to be written - * @param string string to be written - * @throws TestGridException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} - */ - public static void writeToFile(String filePath, String string) throws TestGridException { - createFileIfNotExists(filePath); // Create file if not exists - try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { - writer.write(string); - } catch (FileNotFoundException e) { - throw new TestGridException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); - } catch (UnsupportedEncodingException e) { - throw new TestGridException( - String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); - } - } - - /** - * Creates a file with the given name. - * - * @param filePath absolute path of the file - * @throws TestGridException thrown when IO exception on creating a file - */ - private static void createFileIfNotExists(String filePath) throws TestGridException { - File file = new File(filePath); - if (!file.exists()) { - // Create directories if not exists - Path parent = Paths.get(filePath).getParent(); - - if (parent != null) { - boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); - - if (status) { - // Touch file - try { - new FileOutputStream(file).close(); - } catch (IOException e) { - throw new TestGridException(String.format(Locale.ENGLISH, - "IO Exception occurred when creating file %s", file), e); - } - } - } - } - } - - /** - * Get test plan ids by reading testgrid yaml files contains in the testgrid home. - * - * @param workspace path of the current workspace - * @throws TestGridException thrown when IO exception on reading testgrid yaml files. - */ - public static List getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException { - List testPlanIds = new ArrayList<>(); - Path source = Paths.get(workspace, "test-plans"); - if (!Files.exists(source)) { - logger.error("Test-plans dir does not exist: " + source); - return Collections.emptyList(); - } - try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { - List paths = stream.sorted().collect(Collectors.toList()); - for (Path path : paths) { - if (!path.toFile().exists()) { - throw new IOException( - "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); - } - logger.info("A test plan file found at " + path.toAbsolutePath().toString()); - TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil - .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); - testPlanIds.add(testPlanYaml.getId()); - } - return testPlanIds; - } catch (IOException e) { - throw new TestGridException("Error occurred while reading the test-plan yamls in workspace " + workspace, - e); - } - - } } diff --git a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java index 4cff2a3a3..022962f05 100644 --- a/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java +++ b/core/src/main/java/org/wso2/testgrid/core/TestPlanExecutor.java @@ -632,11 +632,11 @@ private void persistTestPlanStatus(TestPlan testPlan, Status status) { private void persistTestScenario(TestScenario testScenario) throws TestPlanExecutorException { //Persist test scenario try { - if (testScenario.getTestCases().isEmpty()) { + if (testScenario.getTestCases().size() == 0) { testScenario.setStatus(Status.ERROR); } else { for (TestCase testCase : testScenario.getTestCases()) { - if (Status.FAIL.equals(testCase.getStatus())) { + if (!testCase.isSuccess()) { testScenario.setStatus(Status.FAIL); break; } else { @@ -730,7 +730,7 @@ private static void printFailState(TestPlan testPlan) { .filter(ts -> ts.getStatus() != Status.SUCCESS) .map(TestScenario::getTestCases) .flatMap(Collection::stream) - .filter(tc -> Status.FAIL.equals(tc.getStatus())) + .filter(tc -> !tc.isSuccess()) .forEachOrdered( tc -> { failedTestCaseCount.incrementAndGet(); @@ -792,3 +792,4 @@ public String toString() { } } + diff --git a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java index b76ce8fb4..4f7730981 100644 --- a/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java +++ b/core/src/test/java/org/wso2/testgrid/core/TestPlanExecutorTest.java @@ -74,21 +74,21 @@ public void testPrintSummary() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(Status.SUCCESS); + tc.setSuccess(true); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(Status.FAIL); + tc.setSuccess(false); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(Status.FAIL); + tc.setSuccess(false); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java deleted file mode 100644 index 3db6daad4..000000000 --- a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.testgrid.dao.dto; - -import javax.persistence.ColumnResult; -import javax.persistence.ConstructorResult; -import javax.persistence.SqlResultSetMapping; - -/** - * Defines a model object of TestPlan with required attributes. - * - * @since 1.0.0 - */ -@SqlResultSetMapping(name = "TestCaseFailureResult", classes = { - @ConstructorResult(targetClass = TestCaseFailureResultDTO.class, columns = { @ColumnResult(name = "testName"), - @ColumnResult(name = "failureMessage"), - @ColumnResult(name = "infraParameters") }) }) -public class TestCaseFailureResultDTO { - - private String testName; - private String failureMessage; - private String infraParameters; - - public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) { - this.testName = testname; - this.failureMessage = failureMessage; - this.infraParameters = infraParameters; - } - - public String getTestName() { - return testName; - } - - public void setTestName(String testName) { - this.testName = testName; - } - - public String getFailureMessage() { - return failureMessage; - } - - public void setFailureMessage(String failureMessage) { - this.failureMessage = failureMessage; - } - - public String getInfraParameters() { - return infraParameters; - } - - public void setInfraParameters(String infraParameters) { - this.infraParameters = infraParameters; - } -} diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index f1ea6f904..7e8866400 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -24,7 +24,6 @@ import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.SortOrder; import org.wso2.testgrid.dao.TestGridDAOException; -import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import java.sql.Timestamp; import java.util.Collections; @@ -291,54 +290,4 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { .getResultList(); return EntityManagerHelper.refreshResultList(entityManager, resultList); } - - /** - * This method returns all the test plans that belongs to same infrastructure set,same deployment pattern - * and same product. - * - * @param testPlanIds testPlan being queried - * @return a List of {@link TestPlan} representing the history of that test plan - */ - public List getTestFailureSummaryByTPId(List testPlanIds) { - StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " - + "testName, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " - + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " - + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); - for (int i = 0; i < testPlanIds.size() - 1; i++) { - sql.append("?, "); - } - sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;"); - Query query = entityManager.createNativeQuery(sql.toString(), "TestCaseFailureResult"); - int index = 1; - for (String s : testPlanIds) { - query.setParameter(index++, s); - } - @SuppressWarnings("unchecked") - List testCaseFailureResultDTO = (List) query - .getResultList(); - return testCaseFailureResultDTO; - } - - /** - * This method returns all the test plans that belongs to same infrastructure set,same deployment pattern - * and same product. - * - * @param testPlanIds testPlan being queried - * @return a List of {@link TestPlan} representing the history of that test plan - */ - public List getTestExecutionSummaryByTPId(List testPlanIds) { - StringBuilder sql = new StringBuilder("select status from test_plan where id in ("); - for (int i = 0; i < testPlanIds.size() - 1; i++) { - sql.append("?, "); - } - sql.append("?):"); - Query query = entityManager.createNativeQuery(sql.toString()); - int index = 1; - for (String s : testPlanIds) { - query.setParameter(index++, s); - } - @SuppressWarnings("unchecked") - List statuses = (List) query.getResultList(); - return statuses; - } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index 35b42f6e1..4d093382d 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -22,7 +22,6 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.TestGridDAOException; -import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import org.wso2.testgrid.dao.repository.TestPlanRepository; import java.sql.Timestamp; @@ -181,26 +180,4 @@ public List getTestPlanHistory(TestPlan testPlan) { public List getTestPlansOlderThan(String duration, String timeUnit) { return testPlanRepository.getTestPlanOlderThan(duration, timeUnit); } - - - /** - * Returns the test plans older than a specified period of time. - * This will be used to resolve the statuses of testplans with erroneous statuses. - * - * @return a List of TestPlans corresponding to the query - */ - public List getTestExecutionSummary(List tpIds) { - return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); - } - - - /** - * Returns the test plans older than a specified period of time. - * This will be used to resolve the statuses of testplans with erroneous statuses. - * - * @return a List of TestPlans corresponding to the query - */ - public List getTestFailureSummary(List tpId) { - return testPlanRepository.getTestFailureSummaryByTPId(tpId); - } } diff --git a/reporting/pom.xml b/reporting/pom.xml index 520659ee3..fe3377a33 100755 --- a/reporting/pom.xml +++ b/reporting/pom.xml @@ -100,9 +100,5 @@ org.jacoco.agent runtime - - com.google.code.gson - gson - \ No newline at end of file diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java deleted file mode 100644 index 7e0c5817c..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.wso2.testgrid.reporting; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import org.wso2.testgrid.common.InfraCombination; -import org.wso2.testgrid.common.Status; -import org.wso2.testgrid.common.exception.TestGridException; -import org.wso2.testgrid.common.util.FileUtil; -import org.wso2.testgrid.common.util.StringUtil; -import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; -import org.wso2.testgrid.dao.uow.TestPlanUOW; -import org.wso2.testgrid.reporting.model.email.TestExecutionSummary; -import org.wso2.testgrid.reporting.model.email.TestFailureSummary; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.TreeMap; - -/** - * This class is responsible for providing required data in order to generate email graphs. - * - * @since 1.0.0 - */ -public class GraphDataProvider { - private TestPlanUOW testPlanUOW; - private int passedTestCases = 0; - private int failedTestCases = 0; - private int skippedTestCases = 0; - - public GraphDataProvider() { - this.testPlanUOW = new TestPlanUOW(); - } - - public List getTestFailureSummary(String workspace) throws TestGridException { - List testFailureSummary = testPlanUOW - .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); - if (testFailureSummary.isEmpty()) { - throw new TestGridException("Couldn't find test case data for given test plan ids"); - } - return processTestFailureSummary(testFailureSummary); - } - - private List processTestFailureSummary(List testFailureSummary) { - TreeMap testFailureSummaryMap = new TreeMap<>(); - for (TestCaseFailureResultDTO testFailure : testFailureSummary) { - TestFailureSummary testFailureSummaryData = new TestFailureSummary(); - Gson gson = new GsonBuilder().create(); - InfraCombination infraCombination = new InfraCombination(); - String testName = testFailure.getTestName(); - JsonElement jelem = gson.fromJson(testFailure.getInfraParameters(), JsonElement.class); - JsonObject jobj = jelem.getAsJsonObject(); - infraCombination.setOs(StringUtil - .concatStrings(jobj.get("OS").getAsString(), " - ", jobj.get("OSVersion").getAsString())); - infraCombination.setJdk(jobj.get("JDK").getAsString()); - infraCombination.setDbEngine(StringUtil.concatStrings(jobj.get("DBEngine").getAsString(), " - ", - jobj.get("DBEngineVersion").getAsString())); - infraCombination.setOs(jobj.get("OS").getAsString()); - if (testFailureSummaryMap.containsKey(testName)) { - testFailureSummaryMap.get(testName).getInfraCombinations().add(infraCombination); - } else { - testFailureSummaryData.setTestCaseName(testName); - testFailureSummaryData.setTestCaseDescription(testFailure.getFailureMessage()); - testFailureSummaryData.setInfraCombinations(Collections.singletonList(infraCombination)); - testFailureSummaryMap.put(testName, testFailureSummaryData); - } - } - return new ArrayList<>(testFailureSummaryMap.values()); - } - - public TestExecutionSummary getTestExecutionSummary(String workspace) throws TestGridException { - List testExecutionSummary = testPlanUOW - .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); - TestExecutionSummary testExecutionSummaryData = new TestExecutionSummary(); - if (testExecutionSummary.isEmpty()) { - throw new TestGridException("Couldn't find test plan status for given test plan ids"); - } - - for (String status : testExecutionSummary) { - if (Status.SUCCESS.toString().equals(status)) { - this.passedTestCases++; - } else if (Status.FAIL.toString().equals(status)) { - this.failedTestCases++; - } else if (Status.SKIP.toString().equals(status)) { - this.skippedTestCases++; - } - } - testExecutionSummaryData.setPassedTestCases(this.passedTestCases); - testExecutionSummaryData.setFailedTestCases(this.failedTestCases); - testExecutionSummaryData.setSkippedTestCase(this.skippedTestCases); - return testExecutionSummaryData; - } -} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index ca10a8c3f..6ee88cd8f 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -21,12 +21,9 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.DeploymentPattern; import org.wso2.testgrid.common.Product; -import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; -import org.wso2.testgrid.common.exception.TestGridException; -import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -39,6 +36,7 @@ import org.wso2.testgrid.reporting.model.performance.PerformanceReport; import org.wso2.testgrid.reporting.renderer.Renderable; import org.wso2.testgrid.reporting.renderer.RenderableFactory; +import org.wso2.testgrid.reporting.util.FileUtil; import java.io.IOException; import java.nio.file.Files; @@ -56,12 +54,13 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; -import static org.wso2.testgrid.common.util.FileUtil.writeToFile; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; +import static org.wso2.testgrid.reporting.util.FileUtil.writeToFile; /** * This class is responsible for generating the test reports. @@ -106,8 +105,7 @@ public TestReportEngine() { * @param groupBy columns to group by * @throws ReportingException thrown when error on generating test report */ - public void generateReport(Product product, boolean showSuccess, String groupBy) - throws ReportingException, TestGridException { + public void generateReport(Product product, boolean showSuccess, String groupBy) throws ReportingException { AxisColumn uniqueAxisColumn = getGroupByColumn(groupBy); // Construct report elements @@ -141,7 +139,7 @@ public void generateReport(Product product, boolean showSuccess, String groupBy) * @param testScenarios A List of TestScenarios included in the report */ public void generatePerformanceReport(PerformanceReport report, List testScenarios) - throws ReportingException, TestGridException { + throws ReportingException { try { Map parsedResultMap = new HashMap<>(); parsedResultMap.put(REPORT_TEMPLATE_KEY, report); @@ -280,7 +278,7 @@ private List processOverallResultForScenarioAxis(List failList = distinctElements.stream() - .filter(ReportElement::isTestFail) + .filter(reportElement -> !reportElement.isTestSuccess()) .collect(Collectors.toList()); // Success list @@ -323,7 +321,7 @@ private List processOverallResultForDeploymentAxis(List failList = distinctElements.stream() - .filter(ReportElement::isTestFail) + .filter(reportElement -> !reportElement.isTestSuccess()) .collect(Collectors.toList()); // Success list @@ -367,7 +365,7 @@ private List processOverallResultForInfrastructureAxis(List failList = distinctElements.stream() - .filter(ReportElement::isTestFail) + .filter(reportElement -> !reportElement.isTestSuccess()) .collect(Collectors.toList()); // Success list @@ -544,7 +542,7 @@ private Map> getGroupedReportElementsByColumn(AxisCo */ private List filterSuccessReportElements(List reportElements) { return reportElements.stream() - .filter(ReportElement::isTestFail) + .filter(reportElement -> !reportElement.isTestSuccess()) .collect(Collectors.toList()); } @@ -706,13 +704,14 @@ private ReportElement createReportElement(DeploymentPattern deploymentPattern, T // Test case can be null if the infra fails. if (testCase != null) { reportElement.setTestCase(testCase.getName()); - reportElement.setTestSuccess(testCase.getStatus()); - if (Status.FAIL.equals(testCase.getStatus())) { + reportElement.setTestSuccess(testCase.isSuccess()); + + if (!testCase.isSuccess()) { reportElement.setTestCaseFailureMessage(testCase.getFailureMessage()); } } else { reportElement.setTestCase(""); - reportElement.setTestSuccess(Status.FAIL); + reportElement.setTestSuccess(false); } return reportElement; } @@ -724,7 +723,7 @@ private ReportElement createReportElement(DeploymentPattern deploymentPattern, T * @param htmlString HTML string to be written to the file * @throws ReportingException thrown when error on writing the HTML string to file */ - private void writeHTMLToFile(Path filePath, String htmlString) throws TestGridException { + private void writeHTMLToFile(Path filePath, String htmlString) throws ReportingException { logger.info("Writing test results to file: " + filePath.toString()); FileUtil.writeToFile(filePath.toAbsolutePath().toString(), htmlString); } @@ -736,30 +735,45 @@ private void writeHTMLToFile(Path filePath, String htmlString) throws TestGridEx * @param product product needing the report. * @param workspace workspace containing the test-plan yamls */ - public Optional generateEmailReport(Product product, String workspace) - throws ReportingException, TestGridException { + public Optional generateEmailReport(Product product, String workspace) throws ReportingException { List testPlans = new ArrayList<>(); - List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); - try { - for (String testPlanId : testPlanIds) { - Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); + Path source = Paths.get(workspace, "test-plans"); + if (!Files.exists(source)) { + logger.error("Test-plans dir does not exist: " + source); + return Optional.empty(); + } + try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { + List paths = stream.sorted().collect(Collectors.toList()); + for (Path path : paths) { + if (!path.toFile().exists()) { + throw new ReportingException( + "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); + } + logger.info("A test plan file found at " + path.toAbsolutePath().toString()); + TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil + .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); + Optional testPlanById = testPlanUOW.getTestPlanById(testPlanYaml.getId()); if (testPlanById.isPresent()) { - logger.info("Derived test plan dir in email phase : " + TestGridUtil - .deriveTestPlanDirName(testPlanById.get())); + logger.info("Derived test plan dir in email phase : " + + TestGridUtil.deriveTestPlanDirName(testPlanById.get())); testPlans.add(testPlanById.get()); } else { logger.error(String.format( "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", testPlanId)); + + "Ignoring the test plan...", + testPlanYaml.getId())); } } + } catch (IOException e) { + throw new ReportingException("Error occurred while reading the test-plan yamls in workspace " + + workspace, e); } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); } //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { - logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " - + "Hence skipping email-report generation.."); + logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + + "Hence skipping email-report generation.."); return Optional.empty(); } Renderable renderer = RenderableFactory.getRenderable(EMAIL_REPORT_MUSTACHE); diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java index cb9931476..8e3117f21 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/ReportElement.java @@ -17,7 +17,6 @@ */ package org.wso2.testgrid.reporting.model; -import org.wso2.testgrid.common.Status; import org.wso2.testgrid.reporting.AxisColumn; /** @@ -35,7 +34,7 @@ public class ReportElement { private String scenarioDescription; private String testCase; private String testCaseFailureMessage; - private Status isTestSuccess; + private boolean isTestSuccess; /** * Constructs an instance of {@link ReportElement} for the given parameters. @@ -144,16 +143,7 @@ public void setTestCaseFailureMessage(String testCaseFailureMessage) { * @return {@code true} if the test case is successful, {@code false} otherwise */ public boolean isTestSuccess() { - return Status.SUCCESS.equals(isTestSuccess); - } - - /** - * Returns whether the test case is successful or not. - * - * @return {@code true} if the test case is successful, {@code false} otherwise - */ - public boolean isTestFail() { - return Status.FAIL.equals(isTestSuccess); + return isTestSuccess; } /** @@ -161,7 +151,7 @@ public boolean isTestFail() { * * @param testSuccess whether the test case is successful or not. */ - public void setTestSuccess(Status testSuccess) { + public void setTestSuccess(boolean testSuccess) { isTestSuccess = testSuccess; } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java deleted file mode 100644 index 5e179d764..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestExecutionSummary.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.testgrid.reporting.model.email; - -/** - * This defines the possible statuses of an entity. - * - * @since 1.0.0 - */ -public class TestExecutionSummary { - private int failedTestCases; - private int passedTestCases; - private int skippedTestCase; - - public int getFailedTestCases() { - return failedTestCases; - } - - public void setFailedTestCases(int failedTestCases) { - this.failedTestCases = failedTestCases; - } - - public int getPassedTestCases() { - return passedTestCases; - } - - public void setPassedTestCases(int passedTestCases) { - this.passedTestCases = passedTestCases; - } - - public int getSkippedTestCase() { - return skippedTestCase; - } - - public void setSkippedTestCase(int skippedTestCase) { - this.skippedTestCase = skippedTestCase; - } -} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java deleted file mode 100644 index 63bed444a..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestFailureSummary.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.testgrid.reporting.model.email; - -import org.wso2.testgrid.common.InfraCombination; - -import java.util.ArrayList; -import java.util.List; - -/** - * This defines the possible statuses of an entity. - * - * @since 1.0.0 - */ -public class TestFailureSummary { - private String testCaseName; - private String testCaseDescription; - private List infraCombinations = new ArrayList<>(); - - public String getTestCaseName() { - return testCaseName; - } - - public void setTestCaseName(String testCaseName) { - this.testCaseName = testCaseName; - } - - public String getTestCaseDescription() { - return testCaseDescription; - } - - public void setTestCaseDescription(String testCaseDescription) { - this.testCaseDescription = testCaseDescription; - } - - public List getInfraCombinations() { - return infraCombinations; - } - - public void setInfraCombinations(List infraCombinations) { - this.infraCombinations = infraCombinations; - } -} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java b/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java new file mode 100755 index 000000000..32b40cff7 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.wso2.testgrid.reporting.util; + +import org.wso2.testgrid.reporting.ReportingException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Locale; + +/** + * This class is responsible for handling file operations. + * + * @since 1.0.0 + */ +public class FileUtil { + + /** + * Writes a given string to a given file to persistent media. + * + * @param filePath absolute path of the file to be written + * @param string string to be written + * @throws ReportingException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} + */ + public static void writeToFile(String filePath, String string) throws ReportingException { + createFileIfNotExists(filePath); // Create file if not exists + try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { + writer.write(string); + writer.close(); + } catch (FileNotFoundException e) { + throw new ReportingException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); + } catch (UnsupportedEncodingException e) { + throw new ReportingException( + String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); + } + } + + /** + * Creates a file with the given name. + * + * @param filePath absolute path of the file + * @throws ReportingException thrown when IO exception on creating a file + */ + private static void createFileIfNotExists(String filePath) throws ReportingException { + File file = new File(filePath); + if (!file.exists()) { + // Create directories if not exists + Path parent = Paths.get(filePath).getParent(); + + if (parent != null) { + boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); + + if (status) { + // Touch file + try { + new FileOutputStream(file).close(); + } catch (IOException e) { + throw new ReportingException(String.format(Locale.ENGLISH, + "IO Exception occurred when creating file %s", file), e); + } + } + } + } + } +} diff --git a/reporting/src/main/resources/templates/report_element.mustache b/reporting/src/main/resources/templates/report_element.mustache index 64a01f4bc..0a198d77a 100644 --- a/reporting/src/main/resources/templates/report_element.mustache +++ b/reporting/src/main/resources/templates/report_element.mustache @@ -3,12 +3,12 @@
- {{#status}} + {{#isTestSuccess}} - {{/status}} - {{^status}} + {{/isTestSuccess}} + {{^isTestSuccess}} - {{/status}} + {{/isTestSuccess}}
@@ -24,28 +24,28 @@ {{^isGroupByScenario}} - {{#status}} + {{#isTestSuccess}} {{scenarioDescription}} - {{/status}} - {{^status}} + {{/isTestSuccess}} + {{^isTestSuccess}} {{scenarioDescription}} - {{/status}} + {{/isTestSuccess}} {{/isGroupByScenario}} - {{#status}} + {{#isTestSuccess}} {{testCase}} - {{/status}} - {{^status}} + {{/isTestSuccess}} + {{^isTestSuccess}} {{testCase}} - {{/status}} + {{/isTestSuccess}} - {{#status}} + {{#isTestSuccess}} - {{/status}} - {{^status}} + {{/isTestSuccess}} + {{^isTestSuccess}} {{testCaseFailureMessage}} - {{/status}} + {{/isTestSuccess}} {{/parsedReportElements}} \ No newline at end of file diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 8b13b1e7b..9ab311641 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -112,21 +112,21 @@ public void init() throws Exception { s2.setStatus(Status.FAIL); TestCase tc = new TestCase(); - tc.setSuccess(Status.SUCCESS); + tc.setSuccess(true); tc.setFailureMessage("success"); tc.setName("Sample Testcase 01"); tc.setTestScenario(s); s.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(Status.FAIL); + tc.setSuccess(false); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 02"); tc.setTestScenario(s2); s2.addTestCase(tc); tc = new TestCase(); - tc.setSuccess(Status.FAIL); + tc.setSuccess(false); tc.setFailureMessage("fail"); tc.setName("Sample Testcase 03"); tc.setTestScenario(s2); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java index e0e87562c..aec97c625 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/APIUtil.java @@ -213,7 +213,7 @@ static TestCase getTestCaseBean(org.wso2.testgrid.common.TestCase testCase) { if (testCase != null) { testCaseBean.setId(testCase.getId()); testCaseBean.setName(testCase.getName()); - testCaseBean.setStatus(testCase.getStatus()); + testCaseBean.setSuccess(testCase.isSuccess()); testCaseBean.setModifiedTimestamp(testCase.getModifiedTimestamp()); testCaseBean.setCreatedTimestamp(testCase.getCreatedTimestamp()); testCaseBean.setErrorMsg(testCase.getFailureMessage()); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java index 8b1650aba..0e90df7fa 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/TestPlanService.java @@ -21,7 +21,6 @@ import org.apache.hc.core5.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestGridConstants; import org.wso2.testgrid.common.TestPlan; @@ -429,19 +428,18 @@ private TestExecutionSummary getTestExecutionSummary(TestPlan testPlan) { // TODO: change backend design to store these info within the db to reduce UI latency. // Create scenario summary - long totalSuccess = testCases.stream().filter(testCase -> Status.SUCCESS.equals(testCase.getStatus())) - .count(); - long totalFailed = testCases.stream().filter(testCase -> Status.FAIL.equals(testCase.getStatus())).count(); + long totalSuccess = testCases.stream().filter(TestCase::isSuccess).count(); + long totalFailed = testCases.stream().filter(testCase -> !testCase.isSuccess()).count(); ScenarioSummary scenarioSummary = new ScenarioSummary(testScenario.getDescription(), - testScenario.getConfigChangeSetName(), testScenario.getConfigChangeSetDescription(), totalSuccess, + testScenario.getConfigChangeSetName() , testScenario.getConfigChangeSetDescription(), totalSuccess, totalFailed, testScenario.getStatus(), testScenario.getName()); scenarioSummaries.add(scenarioSummary); // Create test case entries for failed tests List failedTestCaseEntries = testCases.stream() - .filter(testCase -> Status.FAIL.equals(testCase.getStatus())) + .filter(testCase -> !testCase.isSuccess()) .map(testCase -> new TestCaseEntry(testCase.getName(), testCase.getFailureMessage(), - testCase.getStatus()) + testCase.isSuccess()) ) .collect(Collectors.toList()); scenarioTestCaseEntries.add(new ScenarioTestCaseEntry( diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java index 6b1d253dc..dd785acbd 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCase.java @@ -18,8 +18,6 @@ package org.wso2.testgrid.web.bean; -import org.wso2.testgrid.common.Status; - import java.sql.Timestamp; import java.util.Date; @@ -33,7 +31,7 @@ public class TestCase { private String errorMsg; private Timestamp createdTimestamp; private Timestamp modifiedTimestamp; - private Status status; + private boolean isSuccess; /** * Returns the id of the test-case. @@ -114,21 +112,21 @@ public void setModifiedTimestamp(Timestamp modifiedTimestamp) { } /** - * Returns the status of the test-case. + * Returns the isSuccess of the test-case. * * @return {@code true} if the test is success, {@code false} otherwise */ - public Status getStatus() { - return status; + public boolean isSuccess() { + return isSuccess; } /** - * Sets the status of the test-case. + * Sets the isSuccess of the test-case. * - * @param status test-case getStatus + * @param success test-case isSuccess */ - public void setStatus(Status status) { - this.status = status; + public void setSuccess(boolean success) { + this.isSuccess = success; } /** diff --git a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java index fe48acf68..0ca6b52c7 100644 --- a/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java +++ b/web/src/main/java/org/wso2/testgrid/web/bean/TestCaseEntry.java @@ -17,8 +17,6 @@ */ package org.wso2.testgrid.web.bean; -import org.wso2.testgrid.common.Status; - /** * Bean class for managing information related to test case. * @@ -28,19 +26,19 @@ public class TestCaseEntry { private final String testCase; private final String failureMessage; - private final Status status; + private final boolean isTestSuccess; /** * Constructs an instance of {@link TestCaseEntry} * * @param testCase test case name * @param failureMessage test case failure message - * @param status whether the test case is successful or not + * @param isTestSuccess whether the test case is successful or not */ - public TestCaseEntry(String testCase, String failureMessage, Status status) { + public TestCaseEntry(String testCase, String failureMessage, boolean isTestSuccess) { this.testCase = testCase; this.failureMessage = failureMessage; - this.status = status; + this.isTestSuccess = isTestSuccess; } /** @@ -62,12 +60,12 @@ public String getFailureMessage() { } /** - * Returns status of the test case. + * Returns whether the test case is successful or not. * - * @return 'SUCCESS' if the test case is success,return 'FALSE' if the test case is failed,otherwise returns 'SKIP' + * @return {@code true} if the test case is success, {@code false} otherwise */ - public Status getTestStatus() { - return status; + public boolean isTestSuccess() { + return isTestSuccess; } @Override @@ -75,7 +73,7 @@ public String toString() { return "TestCaseEntry{" + "testCase='" + testCase + '\'' + ", failureMessage='" + failureMessage + '\'' + - ", status='" + status + '\'' + + ", isTestSuccess='" + isTestSuccess + '\'' + '}'; } } From 6e0c3a45f98a4eb838a9d474b444237a575a5ce7 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Wed, 25 Jul 2018 11:03:23 +0530 Subject: [PATCH 10/22] Add temp fixes --- .../dao/repository/TestPlanRepository.java | 24 +++++ .../wso2/testgrid/dao/uow/TestPlanUOW.java | 11 ++- .../testgrid/reporting/GraphDataProvider.java | 91 +++++++++++++++++-- .../wso2/testgrid/web/api/ProductService.java | 3 + 4 files changed, 118 insertions(+), 11 deletions(-) diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 961d051c7..087365854 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -339,4 +339,28 @@ public List getTestExecutionSummaryByTPId(List testPlanIds) { List statuses = (List) query.getResultList(); return statuses; } + + /** + * This method returns the history of test execution summary for given product. + * + * @param productId id of the product + * @param from starting point of the considering time range + * @param to end point of the considering time range + * @return a List of {@link TestPlan} representing executed test plans of a given product for a given time range + */ + public List getTestExecutionHistory(String productId, String from, String to) { + String sql = "select tp.* from test_plan tp inner join (Select distinct infra_parameters from test_plan where " + + "DEPLOYMENTPATTERN_id in (select id from deployment_pattern where PRODUCT_id=?)) as rn on " + + "tp.infra_parameters=rn.infra_parameters and tp.DEPLOYMENTPATTERN_id " + + "in (select id from deployment_pattern where PRODUCT_id=?) and modified_timestamp between ? and ?;"; + + @SuppressWarnings("unchecked") + List resultList = (List) entityManager.createNativeQuery(sql, TestPlan.class) + .setParameter(1, productId) + .setParameter(2, productId) + .setParameter(3, from) + .setParameter(4, to) + .getResultList(); + return EntityManagerHelper.refreshResultList(entityManager, resultList); + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index e59b98214..af179e54b 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -182,7 +182,6 @@ public List getTestPlansOlderThan(String duration, String timeUnit) { return testPlanRepository.getTestPlanOlderThan(duration, timeUnit); } - /** * Returns the test plan statuses for given test plan ids. * @@ -192,7 +191,6 @@ public List getTestExecutionSummary(List tpIds) { return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); } - /** * Returns the representation of failed test cases with test case name, description and infra combination for given * test plan ids. (I.e for a given build job) @@ -202,4 +200,13 @@ public List getTestExecutionSummary(List tpIds) { public List getTestFailureSummary(List tpIds) { return testPlanRepository.getTestFailureSummaryByTPId(tpIds); } + + /** + * Returns the representation of test execution history for q given product in a given time range + * + * @return a List of TestPlan which represent executed test plans in the given time range for a given product. + */ + public List getTestExecutionHistory(String productId, String from, String to) { + return testPlanRepository.getTestExecutionHistory(productId, from, to); + } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java index 21ea375d7..9eaef97b0 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -25,6 +25,7 @@ import com.google.gson.JsonObject; import org.wso2.testgrid.common.InfraCombination; import org.wso2.testgrid.common.Status; +import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; @@ -33,6 +34,11 @@ import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; import org.wso2.testgrid.reporting.model.email.BuildFailureSummary; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -45,9 +51,8 @@ */ public class GraphDataProvider { private TestPlanUOW testPlanUOW; - private int passedTestPlans = 0; - private int failedTestPlans = 0; - private int skippedTestPlans = 0; + private static final int MAXIMUM_TIME_RANGE = 30; + private static final int TEST_EXECUTION_HISTORY_RANGE = 7; public GraphDataProvider() { this.testPlanUOW = new TestPlanUOW(); @@ -111,6 +116,9 @@ private List processTestFailureSummary(List testExecutionSummary = testPlanUOW .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); BuildExecutionSummary testExecutionSummaryData = new BuildExecutionSummary(); @@ -120,16 +128,81 @@ public BuildExecutionSummary getTestExecutionSummary(String workspace) throws Te for (String status : testExecutionSummary) { if (Status.SUCCESS.toString().equals(status)) { - this.passedTestPlans++; + passedTestPlans++; } else if (Status.FAIL.toString().equals(status)) { - this.failedTestPlans++; + failedTestPlans++; } else { - this.skippedTestPlans++; + skippedTestPlans++; } } - testExecutionSummaryData.setPassedTestPlans(this.passedTestPlans); - testExecutionSummaryData.setFailedTestPlans(this.failedTestPlans); - testExecutionSummaryData.setSkippedTestPlans(this.skippedTestPlans); + testExecutionSummaryData.setPassedTestPlans(passedTestPlans); + testExecutionSummaryData.setFailedTestPlans(failedTestPlans); + testExecutionSummaryData.setSkippedTestPlans(skippedTestPlans); return testExecutionSummaryData; } + + /** + * Provide history of the test execution summary for a given build job.. + * + * @throws TestGridException thrown when error on getting test plan ids by reading testgrid yaml files located + * in the current workspace. + */ + public List getTestExecutionHistory(String productId) { + + List buildExecutionSummariesHistory = new ArrayList<>(); + + LocalTime midnight = LocalTime.MIDNIGHT; + LocalDate timeZone = LocalDate.now(ZoneId.of("UTC")); + LocalDateTime todayMidnight = LocalDateTime.of(timeZone, midnight); + + for (int i = 0; i < MAXIMUM_TIME_RANGE; i++) { + if (TEST_EXECUTION_HISTORY_RANGE == buildExecutionSummariesHistory.size()) { + break; + } + String from = todayMidnight.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + String to = todayMidnight.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + TreeMap testExecutionHistory = new TreeMap<>(); + BuildExecutionSummary buildExecutionSummary = new BuildExecutionSummary(); + List filteredTestPlanHistory; + + int passedTestPlans = 0; + int failedTestPlans = 0; + int skippedTestPlans = 0; + + List testPlanHistory = testPlanUOW.getTestExecutionHistory(productId, from, to); + + if (testPlanHistory.isEmpty()) { + todayMidnight = todayMidnight.minusDays(1); + continue; + } + + for (TestPlan testplan : testPlanHistory) { + String key = testplan.getInfraParameters(); + if (testExecutionHistory.containsKey(key)) { + if (testplan.getTestRunNumber() > testExecutionHistory.get(key).getTestRunNumber()) { + testExecutionHistory.replace(key, testplan); + } + } else { + testExecutionHistory.put(testplan.getInfraParameters(), testplan); + } + } + + filteredTestPlanHistory = new ArrayList<>(testExecutionHistory.values()); + for (TestPlan testplan : filteredTestPlanHistory) { + if (Status.SUCCESS.equals(testplan.getStatus())) { + passedTestPlans++; + } else if (Status.FAIL.equals(testplan.getStatus())) { + failedTestPlans++; + } else { + skippedTestPlans++; + } + } + buildExecutionSummary.setPassedTestPlans(passedTestPlans); + buildExecutionSummary.setFailedTestPlans(failedTestPlans); + buildExecutionSummary.setSkippedTestPlans(skippedTestPlans); + buildExecutionSummariesHistory.add(buildExecutionSummary); + todayMidnight = todayMidnight.minusDays(1); + } + return buildExecutionSummariesHistory; + } } diff --git a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java index f11455ae7..ef06fe6f9 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java @@ -29,6 +29,7 @@ import org.wso2.testgrid.dao.uow.ProductUOW; import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.AxisColumn; +import org.wso2.testgrid.reporting.GraphDataProvider; import org.wso2.testgrid.web.bean.ErrorResponse; import org.wso2.testgrid.web.bean.ProductStatus; import org.wso2.testgrid.web.plugins.AWSArtifactReader; @@ -129,6 +130,8 @@ public Response getAllProductStatuses() { status.setLastFailureTimestamp(product.getLastFailureTimestamp()); status.setProductStatus(testPlanUOW.getCurrentStatus(product).toString()); list.add(status); +// GraphDataProvider gp = new GraphDataProvider(); +// gp.getTestExecutionHistory("1d68c7b1-210f-4794-a8a4-58e798155905"); } } catch (TestGridDAOException e) { String msg = "Error occurred while fetching the Product statuses "; From 7e0ad29b46785e679a970698028928f0032bd928 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Mon, 23 Jul 2018 14:14:16 +0530 Subject: [PATCH 11/22] Add email graph data provider In order to create graphs for the generating email added new methods which return test failure summary and test execution summary for a given build. Build ids are read from the testgrid yaml files which are located under the current workspace. --- .../testgrid/common/InfraCombination.java | 85 +++++++ .../wso2/testgrid/common/util/FileUtil.java | 87 ++++++++ .../dao/dto/TestCaseFailureResultDTO.java | 69 ++++++ .../dao/repository/TestPlanRepository.java | 73 ++++++ .../wso2/testgrid/dao/uow/TestPlanUOW.java | 29 +++ reporting/pom.xml | 4 + .../testgrid/reporting/GraphDataProvider.java | 208 ++++++++++++++++++ .../testgrid/reporting/TestReportEngine.java | 54 ++--- .../model/email/BuildExecutionSummary.java | 54 +++++ .../model/email/BuildFailureSummary.java | 59 +++++ .../testgrid/reporting/util/FileUtil.java | 87 -------- .../reporting/TestReportEngineTest.java | 3 +- .../wso2/testgrid/web/api/ProductService.java | 3 + 13 files changed, 695 insertions(+), 120 deletions(-) create mode 100644 common/src/main/java/org/wso2/testgrid/common/InfraCombination.java create mode 100644 dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java delete mode 100755 reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java diff --git a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java new file mode 100644 index 000000000..207ddefbe --- /dev/null +++ b/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.common; + +/** + * This defines s single infra combination. + * + * @since 1.0.0 + */ +public class InfraCombination { + private String os; + private String jdk; + private String dbEngine; + + /** + * Returns name of the operating system. + * + * @return OS name + OS version + */ + public String getOs() { + return os; + } + + /** + * Sets name of the operating system. + * + * @param os OS name + OS version + */ + public void setOs(String os) { + this.os = os; + } + + /** + * Returns jdk name. + * + * @return JDK name + */ + public String getJdk() { + return jdk; + } + + /** + * Sets jdk name. + * + * @param jdk JDK name + */ + public void setJdk(String jdk) { + this.jdk = jdk; + } + + /** + * Returns database engine name. + * + * @return DB engine name + DB engine version + */ + public String getDbEngine() { + return dbEngine; + } + + /** + * Sets database engine name. + * + * @param dbEngine DB engine name + DB engine version + */ + public void setDbEngine(String dbEngine) { + this.dbEngine = dbEngine; + } + +} diff --git a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java index 748b899b6..60c02c352 100644 --- a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java +++ b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java @@ -19,15 +19,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; @@ -38,9 +42,13 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -162,4 +170,83 @@ public static void compress(String sourceDir, String destination) throws IOExcep } } + /** + * Writes a given string to a given file to persistent media. + * + * @param filePath absolute path of the file to be written + * @param string string to be written + * @throws TestGridException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} + */ + public static void writeToFile(String filePath, String string) throws TestGridException { + createFileIfNotExists(filePath); // Create file if not exists + try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { + writer.write(string); + } catch (FileNotFoundException e) { + throw new TestGridException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); + } catch (UnsupportedEncodingException e) { + throw new TestGridException( + String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); + } + } + + /** + * Creates a file with the given name. + * + * @param filePath absolute path of the file + * @throws TestGridException thrown when IO exception on creating a file + */ + private static void createFileIfNotExists(String filePath) throws TestGridException { + File file = new File(filePath); + if (!file.exists()) { + // Create directories if not exists + Path parent = Paths.get(filePath).getParent(); + + if (parent != null) { + boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); + + if (status) { + // Touch file + try { + new FileOutputStream(file).close(); + } catch (IOException e) { + throw new TestGridException(String.format(Locale.ENGLISH, + "IO Exception occurred when creating file %s", file), e); + } + } + } + } + } + + /** + * Get test plan ids by reading testgrid yaml files contains in the testgrid home. + * + * @param workspace path of the current workspace + * @throws TestGridException thrown when IO exception on reading testgrid yaml files. + */ + public static List getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException { + List testPlanIds = new ArrayList<>(); + Path source = Paths.get(workspace, "test-plans"); + if (!Files.exists(source)) { + logger.error("Test-plans dir does not exist: " + source); + return Collections.emptyList(); + } + try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { + List paths = stream.sorted().collect(Collectors.toList()); + for (Path path : paths) { + if (!path.toFile().exists()) { + throw new IOException( + "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); + } + logger.info("A test plan file found at " + path.toAbsolutePath().toString()); + TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil + .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); + testPlanIds.add(testPlanYaml.getId()); + } + return testPlanIds; + } catch (IOException e) { + throw new TestGridException("Error occurred while reading the test-plan yamls in workspace " + workspace, + e); + } + + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java new file mode 100644 index 000000000..057339e60 --- /dev/null +++ b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.dao.dto; + +import javax.persistence.ColumnResult; +import javax.persistence.ConstructorResult; +import javax.persistence.SqlResultSetMapping; + +/** + * Defines a model object of test case failure results. + * + * @since 1.0.0 + */ +@SqlResultSetMapping(name = "TestCaseFailureResult", classes = { + @ConstructorResult(targetClass = TestCaseFailureResultDTO.class, columns = { @ColumnResult(name = "testName"), + @ColumnResult(name = "failureMessage"), + @ColumnResult(name = "infraParameters") }) }) +public class TestCaseFailureResultDTO { + + private String testName; + private String failureMessage; + private String infraParameters; + + public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) { + this.testName = testname; + this.failureMessage = failureMessage; + this.infraParameters = infraParameters; + } + + public String getTestName() { + return testName; + } + + public void setTestName(String testName) { + this.testName = testName; + } + + public String getFailureMessage() { + return failureMessage; + } + + public void setFailureMessage(String failureMessage) { + this.failureMessage = failureMessage; + } + + public String getInfraParameters() { + return infraParameters; + } + + public void setInfraParameters(String infraParameters) { + this.infraParameters = infraParameters; + } +} diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 7e8866400..087365854 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -24,6 +24,7 @@ import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.SortOrder; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import java.sql.Timestamp; import java.util.Collections; @@ -290,4 +291,76 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { .getResultList(); return EntityManagerHelper.refreshResultList(entityManager, resultList); } + + /** + * This method returns test failure summary for given test plan ids. (i.e for a given build job). + * + * @param testPlanIds test plan ids + * @return a List of {@link TestCaseFailureResultDTO} representing the test case failure results for a given build + */ + public List getTestFailureSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " + + "testName, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " + + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;"); + Query query = entityManager.createNativeQuery(sql.toString(), "TestCaseFailureResult"); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List testCaseFailureResultDTO = (List) query + .getResultList(); + return testCaseFailureResultDTO; + } + + /** + * This method returns the test execution summary for given test plan ids(i.e for a given build job). + * + * @param testPlanIds test plan ids of a specific build job + * @return a List of {@link String} representing statuses of given test plans + */ + public List getTestExecutionSummaryByTPId(List testPlanIds) { + StringBuilder sql = new StringBuilder("select status from test_plan where id in ("); + for (int i = 0; i < testPlanIds.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?):"); + Query query = entityManager.createNativeQuery(sql.toString()); + int index = 1; + for (String s : testPlanIds) { + query.setParameter(index++, s); + } + @SuppressWarnings("unchecked") + List statuses = (List) query.getResultList(); + return statuses; + } + + /** + * This method returns the history of test execution summary for given product. + * + * @param productId id of the product + * @param from starting point of the considering time range + * @param to end point of the considering time range + * @return a List of {@link TestPlan} representing executed test plans of a given product for a given time range + */ + public List getTestExecutionHistory(String productId, String from, String to) { + String sql = "select tp.* from test_plan tp inner join (Select distinct infra_parameters from test_plan where " + + "DEPLOYMENTPATTERN_id in (select id from deployment_pattern where PRODUCT_id=?)) as rn on " + + "tp.infra_parameters=rn.infra_parameters and tp.DEPLOYMENTPATTERN_id " + + "in (select id from deployment_pattern where PRODUCT_id=?) and modified_timestamp between ? and ?;"; + + @SuppressWarnings("unchecked") + List resultList = (List) entityManager.createNativeQuery(sql, TestPlan.class) + .setParameter(1, productId) + .setParameter(2, productId) + .setParameter(3, from) + .setParameter(4, to) + .getResultList(); + return EntityManagerHelper.refreshResultList(entityManager, resultList); + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index 4d093382d..af179e54b 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -22,6 +22,7 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.dao.EntityManagerHelper; import org.wso2.testgrid.dao.TestGridDAOException; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import org.wso2.testgrid.dao.repository.TestPlanRepository; import java.sql.Timestamp; @@ -180,4 +181,32 @@ public List getTestPlanHistory(TestPlan testPlan) { public List getTestPlansOlderThan(String duration, String timeUnit) { return testPlanRepository.getTestPlanOlderThan(duration, timeUnit); } + + /** + * Returns the test plan statuses for given test plan ids. + * + * @return a List of Test Plan statuses. + */ + public List getTestExecutionSummary(List tpIds) { + return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); + } + + /** + * Returns the representation of failed test cases with test case name, description and infra combination for given + * test plan ids. (I.e for a given build job) + * + * @return a List of TestCaseFailureResultDTO which represent test cases failure for given test plan ids. + */ + public List getTestFailureSummary(List tpIds) { + return testPlanRepository.getTestFailureSummaryByTPId(tpIds); + } + + /** + * Returns the representation of test execution history for q given product in a given time range + * + * @return a List of TestPlan which represent executed test plans in the given time range for a given product. + */ + public List getTestExecutionHistory(String productId, String from, String to) { + return testPlanRepository.getTestExecutionHistory(productId, from, to); + } } diff --git a/reporting/pom.xml b/reporting/pom.xml index fe3377a33..520659ee3 100755 --- a/reporting/pom.xml +++ b/reporting/pom.xml @@ -100,5 +100,9 @@ org.jacoco.agent runtime + + com.google.code.gson + gson + \ No newline at end of file diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java new file mode 100644 index 000000000..9eaef97b0 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.wso2.testgrid.reporting; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.wso2.testgrid.common.InfraCombination; +import org.wso2.testgrid.common.Status; +import org.wso2.testgrid.common.TestPlan; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; +import org.wso2.testgrid.common.util.StringUtil; +import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; +import org.wso2.testgrid.dao.uow.TestPlanUOW; +import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; +import org.wso2.testgrid.reporting.model.email.BuildFailureSummary; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; + +/** + * This class is responsible for providing required data in order to generate email graphs. + * + * @since 1.0.0 + */ +public class GraphDataProvider { + private TestPlanUOW testPlanUOW; + private static final int MAXIMUM_TIME_RANGE = 30; + private static final int TEST_EXECUTION_HISTORY_RANGE = 7; + + public GraphDataProvider() { + this.testPlanUOW = new TestPlanUOW(); + } + + /** + * Provides the test failure summary for a given build job. Test Plan ids of the build job is retrieved by reading + * testgrid yaml files which contains in the current workspace. + * + * @param workspace current workspace + * @throws TestGridException thrown when getting test plan ids by reading test plan yaml files + */ + public List getTestFailureSummary(String workspace) throws TestGridException { + List testFailureSummary = testPlanUOW + .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + if (testFailureSummary.isEmpty()) { + return Collections.emptyList(); + } + return processTestFailureSummary(testFailureSummary); + } + + /** + * Process the test failure summary which is retrieved by reading database and construct the list of + * {@link BuildFailureSummary} to draw test failure summary chart. + * + * @param testFailureSummary list of {@link TestCaseFailureResultDTO} which are retrieved by quering the databse. + */ + private List processTestFailureSummary(List testFailureSummary) { + TreeMap testFailureSummaryMap = new TreeMap<>(); + for (TestCaseFailureResultDTO testFailure : testFailureSummary) { + BuildFailureSummary buildFailureSummaryData = new BuildFailureSummary(); + Gson gson = new GsonBuilder().create(); + InfraCombination infraCombination = new InfraCombination(); + String testName = testFailure.getTestName(); + JsonElement jelem = gson.fromJson(testFailure.getInfraParameters(), JsonElement.class); + JsonObject jobj = jelem.getAsJsonObject(); + infraCombination.setOs(StringUtil + .concatStrings(jobj.get("OS").getAsString(), " - ", jobj.get("OSVersion").getAsString())); + infraCombination.setJdk(jobj.get("JDK").getAsString()); + infraCombination.setDbEngine(StringUtil.concatStrings(jobj.get("DBEngine").getAsString(), " - ", + jobj.get("DBEngineVersion").getAsString())); + if (testFailureSummaryMap.containsKey(testName)) { + testFailureSummaryMap.get(testName).getInfraCombinations().add(infraCombination); + } else { + List infraCombinations = new ArrayList<>(); + buildFailureSummaryData.setTestCaseName(testName); + buildFailureSummaryData.setTestCaseDescription(testFailure.getFailureMessage()); + infraCombinations.add(infraCombination); + buildFailureSummaryData.setInfraCombinations(infraCombinations); + testFailureSummaryMap.put(testName, buildFailureSummaryData); + } + } + return new ArrayList<>(testFailureSummaryMap.values()); + } + + /** + * Provide test execution summary for a given build job.. + * + * @param workspace current workspace + * @throws TestGridException thrown when error on getting test plan ids by reading testgrid yaml files located + * in the current workspace. + */ + public BuildExecutionSummary getTestExecutionSummary(String workspace) throws TestGridException { + int passedTestPlans = 0; + int failedTestPlans = 0; + int skippedTestPlans = 0; + List testExecutionSummary = testPlanUOW + .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + BuildExecutionSummary testExecutionSummaryData = new BuildExecutionSummary(); + if (testExecutionSummary.isEmpty()) { + throw new TestGridException("Couldn't find test plan status for given test plan ids"); + } + + for (String status : testExecutionSummary) { + if (Status.SUCCESS.toString().equals(status)) { + passedTestPlans++; + } else if (Status.FAIL.toString().equals(status)) { + failedTestPlans++; + } else { + skippedTestPlans++; + } + } + testExecutionSummaryData.setPassedTestPlans(passedTestPlans); + testExecutionSummaryData.setFailedTestPlans(failedTestPlans); + testExecutionSummaryData.setSkippedTestPlans(skippedTestPlans); + return testExecutionSummaryData; + } + + /** + * Provide history of the test execution summary for a given build job.. + * + * @throws TestGridException thrown when error on getting test plan ids by reading testgrid yaml files located + * in the current workspace. + */ + public List getTestExecutionHistory(String productId) { + + List buildExecutionSummariesHistory = new ArrayList<>(); + + LocalTime midnight = LocalTime.MIDNIGHT; + LocalDate timeZone = LocalDate.now(ZoneId.of("UTC")); + LocalDateTime todayMidnight = LocalDateTime.of(timeZone, midnight); + + for (int i = 0; i < MAXIMUM_TIME_RANGE; i++) { + if (TEST_EXECUTION_HISTORY_RANGE == buildExecutionSummariesHistory.size()) { + break; + } + String from = todayMidnight.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + String to = todayMidnight.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + TreeMap testExecutionHistory = new TreeMap<>(); + BuildExecutionSummary buildExecutionSummary = new BuildExecutionSummary(); + List filteredTestPlanHistory; + + int passedTestPlans = 0; + int failedTestPlans = 0; + int skippedTestPlans = 0; + + List testPlanHistory = testPlanUOW.getTestExecutionHistory(productId, from, to); + + if (testPlanHistory.isEmpty()) { + todayMidnight = todayMidnight.minusDays(1); + continue; + } + + for (TestPlan testplan : testPlanHistory) { + String key = testplan.getInfraParameters(); + if (testExecutionHistory.containsKey(key)) { + if (testplan.getTestRunNumber() > testExecutionHistory.get(key).getTestRunNumber()) { + testExecutionHistory.replace(key, testplan); + } + } else { + testExecutionHistory.put(testplan.getInfraParameters(), testplan); + } + } + + filteredTestPlanHistory = new ArrayList<>(testExecutionHistory.values()); + for (TestPlan testplan : filteredTestPlanHistory) { + if (Status.SUCCESS.equals(testplan.getStatus())) { + passedTestPlans++; + } else if (Status.FAIL.equals(testplan.getStatus())) { + failedTestPlans++; + } else { + skippedTestPlans++; + } + } + buildExecutionSummary.setPassedTestPlans(passedTestPlans); + buildExecutionSummary.setFailedTestPlans(failedTestPlans); + buildExecutionSummary.setSkippedTestPlans(skippedTestPlans); + buildExecutionSummariesHistory.add(buildExecutionSummary); + todayMidnight = todayMidnight.minusDays(1); + } + return buildExecutionSummariesHistory; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 99117c5e4..39e0d14a1 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -25,6 +25,8 @@ import org.wso2.testgrid.common.TestCase; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; +import org.wso2.testgrid.common.exception.TestGridException; +import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -37,7 +39,6 @@ import org.wso2.testgrid.reporting.model.performance.PerformanceReport; import org.wso2.testgrid.reporting.renderer.Renderable; import org.wso2.testgrid.reporting.renderer.RenderableFactory; -import org.wso2.testgrid.reporting.util.FileUtil; import java.io.IOException; import java.nio.file.Files; @@ -55,13 +56,11 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; -import static org.wso2.testgrid.reporting.util.FileUtil.writeToFile; /** * This class is responsible for generating the test reports. @@ -106,7 +105,8 @@ public TestReportEngine() { * @param groupBy columns to group by * @throws ReportingException thrown when error on generating test report */ - public void generateReport(Product product, boolean showSuccess, String groupBy) throws ReportingException { + public void generateReport(Product product, boolean showSuccess, String groupBy) + throws ReportingException { AxisColumn uniqueAxisColumn = getGroupByColumn(groupBy); // Construct report elements @@ -166,7 +166,6 @@ public void generatePerformanceReport(PerformanceReport report, List generateEmailReport(Product product, String workspace) throws ReportingException { List testPlans = new ArrayList<>(); - Path source = Paths.get(workspace, "test-plans"); - if (!Files.exists(source)) { - logger.error("Test-plans dir does not exist: " + source); - return Optional.empty(); - } - try (Stream stream = Files.list(source).filter(Files::isRegularFile)) { - List paths = stream.sorted().collect(Collectors.toList()); - for (Path path : paths) { - if (!path.toFile().exists()) { - throw new ReportingException( - "Test Plan File doesn't exist. File path is " + path.toAbsolutePath().toString()); - } - logger.info("A test plan file found at " + path.toAbsolutePath().toString()); - TestPlan testPlanYaml = org.wso2.testgrid.common.util.FileUtil - .readYamlFile(path.toAbsolutePath().toString(), TestPlan.class); - Optional testPlanById = testPlanUOW.getTestPlanById(testPlanYaml.getId()); + try { + List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); + for (String testPlanId : testPlanIds) { + Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); if (testPlanById.isPresent()) { - logger.info("Derived test plan dir in email phase : " + - TestGridUtil.deriveTestPlanDirName(testPlanById.get())); + logger.info("Derived test plan dir in email phase : " + TestGridUtil + .deriveTestPlanDirName(testPlanById.get())); testPlans.add(testPlanById.get()); } else { logger.error(String.format( "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", - testPlanYaml.getId())); + + "Ignoring the test plan...", testPlanId)); } } - } catch (IOException e) { - throw new ReportingException("Error occurred while reading the test-plan yamls in workspace " - + workspace, e); } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); + } catch (TestGridException e) { + throw new ReportingException( + "Error occurred while getting the test plan id by reading test grid yaml files ", e); } //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { - logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + - "Hence skipping email-report generation.."); + logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + + "Hence skipping email-report generation.."); return Optional.empty(); } Renderable renderer = RenderableFactory.getRenderable(EMAIL_REPORT_MUSTACHE); @@ -790,7 +780,7 @@ public Optional generateEmailReport(Product product, String workspace) thr String relativeFilePath = TestGridUtil.deriveTestGridLogFilePath(product.getName(), TESTGRID_EMAIL_REPORT_NAME); String testGridHome = TestGridUtil.getTestGridHomePath(); Path reportPath = Paths.get(testGridHome, relativeFilePath); - writeToFile(reportPath.toString(), htmlString); + writeHTMLToFile(reportPath, htmlString); return Optional.of(reportPath); } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java new file mode 100644 index 000000000..4f0e7d947 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildExecutionSummary.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +/** + * This defines the build execution summary for a build. + * + * @since 1.0.0 + */ +public class BuildExecutionSummary { + private int failedTestPlans; + private int passedTestPlans; + private int skippedTestPlans; + + public int getFailedTestPlans() { + return failedTestPlans; + } + + public void setFailedTestPlans(int failedTestPlans) { + this.failedTestPlans = failedTestPlans; + } + + public int getPassedTestPlans() { + return passedTestPlans; + } + + public void setPassedTestPlans(int passedTestPlans) { + this.passedTestPlans = passedTestPlans; + } + + public int getSkippedTestPlans() { + return skippedTestPlans; + } + + public void setSkippedTestPlans(int skippedTestPlans) { + this.skippedTestPlans = skippedTestPlans; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java new file mode 100644 index 000000000..7afdbfb2e --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.testgrid.reporting.model.email; + +import org.wso2.testgrid.common.InfraCombination; + +import java.util.ArrayList; +import java.util.List; + +/** + * This defines the build failure summary for a specifc test case. + * + * @since 1.0.0 + */ +public class BuildFailureSummary { + private String testCaseName; + private String testCaseDescription; + private List infraCombinations = new ArrayList<>(); + + public String getTestCaseName() { + return testCaseName; + } + + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } + + public String getTestCaseDescription() { + return testCaseDescription; + } + + public void setTestCaseDescription(String testCaseDescription) { + this.testCaseDescription = testCaseDescription; + } + + public List getInfraCombinations() { + return infraCombinations; + } + + public void setInfraCombinations(List infraCombinations) { + this.infraCombinations = infraCombinations; + } +} diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java b/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java deleted file mode 100755 index 32b40cff7..000000000 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/util/FileUtil.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.wso2.testgrid.reporting.util; - -import org.wso2.testgrid.reporting.ReportingException; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Locale; - -/** - * This class is responsible for handling file operations. - * - * @since 1.0.0 - */ -public class FileUtil { - - /** - * Writes a given string to a given file to persistent media. - * - * @param filePath absolute path of the file to be written - * @param string string to be written - * @throws ReportingException thrown on {@link FileNotFoundException} or {@link UnsupportedEncodingException} - */ - public static void writeToFile(String filePath, String string) throws ReportingException { - createFileIfNotExists(filePath); // Create file if not exists - try (PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8.name())) { - writer.write(string); - writer.close(); - } catch (FileNotFoundException e) { - throw new ReportingException(String.format(Locale.ENGLISH, "File %s not found", filePath), e); - } catch (UnsupportedEncodingException e) { - throw new ReportingException( - String.format(Locale.ENGLISH, "Unsupported encoding %s", StandardCharsets.UTF_8.name()), e); - } - } - - /** - * Creates a file with the given name. - * - * @param filePath absolute path of the file - * @throws ReportingException thrown when IO exception on creating a file - */ - private static void createFileIfNotExists(String filePath) throws ReportingException { - File file = new File(filePath); - if (!file.exists()) { - // Create directories if not exists - Path parent = Paths.get(filePath).getParent(); - - if (parent != null) { - boolean status = new File(parent.toAbsolutePath().toString()).mkdirs(); - - if (status) { - // Touch file - try { - new FileOutputStream(file).close(); - } catch (IOException e) { - throw new ReportingException(String.format(Locale.ENGLISH, - "IO Exception occurred when creating file %s", file), e); - } - } - } - } - } -} diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 8b13b1e7b..c3ee2efff 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -36,6 +36,7 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; import org.wso2.testgrid.common.config.InfrastructureConfig; +import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -150,7 +151,7 @@ public void init() throws Exception { } @Test - public void generateEmailReport() throws TestGridDAOException, ReportingException { + public void generateEmailReport() throws TestGridDAOException, ReportingException, TestGridException { when(testPlanUOW.getLatestTestPlans(Matchers.any(Product.class))) .thenReturn(Collections.singletonList(testPlan)); when(testPlanUOW.getTestPlanById("abc")).thenReturn(Optional.of(testPlan)); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java index f11455ae7..ef06fe6f9 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java @@ -29,6 +29,7 @@ import org.wso2.testgrid.dao.uow.ProductUOW; import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.AxisColumn; +import org.wso2.testgrid.reporting.GraphDataProvider; import org.wso2.testgrid.web.bean.ErrorResponse; import org.wso2.testgrid.web.bean.ProductStatus; import org.wso2.testgrid.web.plugins.AWSArtifactReader; @@ -129,6 +130,8 @@ public Response getAllProductStatuses() { status.setLastFailureTimestamp(product.getLastFailureTimestamp()); status.setProductStatus(testPlanUOW.getCurrentStatus(product).toString()); list.add(status); +// GraphDataProvider gp = new GraphDataProvider(); +// gp.getTestExecutionHistory("1d68c7b1-210f-4794-a8a4-58e798155905"); } } catch (TestGridDAOException e) { String msg = "Error occurred while fetching the Product statuses "; From 51f1e80cf087d82afdae1e585ab796991028d3ce Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Wed, 25 Jul 2018 18:08:43 +0530 Subject: [PATCH 12/22] Fix issues related to test execution summary data retrieving method --- .../testgrid/reporting/GraphDataProvider.java | 72 +++++++++++-------- .../reporting/TestReportEngineTest.java | 3 +- .../wso2/testgrid/web/api/ProductService.java | 3 - 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java index 9eaef97b0..b66672c7f 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -42,6 +42,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.TreeMap; /** @@ -63,15 +64,21 @@ public GraphDataProvider() { * testgrid yaml files which contains in the current workspace. * * @param workspace current workspace - * @throws TestGridException thrown when getting test plan ids by reading test plan yaml files + * @throws ReportingException thrown when getting test plan ids by reading test plan yaml files */ - public List getTestFailureSummary(String workspace) throws TestGridException { - List testFailureSummary = testPlanUOW - .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); - if (testFailureSummary.isEmpty()) { - return Collections.emptyList(); + public List getTestFailureSummary(String workspace) throws ReportingException { + List testFailureSummary; + try { + testFailureSummary = testPlanUOW + .getTestFailureSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + if (testFailureSummary.isEmpty()) { + return Collections.emptyList(); + } + return processTestFailureSummary(testFailureSummary); + } catch (TestGridException e) { + throw new ReportingException("Error occurred while reading yaml files in the TG home", e); } - return processTestFailureSummary(testFailureSummary); + } /** @@ -112,44 +119,49 @@ private List processTestFailureSummary(List testExecutionSummary = testPlanUOW - .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); - BuildExecutionSummary testExecutionSummaryData = new BuildExecutionSummary(); - if (testExecutionSummary.isEmpty()) { - throw new TestGridException("Couldn't find test plan status for given test plan ids"); - } + List testExecutionSummary; + try { + testExecutionSummary = testPlanUOW + .getTestExecutionSummary(FileUtil.getTestPlanIdByReadingTGYaml(workspace)); + BuildExecutionSummary testExecutionSummaryData = new BuildExecutionSummary(); + if (testExecutionSummary.isEmpty()) { + throw new ReportingException("Couldn't find test plan status for given test plan ids"); + } - for (String status : testExecutionSummary) { - if (Status.SUCCESS.toString().equals(status)) { - passedTestPlans++; - } else if (Status.FAIL.toString().equals(status)) { - failedTestPlans++; - } else { - skippedTestPlans++; + for (String status : testExecutionSummary) { + if (Status.SUCCESS.toString().equals(status)) { + passedTestPlans++; + } else if (Status.FAIL.toString().equals(status)) { + failedTestPlans++; + } else { + skippedTestPlans++; + } } + testExecutionSummaryData.setPassedTestPlans(passedTestPlans); + testExecutionSummaryData.setFailedTestPlans(failedTestPlans); + testExecutionSummaryData.setSkippedTestPlans(skippedTestPlans); + return testExecutionSummaryData; + } catch (TestGridException e) { + throw new ReportingException("Error occurred while reading yaml files in the TG home", e); } - testExecutionSummaryData.setPassedTestPlans(passedTestPlans); - testExecutionSummaryData.setFailedTestPlans(failedTestPlans); - testExecutionSummaryData.setSkippedTestPlans(skippedTestPlans); - return testExecutionSummaryData; } /** * Provide history of the test execution summary for a given build job.. * - * @throws TestGridException thrown when error on getting test plan ids by reading testgrid yaml files located * in the current workspace. */ - public List getTestExecutionHistory(String productId) { + public Map getTestExecutionHistory(String productId) { + + Map buildExecutionSummariesHistory = new TreeMap<>(); - List buildExecutionSummariesHistory = new ArrayList<>(); LocalTime midnight = LocalTime.MIDNIGHT; LocalDate timeZone = LocalDate.now(ZoneId.of("UTC")); @@ -200,7 +212,7 @@ public List getTestExecutionHistory(String productId) { buildExecutionSummary.setPassedTestPlans(passedTestPlans); buildExecutionSummary.setFailedTestPlans(failedTestPlans); buildExecutionSummary.setSkippedTestPlans(skippedTestPlans); - buildExecutionSummariesHistory.add(buildExecutionSummary); + buildExecutionSummariesHistory.put(to, buildExecutionSummary); todayMidnight = todayMidnight.minusDays(1); } return buildExecutionSummariesHistory; diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index c3ee2efff..8b13b1e7b 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -36,7 +36,6 @@ import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.TestScenario; import org.wso2.testgrid.common.config.InfrastructureConfig; -import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.common.util.TestGridUtil; import org.wso2.testgrid.dao.TestGridDAOException; @@ -151,7 +150,7 @@ public void init() throws Exception { } @Test - public void generateEmailReport() throws TestGridDAOException, ReportingException, TestGridException { + public void generateEmailReport() throws TestGridDAOException, ReportingException { when(testPlanUOW.getLatestTestPlans(Matchers.any(Product.class))) .thenReturn(Collections.singletonList(testPlan)); when(testPlanUOW.getTestPlanById("abc")).thenReturn(Optional.of(testPlan)); diff --git a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java index ef06fe6f9..f11455ae7 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java @@ -29,7 +29,6 @@ import org.wso2.testgrid.dao.uow.ProductUOW; import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.AxisColumn; -import org.wso2.testgrid.reporting.GraphDataProvider; import org.wso2.testgrid.web.bean.ErrorResponse; import org.wso2.testgrid.web.bean.ProductStatus; import org.wso2.testgrid.web.plugins.AWSArtifactReader; @@ -130,8 +129,6 @@ public Response getAllProductStatuses() { status.setLastFailureTimestamp(product.getLastFailureTimestamp()); status.setProductStatus(testPlanUOW.getCurrentStatus(product).toString()); list.add(status); -// GraphDataProvider gp = new GraphDataProvider(); -// gp.getTestExecutionHistory("1d68c7b1-210f-4794-a8a4-58e798155905"); } } catch (TestGridDAOException e) { String msg = "Error occurred while fetching the Product statuses "; From 05156ff9da2f0c07c704cadf3952bf413a346ac4 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Wed, 25 Jul 2018 15:30:48 +0530 Subject: [PATCH 13/22] Integrate chart generation with GraphDataProvider --- .../testgrid/common/TestGridConstants.java | 1 + .../core/command/GenerateEmailCommand.java | 5 +- .../testgrid/reporting/ChartGenerator.java | 57 +++--- .../testgrid/reporting/TestReportEngine.java | 121 ++++++++++-- .../model/email/TestCaseResultSection.java | 76 +++++++ .../summarized_email_report.mustache | 187 ++++++++++++++++++ 6 files changed, 389 insertions(+), 58 deletions(-) create mode 100644 reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java create mode 100644 reporting/src/main/resources/templates/summarized_email_report.mustache diff --git a/common/src/main/java/org/wso2/testgrid/common/TestGridConstants.java b/common/src/main/java/org/wso2/testgrid/common/TestGridConstants.java index 5787b93b5..3c800b20c 100644 --- a/common/src/main/java/org/wso2/testgrid/common/TestGridConstants.java +++ b/common/src/main/java/org/wso2/testgrid/common/TestGridConstants.java @@ -70,6 +70,7 @@ public class TestGridConstants { public static final String TEST_PLANS_URI = "test-plans"; public static final String HTML_LINE_SEPARATOR = "
"; public static final String TESTGRID_EMAIL_REPORT_NAME = "EmailReport.html"; + public static final String TESTGRID_SUMMARIZED_EMAIL_REPORT_NAME = "SummarizedEmailReport.html"; public static final String SHELL_SUFFIX = ".sh"; public static final String PRE_STRING = "pre-scenario-steps"; diff --git a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java index eb7d0aef2..38d23e55b 100644 --- a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java +++ b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java @@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.Product; import org.wso2.testgrid.common.exception.CommandExecutionException; +import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.dao.TestGridDAOException; import org.wso2.testgrid.dao.uow.ProductUOW; @@ -52,11 +53,11 @@ public class GenerateEmailCommand implements Command { private String workspace = ""; @Override - public void execute() throws CommandExecutionException { + public void execute() throws CommandExecutionException, TestGridException { Product product = getProduct(productName); try { TestReportEngine testReportEngine = new TestReportEngine(); - final Optional path = testReportEngine.generateEmailReport(product, workspace); + final Optional path = testReportEngine.generateSummarizedEmailReport(product, workspace); path.ifPresent(p -> logger.info("Written the email report body contents to: " + p)); } catch (ReportingException e) { throw new CommandExecutionException(StringUtil diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java index 8ca9bbfb0..f80eda13f 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -24,7 +24,9 @@ import javax.imageio.ImageIO; /** - * This class is responsib;e generating the necessary charts fot the email report. + * This class is responsible for generating the necessary charts for the email report. + * + * @since 1.0.0 */ public class ChartGenerator { @@ -39,14 +41,14 @@ public ChartGenerator(String chartGenLocation) { } /** - * Generatees a pie chart with the summary test results of the current build. + * Generates a pie chart with the summary test results of the current build. * * @param passedCount passed test count * @param failedCount failed test count * @param skippedCount skipped test count * @throws IOException if the chart cannot be written into a file */ - public void generateSummaryChart(int passedCount, int failedCount, int skippedCount) throws IOException { + public void generateSummaryChart(int passedCount, int failedCount, int skippedCount) { ObservableList pieChartData = FXCollections.observableArrayList( @@ -54,7 +56,7 @@ public void generateSummaryChart(int passedCount, int failedCount, int skippedCo new PieChart.Data("Skipped", skippedCount), new PieChart.Data("Passed", passedCount)); final PieChart chart = new PieChart(pieChartData); - chart.setTitle("Test Failure Summary"); + chart.setTitle("Build Failure Summary by Test Plans"); genChart(chart, 500, 500, summaryChartFileName); } @@ -108,43 +110,23 @@ public void generateResultHistoryChart(Map dataSet) { genChart(stackedBarChart, 800, 800, historyChartFileName); } -// /** -// * Generate the test failure summary table for failed test cases. -// * -// * @return a html table with contents. -// */ -// public String generaeSummaryTable() { -// -// // Color pallet is used to inject colors to differentiate the testcase rows. -// String[] colorPallette = new String[]{"#b2ad7f", "#a2b9bc", "#d6cbd3", "#bdcebe", "#e3eaa7", "#e6e2d3", -// "#dac292", "#c6bcb6", "#b7d7e8", "#b8a9c9", "#f2ae72"}; -// -// StringBuilder tableContent = new StringBuilder(); -// tableContent.append(""); -// tableContent.append(""); -// tableContent.append(""); -// tableContent.append(""); -// tableContent.append(""); -// tableContent.append(""); -// tableContent.append(""); -// // loop the content -//// for testcase -//// for OS -//// for JDK -//// for DB -// tableContent.append("
Failing Test CaseOSJDKDB
"); -// return null; -// } - /** * Returns the chart generation location. * - * @return chart generation dir + * @return chart generation directory */ public String getChartGenLocation() { return chartGenLocation; } + /** + * Generates the chart and writes to an image. + * + * @param chart to be rendered + * @param width with of the chart in pixels + * @param height height of the chart in pixels + * @param fileName of the written image + */ private void genChart(Chart chart, int width, int height, String fileName) { Platform.runLater(() -> { Stage stage = new Stage(); @@ -156,13 +138,18 @@ private void genChart(Chart chart, int width, int height, String fileName) { }); } + /** + * Writes the {@link WritableImage} to a file. + * + * @param image {@link WritableImage} which is written the given file + * @param fileName file name of the image to be written + */ private void writeImage(WritableImage image, String fileName) { - File file = new File(Paths.get(chartGenLocation, fileName).toString()); try { ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file); } catch (IOException e) { - logger.error("Error occured while writing the chart image", e); + logger.error("Error occurred while writing the chart image", e); } } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 39e0d14a1..dacda6a67 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.DeploymentPattern; +import org.wso2.testgrid.common.InfraCombination; import org.wso2.testgrid.common.Product; import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestCase; @@ -36,6 +37,9 @@ import org.wso2.testgrid.reporting.model.PerAxisSummary; import org.wso2.testgrid.reporting.model.Report; import org.wso2.testgrid.reporting.model.ReportElement; +import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; +import org.wso2.testgrid.reporting.model.email.BuildFailureSummary; +import org.wso2.testgrid.reporting.model.email.TestCaseResultSection; import org.wso2.testgrid.reporting.model.performance.PerformanceReport; import org.wso2.testgrid.reporting.renderer.Renderable; import org.wso2.testgrid.reporting.renderer.RenderableFactory; @@ -58,6 +62,8 @@ import java.util.stream.Collectors; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; +import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_SUMMARIZED_EMAIL_REPORT_NAME; +import static org.wso2.testgrid.common.util.FileUtil.writeToFile; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; @@ -74,8 +80,10 @@ public class TestReportEngine { private static final String REPORT_MUSTACHE = "report.mustache"; private static final String PERFORMANCE_REPORT_MUSTACHE = "performance_report.mustache"; private static final String EMAIL_REPORT_MUSTACHE = "email_report.mustache"; + private static final String SUMMARIZED_EMAIL_REPORT_MUSTACHE = "summarized_email_report.mustache"; private static final String REPORT_TEMPLATE_KEY = "parsedReport"; private static final String PER_TEST_PLAN_TEMPLATE_KEY = "perTestPlan"; + private static final String PER_TEST_CASE_TEMPLATE_KEY = "perTestCase"; private static final String PRODUCT_STATUS_TEMPLATE_KEY = "productTestStatus"; private static final String PRODUCT_NAME_TEMPLATE_KEY = "productName"; private static final String GIT_BUILD_DETAILS_TEMPLATE_KEY = "gitBuildDetails"; @@ -739,27 +747,7 @@ private void writeHTMLToFile(Path filePath, String htmlString) throws ReportingE * @param workspace workspace containing the test-plan yamls */ public Optional generateEmailReport(Product product, String workspace) throws ReportingException { - List testPlans = new ArrayList<>(); - try { - List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); - for (String testPlanId : testPlanIds) { - Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); - if (testPlanById.isPresent()) { - logger.info("Derived test plan dir in email phase : " + TestGridUtil - .deriveTestPlanDirName(testPlanById.get())); - testPlans.add(testPlanById.get()); - } else { - logger.error(String.format( - "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", testPlanId)); - } - } - } catch (TestGridDAOException e) { - throw new ReportingException("Error occurred while getting the test plan from database ", e); - } catch (TestGridException e) { - throw new ReportingException( - "Error occurred while getting the test plan id by reading test grid yaml files ", e); - } + List testPlans = getTestPlansInWorkspace(workspace); //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " @@ -783,4 +771,95 @@ public Optional generateEmailReport(Product product, String workspace) thr writeHTMLToFile(reportPath, htmlString); return Optional.of(reportPath); } + + /** + * Generate a summarized HTML report which is used as the content of the email to be sent out to + * relevant parties interested in TestGrid test job. + * + * @param product product needing the report + * @param workspace workspace containing the test-plan yamls + * @return {@link Path} of the created report + */ + public Optional generateSummarizedEmailReport(Product product, String workspace) + throws ReportingException, TestGridException { + + List testPlans = getTestPlansInWorkspace(workspace); + + //start email generation + if (!emailReportProcessor.hasFailedTests(testPlans)) { + logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " + + "Hence skipping email-report generation.."); + return Optional.empty(); + } + GraphDataProvider graphDataProvider = new GraphDataProvider(); + + List failureSummary = graphDataProvider.getTestFailureSummary(workspace); + Map results = new HashMap<>(); + + List resultList = new ArrayList<>(); + + for (BuildFailureSummary summary : failureSummary) { + TestCaseResultSection resultSection = new TestCaseResultSection(); + resultSection.setTestCaseName(summary.getTestCaseName()); + resultSection.setTestCaseDescription(summary.getTestCaseDescription()); + List combinations = summary.getInfraCombinations(); + resultSection.setTestCaseExecutedOS(combinations.get(0).getOs()); + resultSection.setTestCaseExecutedJDK(combinations.get(0).getJdk()); + resultSection.setTestCaseExecutedDB(combinations.get(0).getDbEngine()); + + if (combinations.size() > 1) { + resultSection.setInfraCombinations(combinations.subList(1, combinations.size())); + } + resultList.add(resultSection); + } + + Renderable renderer = RenderableFactory.getRenderable(EMAIL_REPORT_MUSTACHE); + + results.put(PRODUCT_NAME_TEMPLATE_KEY, product.getName()); + results.put(GIT_BUILD_DETAILS_TEMPLATE_KEY, emailReportProcessor.getGitBuildDetails(product, testPlans)); + results.put(PRODUCT_STATUS_TEMPLATE_KEY, emailReportProcessor.getProductStatus(product).toString()); + results.put(PER_TEST_CASE_TEMPLATE_KEY, resultList); + String htmlString = renderer.render(SUMMARIZED_EMAIL_REPORT_MUSTACHE, results); + + // Write to HTML file + String relativeFilePath = TestGridUtil + .deriveTestGridLogFilePath(product.getName(), TESTGRID_SUMMARIZED_EMAIL_REPORT_NAME); + String testGridHome = TestGridUtil.getTestGridHomePath(); + Path reportPath = Paths.get(testGridHome, relativeFilePath); + writeToFile(reportPath.toString(), htmlString); + + // Generating the charts + BuildExecutionSummary summary = graphDataProvider.getTestExecutionSummary(workspace); + ChartGenerator chartGenerator = new ChartGenerator(reportPath.toString()); + chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary + .getSkippedTestPlans()); + + return Optional.of(reportPath); + } + + // + private List getTestPlansInWorkspace(String workspace) throws ReportingException { + List testPlans = new ArrayList<>(); + try { + List testPlanIds = FileUtil.getTestPlanIdByReadingTGYaml(workspace); + for (String testPlanId : testPlanIds) { + Optional testPlanById = testPlanUOW.getTestPlanById(testPlanId); + if (testPlanById.isPresent()) { + logger.info("Derived test plan dir in email phase : " + TestGridUtil + .deriveTestPlanDirName(testPlanById.get())); + testPlans.add(testPlanById.get()); + } else { + logger.error(String.format( + "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " + + "Ignoring the test plan...", testPlanId)); + } + } + } catch (TestGridDAOException e) { + throw new ReportingException("Error occurred while getting the test plan from database ", e); + } catch (TestGridException e) { + throw new ReportingException( + "Error occurred while getting the test plan id by reading test grid yaml files ", e); + } + return testPlans; + } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java new file mode 100644 index 000000000..f5b377de1 --- /dev/null +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java @@ -0,0 +1,76 @@ +package org.wso2.testgrid.reporting.model.email; + +import org.wso2.testgrid.common.InfraCombination; + +import java.util.List; + +/** + * Model class representing the test-plan result section in summarized email-report. + */ +public class TestCaseResultSection { + + private String testCaseName; + private String testCaseDescription; + private String testCaseExecutedOS; + private String testCaseExecutedJDK; + private String testCaseExecutedDB; + int rowSpan; + + List infraCombinations; + + public String getTestCaseName() { + return testCaseName; + } + + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } + + public String getTestCaseDescription() { + return testCaseDescription; + } + + public void setTestCaseDescription(String testCaseDescription) { + this.testCaseDescription = testCaseDescription; + } + + public String getTestCaseExecutedOS() { + return testCaseExecutedOS; + } + + public void setTestCaseExecutedOS(String testCaseExecutedOS) { + this.testCaseExecutedOS = testCaseExecutedOS; + } + + public String getTestCaseExecutedJDK() { + return testCaseExecutedJDK; + } + + public void setTestCaseExecutedJDK(String testCaseExecutedJDK) { + this.testCaseExecutedJDK = testCaseExecutedJDK; + } + + public String getTestCaseExecutedDB() { + return testCaseExecutedDB; + } + + public void setTestCaseExecutedDB(String testCaseExecutedDB) { + this.testCaseExecutedDB = testCaseExecutedDB; + } + + public List getInfraCombinations() { + return infraCombinations; + } + + public void setInfraCombinations(List infraCombinations) { + this.infraCombinations = infraCombinations; + } + + public int getRowSpan() { + return rowSpan; + } + + public void setRowSpan(int rowSpan) { + this.rowSpan = rowSpan; + } +} diff --git a/reporting/src/main/resources/templates/summarized_email_report.mustache b/reporting/src/main/resources/templates/summarized_email_report.mustache new file mode 100644 index 000000000..62b9feb45 --- /dev/null +++ b/reporting/src/main/resources/templates/summarized_email_report.mustache @@ -0,0 +1,187 @@ + + + + + + WSO2 Test Grid - Test Execution Summary + + + + + + + + + +
WSO2

TestGrid Test Execution Results

+
+
+ + + + +
+ + + + +
+ {{productName}} integration tests {{productTestStatus}}!
+
+
+
+
{{{gitBuildDetails}}}
+
+ Test Result Summary +

+ + + + + +
+ + + +
+
+ Testcase Failure Summary Table +
+ + + + + + + + + + {{#perTestCase}} + + + + + + + + {{#infraCombinations}} + + + + + + {{/infraCombinations}} + {{/perTestCase}} + +
Failed Test CaseDescriptionOSJDKDB
{{testCaseName}}{{testCaseDescription}}{{testCaseExecutedOS}}{{testCaseExecutedJDK}}{{testCaseExecutedDB}}
{{os}}{{jdk}}{{dbEngine}}
+ Tested by WSO2 TestGrid. +
+ + From 1f54a32ba525b46ff62de30747daeb5f9dd352fa Mon Sep 17 00:00:00 2001 From: Yasassri Date: Wed, 25 Jul 2018 23:42:25 +0530 Subject: [PATCH 14/22] Code refactor --- .../wso2/testgrid/dao/uow/TestCaseUOW.java | 2 +- .../testgrid/reporting/TestReportEngine.java | 55 +++++++++++++------ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestCaseUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestCaseUOW.java index 281d91c88..09d6cfc15 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestCaseUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestCaseUOW.java @@ -79,7 +79,7 @@ public Optional getTestCaseById(String id) throws TestGridDAOException @SuppressWarnings("unchecked") public boolean isExistsFailedTests(TestScenario testScenario) throws TestGridDAOException { List resultObject = testCaseRepository.executeTypedQuery("SELECT * FROM test_case " - + "WHERE TESTSCENARIO_id = '" + testScenario.getId() + "' AND is_success = FALSE;"); + + "WHERE TESTSCENARIO_id = '" + testScenario.getId() + "' AND status = FAIL;"); return resultObject.isEmpty(); } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index dacda6a67..7d15a77ca 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -63,7 +63,6 @@ import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_EMAIL_REPORT_NAME; import static org.wso2.testgrid.common.TestGridConstants.TESTGRID_SUMMARIZED_EMAIL_REPORT_NAME; -import static org.wso2.testgrid.common.util.FileUtil.writeToFile; import static org.wso2.testgrid.reporting.AxisColumn.DEPLOYMENT; import static org.wso2.testgrid.reporting.AxisColumn.INFRASTRUCTURE; import static org.wso2.testgrid.reporting.AxisColumn.SCENARIO; @@ -780,8 +779,7 @@ public Optional generateEmailReport(Product product, String workspace) thr * @param workspace workspace containing the test-plan yamls * @return {@link Path} of the created report */ - public Optional generateSummarizedEmailReport(Product product, String workspace) - throws ReportingException, TestGridException { + public Optional generateSummarizedEmailReport(Product product, String workspace) throws ReportingException { List testPlans = getTestPlansInWorkspace(workspace); @@ -792,17 +790,16 @@ public Optional generateSummarizedEmailReport(Product product, String work return Optional.empty(); } GraphDataProvider graphDataProvider = new GraphDataProvider(); - List failureSummary = graphDataProvider.getTestFailureSummary(workspace); - Map results = new HashMap<>(); + Map results = new HashMap<>(); List resultList = new ArrayList<>(); - for (BuildFailureSummary summary : failureSummary) { + for (BuildFailureSummary buildFailureSummary : failureSummary) { TestCaseResultSection resultSection = new TestCaseResultSection(); - resultSection.setTestCaseName(summary.getTestCaseName()); - resultSection.setTestCaseDescription(summary.getTestCaseDescription()); - List combinations = summary.getInfraCombinations(); + resultSection.setTestCaseName(buildFailureSummary.getTestCaseName()); + resultSection.setTestCaseDescription(buildFailureSummary.getTestCaseDescription()); + List combinations = buildFailureSummary.getInfraCombinations(); resultSection.setTestCaseExecutedOS(combinations.get(0).getOs()); resultSection.setTestCaseExecutedJDK(combinations.get(0).getJdk()); resultSection.setTestCaseExecutedDB(combinations.get(0).getDbEngine()); @@ -826,18 +823,20 @@ public Optional generateSummarizedEmailReport(Product product, String work .deriveTestGridLogFilePath(product.getName(), TESTGRID_SUMMARIZED_EMAIL_REPORT_NAME); String testGridHome = TestGridUtil.getTestGridHomePath(); Path reportPath = Paths.get(testGridHome, relativeFilePath); - writeToFile(reportPath.toString(), htmlString); - - // Generating the charts - BuildExecutionSummary summary = graphDataProvider.getTestExecutionSummary(workspace); - ChartGenerator chartGenerator = new ChartGenerator(reportPath.toString()); - chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary - .getSkippedTestPlans()); + writeHTMLToFile(reportPath, htmlString); + // Generating the charts required for the email + generateSummarizedCharts(workspace, reportPath.getParent().toString()); return Optional.of(reportPath); } - // + /** + * Returns a list of {@link TestPlan} for a given workspace. + * + * @param workspace build workspace + * @return a list of {@link TestPlan} in the given workspace + * @throws ReportingException if {@link TestGridDAOException} or {@link TestGridException} occurs + */ private List getTestPlansInWorkspace(String workspace) throws ReportingException { List testPlans = new ArrayList<>(); try { @@ -856,10 +855,30 @@ private List getTestPlansInWorkspace(String workspace) throws Reportin } } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); - } catch (TestGridException e) { + } catch (TestGridException e) { throw new ReportingException( "Error occurred while getting the test plan id by reading test grid yaml files ", e); } return testPlans; } + + /** + * Generate summarized charts for the summary email. + * + * @param workspace curent workspace of the build + * @param chartGenLocation location where charts should be generated + */ + private void generateSummarizedCharts(String workspace, String chartGenLocation) throws ReportingException { + GraphDataProvider dataProvider = new GraphDataProvider(); + logger.info(StringUtil + .concatStrings("Generating Charts with workspace : ", workspace, " at ", chartGenLocation)); + BuildExecutionSummary summary = dataProvider.getTestExecutionSummary(workspace); + ChartGenerator chartGenerator = new ChartGenerator(chartGenLocation); + + // Generating the charts + chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary + .getSkippedTestPlans()); + // Generate history chart + //chartGenerator.generateResultHistoryChart("",""); + } } From c89eec0c74934148d9da4e216c518f08dbfa085a Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Thu, 26 Jul 2018 07:30:55 +0530 Subject: [PATCH 15/22] Fix build failure and test failure summary getting issue --- .../core/command/GenerateEmailCommand.java | 3 +- .../dao/dto/TestCaseFailureResultDTO.java | 20 +++----- .../dao/repository/TestPlanRepository.java | 51 ++++++++++++++++--- .../wso2/testgrid/dao/uow/TestPlanUOW.java | 2 +- .../testgrid/reporting/GraphDataProvider.java | 5 +- .../testgrid/reporting/TestReportEngine.java | 11 ++-- .../wso2/testgrid/web/api/ProductService.java | 1 - 7 files changed, 64 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java index 38d23e55b..5ed37deb9 100644 --- a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java +++ b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java @@ -24,7 +24,6 @@ import org.slf4j.LoggerFactory; import org.wso2.testgrid.common.Product; import org.wso2.testgrid.common.exception.CommandExecutionException; -import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.StringUtil; import org.wso2.testgrid.dao.TestGridDAOException; import org.wso2.testgrid.dao.uow.ProductUOW; @@ -53,7 +52,7 @@ public class GenerateEmailCommand implements Command { private String workspace = ""; @Override - public void execute() throws CommandExecutionException, TestGridException { + public void execute() throws CommandExecutionException { Product product = getProduct(productName); try { TestReportEngine testReportEngine = new TestReportEngine(); diff --git a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java index 057339e60..0e223b1ef 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/dto/TestCaseFailureResultDTO.java @@ -18,37 +18,29 @@ package org.wso2.testgrid.dao.dto; -import javax.persistence.ColumnResult; -import javax.persistence.ConstructorResult; -import javax.persistence.SqlResultSetMapping; - /** * Defines a model object of test case failure results. * * @since 1.0.0 */ -@SqlResultSetMapping(name = "TestCaseFailureResult", classes = { - @ConstructorResult(targetClass = TestCaseFailureResultDTO.class, columns = { @ColumnResult(name = "testName"), - @ColumnResult(name = "failureMessage"), - @ColumnResult(name = "infraParameters") }) }) public class TestCaseFailureResultDTO { - private String testName; + private String name; private String failureMessage; private String infraParameters; public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) { - this.testName = testname; + this.name = testname; this.failureMessage = failureMessage; this.infraParameters = infraParameters; } - public String getTestName() { - return testName; + public String getName() { + return name; } - public void setTestName(String testName) { - this.testName = testName; + public void setName(String name) { + this.name = name; } public String getFailureMessage() { diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 087365854..84fe14b17 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -26,8 +26,12 @@ import org.wso2.testgrid.dao.TestGridDAOException; import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; @@ -298,24 +302,22 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { * @param testPlanIds test plan ids * @return a List of {@link TestCaseFailureResultDTO} representing the test case failure results for a given build */ - public List getTestFailureSummaryByTPId(List testPlanIds) { + public List getTestFailureSummaryByTPId(List testPlanIds) + throws TestGridDAOException { StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " - + "testName, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " + + "name, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); for (int i = 0; i < testPlanIds.size() - 1; i++) { sql.append("?, "); } sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;"); - Query query = entityManager.createNativeQuery(sql.toString(), "TestCaseFailureResult"); + Query query = entityManager.createNativeQuery(sql.toString()); int index = 1; for (String s : testPlanIds) { query.setParameter(index++, s); } - @SuppressWarnings("unchecked") - List testCaseFailureResultDTO = (List) query - .getResultList(); - return testCaseFailureResultDTO; + return getResultList(query, TestCaseFailureResultDTO.class); } /** @@ -363,4 +365,39 @@ public List getTestExecutionHistory(String productId, String from, Str .getResultList(); return EntityManagerHelper.refreshResultList(entityManager, resultList); } + + public static T map(Class type, Object[] tuple) throws TestGridDAOException { + List> tupleTypes = new ArrayList<>(); + for (Object field : tuple) { + tupleTypes.add(field.getClass()); + } + + Constructor ctor; + try { + ctor = type.getConstructor(tupleTypes.toArray(new Class[tuple.length])); + return ctor.newInstance(tuple); + } catch (NoSuchMethodException e) { + throw new TestGridDAOException("ss", e); + } catch (InstantiationException e) { + throw new TestGridDAOException("ssaa", e); + } catch (IllegalAccessException e) { + throw new TestGridDAOException("ssdddd", e); + } catch (InvocationTargetException e) { + throw new TestGridDAOException("ssrrrrrr", e); + } + + } + + public static List map(Class type, List records) throws TestGridDAOException { + List result = new LinkedList<>(); + for (Object[] record : records) { + result.add(map(type, record)); + } + return result; + } + + public static List getResultList(Query query, Class type) throws TestGridDAOException { + @SuppressWarnings("unchecked") List records = query.getResultList(); + return map(type, records); + } } diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index af179e54b..878d2361f 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -197,7 +197,7 @@ public List getTestExecutionSummary(List tpIds) { * * @return a List of TestCaseFailureResultDTO which represent test cases failure for given test plan ids. */ - public List getTestFailureSummary(List tpIds) { + public List getTestFailureSummary(List tpIds) throws TestGridDAOException { return testPlanRepository.getTestFailureSummaryByTPId(tpIds); } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java index 1ccadd63d..e3c79d619 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -29,6 +29,7 @@ import org.wso2.testgrid.common.exception.TestGridException; import org.wso2.testgrid.common.util.FileUtil; import org.wso2.testgrid.common.util.StringUtil; +import org.wso2.testgrid.dao.TestGridDAOException; import org.wso2.testgrid.dao.dto.TestCaseFailureResultDTO; import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; @@ -77,6 +78,8 @@ public List getTestFailureSummary(String workspace) throws return processTestFailureSummary(testFailureSummary); } catch (TestGridException e) { throw new ReportingException("Error occurred while reading yaml files in the TG home", e); + } catch (TestGridDAOException e) { + throw new ReportingException("Error occurred while reading yaml files in the TG home", e); } } @@ -92,7 +95,7 @@ private List processTestFailureSummary(List generateSummarizedEmailReport(Product product, String work Path reportPath = Paths.get(testGridHome, relativeFilePath); writeHTMLToFile(reportPath, htmlString); // Generating the charts required for the email - generateSummarizedCharts(workspace, reportPath.getParent().toString()); + //todo need to fix properly + try { + generateSummarizedCharts(workspace, reportPath.getParent().toString()); + } catch (NullPointerException e) { + throw new ReportingException("Null point exception occured"); + } return Optional.of(reportPath); } @@ -850,12 +855,12 @@ private List getTestPlansInWorkspace(String workspace) throws Reportin } else { logger.error(String.format( "Inconsistent state: The test plan yaml with id '%s' has no entry in the database. " - + "Ignoring the test plan...", testPlanId)); + + "Ignoring the test plan...", testPlanId)); } } } catch (TestGridDAOException e) { throw new ReportingException("Error occurred while getting the test plan from database ", e); - } catch (TestGridException e) { + } catch (TestGridException e) { throw new ReportingException( "Error occurred while getting the test plan id by reading test grid yaml files ", e); } diff --git a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java index ef06fe6f9..88493f8e8 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java @@ -29,7 +29,6 @@ import org.wso2.testgrid.dao.uow.ProductUOW; import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.AxisColumn; -import org.wso2.testgrid.reporting.GraphDataProvider; import org.wso2.testgrid.web.bean.ErrorResponse; import org.wso2.testgrid.web.bean.ProductStatus; import org.wso2.testgrid.web.plugins.AWSArtifactReader; From d4358844358ff368032daa2c2d2da5608cff1dd7 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Thu, 26 Jul 2018 10:01:58 +0530 Subject: [PATCH 16/22] Fix templating and DB mapping issue --- .../dao/repository/TestPlanRepository.java | 8 +++--- .../testgrid/reporting/ChartGenerator.java | 28 ++++++++----------- .../testgrid/reporting/TestReportEngine.java | 18 ++++++------ .../model/email/TestCaseResultSection.java | 2 +- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 84fe14b17..9c32a7aed 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -304,9 +304,9 @@ public List getTestPlanOlderThan(String duration, String timeUnit) { */ public List getTestFailureSummaryByTPId(List testPlanIds) throws TestGridDAOException { - StringBuilder sql = new StringBuilder("select tp.infra_parameters as infraParametrs , failed_tc.test_name as " - + "name, failed_tc.failure_message as failureMessage from test_plan tp join (select tc.test_name, " - + "tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + StringBuilder sql = new StringBuilder("select failed_tc.test_name as name, failed_tc.failure_message as " + + "failureMessage, tp.infra_parameters as infraParametrs from test_plan tp join (select tc" + + ".test_name, tc.failure_message, ts.TESTPLAN_id from test_case tc inner join test_scenario ts on " + "ts.id=tc.TESTSCENARIO_id and tc.status = 'FAIL' and ts.TESTPLAN_id in ("); for (int i = 0; i < testPlanIds.size() - 1; i++) { sql.append("?, "); @@ -331,7 +331,7 @@ public List getTestExecutionSummaryByTPId(List testPlanIds) { for (int i = 0; i < testPlanIds.size() - 1; i++) { sql.append("?, "); } - sql.append("?):"); + sql.append("?);"); Query query = entityManager.createNativeQuery(sql.toString()); int index = 1; for (String s : testPlanIds) { diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java index f80eda13f..ac80096cf 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -16,6 +16,7 @@ import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; import java.io.File; import java.io.IOException; @@ -65,7 +66,7 @@ public void generateSummaryChart(int passedCount, int failedCount, int skippedCo * * @param dataSet input data-set for the chart */ - public void generateResultHistoryChart(Map dataSet) { + public void generateResultHistoryChart(Map dataSet) { final CategoryAxis xAxis = new CategoryAxis(); final NumberAxis yAxis = new NumberAxis(); @@ -74,33 +75,28 @@ public void generateResultHistoryChart(Map dataSet) { final XYChart.Series[] seriesSet = new XYChart.Series[]{new XYChart.Series<>(), new XYChart.Series<>(), new XYChart.Series<>()}; + xAxis.setCategories(FXCollections.observableArrayList(dataSet.keySet())); + // Disabling animation + xAxis.setAnimated(false); + yAxis.setAnimated(false); + stackedBarChart.setAnimated(false); // Set Axis Names - xAxis.setLabel("Build Number"); + xAxis.setLabel("Build Timestamp"); yAxis.setLabel("Number of Infra Combinations"); // Setting series names seriesSet[0].setName("Build Failed Combinations"); seriesSet[1].setName("Build Passed Combinations"); seriesSet[2].setName("Infra Failed Combinations"); - // Setting space between the bars stackedBarChart.setCategoryGap(50); - //Setting the title of the bar chart. stackedBarChart.setTitle("History of test execution summary"); - dataSet.forEach((key, value) -> { - String[] resultSet = value.split(","); - if (resultSet.length != seriesSet.length) { - logger.error("Input value set didn't match the series count!! Total number of series " + - "expected : " + seriesSet.length + " Total number of series received " + - resultSet.length); - } - int i = 0; - for (XYChart.Series series : seriesSet) { - series.getData().add(new XYChart.Data<>(key, Integer.parseInt(resultSet[i]))); - i++; - } + dataSet.forEach((key, summary) -> { + seriesSet[0].getData().add(new XYChart.Data<>(key, summary.getFailedTestPlans())); + seriesSet[1].getData().add(new XYChart.Data<>(key, summary.getPassedTestPlans())); + seriesSet[2].getData().add(new XYChart.Data<>(key, summary.getSkippedTestPlans())); }); // Adding the series to the chart diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 5dd2d11cd..28a2b48c2 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -806,6 +806,7 @@ public Optional generateSummarizedEmailReport(Product product, String work if (combinations.size() > 1) { resultSection.setInfraCombinations(combinations.subList(1, combinations.size())); + resultSection.setRowSpan(combinations.size()); } resultList.add(resultSection); } @@ -827,11 +828,10 @@ public Optional generateSummarizedEmailReport(Product product, String work // Generating the charts required for the email //todo need to fix properly try { - generateSummarizedCharts(workspace, reportPath.getParent().toString()); + generateSummarizedCharts(workspace, reportPath.getParent().toString(), product.getId()); } catch (NullPointerException e) { throw new ReportingException("Null point exception occured"); } - return Optional.of(reportPath); } @@ -869,11 +869,12 @@ private List getTestPlansInWorkspace(String workspace) throws Reportin /** * Generate summarized charts for the summary email. - * - * @param workspace curent workspace of the build + * @param workspace curent workspace of the build * @param chartGenLocation location where charts should be generated + * @param id */ - private void generateSummarizedCharts(String workspace, String chartGenLocation) throws ReportingException { + private void generateSummarizedCharts(String workspace, String chartGenLocation, String id) + throws ReportingException { GraphDataProvider dataProvider = new GraphDataProvider(); logger.info(StringUtil .concatStrings("Generating Charts with workspace : ", workspace, " at ", chartGenLocation)); @@ -881,9 +882,10 @@ private void generateSummarizedCharts(String workspace, String chartGenLocation) ChartGenerator chartGenerator = new ChartGenerator(chartGenLocation); // Generating the charts - chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary - .getSkippedTestPlans()); + // chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary + // .getSkippedTestPlans()); + // Generate history chart - //chartGenerator.generateResultHistoryChart("",""); + // chartGenerator.generateResultHistoryChart(dataProvider.getTestExecutionHistory(id)); } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java index f5b377de1..925c4d71d 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java @@ -14,7 +14,7 @@ public class TestCaseResultSection { private String testCaseExecutedOS; private String testCaseExecutedJDK; private String testCaseExecutedDB; - int rowSpan; + int rowSpan = -1; List infraCombinations; From 9008084014dccd76933a118b6bc455d7331d6c75 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Thu, 26 Jul 2018 12:54:54 +0530 Subject: [PATCH 17/22] Enable Analyzed report generation --- .../core/command/GenerateEmailCommand.java | 10 +- .../testgrid/reporting/ChartGenerator.java | 1 + .../testgrid/reporting/TestReportEngine.java | 8 +- .../reporting/TestReportEngineTest.java | 93 ------------------- 4 files changed, 12 insertions(+), 100 deletions(-) diff --git a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java index 5ed37deb9..ed7a9167f 100644 --- a/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java +++ b/core/src/main/java/org/wso2/testgrid/core/command/GenerateEmailCommand.java @@ -56,8 +56,14 @@ public void execute() throws CommandExecutionException { Product product = getProduct(productName); try { TestReportEngine testReportEngine = new TestReportEngine(); - final Optional path = testReportEngine.generateSummarizedEmailReport(product, workspace); - path.ifPresent(p -> logger.info("Written the email report body contents to: " + p)); + // Generating the summary report + final Optional summarizedReportPath = testReportEngine.generateSummarizedEmailReport(product, + workspace); + summarizedReportPath.ifPresent(p -> logger.info("Written the summarized email " + + "report body contents to: " + p)); + + final Optional reportPath = testReportEngine.generateEmailReport(product, workspace); + reportPath.ifPresent(p -> logger.info("Written the email report body contents to: " + p)); } catch (ReportingException e) { throw new CommandExecutionException(StringUtil .concatStrings("Error occurred when generating email report for {" + diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java index ac80096cf..784e4028e 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -57,6 +57,7 @@ public void generateSummaryChart(int passedCount, int failedCount, int skippedCo new PieChart.Data("Skipped", skippedCount), new PieChart.Data("Passed", passedCount)); final PieChart chart = new PieChart(pieChartData); + chart.setAnimated(false); chart.setTitle("Build Failure Summary by Test Plans"); genChart(chart, 500, 500, summaryChartFileName); } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index 0cb4e77ab..fe6497605 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -835,7 +835,6 @@ private List getTestPlans(String workspace, Path testPlansDir) throws public Optional generateSummarizedEmailReport(Product product, String workspace) throws ReportingException { List testPlans = getTestPlansInWorkspace(workspace); - //start email generation if (!emailReportProcessor.hasFailedTests(testPlans)) { logger.info("Latest build of '" + product.getName() + "' does not contain failed tests. " @@ -935,10 +934,9 @@ private void generateSummarizedCharts(String workspace, String chartGenLocation, ChartGenerator chartGenerator = new ChartGenerator(chartGenLocation); // Generating the charts - // chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary - // .getSkippedTestPlans()); - + chartGenerator.generateSummaryChart(summary.getPassedTestPlans(), summary.getFailedTestPlans(), summary + .getSkippedTestPlans()); // Generate history chart - // chartGenerator.generateResultHistoryChart(dataProvider.getTestExecutionHistory(id)); + chartGenerator.generateResultHistoryChart(dataProvider.getTestExecutionHistory(id)); } } diff --git a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java index 4cbf1f554..7ae81ab93 100644 --- a/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java +++ b/reporting/src/test/java/org/wso2/testgrid/reporting/TestReportEngineTest.java @@ -27,18 +27,6 @@ import org.wso2.testgrid.common.Product; import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestPlan; -<<<<<<< HEAD -import org.wso2.testgrid.common.TestScenario; -import org.wso2.testgrid.common.config.InfrastructureConfig; -import org.wso2.testgrid.common.exception.TestGridException; -import org.wso2.testgrid.common.util.StringUtil; -import org.wso2.testgrid.common.util.TestGridUtil; -import org.wso2.testgrid.dao.TestGridDAOException; -import org.wso2.testgrid.dao.uow.TestCaseUOW; -import org.wso2.testgrid.dao.uow.TestPlanUOW; -import org.wso2.testgrid.dao.uow.TestScenarioUOW; -======= ->>>>>>> upstream/master import java.nio.file.Path; import java.util.List; @@ -59,86 +47,6 @@ public void generateEmailReport(String testNum) throws Exception { logger.info("---- Running " + testNum); List testPlans = getTestPlansFor(testNum); - -<<<<<<< HEAD - @BeforeMethod - public void init() throws Exception { - System.setProperty(TestGridConstants.TESTGRID_HOME_SYSTEM_PROPERTY, TESTGRID_HOME); - Files.createDirectories(Paths.get(TESTGRID_HOME)); - - final String randomStr = StringUtil.generateRandomString(5); - String productName = "wso2-" + randomStr; - this.product = new Product(); - product.setName(productName); - productDir = Paths.get(TESTGRID_HOME).resolve("jobs").resolve(productName); - Files.createDirectories(productDir); - - MockitoAnnotations.initMocks(this); - - testPlan = new TestPlan(); - testPlan.setInfraParameters("{\"OSVersion\":\"2016\",\"JDK\":\"ORACLE_JDK8\",\"OS\":\"Windows\"," - + "\"DBEngineVersion\":\"5.7\",\"DBEngine\":\"mysql\"}"); - testPlan.setStatus(Status.FAIL); - testPlan.setId(testPlanId); - - InfrastructureConfig infraConfig = new InfrastructureConfig(); - Properties p = new Properties(); - p.setProperty("DBEngine", "mysql"); - p.setProperty("DBEngineVersion", "5.7"); - p.setProperty("OS", "CentOS"); - p.setProperty("JDK", "ORACLE_JDK8"); - infraConfig.setParameters(p); - testPlan.setInfrastructureConfig(infraConfig); - - TestScenario s = new TestScenario(); - s.setName("Sample scenario 01"); - s.setStatus(Status.SUCCESS); - TestScenario s2 = new TestScenario(); - s2.setName("Sample scenario 02"); - s2.setStatus(Status.FAIL); - - TestCase tc = new TestCase(); - tc.setSuccess(Status.SUCCESS); - tc.setFailureMessage("success"); - tc.setName("Sample Testcase 01"); - tc.setTestScenario(s); - s.addTestCase(tc); - - tc = new TestCase(); - tc.setSuccess(Status.FAIL); - tc.setFailureMessage("fail"); - tc.setName("Sample Testcase 02"); - tc.setTestScenario(s2); - s2.addTestCase(tc); - - tc = new TestCase(); - tc.setSuccess(Status.FAIL); - tc.setFailureMessage("fail"); - tc.setName("Sample Testcase 03"); - tc.setTestScenario(s2); - s2.addTestCase(tc); - testPlan.setTestScenarios(Arrays.asList(s, s2)); - - DeploymentPattern dp = new DeploymentPattern(); - dp.setName("dp"); - dp.setProduct(product); - testPlan.setDeploymentPattern(dp); - - final Path testPlanPath = Paths.get("src", "test", "resources", "test-plan-01.yaml"); - final Path testPlanFinalPath = Paths.get("target", "testgrid-home", TestGridConstants.TESTGRID_JOB_DIR, - product.getName(), TestGridConstants.PRODUCT_TEST_PLANS_DIR, "test-plan-01.yaml"); - Files.createDirectories(testPlanFinalPath.getParent()); - Files.copy(testPlanPath, testPlanFinalPath, StandardCopyOption.REPLACE_EXISTING); - - Path testSuiteTxtPath = Paths.get("src", "test", "resources", "surefire-reports"); - Path testSuiteTxtFinalPath = TestGridUtil.getSurefireReportsDir(testPlan); - FileUtils.copyDirectory(testSuiteTxtPath.toFile(), testSuiteTxtFinalPath.toFile()); - } - - @Test - public void generateEmailReport() throws TestGridDAOException, ReportingException, TestGridException { -======= ->>>>>>> upstream/master when(testPlanUOW.getLatestTestPlans(Matchers.any(Product.class))) .thenReturn(testPlans); when(testPlanUOW.getTestPlanById("abc")).thenReturn(Optional.of(testPlans.get(0))); @@ -158,5 +66,4 @@ public void generateEmailReport() throws TestGridDAOException, ReportingExceptio Assert.assertTrue(path.isPresent(), "Email report generation has failed. File path is empty."); logger.info("email report file: " + path.get()); } - } From 5966afe8e6cddbbad6900c9b6b238e224476ee86 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Thu, 26 Jul 2018 15:54:53 +0530 Subject: [PATCH 18/22] Improve mutache template --- .../summarized_email_report.mustache | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/reporting/src/main/resources/templates/summarized_email_report.mustache b/reporting/src/main/resources/templates/summarized_email_report.mustache index 62b9feb45..86d3ed2a9 100644 --- a/reporting/src/main/resources/templates/summarized_email_report.mustache +++ b/reporting/src/main/resources/templates/summarized_email_report.mustache @@ -30,7 +30,8 @@ font-family: sans-serif; border: 0px solid #000000; background-color: #FFFFFF; - width: 95%; + width: 90%; + table-layout: fixed; text-align: left; border-collapse: collapse; } @@ -42,6 +43,7 @@ table.reportTable tbody td { font-size: 12px; + word-break: break-word; } table.reportTable tr:nth-child(even) { @@ -94,10 +96,11 @@ .testResultSubTitle { font-family: sans-serif; - font-size: 17px; + font-size: 23px; line-height: 20px; font-weight: bold; color: #e46226; + padding: 5px; } .consoleLog { @@ -118,7 +121,7 @@ - +
WSO2

TestGrid Test Execution Results

TestGrid : Test Execution Results


@@ -129,7 +132,7 @@
- {{productName}} integration tests {{productTestStatus}}!
+ {{productName}} integration tests FAILED!
@@ -140,7 +143,7 @@
{{{gitBuildDetails}}}

Test Result Summary -

+

@@ -153,15 +156,17 @@

Testcase Failure Summary Table -
+

+ - - + + + {{#perTestCase}} From 8c373831f0854e0154e1c3cd847c800fcab30a19 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Thu, 26 Jul 2018 17:05:12 +0530 Subject: [PATCH 19/22] Improve email generating methond and fix formatting issues --- .../dao/repository/TestPlanRepository.java | 65 +++++++++++-------- .../testgrid/reporting/TestReportEngine.java | 19 +++--- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index 9c32a7aed..a26471c83 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -366,38 +366,49 @@ public List getTestExecutionHistory(String productId, String from, Str return EntityManagerHelper.refreshResultList(entityManager, resultList); } - public static T map(Class type, Object[] tuple) throws TestGridDAOException { - List> tupleTypes = new ArrayList<>(); - for (Object field : tuple) { - tupleTypes.add(field.getClass()); - } - - Constructor ctor; - try { - ctor = type.getConstructor(tupleTypes.toArray(new Class[tuple.length])); - return ctor.newInstance(tuple); - } catch (NoSuchMethodException e) { - throw new TestGridDAOException("ss", e); - } catch (InstantiationException e) { - throw new TestGridDAOException("ssaa", e); - } catch (IllegalAccessException e) { - throw new TestGridDAOException("ssdddd", e); - } catch (InvocationTargetException e) { - throw new TestGridDAOException("ssrrrrrr", e); - } - - } - - public static List map(Class type, List records) throws TestGridDAOException { + /** + * This method is responsible to map list of objects to a given class. + * + * @param type Mapping class + * @param records lst of objects that are mapping to instance of the given class + * @return a List of mapped objects + */ + public static List mapObject(Class type, List records) throws TestGridDAOException { List result = new LinkedList<>(); for (Object[] record : records) { - result.add(map(type, record)); + List> tupleTypes = new ArrayList<>(); + for (Object field : record) { + //if a filed contains null value assign empty string. If null values in the either infra_combination + // column or test case name column or test case description column, null value could be passed to here. + if (field == null) { + field = ""; + } + tupleTypes.add(field.getClass()); + } + Constructor ctor; + try { + ctor = type.getConstructor(tupleTypes.toArray(new Class[record.length])); + result.add(ctor.newInstance(record)); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | + InstantiationException e) { + throw new TestGridDAOException("Error occured while mapping object to TestCaseFailureResultDTO object", + e); + } + } return result; } - public static List getResultList(Query query, Class type) throws TestGridDAOException { - @SuppressWarnings("unchecked") List records = query.getResultList(); - return map(type, records); + /** + * This method is responsible to execute the native query and return mapped oject to a given class. + * + * @param query native query + * @param type class of the mapping object + * @return a List of mapped objects + */ + private static List getResultList(Query query, Class type) throws TestGridDAOException { + @SuppressWarnings("unchecked") + List records = query.getResultList(); + return mapObject(type, records); } } diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java index fe6497605..a129d5417 100755 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/TestReportEngine.java @@ -877,13 +877,14 @@ public Optional generateSummarizedEmailReport(Product product, String work String testGridHome = TestGridUtil.getTestGridHomePath(); Path reportPath = Paths.get(testGridHome, relativeFilePath); writeHTMLToFile(reportPath, htmlString); + Path reportParentPath = reportPath.getParent(); + // Generating the charts required for the email - //todo need to fix properly - try { - generateSummarizedCharts(workspace, reportPath.getParent().toString(), product.getId()); - } catch (NullPointerException e) { - throw new ReportingException("Null point exception occured"); + if (reportParentPath == null) { + throw new ReportingException( + "Couldn't find the parent of the report path: " + reportPath.toAbsolutePath().toString()); } + generateSummarizedCharts(workspace, reportParentPath.toString(), product.getId()); return Optional.of(reportPath); } @@ -923,14 +924,14 @@ private List getTestPlansInWorkspace(String workspace) throws Reportin * Generate summarized charts for the summary email. * @param workspace curent workspace of the build * @param chartGenLocation location where charts should be generated - * @param id + * @param id product id */ private void generateSummarizedCharts(String workspace, String chartGenLocation, String id) throws ReportingException { GraphDataProvider dataProvider = new GraphDataProvider(); - logger.info(StringUtil - .concatStrings("Generating Charts with workspace : ", workspace, " at ", chartGenLocation)); - BuildExecutionSummary summary = dataProvider.getTestExecutionSummary(workspace); + logger.info(StringUtil.concatStrings("Generating Charts with workspace : ", workspace, " at ", + chartGenLocation)); + BuildExecutionSummary summary = dataProvider.getTestExecutionSummary(workspace); ChartGenerator chartGenerator = new ChartGenerator(chartGenLocation); // Generating the charts From db76a0f9a647c8075d5727ea76bd065ed1b41928 Mon Sep 17 00:00:00 2001 From: Yasassri Date: Thu, 26 Jul 2018 17:29:33 +0530 Subject: [PATCH 20/22] Remove hardcoded test-plans dir name and improve error message --- .../src/main/java/org/wso2/testgrid/common/util/FileUtil.java | 4 +++- .../java/org/wso2/testgrid/reporting/GraphDataProvider.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java index 60c02c352..c21046894 100644 --- a/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java +++ b/common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java @@ -52,6 +52,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static org.wso2.testgrid.common.TestGridConstants.PRODUCT_TEST_PLANS_DIR; + /** * Utility class for handling file operations. * @@ -225,7 +227,7 @@ private static void createFileIfNotExists(String filePath) throws TestGridExcept */ public static List getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException { List testPlanIds = new ArrayList<>(); - Path source = Paths.get(workspace, "test-plans"); + Path source = Paths.get(workspace, PRODUCT_TEST_PLANS_DIR); if (!Files.exists(source)) { logger.error("Test-plans dir does not exist: " + source); return Collections.emptyList(); diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java index e3c79d619..b5eafccdd 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -79,7 +79,7 @@ public List getTestFailureSummary(String workspace) throws } catch (TestGridException e) { throw new ReportingException("Error occurred while reading yaml files in the TG home", e); } catch (TestGridDAOException e) { - throw new ReportingException("Error occurred while reading yaml files in the TG home", e); + throw new ReportingException("Error occurred while getting test failure summary from the database", e); } } From 36d0926a4569f35085f85b4cc26fc85e24127e52 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Thu, 26 Jul 2018 17:39:44 +0530 Subject: [PATCH 21/22] Refactor method names --- .../org/wso2/testgrid/dao/repository/TestPlanRepository.java | 2 +- dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java index a26471c83..214abe420 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/repository/TestPlanRepository.java @@ -326,7 +326,7 @@ public List getTestFailureSummaryByTPId(List t * @param testPlanIds test plan ids of a specific build job * @return a List of {@link String} representing statuses of given test plans */ - public List getTestExecutionSummaryByTPId(List testPlanIds) { + public List getTestPlanStatuses(List testPlanIds) { StringBuilder sql = new StringBuilder("select status from test_plan where id in ("); for (int i = 0; i < testPlanIds.size() - 1; i++) { sql.append("?, "); diff --git a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java index 878d2361f..97f19e865 100644 --- a/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java +++ b/dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java @@ -188,7 +188,7 @@ public List getTestPlansOlderThan(String duration, String timeUnit) { * @return a List of Test Plan statuses. */ public List getTestExecutionSummary(List tpIds) { - return testPlanRepository.getTestExecutionSummaryByTPId(tpIds); + return testPlanRepository.getTestPlanStatuses(tpIds); } /** From ae9f5772cc480f1f2bed8ff99a3ae889e9e4e304 Mon Sep 17 00:00:00 2001 From: lasanthaDLPDS Date: Thu, 26 Jul 2018 18:17:10 +0530 Subject: [PATCH 22/22] Incorporate review changes --- .../testgrid/reporting/ChartGenerator.java | 19 +++++++++++++++ .../testgrid/reporting/GraphDataProvider.java | 16 ++++++++----- .../testgrid/reporting/TestReportEngine.java | 4 ++-- .../model/email/BuildFailureSummary.java | 2 -- .../model/email}/InfraCombination.java | 2 +- .../model/email/TestCaseResultSection.java | 23 ++++++++++++++++--- .../wso2/testgrid/web/api/ProductService.java | 2 -- 7 files changed, 52 insertions(+), 16 deletions(-) rename {common/src/main/java/org/wso2/testgrid/common => reporting/src/main/java/org/wso2/testgrid/reporting/model/email}/InfraCombination.java (97%) diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java index 784e4028e..4f537fdc4 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/ChartGenerator.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + package org.wso2.testgrid.reporting; import javafx.application.Platform; diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java index e3c79d619..0db028af0 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/GraphDataProvider.java @@ -23,7 +23,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.wso2.testgrid.common.InfraCombination; import org.wso2.testgrid.common.Status; import org.wso2.testgrid.common.TestPlan; import org.wso2.testgrid.common.exception.TestGridException; @@ -34,6 +33,7 @@ import org.wso2.testgrid.dao.uow.TestPlanUOW; import org.wso2.testgrid.reporting.model.email.BuildExecutionSummary; import org.wso2.testgrid.reporting.model.email.BuildFailureSummary; +import org.wso2.testgrid.reporting.model.email.InfraCombination; import java.time.LocalDate; import java.time.LocalDateTime; @@ -55,6 +55,10 @@ public class GraphDataProvider { private TestPlanUOW testPlanUOW; private static final int MAXIMUM_TIME_RANGE = 30; private static final int TEST_EXECUTION_HISTORY_RANGE = 7; + private static final String OPERATING_SYSTEM = "OS"; + private static final String JDK = "JDK"; + private static final String DATABASE_ENGINE = "DBEngine"; + private static final String DATABASE_ENGINE_VERSION = "DBEngineVersion"; public GraphDataProvider() { this.testPlanUOW = new TestPlanUOW(); @@ -98,11 +102,11 @@ private List processTestFailureSummary(List getTestPlansInWorkspace(String workspace) throws Reportin /** * Generate summarized charts for the summary email. - * @param workspace curent workspace of the build + * @param workspace curent workspace of the build * @param chartGenLocation location where charts should be generated * @param id product id */ diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java index 7afdbfb2e..8cb93f89a 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/BuildFailureSummary.java @@ -18,8 +18,6 @@ package org.wso2.testgrid.reporting.model.email; -import org.wso2.testgrid.common.InfraCombination; - import java.util.ArrayList; import java.util.List; diff --git a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/InfraCombination.java similarity index 97% rename from common/src/main/java/org/wso2/testgrid/common/InfraCombination.java rename to reporting/src/main/java/org/wso2/testgrid/reporting/model/email/InfraCombination.java index 207ddefbe..f5df491b0 100644 --- a/common/src/main/java/org/wso2/testgrid/common/InfraCombination.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/InfraCombination.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.testgrid.common; +package org.wso2.testgrid.reporting.model.email; /** * This defines s single infra combination. diff --git a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java index 925c4d71d..45d438b16 100644 --- a/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java +++ b/reporting/src/main/java/org/wso2/testgrid/reporting/model/email/TestCaseResultSection.java @@ -1,11 +1,28 @@ -package org.wso2.testgrid.reporting.model.email; +/* + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ -import org.wso2.testgrid.common.InfraCombination; +package org.wso2.testgrid.reporting.model.email; import java.util.List; /** - * Model class representing the test-plan result section in summarized email-report. + * Model class representing the test-case result section in summarized email-report. */ public class TestCaseResultSection { diff --git a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java index 88493f8e8..f11455ae7 100644 --- a/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java +++ b/web/src/main/java/org/wso2/testgrid/web/api/ProductService.java @@ -129,8 +129,6 @@ public Response getAllProductStatuses() { status.setLastFailureTimestamp(product.getLastFailureTimestamp()); status.setProductStatus(testPlanUOW.getCurrentStatus(product).toString()); list.add(status); -// GraphDataProvider gp = new GraphDataProvider(); -// gp.getTestExecutionHistory("1d68c7b1-210f-4794-a8a4-58e798155905"); } } catch (TestGridDAOException e) { String msg = "Error occurred while fetching the Product statuses ";
Failed Test CaseDescriptionFailed Test CaseFailure Message OS JDK DB