Skip to content

Commit

Permalink
Merge pull request #909 from yasassri/conflict-fix
Browse files Browse the repository at this point in the history
This PR introduces the Summarized Email Report with Summary Graphs
  • Loading branch information
yasassri committed Jul 26, 2018
2 parents a976a00 + 923905c commit d32f6c7
Show file tree
Hide file tree
Showing 18 changed files with 1,326 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public class TestGridConstants {
public static final String TEST_PLANS_URI = "test-plans";
public static final String HTML_LINE_SEPARATOR = "<br/>";
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";
Expand Down
89 changes: 89 additions & 0 deletions common/src/main/java/org/wso2/testgrid/common/util/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -38,12 +42,18 @@
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;

import static org.wso2.testgrid.common.TestGridConstants.PRODUCT_TEST_PLANS_DIR;

/**
* Utility class for handling file operations.
*
Expand Down Expand Up @@ -162,4 +172,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<String> getTestPlanIdByReadingTGYaml(String workspace) throws TestGridException {
List<String> testPlanIds = new ArrayList<>();
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();
}
try (Stream<Path> stream = Files.list(source).filter(Files::isRegularFile)) {
List<Path> 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);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ public void execute() throws CommandExecutionException {
Product product = getProduct(productName);
try {
TestReportEngine testReportEngine = new TestReportEngine();
final Optional<Path> path = testReportEngine.generateEmailReport(product, workspace);
path.ifPresent(p -> logger.info("Written the email report body contents to: " + p));
// Generating the summary report
final Optional<Path> summarizedReportPath = testReportEngine.generateSummarizedEmailReport(product,
workspace);
summarizedReportPath.ifPresent(p -> logger.info("Written the summarized email " +
"report body contents to: " + p));

final Optional<Path> 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 {" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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;

/**
* Defines a model object of test case failure results.
*
* @since 1.0.0
*/
public class TestCaseFailureResultDTO {

private String name;
private String failureMessage;
private String infraParameters;

public TestCaseFailureResultDTO(String testname, String failureMessage, String infraParameters) {
this.name = testname;
this.failureMessage = failureMessage;
this.infraParameters = infraParameters;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@
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.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;
Expand Down Expand Up @@ -290,4 +295,120 @@ public List<TestPlan> 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<TestCaseFailureResultDTO> getTestFailureSummaryByTPId(List<String> testPlanIds)
throws TestGridDAOException {
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("?, ");
}
sql.append("?)) failed_tc on tp.id = failed_tc.TESTPLAN_id;");
Query query = entityManager.createNativeQuery(sql.toString());
int index = 1;
for (String s : testPlanIds) {
query.setParameter(index++, s);
}
return getResultList(query, TestCaseFailureResultDTO.class);
}

/**
* 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<String> getTestPlanStatuses(List<String> 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<String> statuses = (List<String>) 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<TestPlan> 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<TestPlan> resultList = (List<TestPlan>) entityManager.createNativeQuery(sql, TestPlan.class)
.setParameter(1, productId)
.setParameter(2, productId)
.setParameter(3, from)
.setParameter(4, to)
.getResultList();
return EntityManagerHelper.refreshResultList(entityManager, resultList);
}

/**
* 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 <T> List<T> mapObject(Class<T> type, List<Object[]> records) throws TestGridDAOException {
List<T> result = new LinkedList<>();
for (Object[] record : records) {
List<Class<?>> 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<T> 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;
}

/**
* 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 <T> List<T> getResultList(Query query, Class<T> type) throws TestGridDAOException {
@SuppressWarnings("unchecked")
List<Object[]> records = query.getResultList();
return mapObject(type, records);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Optional<TestCase> getTestCaseById(String id) throws TestGridDAOException
@SuppressWarnings("unchecked")
public boolean isExistsFailedTests(TestScenario testScenario) throws TestGridDAOException {
List<Object> 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();
}
Expand Down
29 changes: 29 additions & 0 deletions dao/src/main/java/org/wso2/testgrid/dao/uow/TestPlanUOW.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -180,4 +181,32 @@ public List<TestPlan> getTestPlanHistory(TestPlan testPlan) {
public List<TestPlan> 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<String> getTestExecutionSummary(List<String> tpIds) {
return testPlanRepository.getTestPlanStatuses(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<TestCaseFailureResultDTO> getTestFailureSummary(List<String> tpIds) throws TestGridDAOException {
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<TestPlan> getTestExecutionHistory(String productId, String from, String to) {
return testPlanRepository.getTestExecutionHistory(productId, from, to);
}
}
Loading

0 comments on commit d32f6c7

Please sign in to comment.