/* * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. * * Copyright 2013 - 2015 the original author or authors. * * Licensed 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.sakuli.starter; import net.sf.sahi.ant.Report; import net.sf.sahi.test.TestRunner; import net.sf.sahi.util.Utils; import org.sakuli.datamodel.TestSuite; import org.sakuli.datamodel.properties.SahiProxyProperties; import org.sakuli.datamodel.properties.SakuliProperties; import org.sakuli.exceptions.SakuliException; import org.sakuli.exceptions.SakuliExceptionHandler; import org.sakuli.exceptions.SakuliInitException; import org.sakuli.services.InitializingServiceHelper; import org.sakuli.starter.helper.SahiProxy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.File; import java.io.FileNotFoundException; import java.net.ConnectException; import java.util.Date; import java.util.concurrent.TimeUnit; @Component public class SahiConnector { private final Logger logger = LoggerFactory.getLogger(this.getClass()); protected int countConnections = 0; @Autowired private SahiProxy sahiProxy; @Autowired private TestSuite testSuite; @Autowired private SakuliProperties sakuliProperties; @Autowired private SahiProxyProperties sahiProxyProperties; @Autowired private SakuliExceptionHandler sakuliExceptionHandler; static boolean isSahiScriptTimout(Throwable exception) { return exception != null && ( exception.getMessage().startsWith("Script did not start within") //check also the suppressed Exceptions || isSahiScriptTimout(exception.getCause()) ); } /** * Initialize method to start the sahi proxy thread, if needed */ public void init() throws SakuliInitException { logger.info("Initialize Sahi Proxy! "); try { sahiProxy.startProxy(); } catch (FileNotFoundException e) { throw new SakuliInitException(e); } } /** * starts a specific sahi test suite in sakuli */ public void startSahiTestSuite() throws SakuliInitException { logger.info("Start Sakuli-Test-Suite from folder \"" + testSuite.getTestSuiteFolder().toAbsolutePath().toString() + "\""); checkTestSuiteFile(); // ConnectionTester.checkTestCaseInitURL(testSuite); //default sahi runner to play the sahi script TestRunner runner = getTestRunner(); runner.setIsSingleSession(false); //config reporter runner.addReport(new Report("html", sakuliProperties.getLogFolder().toAbsolutePath().toString())); //add include folder property runner.setInitJS(getInitJSString()); try { //is there to handle exceptions in the catch block from this.reconnect() try { countConnections++; // Script-Runner starts logger.info("Sahi-Script-Runner starts!\n"); //starts the script runner with the prefilled configurations String output = runner.execute(); testSuite.setStopDate(new Date()); logger.info("test suite '" + testSuite.getId() + "' stopped at " + TestSuite.GUID_DATE_FORMATE.format(testSuite.getStopDate())); logger.info("Sahi-Script-Runner executed with " + output); //should only thrown if an exception could fetched by the backend of some reason if (output.equals("FAILURE")) { if (isSahiScriptTimout(testSuite.getException())) { logger.warn("Sahi-Script-Runner timeout detected, start retry!"); SakuliException causingError = new SakuliException(testSuite.getException()); //reset all values InitializingServiceHelper.invokeInitializingServcies(); this.reconnect(causingError); } else if (testSuite.getException() == null) { throw new SakuliInitException("SAHI-Proxy returned 'FAILURE' "); } } } catch (ConnectException | IllegalMonitorStateException e) { //Reconnect - wait for Thread "sahiRunner" this.reconnect(e); } } catch (Throwable e) { sakuliExceptionHandler.handleException(e); } finally { logger.info("test suite finished"); //shutdown sahi proxy! sahiProxy.shutdown(); } } /** * checks the 'testsuite.suite' file if it is walid!. * * @throws SakuliInitException */ void checkTestSuiteFile() throws SakuliInitException { try { Utils.readFileAsString(testSuite.getAbsolutePathOfTestSuiteFile()); } catch (Exception e) { throw new SakuliInitException(e, String.format("Error - %s - during reading in testsuite.suite file '%s'", (e instanceof NullPointerException) ? "unable to read or locate file" : e.getMessage(), testSuite.getAbsolutePathOfTestSuiteFile())); } } //TODO TS #96 refactor, write Test and document protected String getInitJSString() { return String.format("var $includeFolder = '%s'; var $testSuiteFolder = '%s';", getIncludeFolderJsPath(), getTestSuiteFolderJsPath() ); } protected TestRunner getTestRunner() { //have to be always one, to prevent errors in the sikuli screen capturing parts String threads = "1"; //default start URL of the sahi proxy final String sahiHost = "localhost"; final String sahiPort = sahiProxyProperties.getProxyPort().toString(); String startUrl = String.format("http://%s:%s", sahiHost, sahiPort); logger.info("connect Sahi-TestRunner:{}", startUrl); return new TestRunner( testSuite.getAbsolutePathOfTestSuiteFile(), //path to the .suite file testSuite.getBrowserName(), //the browser name, for example "firefox" startUrl, //the start url, for example "http://localhost:9999" sahiHost, //host on which the sahi proxy will started sahiPort, //port on which the sahi port is opend threads); //numer of parallel process in the sakuli application still 1 } protected String getIncludeFolderJsPath() { String path = sakuliProperties.getJsLibFolder().toAbsolutePath().toString() + File.separator + "sakuli.js"; if (path.contains("\\")) { //replace \ with \\ path = path.replaceAll("\\\\", "\\\\\\\\"); } return path; } protected String getTestSuiteFolderJsPath() { String path = testSuite.getTestSuiteFolder().toAbsolutePath().toString(); if (path.contains("\\")) { //replace \ with \\ path = path.replaceAll("\\\\", "\\\\\\\\"); } return path; } /** * reconnect method for method {@link #startSahiTestSuite()} * * @param e the thrown ConnectException or IllegalMonitorStateException * @throws InterruptedException */ protected void reconnect(Exception e) throws InterruptedException, SakuliException { logger.warn("Cannot connect to sahi proxy - start Proxy.main()"); if (countConnections <= sahiProxyProperties.getMaxConnectTries()) { logger.info( "RECONNECT to sahi proxy in " + sahiProxyProperties.getReconnectSeconds() + " seconds" ); //send thread to sleep Thread.sleep(TimeUnit.SECONDS.toMillis(sahiProxyProperties.getReconnectSeconds())); this.startSahiTestSuite(); } else { logger.info("Reconnect to sahi proxy unsuccessful - Connection refused"); throw new InterruptedException(e.getMessage()); } } }