/*
* Copyright (C) 2013 Ustream Inc.
* author chaotx <lombai.ferenc@ustream.tv>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package com.robin;
import org.testng.IExecutionListener;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import com.robin.capture.Screenshot;
import com.robin.device.DevicePool;
import com.robin.reporter.Reporter;
import com.robin.reporter.logcat.LogCatHandler;
import com.robin.testcase.BaseTest;
import com.robin.testcase.SetupException;
import com.robin.testcase.TestCaseSetup;
import com.robin.uielements.TranslationMap;
import com.robin.utilities.config.ConfigParams;
import com.robin.utilities.config.Configuration;
/**
* TestNG custom listener to save screenshot and LogCat when a test fails.
* */
public class ScreenshotListener implements ITestListener,
IInvokedMethodListener, IExecutionListener
{
private static int allTestRun = 0;
private static int allTestSkip = 0;
private static int allTestFail = 0;
private static int allConfigFail = 0;
/**
* Toggles command line output for test start.
*/
protected boolean notifyStart = true;
/**
* Toggles command line output for Passed tests.
*/
protected boolean notifyPass = true;
/**
* Toggles command line output for Skipped tests.
*/
protected boolean notifySkip = true;
/**
* Toggles command line output for Failed tests.
*/
protected boolean notifyFail = true;
/**
* Toggles screenshot creation for failed tests.
*/
protected boolean screenshotOnFail = true;
@Override
public synchronized void onStart(final ITestContext context)
{
}
@Override
public void onFinish(final ITestContext arg0)
{
}
@Override
public void onTestStart(final ITestResult result)
{
synchronized (this)
{
allTestRun++;
}
if (notifyStart)
{
Reporter.logConsole(String.format(
"STARTED %s.",
getNotifyMessage()));
}
TestCaseSetup testSetup = BaseFunctionality.test().setup();
if (testSetup != null)
{
final String deviceName =
Reporter.getDiv(Reporter.VALUE_STYLE, DevicePool
.getDeviceDescriptionString(testSetup.getDevice()));
Reporter.setCurrentTestResult(result);
Reporter.log(String.format(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"Robin session started on %s."), deviceName));
} else
{
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"TestCaseSetup instance(s) found for thread "
+ BaseFunctionality.test().threadId()));
}
}
@Override
public void onTestSuccess(final ITestResult result)
{
if (notifyPass)
{
Reporter.logConsole(String
.format("PASSED %s.", getNotifyMessage()));
}
Reporter.setCurrentTestResult(result);
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"Test completed succesfully."));
try
{
deleteLogcat();
} catch (SetupException e)
{
e.printStackTrace();
}
}
@Override
public void onTestSkipped(final ITestResult result)
{
synchronized (this)
{
allTestSkip++;
}
if (notifySkip)
{
Reporter.logConsole(String.format(
"SKIPPED %s.",
getNotifyMessage()));
}
Reporter.setCurrentTestResult(result);
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"Test is skipped."));
}
@Override
public void onTestFailure(final ITestResult result)
{
synchronized (this)
{
allTestFail++;
}
if (notifyFail)
{
Reporter.logConsole(String.format(
"FAILED %s because of '%s'.",
getNotifyMessage(),
result.getThrowable().toString()));
}
Reporter.setCurrentTestResult(result);
createSavedFiles();
}
@Override
public void onTestFailedButWithinSuccessPercentage(final ITestResult arg0)
{
}
/**
* Generates a String containing all test specific information: ThreadID,
* method name, device name.
* @return the test descriptor string
*/
protected String getNotifyMessage()
{
final long threadID = Thread.currentThread().getId();
TestCaseSetup testSetup = BaseFunctionality.test().setup();
if (testSetup != null)
{
final String methodName = BaseTest.test().methodName();
final String deviceName =
DevicePool.getDeviceDescriptionString(testSetup.getDevice());
return String.format(
"(thread %d) '%s' in %s.",
threadID,
methodName,
deviceName);
} else
{
return String.format("(thread %d)", threadID);
}
}
/**
* Creates Screenshot and LogCat with appropriate filenames.
*/
private void createSavedFiles()
{
try
{
for (int i = 0; i <= BaseTest.test().lastSoloIndex(); i++)
{
Reporter.log("");
String lastActivity = "???";
try
{
lastActivity =
BaseTest.test().solo(i).getCurrentActivity();
} catch (Exception e)
{
Reporter.log("Could not recive last activity due to "
+ e.getMessage());
}
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"Test failed at "
+ Reporter.getDiv(Reporter.VALUE_STYLE, lastActivity)
+ "."));
final String screenshotName =
BaseTest.test().screenShotFileName(i);
if (screenshotOnFail)
{
Screenshot.capture(screenshotName, i);
}
reportLogCat();
}
} catch (Exception e)
{
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"Screenshot listener failure: '"
+ Reporter.getDiv(Reporter.VALUE_STYLE, e.getMessage())
+ "'."));
}
}
private void reportLogCat()
{
for (LogCatHandler logCatHandler : BaseTest
.test()
.setup()
.getLogCatHandlers())
{
logCatHandler.closeLogCatFile();
Reporter.log(Reporter.getDiv(
Reporter.CONFIG_EVENT_STYLE,
"LogCat: "
+ Reporter.getDiv(Reporter.VALUE_STYLE, Reporter
.getFileInsert(logCatHandler
.getLogCatFile()
.getAbsolutePath(), logCatHandler
.getLogCatFile()
.getName())) + " saved."));
}
}
private void deleteLogcat() throws SetupException
{
for (LogCatHandler logCatHandler : BaseTest
.test()
.setup()
.getLogCatHandlers())
{
logCatHandler.closeLogCatFile();
if (!logCatHandler.getLogCatFile().delete())
{
throw new SetupException(new RuntimeException(
"Unable to delete logcat file."));
}
}
}
@Override
public void afterInvocation(final IInvokedMethod method,
final ITestResult result)
{
if (result.getMethod().isBeforeMethodConfiguration()
&& !isSetupError(result)
&& result.getStatus() == ITestResult.FAILURE)
{
synchronized (this)
{
allConfigFail++;
}
if (notifyFail)
{
Reporter.logConsole(String.format(
"SETUP FAILED %s because of '%s'.",
getNotifyMessage().replaceFirst(
BaseTest.test().methodName(),
method.getTestMethod().getMethodName() + " ("
+ BaseTest.test().methodName() + ")"),
result.getThrowable().getMessage()));
}
Reporter.setCurrentTestResult(result);
createSavedFiles();
}
}
@Override
public void beforeInvocation(final IInvokedMethod method,
final ITestResult result)
{
}
private boolean isSetupError(final ITestResult result)
{
return result.getThrowable() != null
&& result.getThrowable() instanceof SetupException;
}
@Override
public void onExecutionStart()
{
Configuration config = BaseFunctionality.config();
Reporter.storeOriginalSysOut();
System.setOut(Reporter.getLogFileOutputStream());
TranslationMap.parse(config);
DevicePool.init(Integer.parseInt(config
.getValue(ConfigParams.MIN_DEVICE_TO_USE)));
}
@Override
public void onExecutionFinish()
{
Reporter.logConsole("Total tests run: " + allTestRun + ", Failures: "
+ allTestFail + ", Skips: " + allTestSkip + ", ConfigFail: "
+ allConfigFail);
}
}