...9import com.leroy.core.configuration.DriverFactory;10import com.leroy.core.configuration.Log;11import com.leroy.core.configuration.TestInfo;12import com.leroy.core.listeners.helpers.RetryAnalyzer;13import com.leroy.core.listeners.helpers.XMLSuiteResultWriter;14import com.leroy.core.pages.AnyPage;15import io.qameta.allure.Issue;16import org.apache.commons.lang3.RandomStringUtils;17import org.apache.commons.lang3.StringUtils;18import org.openqa.selenium.remote.RemoteWebDriver;19import org.testng.*;20import org.testng.annotations.ITestAnnotation;21import org.testng.internal.Utils;22import org.testng.reporters.XMLReporterConfig;23import org.testng.reporters.XMLStringBuffer;24import org.testng.util.Strings;25import org.testng.xml.XmlSuite;26import java.io.File;27import java.io.FileOutputStream;28import java.io.IOException;29import java.lang.reflect.Constructor;30import java.lang.reflect.Method;31import java.text.SimpleDateFormat;32import java.util.*;33import java.util.regex.Matcher;34import java.util.regex.Pattern;35public class Listener implements ITestListener, ISuiteListener,36 IInvokedMethodListener, IReporter, IAnnotationTransformer {37 private String BROWSER_PROFILE;38 private boolean outputDirExist = false;39 private Map<String, String> outputConfig = new HashMap<String, String>();40 private int testPassed = 0;41 private int testFailed = 0;42 private int testSkipped = 0;43 private static final String TEST_CASE_ID_PATTERN = "C\\d+";44 private static final ThreadLocal<String> context = new ThreadLocal<>();45 public static final String FILE_NAME = "testng-results.xml";46 protected final XMLReporterConfig config = new XMLReporterConfig();47 private XMLStringBuffer rootBuffer;48 public Listener() {49 BROWSER_PROFILE = readBrowserFromPropertyFile();50 }51 //right now only AFTER_SUITE and AFTER_ALL methods are working correctly52 enum ResultGenerationMode {53 AFTER_TEST, AFTER_CLASS, AFTER_SUITE, AFTER_ALL54 }55 private static Listener.ResultGenerationMode resultGenerationMode;56 private ArrayList<ISuite> suites = new ArrayList<>();57 private static boolean processFail;58 private static boolean disableScreenshots;59 protected String currentScreenshotPath;60 private static ObjectMapper mapper = new ObjectMapper();61 static {62 try {63 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);64 String mode = System.getProperty("resultGenerationMode", "all");65 switch (mode) {66 case "test":67 resultGenerationMode = Listener.ResultGenerationMode.AFTER_TEST;68 break;69 case "class":70 resultGenerationMode = Listener.ResultGenerationMode.AFTER_CLASS;71 break;72 case "suite":73 resultGenerationMode = Listener.ResultGenerationMode.AFTER_SUITE;74 break;75 default:76 resultGenerationMode = Listener.ResultGenerationMode.AFTER_ALL;77 break;78 }79 processFail = Boolean.parseBoolean(System.getProperty("processFail", "true"));80 disableScreenshots = Boolean.parseBoolean(System.getProperty("disableScreenshots", "false"));81 } catch (Exception e) {82 e.printStackTrace();83 }84 }85 // Retry analyzer86 @Override87 public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {88 annotation.setRetryAnalyzer(RetryAnalyzer.class);89 if (isTestNeedToDisable(testMethod)) {90 annotation.setEnabled(false);91 }92 }93 private String readBrowserFromPropertyFile() {94 String pathPropsFile = System.getProperty("mpropsFile");95 if (pathPropsFile == null)96 return null;97 Map<String, Object> properties = (Map<String, Object>)98 DriverFactory.loadPropertiesFromFile(pathPropsFile);99 Map<String, Object> settings = (Map<String, Object>) properties.get("settings");100 return DriverFactory.getPropertyValue("", settings, "browser",101 System.getProperty("mBrowser"));102 }103 private boolean isTestNeedToDisable(Method method) {104 String smoke = System.getProperty("smoke");105 String withIssues = System.getProperty("runWithIssues");106 if (Strings.isNotNullAndNotEmpty(withIssues) && withIssues.equalsIgnoreCase("false")) {107 return method.isAnnotationPresent(Issue.class);108 }109 if (Strings.isNotNullAndNotEmpty(smoke) && smoke.equals("true")) {110 return !method.isAnnotationPresent(Smoke.class);111 }112 if (method.isAnnotationPresent(DisableTestWhen.class)) {113 String[] browsers = method.getAnnotation(DisableTestWhen.class).browsers();114 return Arrays.asList(browsers).contains(BROWSER_PROFILE);115 }116 return false;117 }118 // This belongs to ISuiteListener and will execute before the Suite start119 @Override120 public void onStart(ISuite arg0) {121 System.setProperty("current.date", new SimpleDateFormat("E_yyyy.MM.dd_HH.mm.ss_z").format(new Date()));122 arg0.getXmlSuite().setName(arg0.getName());123 // Continue with the rest of the initialization of the system properties124 if (!outputDirExist) {125 System.setProperty("suite.name", "TestResults");126 System.setProperty(127 "output.path",128 "data-output/" + "__Run_"129 + System.getProperty("suite.name") + "_"130 + System.getProperty("current.date"));131 // if TestDataOutput doesn't exist, create it132 File TestDataOutputDir = new File(System.getProperty("output.path"));133 if (!TestDataOutputDir.exists()) {134 TestDataOutputDir.mkdirs();135 }136 this.outputConfig.put("outputDir",137 System.getProperty("output.path"));138 this.outputConfig.put("ExecutionStatus", "started");139 this.outputConfig.put("Started_Time",140 new SimpleDateFormat("E_yyyy.MM.dd_HH.mm.ss_z").format(new Date()));141 generateRunConfig();142 outputDirExist = true;143 }144 Log.info("About to begin executing Suite " + arg0.getName());145 System.setProperty("suitename", arg0.getName());146 String threadCount = System.getProperty("threadCount");147 // Setting the environment parameters148 if (threadCount != null) {149 arg0.getXmlSuite().setThreadCount(Integer.parseInt(threadCount));150 arg0.getXmlSuite().setPreserveOrder(true);151 }152 suites.add(arg0);153 }154 @Override155 // This belongs to ISuiteListener and will execute, once the Suite is156 // finished157 public void onFinish(ISuite arg0) {158 if (resultGenerationMode == Listener.ResultGenerationMode.AFTER_SUITE) {159 generateReport();160 }161 }162 private void generateReport() {163 String outDir = config.getOutputDirectory();164 if (outDir == null || outDir.isEmpty()) {165 outDir = "test-output";166 }167 generateReport(null, suites, outDir);168 }169 // This belongs to ITestListener and will execute before starting of Test170 // set/batch171 @Override172 public void onStart(ITestContext arg0) {173 Log.startTestCase(arg0.getName());174 Log.info("About to begin executing Test " + arg0.getName());175 //find out Test Case ID and set in threadLocal for DriverFactory to set up tag176 Pattern testIDpattern = Pattern.compile(TEST_CASE_ID_PATTERN);177 Matcher matcher = testIDpattern.matcher(arg0.getName());178 if (matcher.find()) {179 Log.info("@@@Test Case ID: " + matcher.group(0));180 context.set(matcher.group(0));181 }182 }183 // This belongs to ITestListener and will execute, once the Test set/batch184 // is finished185 @Override186 public void onFinish(ITestContext arg0) {187 Log.info("Completed executing test " + arg0.getName());188 Log.endTestCase(arg0.getName());189 }190 // This belongs to ITestListener and will execute only when the test is passed191 @Override192 public void onTestSuccess(ITestResult arg0) {193 printTestResults(arg0);194 }195 // This belongs to ITestListener and will execute only when the test is failed196 @Override197 public void onTestFailure(ITestResult arg0) {198 printTestResults(arg0);199 }200 // This belongs to ITestListener and will execute before the main test start201 // (@Test)202 @Override203 public void onTestStart(ITestResult arg0) {204 currentScreenshotPath = null;205 Object currentClass = arg0.getInstance();206 try {207 RemoteWebDriver driver = (RemoteWebDriver) ContextProvider.getDriver();208 if (driver != null) {209 Log.info("Test started on the following configuration " + driver.getCapabilities().toString());210 // Add run configuration211 arg0.setAttribute("configuration::Browser", System.getProperty("mbrowserfullname"));212 arg0.setAttribute("configuration::Platform", System.getProperty("mplatformfullname"));213 arg0.setAttribute("configuration::Environment", System.getProperty("menv"));214 setGenerateTestResultAttributes(true);215 }216 } catch (Exception e) {217 // do nothing.218 }219 }220 // This belongs to ITestListener and will execute only if any of the main221 // test(@Test) get skipped222 @Override223 public void onTestSkipped(ITestResult arg0) {224 Log.info("Skipping Test");225 printTestResults(arg0);226 }227 @Override228 public void onTestFailedButWithinSuccessPercentage(ITestResult arg0) {229 //Not implemented at the moment230 }231 // This belongs to IInvokedMethodListener and will execute before every232 // method including @Before @After @Test233 @Override234 public void beforeInvocation(IInvokedMethod arg0, ITestResult arg1) {235 Log.info("Started execution of the following method: "236 + returnMethodName(arg0.getTestMethod()));237 }238 // This belongs to IInvokedMethodListener and will execute after every239 // method including @Before @After @Test240 @Override241 public void afterInvocation(IInvokedMethod arg0, ITestResult arg1) {242 if (processFail) {243 if (arg1.getStatus() == ITestResult.FAILURE)244 updateResultWithScreenshot(arg1);245 }246 try {247 ITestNGMethod testMethod = arg0.getTestMethod();248 if (resultGenerationMode == Listener.ResultGenerationMode.AFTER_CLASS249 && testMethod.isAfterClassConfiguration() && !testMethod.hasMoreInvocation()) {250 generateReport();251 } else if (resultGenerationMode == Listener.ResultGenerationMode.AFTER_TEST && testMethod.isTest()) {252 generateReport();253 }254 if (!arg1.getMethod().isTest()) {255 printTestResults(arg1);256 }257 } catch (Exception e) {258 e.printStackTrace();259 }260 }261 @Override262 public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites,263 String outputDirectory) {264 if (Utils.isStringEmpty(config.getOutputDirectory())) {265 config.setOutputDirectory(outputDirectory);266 }267 // Calculate passed/failed/skipped268 int passed = 0;269 int failed = 0;270 int skipped = 0;271 for (ISuite s : suites) {272 Map<String, ISuiteResult> suiteResults = s.getResults();273 synchronized (suiteResults) {274 for (ISuiteResult sr : suiteResults.values()) {275 ITestContext testContext = sr.getTestContext();276 passed += testContext.getPassedTests().size();277 failed += testContext.getFailedTests().size();278 skipped += testContext.getSkippedTests().size();279 }280 }281 }282 rootBuffer = new XMLStringBuffer();283 Properties p = new Properties();284 p.put("passed", passed);285 p.put("failed", failed);286 p.put("skipped", skipped);287 p.put("total", passed + failed + skipped);288 rootBuffer.push(XMLReporterConfig.TAG_TESTNG_RESULTS, p);289 // skipped the full report-output in favor of individual suite290 // output291 // writeReporterOutput(rootBuffer);292 for (ISuite suite : suites) {293 writeSuite(suite.getXmlSuite(), suite);294 }295 rootBuffer.pop();296 if (config.getOutputDirectory().contains("surefire-reports"))297 Utils.writeUtf8File("test-output", FILE_NAME, rootBuffer,298 null /* no prefix */);299 Utils.writeUtf8File(config.getOutputDirectory(), FILE_NAME, rootBuffer,300 null /* no prefix */);301 }302 /**303 * This method is used to spit out the first cummulative reporter-outut304 * It's not being used right now in favor of the individual reporter-output305 * for each suite306 *307 * @param xmlBuffer308 */309 private void writeReporterOutput(XMLStringBuffer xmlBuffer) {310 xmlBuffer.push(XMLReporterConfig.TAG_REPORTER_OUTPUT);311 List<String> output = Reporter.getOutput();312 for (String line : output) {313 if (line != null) {314 xmlBuffer.push(XMLReporterConfig.TAG_LINE);315 xmlBuffer.addCDATA(XMLSuiteResultWriter.filterInvalidChars(line));316 xmlBuffer.pop();317 }318 }319 xmlBuffer.pop();320 }321 private void writeSuite(XmlSuite xmlSuite, ISuite suite) {322 switch (config.getFileFragmentationLevel()) {323 case XMLReporterConfig.FF_LEVEL_NONE:324 writeSuiteToBuffer(rootBuffer, suite);325 break;326 case XMLReporterConfig.FF_LEVEL_SUITE:327 case XMLReporterConfig.FF_LEVEL_SUITE_RESULT:328 File suiteFile = referenceSuite(rootBuffer, suite);329 writeSuiteToFile(suiteFile, suite);330 break;331 default:332 throw new AssertionError("Unexpected value: "333 + config.getFileFragmentationLevel());334 }335 }336 private void writeSuiteToFile(File suiteFile, ISuite suite) {337 XMLStringBuffer xmlBuffer = new XMLStringBuffer();338 writeSuiteToBuffer(xmlBuffer, suite);339 File parentDir = suiteFile.getParentFile();340 if (parentDir.exists() || suiteFile.getParentFile().mkdirs()) {341 Utils.writeFile(parentDir.getAbsolutePath(), FILE_NAME,342 xmlBuffer.toXML());343 }344 }345 private File referenceSuite(XMLStringBuffer xmlBuffer, ISuite suite) {346 String relativePath = suite.getName() + File.separatorChar + FILE_NAME;347 File suiteFile = new File(config.getOutputDirectory(), relativePath);348 Properties attrs = new Properties();349 attrs.setProperty(XMLReporterConfig.ATTR_URL, relativePath);350 xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_SUITE, attrs);351 return suiteFile;352 }353 private void writeSuiteToBuffer(XMLStringBuffer xmlBuffer, ISuite suite) {354 xmlBuffer.push(XMLReporterConfig.TAG_SUITE, getSuiteAttributes(suite));355 writeSuiteGroups(xmlBuffer, suite);356 Map<String, ISuiteResult> results = suite.getResults();357 XMLSuiteResultWriter suiteResultWriter = getSuiteResultWriter();358 for (Map.Entry<String, ISuiteResult> result : results.entrySet()) {359 suiteResultWriter.writeSuiteResult(xmlBuffer, result.getValue());360 }361 xmlBuffer.pop();362 }363 protected XMLSuiteResultWriter getSuiteResultWriter() {364 return new XMLSuiteResultWriter(config);365 }366 private void generateRunConfig() {367 try {368 Properties properties = new Properties();369 for (String key : this.outputConfig.keySet()) {370 properties.setProperty(key, this.outputConfig.get(key));371 }372 File file = new File("runConfiguration.properties");373 FileOutputStream fileOut = new FileOutputStream(file);374 properties.store(fileOut, "Framework Run Configuration");375 fileOut.close();376 } catch (IOException e) {377 e.printStackTrace();378 }...