/**
*
*/
package com.redhat.qe.auto.tcms;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.internal.IResultListener;
import com.redhat.qe.auto.testng.BlockedByBzBug;
import tcms.API.Build;
import tcms.API.Environment;
import tcms.API.Product;
import tcms.API.Session;
import tcms.API.TestCase;
import tcms.API.TestCaseRun;
import tcms.API.TestPlan;
import tcms.API.TestRun;
import tcms.API.TestopiaException;
import tcms.API.User;
/**
* @author jweiss
*
*/
public class TCMSTestNGListener implements IResultListener, ISuiteListener {
protected static final String TESTNG_COMPONENT_MARKER = "component-";
protected static final String TESTNG_TESTPLAN_MARKER = "testplan-";
protected static String TESTOPIA_PW = "";
protected static String TESTOPIA_USER = "";
protected static String TESTOPIA_URL = "";
protected static String TESTOPIA_TESTRUN_TESTPLAN = "";
protected static String TESTOPIA_TESTRUN_PRODUCT = "";
protected static String sProcedurePreText = null;
protected static Environment env = null;
protected static Logger log = Logger.getLogger(TCMSTestNGListener.class.getName());
protected TestRun testrun;
protected Product product;
protected Build build;
//protected Environment environment;
protected TestPlan testplan;
protected TestCase testcase;
protected Session session;
protected TestCaseRun testcaserun = null;
protected static String buildName = "";
protected static String environmentName = "";
protected static String version = null;
protected static boolean testcaseOverwrite = true;
protected static String myOverwrite = null;
protected static boolean isInUse = false;
static {
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "severe");
}
public static void setBuild(String buildName){
TCMSTestNGListener.buildName = buildName;
}
public static void setEnvironment(String environmentName){
TCMSTestNGListener.environmentName = environmentName;
}
public static void setVersion(String version){
TCMSTestNGListener.version = version;
}
public static void setTestcaseOverwrite(boolean overwrite){
TCMSTestNGListener.testcaseOverwrite = overwrite;
}
public static boolean isInUse(){
return isInUse;
}
public void onFinish(ISuite suite) {
// TODO Auto-generated method stub
}
public void onStart(ISuite suite) {
isInUse = true;
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onFinish(org.testng.ITestContext)
*/
public void onFinish(ITestContext context) {
testrun.setStatus(TestRun.Status.Stopped);
String notes = String.format("RESULTS: %d Passed, %d Failed, %d Skipped",
context.getPassedTests().size(),
context.getFailedTests().size(),
context.getSkippedTests().size());
testrun.setNotes(notes);
try{
testrun.update();
}catch(Exception e){
throw new TestopiaException(e);
}
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onStart(org.testng.ITestContext)
*/
public void onStart(ITestContext context) {
//create new test run
String testname = context.getName();
try {
loginTestopia();
retrieveContext();
// if set, onStart determine env id that needs to be set
String sEnvironment = System.getProperty("testopia.testrun.environment");
int iEnvID = -1;
if (sEnvironment != null) {
if (env == null ) {
String[] saEnv = sEnvironment.split(":");
try {
env = new Environment(session, product.getId(), saEnv[0], saEnv[1]);
iEnvID = env.getValueId();
} catch(Exception e) {
throw new TestopiaException(e);
}
}
}
testrun = new TestRun(session, testplan.getId(), iEnvID, build.getId(), session.getUserid(), testname, product.getId(), product.getVersionIDByName(version));
testrun.create();
// if set, onStart globally set environment for test run
if (iEnvID != -1) {
testrun.applyEnvironmentValue();
}
// if set, onStart set tags on test run
String sTags = System.getProperty("testopia.testrun.tags");
if (sTags != null) {
Object result = testrun.setTags(sTags);
if (result != null) {
System.out.println("Setting tag result: " + result.toString());
} else {
System.out.println("Setting tag result: null");
}
}
} catch(Exception e){
//log.severe("Could not create new test run in testopia! Aborting!");
TestopiaException te=new TestopiaException("Could not create new test run in testopia.");
te.initCause(e);
throw te;
}
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onTestFailedButWithinSuccessPercentage(org.testng.ITestResult)
*/
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onTestFailure(org.testng.ITestResult)
*/
public void onTestFailure(ITestResult result) {
//also update the test run
markTestRunComplete(result);
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onTestSkipped(org.testng.ITestResult)
*/
public void onTestSkipped(ITestResult result) {
markTestRunComplete(result);
}
/**
* Take component names from testng annotation - convention is if you
* mark a test with groups="component-Xyz" then the testcase in testopia
* will be created with a component "Xyz" added. If the component
* can't be found in testopia, it'll be skipped. Can add multiple components
* in this manner (with multiple groups that start with "component-". Will also
* remove components that are not in the annotation.
* -jweiss
*
* @param result
*/
protected void syncComponents(ITestResult result){
List<String> existingComponents = new ArrayList<String>();
try {
Object[] components = testcase.getComponents();
for (Object component: components){
String componentName = (String)((Map<String,Object>)component).get("name");
existingComponents.add(componentName);
}
}catch(Exception e){
log.log(Level.FINER, "Unable to retrieve existing components for testcase " + testcase.getId() + ".", e);
}
List<String> newComponents = getComponentsFromGroupAnnotations(result);
for (String component: newComponents){
if (existingComponents.contains(component)) {
log.finer("Component is already in testcase.");
}
else {
try {
Integer componentID = product.getComponentIDByName(component, TESTOPIA_TESTRUN_PRODUCT);
testcase.addComponent(componentID);
}
catch(Exception e){
log.log(Level.FINER, "Unable to add component '" + component + "' in product '" +
TESTOPIA_TESTRUN_PRODUCT + "' to testcase.", e);
continue;
}
}
}
//remove old components
for (String component: existingComponents){
if (!newComponents.contains(component)){
try {
Integer componentID = product.getComponentIDByName(component, TESTOPIA_TESTRUN_PRODUCT);
testcase.removeComponent(componentID);
}
catch(Exception e){
log.log(Level.FINER, "Unable to remove component '" + component + "' in product '" +
TESTOPIA_TESTRUN_PRODUCT + "' to testcase.", e);
continue;
}
}
}
}
protected void syncTestPlans(ITestResult result){
List<Integer> existingTestPlans = new ArrayList<Integer>();
try {
Object[] testplans = testcase.getTestPlans();
for (Object testplan: testplans){
String testPlanName = (String)((Map<String,Object>)testplan).get("name");
existingTestPlans.add(new TestPlan(session, product.getId(), testPlanName, version).getId());
}
}
catch(Exception e){
log.log(Level.FINER, "Unable to retrieve associated test plans for testcase " + testcase.getId() + ".", e);
}
List<Integer> newTestPlans = getTestPlansFromGroupAnnotations(result);
for (Integer testplan: newTestPlans){
if (existingTestPlans.contains(testplan))
log.finer("Testcase is already assigned to test plan.");
else {
try {
testcase.addTestPlan(testplan);
}
catch (Exception e){
log.log(Level.FINER, "Unable to add test plan '" + testplan + "' in product '" +
TESTOPIA_TESTRUN_PRODUCT + "' to testcase.", e);
continue;
}
}
}
//remove old test plans
for (Integer testplan: existingTestPlans){
if (!newTestPlans.contains(testplan)){
try {
testcase.removeTestPlan(testplan);
}
catch(Exception e){
log.log(Level.FINER, "Unable to remove test plan '" + testplan + "' in product '" +
TESTOPIA_TESTRUN_PRODUCT + "' to testcase.", e);
continue;
}
}
}
}
private List<String> getComponentsFromGroupAnnotations(ITestResult result){
List<String> groups = Arrays.asList(result.getMethod().getGroups());
List<String> components= new ArrayList<String>();
for (String group: groups){
if (group.startsWith(TESTNG_COMPONENT_MARKER)) {
String component = group.split(TESTNG_COMPONENT_MARKER)[1];
log.finer("Found component: " + component);
components.add(component);
}
}
return components;
}
protected List<Integer> getTestPlansFromGroupAnnotations(ITestResult result){
List<String> groups = Arrays.asList(result.getMethod().getGroups());
List<Integer> testplans= new ArrayList<Integer>();
for (String group: groups){
if (group.startsWith(TESTNG_TESTPLAN_MARKER)) {
String testplan = group.split(TESTNG_TESTPLAN_MARKER)[1];
log.finer("Found test plan: " + testplan);
try{
Integer testplanid = new TestPlan(session, product.getId(), testplan, version).getId();
log.finer("with plan ID: " + testplanid);
testplans.add(testplanid);
}
catch(Exception e){
log.finer("Test plan \"" + testplan + "\" not found on Testopia, skipping...");
continue;
}
}
}
return testplans;
}
protected String getPackagelessTestClass(ITestResult result){
String pkg_class = result.getTestClass().getName();
log.finest("Got test class of " + pkg_class);
String[] pkgs= pkg_class.split("\\.");
return pkgs[pkgs.length-1];
}
protected TestCase getTestCaseByAnnotation(ITestResult result){
if (result.getMethod().getInvocationCount() > 1)
throw new RuntimeException("Cannot overwrite TCMS testcase from method that will be invoked multiple times: " + result.getMethod().getMethodName());
ImplementsNitrateTest annotation = result.getMethod().getMethod().getAnnotation(ImplementsNitrateTest.class);
if (annotation == null) throw new RuntimeException("No TCMS annotation present.");
return new TestCase(session, annotation.caseId());
}
// Remove some messages that don't belong in the tcms test case procedures
private String cleanUpLog(String sLogText) {
String sFinalString = "";
String[] array = sLogText.split("<br>");
for( int i = 0; i < array.length; i++) {
if (!array[i].startsWith("System property automation.propertiesfile is not set") &&
!array[i].startsWith("\nRunning against") &&
!array[i].startsWith("\nStarting TestNG Suite") &&
!array[i].startsWith("\nCurrent URL") &&
!array[i].startsWith("\nStarting TestNG Script") &&
!array[i].startsWith("\nStarting Test") &&
!array[i].startsWith("Starting Test") &&
!array[i].startsWith("\nTest Passed") &&
!array[i].startsWith("\nTest Skipped") &&
!array[i].startsWith("\nTest Failed")) {
if (sFinalString.equals("")) {
sFinalString = array[i];
} else {
sFinalString = sFinalString + "<br>" + array[i];
}
}
}
if (sFinalString.equals("\n")) {
sFinalString = "";
}
return sFinalString;
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onTestStart(org.testng.ITestResult)
*/
public void onTestStart(ITestResult result) {
// if the first time, capture & cleanup the initial login process of selenium test script
if (sProcedurePreText == null) {
sProcedurePreText = TestProcedureHandler.getActiveLog();
sProcedurePreText = cleanUpLog(sProcedurePreText);
}
// resetting active log to remove messages from previous tests that were bleeding over
TestProcedureHandler.resetActiveLog();
// useful kvp when trying to document data provided tests
String sAppendParmOneToSummary = System.getProperty("testopia.testcase.appendParmOneToSummary");
if (sAppendParmOneToSummary == null) {
sAppendParmOneToSummary = "0";
}
//create new testcaserun
int iteration = result.getMethod().getCurrentInvocationCount();
log.finer("Got getCurrentInvocationCount()=" + iteration + ", total=" + result.getMethod().getInvocationCount());
String count = "";
String className = getPackagelessTestClass(result);
if (iteration > 0) count = new Integer(iteration+1).toString();
String alias = className + "." + result.getMethod().getMethodName() + count;
String script = className + "." + result.getMethod().getMethodName();
String description = result.getMethod().getDescription();
String summary = null;
if ( (sAppendParmOneToSummary.equals("1")) && (result.getParameters() != null && result.getParameters().length > 0) ) {
summary = description.length()>0 ? description : script;
int indexToCheck = 0;
// check/skip blockedByBugzillaBug
if (result.getParameters()[0] instanceof BlockedByBzBug)
indexToCheck = 1;
if (result.getParameters()[indexToCheck] instanceof String) {
String parmOne = (String) result.getParameters()[indexToCheck];
summary = summary + " - " + parmOne;
} else
summary = description.length()>0 ? (description + count) : (script + count);
} else
summary = description.length()>0 ? (description + count) : (script + count);
try {
try {
testcase = getTestCaseByAnnotation(result);
}catch (Exception e){
log.log(Level.FINER, "Couldn't retrieve testcase via tcms annotation, falling back to retrieving by method name.", e);
testcase = new TestCase(session, alias);
}
//FIXME temporary to fix testcase names
testcase.setSummary(summary);
if (result.getParameters() != null && result.getParameters().length > 0) {
String args =Arrays.deepToString(result.getParameters());
testcase.setArguments(args);
}
testcase.update();
}catch(Exception e){
log.log(Level.FINER, "Testcase retrieval failed on '" + summary + "', probably doesn't exist yet.", e);
try {
log.info("Creating new testcase: " + alias);
testcase = new TestCase(session, "PROPOSED", "--default--", "P1",
summary, TESTOPIA_TESTRUN_TESTPLAN, TESTOPIA_TESTRUN_PRODUCT, version);
testcase.setAlias(alias);
testcase.setIsAutomated(1);
testcase.create();
}
catch(Exception e2){
throw new TestopiaException(e2);
}
}
syncComponents(result);
syncTestPlans(result);
log.finer("Testrun is " + testrun.getId());
testcaserun = new TestCaseRun(session, testrun.getId(), testcase.getId(), build.getId());
testcaserun.setStatus(TestCaseRun.Statuses.RUNNING);
try {
testcaserun.create();
testrun.addCases(testcaserun.getId());
}catch(Exception e) {
throw new TestopiaException(e);
}
}
/* (non-Javadoc)
* @see org.testng.ITestListener#onTestSuccess(org.testng.ITestResult)
*/
public void onTestSuccess(ITestResult result) {
myOverwrite = System.getProperty("testopia.testcase.overwrite");
//get the procedure log from the handler
String action= TestProcedureHandler.getActiveLog();
action = cleanUpLog(action);
action = sProcedurePreText + action;
if (action == null)
action = "no procedure found!";
if(myOverwrite.equalsIgnoreCase("1")){
log.fine("Updating testcase " + testcase.getAlias() + " with successful action log: \n" + action);
//put it in testopia
testcase.setAction(action);
try {
testcase.storeText();
//FIXME remove the following lines later when all records are updated
testcase.setIsAutomated(1);
testcase.update();
}catch(Exception e){
//throw new TestopiaException(e);
log.log(Level.WARNING, "Could not update testopia with successful status." + result.getName(), e);
}
}
//also update the test run
markTestRunComplete(result);
}
protected void markTestRunComplete(ITestResult result){
if(testcaserun == null)
return;
if (result.getStatus() == ITestResult.SKIP) testcaserun.setStatus(TestCaseRun.Statuses.BLOCKED);
else {
//testcaserun.setNotes(throwableToString(result.getThrowable()));
//put the whole log instead
testcaserun.setNotes(AbstractTestProcedureHandler.getActiveLog());
testcaserun.setStatus(result.isSuccess() ? TestCaseRun.Statuses.PASSED : TestCaseRun.Statuses.FAILED);
}
try {
testcaserun.update();
}catch(Exception e){
throw new TestopiaException(e);
}finally{
//reset the handler so that our log for the next testcase run starts fresh.
AbstractTestProcedureHandler.resetActiveLog();
}
}
protected String throwableToString(Throwable t){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
return sw.toString();
}
/* (non-Javadoc)
* @see org.testng.internal.IConfihttps://testopia.devel.redhat.com/bugzilla/tr_show_plan.cgi?plan_id=425gurationListener#onConfigurationFailure(org.testng.ITestResult)
*/
public void onConfigurationFailure(ITestResult result) {
//markTestRunComplete(result);
}
/* (non-Javadoc)
* @see org.testng.internal.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult)
*/
public void onConfigurationSkip(ITestResult result) {
//markTestRunComplete(result);
}
/* (non-Javadoc)
* @see org.testng.internal.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult)
*/
public void onConfigurationSuccess(ITestResult result) {
//markTestRunComplete(result);
}
//FIXME this is just temporary for testing
private static void setLogConfig() throws Exception{
/*Logger.getLogger("").setLevel(Level.ALL);
Logger.getLogger("").getHandlers()[0].setFormatter(new ConsoleLogFormatter());
Logger.getLogger("").getHandlers()[0].setLevel(Level.ALL);*/
LogManager.getLogManager().readConfiguration(new FileInputStream("/home/weissj/log.properties"));
log.info("Hello");
}
protected void loginTestopia() throws XmlRpcException, GeneralSecurityException, IOException{
TESTOPIA_URL = System.getProperty("testopia.url");
TESTOPIA_USER = System.getProperty("testopia.login");
TESTOPIA_PW = System.getProperty("testopia.password");
TESTOPIA_TESTRUN_PRODUCT = System.getProperty("testopia.testrun.product");
TESTOPIA_TESTRUN_TESTPLAN = System.getProperty("testopia.testrun.testplan");
log.finer("Logging in to testopia as " + TESTOPIA_USER);
session = new Session(TESTOPIA_USER, TESTOPIA_PW, new URL(TESTOPIA_URL));
session.init();
session.setUserid(new User(session).getId());
//session.login();
}
protected void retrieveContext() throws XmlRpcException{
product = new Product(session, System.getProperty("testopia.testrun.product"));
testplan = new TestPlan(session, product.getId(), System.getProperty("testopia.testrun.testplan"), version);
build = new Build(session, product.getId());
try {
build.getBuildIDByName(buildName);
}
catch(Exception e){
log.log(Level.FINER, "Couldn't find build " + buildName + ", creating new.", e);
build.setName(buildName);
build.create();
}
/*HashMap<String,Object> trinst= (HashMap<String, Object>) tr.create();
TestCaseRun tcr = new TestCaseRun(session,
(Integer)trinst.get("run_id"),
2948,
buildID,
envId);
tcr.create();*/
}
public static void main(String args[]) throws Exception{
//System.out.println(Arrays.deepToString(new Object[]{new Integer(4), "hi"}));
/*setLogConfig();
log.finer("Testing log setting.");
/*
String test = "component-Hi There";
System.out.println(test.split("component-")[1]);
String pkg_class = "com.jboss.qa.jon20.tests.DynaGroups";
//log.finer("Got test class of " + pkg_class);
String[] pkgs= pkg_class.split("\\.");
System.out.println("Found class" + pkgs[pkgs.length-1]);*/
LogManager.getLogManager().readConfiguration(new FileInputStream("/home/weissj/log.properties"));
TCMSTestNGListener ttl = new TCMSTestNGListener();
Properties p = new Properties();
p.load(new FileInputStream("/home/weissj/automation.properties"));
for (Object key: p.keySet()){
System.setProperty((String)key, p.getProperty((String)(key)));
}
ttl.loginTestopia();
Product product = new Product(ttl.session, System.getProperty("testopia.testrun.product"));
TestPlan testplan = new TestPlan(ttl.session, product.getId(), System.getProperty("testopia.testrun.testplan"), "2.4.0-SNAPSHOT");
System.out.println(product.getId() + "\n" + testplan.getId());
/*Session session = new Session(TESTOPIA_USER, TESTOPIA_PW, new URL(TESTOPIA_URL));
session.login();*/
/*//tc.makeTestCase(id, 0, 0, true, 271, "This is a test of the testy test", 0);
Map<String, Object> values = new HashMap<String, Object>();
values.put("summary", "dfdfg");
Object[] result = new TestopiaTestCase(session, 0).getList(values);
for (Object res: result){
System.out.println(res.toString());
}
TestCaseRun tcr = new TestCaseRun(session, 2935, 1, 1, 1, 1);
tcr.makeTestCaseRun(1, 1);
tcr.setNotes("RICK ASTLEY");
tcr.setStatus(2);
tcr.update();*/
/*TestCase tc2 = new TestCase(session, "PROPOSED", "--default--", "P1", "what up dude", "Acceptance", "JBoss ON");
tc2.setIsAutomated(true);
tc2.create();
tc2.setPriorityID("P2");
tc2.update();
tc2.update();*/
//TestRun tcr = new TestRun(session, 2948, "2.2 CR1", "Windows + Postgres" );
//tcr.create();
//TestCaseRun tcr = new TestCaseRun(session, 2935, )
/*Product prod = new Product(session);
Integer prodId = prod.getProductIDByName("JBoss ON");
TestPlan tp = new TestPlan(session, "Acceptance");
Integer plan = tp.getId();
Build bu = new Build(session, prodId);
Integer build = bu.getBuildIDByName("2.2 CR1");
Environment env = new Environment(session, prodId, null);
Integer envId = env.getEnvironemntIDByName("Windows+Postgres");
TestRun tr = new TestRun(session, plan, envId, build, session.getUserid(), "Test" + System.currentTimeMillis());
HashMap<String,Object> trinst= (HashMap<String, Object>) tr.create();
TestCaseRun tcr = new TestCaseRun(session,
(Integer)trinst.get("run_id"),
2948,
build,
envId);
tcr.create();*/
}
}