Skip to content

Instantly share code, notes, and snippets.

@sjethvani
Created September 7, 2017 07:24
Show Gist options
  • Save sjethvani/d8538c41f351017c614e6d0b64f64502 to your computer and use it in GitHub Desktop.
Save sjethvani/d8538c41f351017c614e6d0b64f64502 to your computer and use it in GitHub Desktop.
Java Program to generate consolidated testng-results.xml from two executions (Normal execution testng-results.xml & Rerun failing tests execution testng-results.xml)
package com.mergeTestNgXml;
import java.util.List;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class MergeTestNgXmlsAfterRetryingFailingTests
{
public static Logger LOG = LogManager.getLogger(MergeTestNgXmlsAfterRetryingFailingTests.class);
public static void main(String[] testNgFiles) throws ParserConfigurationException, SAXException, IOException, TransformerException, XPathExpressionException
{
if (testNgFiles.length != 3)
{
System.out.println("No of parameters you passed as args is :- " + testNgFiles.length + " however it should be 3 only");
System.out.println("Usage: run this programm with 3 arguments . Arguments : <testNg primaryFile> <testNg secondaryFile> <testNg mergeExpectedFile>");
return;
}
LOG.info("Merging testng-files Start");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbFactory.newDocumentBuilder();
LOG.info("Primary testng-results File is : "+testNgFiles[0]);
InputStream inputStream = new FileInputStream(new File(testNgFiles[0]));
Reader reader = new InputStreamReader(inputStream, "UTF-8");
InputSource is = new InputSource(reader);
is.setEncoding("UTF-8");
Document doc1 = builder.parse(is); //"test-output/testng-results-base.xml"
LOG.info("Secondary(failed) testng-results File is : "+testNgFiles[1]);
inputStream = new FileInputStream(new File(testNgFiles[1]));
reader = new InputStreamReader(inputStream, "UTF-8");
is = new InputSource(reader);
is.setEncoding("UTF-8");
Document doc2 = builder.parse(is); //"test-output/testng-results-retry.xml"
doc1.normalizeDocument();
doc2.normalizeDocument();
XPath pathToTests = XPathFactory.newInstance().newXPath();
Element testNGResultTag = (Element) pathToTests.evaluate("/testng-results", doc1.getDocumentElement(), XPathConstants.NODE);
String skiipedCount = testNGResultTag.getAttribute("skipped");
String failedCount = testNGResultTag.getAttribute("failed");
String passedCount = testNGResultTag.getAttribute("passed");
// NodeList of <test> tags
NodeList testTagNodeList_primaryFile = (NodeList) pathToTests.evaluate("/testng-results/suite/test", doc1.getDocumentElement(), XPathConstants.NODESET);
NodeList testTagNodeList_secondaryFile = (NodeList) pathToTests.evaluate("/testng-results/suite/test", doc2.getDocumentElement(), XPathConstants.NODESET);
// fetching 'name' attributes of all <test> tags from secondary(failed testng-results.xml) file & storing them in list
ArrayList<String> testNameList_secondaryFile = new ArrayList<>();
for (int j = 0; j < testTagNodeList_secondaryFile.getLength(); j++)
{
Element testTagElement = (Element) testTagNodeList_secondaryFile.item(j);
String testName = testTagElement.getAttribute("name");
testNameList_secondaryFile.add(testName);
}
List<Node> testMethodWithFailStatusNodeListTobedeleted_primaryFile = new ArrayList<Node>();
List<Node> testMethodWithSkipStatusNodeListTobedeleted_primaryFile = new ArrayList<Node>();
// iterating through all '<test>' tags of primary file
for (int j = 0; j < testTagNodeList_primaryFile.getLength(); j++)
{
//check if '<test>' tag of primary file exists in secondary file
Element testTagElement_primaryFile = (Element) testTagNodeList_primaryFile.item(j);
String testName_primaryFile = testTagElement_primaryFile.getAttribute("name");
String testName_secondaryFile = null ;
boolean testFound = false;
for (int i = 0; i < testNameList_secondaryFile.size(); i++)
{
if(testNameList_secondaryFile.get(i).contains(testName_primaryFile))
{
testFound = true;
testName_secondaryFile = testNameList_secondaryFile.get(i);
break;
}
}
// '<test>' tag of primary file is found in secondary file
if(testFound)
{
NodeList testMethodTagNodeList_primaryFile = (NodeList) pathToTests.evaluate(getTestmethodXpath(testName_primaryFile), doc1.getDocumentElement(), XPathConstants.NODESET);
NodeList testMethodTagNodeList_secondaryFile = (NodeList) pathToTests.evaluate(getTestmethodXpath(testName_secondaryFile), doc2.getDocumentElement(), XPathConstants.NODESET);
// iterating through all '<test-method>' tags of above '<test>' tag of secondary file
for (int i = 0; i < testMethodTagNodeList_secondaryFile.getLength(); i++)
{
Element testMethodTag_secondaryFile = (Element) testMethodTagNodeList_secondaryFile.item(i);
Element testMethodTag_primaryFile = getTestMethodElementByAttribute(testMethodTagNodeList_primaryFile, "name", testMethodTag_secondaryFile.getAttribute("name"));
// if '<test-method>' tag under primary file has status='FAIL' but same 'test-method' tag under secondary file has status='PASS' then override 'PASS' status over 'FAIL'
if(testMethodTag_primaryFile != null && testMethodTag_secondaryFile != null)
{
if(testMethodTag_primaryFile.getAttribute("status").equals("FAIL") && testMethodTag_secondaryFile.getAttribute("status").equals("PASS"))
{
Node n1 = (Node) doc1.importNode(testMethodTag_secondaryFile, true);
testMethodTagNodeList_primaryFile.item(0).getParentNode().appendChild(n1);
testMethodWithFailStatusNodeListTobedeleted_primaryFile.add(testMethodTag_primaryFile);
}
// if '<test-method>' tag under primary file has status='SKIP' but same 'test-method' tag under secondary file has status='PASS' then override 'PASS' status over 'SKIP'
else if(testMethodTag_primaryFile.getAttribute("status").equals("SKIP") && testMethodTag_secondaryFile.getAttribute("status").equals("PASS"))
{
Node n1 = (Node) doc1.importNode(testMethodTag_secondaryFile, true);
testMethodTagNodeList_primaryFile.item(0).getParentNode().appendChild(n1);
testMethodWithSkipStatusNodeListTobedeleted_primaryFile.add(testMethodTag_primaryFile);
}
}
}
}
}
// delete all '<test-method>' nodes from primary file now
for( int i=0; i<testMethodWithFailStatusNodeListTobedeleted_primaryFile.size(); i++ ) {
Node node = testMethodWithFailStatusNodeListTobedeleted_primaryFile.get( i );
node.getParentNode().removeChild( node );
}
// delete all '<test-method>' nodes from primary file now
for( int i=0; i<testMethodWithSkipStatusNodeListTobedeleted_primaryFile.size(); i++ ) {
Node node = testMethodWithSkipStatusNodeListTobedeleted_primaryFile.get( i );
node.getParentNode().removeChild( node );
}
// setting pass , fail , skip count
testNGResultTag.setAttribute( "skipped", ""+(Integer.parseInt(skiipedCount) - testMethodWithSkipStatusNodeListTobedeleted_primaryFile.size()) );
testNGResultTag.setAttribute( "failed", ""+(Integer.parseInt(failedCount) - testMethodWithFailStatusNodeListTobedeleted_primaryFile.size()) );
testNGResultTag.setAttribute( "passed", ""+(Integer.parseInt(passedCount) + testMethodWithFailStatusNodeListTobedeleted_primaryFile.size() + testMethodWithSkipStatusNodeListTobedeleted_primaryFile.size()) );
// generating consolidated merge file
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc1);
transformer.transform(source, result);
Writer output = null;
output = new BufferedWriter(new FileWriter(testNgFiles[2])); //"/test-output/consolidatedResults/testng-mergedResults.xml"
String xmlOutput = result.getWriter().toString();
output.write(xmlOutput);
output.close();
LOG.info("Merging testng-files Completed");
LOG.info("Merged testng-results file is " + testNgFiles[2]);
}
/*
* returns 'test-method' element matching attribute with its value passed as input
*/
private static Element getTestMethodElementByAttribute(NodeList testMethodNodeList, String attributeName , String attributeValueToBeMatched)
{
for (int k = 0; k < testMethodNodeList.getLength(); k++)
{
Element testMethodElement = (Element) testMethodNodeList.item(k);
String testMethodElementAttributeValue = testMethodElement.getAttribute(attributeName);
if(testMethodElementAttributeValue.equals(attributeValueToBeMatched))
{
return testMethodElement;
}
}
return null;
}
/*
* returns xpath of 'test-method' attribute by 'test' tag's name attribute
*/
private static String getTestmethodXpath(String testName)
{
String TEST_METHOD_XPATH = "/testng-results/suite/test[@name ='" + testName
+ "']/class/test-method";
return TEST_METHOD_XPATH;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment