package com.gfk.senbot.framework.context; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import org.apache.commons.lang.StringUtils; import org.openqa.selenium.WebDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.ResourceUtils; import com.gfk.senbot.framework.data.SenBotReferenceService; /** * A central SenBot context class managing all SenBot functions and modules. It follows a singleton approach where the * instantiation is managed by Spring in the spring/senbot-runner-beans.xml file. * * @author joostschouten * */ public class SenBotContext { public static final String SPRING_CONFIG_LOCATION = "springConfig"; private static Logger log = LoggerFactory.getLogger(SenBotContext.class); /** * The location to the resources needed for running the tests. Eg. html files to use for testing cetrain step def behaviour, files to upload etc. */ private String runtimeResources = null; private static SenBotContext senBotContextSingleton = null; private File testResultsFolder = null; private final SeleniumManager seleniumManager; private final CucumberManager cucumberManager; private static ApplicationContext context; private final SenBotReferenceService referenceService; public static final String SENBOT_CONTEXT_ALTERNATE_RUNTIME_RESOURCES_PROPERTY_NAME = "senbotContext.alternateRuntimeResources"; public static final String RESOURCE_LOCATION_PREFIX = "resource_location:"; private static Thread reportingCreationHook; /** * Constructor * * @param testResultsFolder The folder where to store te test results * @param cucumberManager The cucumber manager object * @param seleniumManager The selenium manager object * @param referenceService The reference service object * @param alternateRuntimeResources TODO * @throws IOException * @throws URISyntaxException */ public SenBotContext(String testResultsFolder, CucumberManager cucumberManager, SeleniumManager seleniumManager, SenBotReferenceService referenceService, String alternateRuntimeResources) throws IOException, URISyntaxException { super(); this.cucumberManager = cucumberManager; this.seleniumManager = seleniumManager; this.referenceService = referenceService; if (StringUtils.isBlank(testResultsFolder)) { throw new IllegalArgumentException("The target folder for the test results cannot be blank. Refer to senbot-runner.properties"); } else { // make sure the output folder exists if it does not already this.testResultsFolder = getOrCreateFile(testResultsFolder, true); } if (StringUtils.isBlank(alternateRuntimeResources)) { URL classPathLocation = this.getClass().getClassLoader().getResource(""); File classPathFile = new File(new URI(classPathLocation.toExternalForm())); this.runtimeResources = classPathFile.getAbsolutePath(); } else { this.runtimeResources = alternateRuntimeResources; } log.info("Initializing the SenBotContext with arguments: testResultsFolder: " + testResultsFolder + ", cucumberManager: " + cucumberManager + ", seleniumManager: " + seleniumManager + ", referenceService: " + referenceService+ ", alternateRuntimeResources: " + alternateRuntimeResources); if(reportingCreationHook == null) { //register a shutdownhook that generates the cucumber reports once all have finished final String testFolder = getTestResultsFolder().getAbsolutePath(); reportingCreationHook = cucumberManager.getReportingShutdownHook(testFolder); Runtime.getRuntime().addShutdownHook(reportingCreationHook); } } /** * Obtain the {@link SenBotContext} singleton. Instantiate it if not yet available * @return SenBotContext */ public static SenBotContext getSenBotContext() { if (senBotContextSingleton == null) { //synchronize instantiation synchronized (SenBotContext.class) { //another null check as two threads might have passed the first null check, wait in line on the //synchronized block and both instantiate the singleton. if (senBotContextSingleton == null) { String springConfigLocation = System.getProperty(SPRING_CONFIG_LOCATION); if(springConfigLocation == null) { springConfigLocation = "classpath*:cucumber.xml"; } context = new ClassPathXmlApplicationContext(new String[]{springConfigLocation}); senBotContextSingleton = context.getBean(SenBotContext.class); } } } return senBotContextSingleton; } /** * Gets the bean class * @param clazz * @return {@link Object} Spring service mapped to the passed in class */ public static <T> T getBean(Class<T> clazz) { return getSenBotContext().context.getBean(clazz); } /** * Gets the bean class * @param name * @param requiredType * * @return {@link Object} Spring service mapped to the passed in Spring id */ public static <T> T getBean(String name, Class<T> requiredType) { return getSenBotContext().context.getBean(name, requiredType); } /** * Cleanup the singleton */ public static void cleanupSenBot() { log.info("Cleaning up the SenBotContext and unreferencing the singleton"); if (senBotContextSingleton != null) { senBotContextSingleton.cleanUp(); senBotContextSingleton = null; } } /** * delegate cleanup to all managers */ private void cleanUp() { if (getSeleniumManager() != null) { getSeleniumManager().cleanUp(); } if (getCucumberManager() != null) { getCucumberManager().cleanUp(); } } /** * @return Class managing all selenium variables, drivers and environments */ public SeleniumManager getSeleniumManager() { return seleniumManager; } /** * @return The folder to generate the test results in */ public File getTestResultsFolder() { return testResultsFolder; } /** * @return The selenium web driver for the browser */ public static WebDriver getSeleniumDriver() { TestEnvironment lastAccessed = getSenBotContext().getSeleniumManager().getAssociatedTestEnvironment(); return lastAccessed == null ? null : lastAccessed.getWebDriver(); } /** * Get a File on the class path or file system or create it if it does not * exist */ public static File getOrCreateFile(String url, boolean createIfNotFound) throws IOException { File file = null; if (url.contains(ResourceUtils.CLASSPATH_URL_PREFIX)) { url = url.replaceAll(ResourceUtils.CLASSPATH_URL_PREFIX, ""); if (url.startsWith("/")) { url = url.substring(1); } URL resource = SenBotContext.class.getClassLoader().getResource(""); if (resource == null) { throw new IOException("creating a new folder on the classpath is not allowed"); } else { file = new File(resource.getFile() + "/" + url); } } else { file = new File(url); } if (createIfNotFound && !file.exists()) { file.mkdirs(); } return file; } /** * @return The cucumberManager */ public CucumberManager getCucumberManager() { return cucumberManager; } /** * @return The SenBotReferenceService */ public SenBotReferenceService getReferenceService() { return referenceService; } /** * @return The runtimeRessources */ public String getRuntimeResources() { return runtimeResources; } }