diff --git a/config/browser.properties b/config/browser.properties index 14ad6cbef..563028f0b 100644 --- a/config/browser.properties +++ b/config/browser.properties @@ -32,6 +32,10 @@ neodymium.webDriver.reuseDriver = false # Warning: The webdriver process might stay alive even if you close the browser afterwards neodymium.webDriver.keepBrowserOpen = false +## Whether to keep the browser instance open only if the test fails +# Warning: The webdriver process might stay alive even if you close the browser afterwards +neodymium.webDriver.keepBrowserOpenOnFailure = false + ## HTTP proxy settings. Specify host and port of the proxy server and ## whether it should be used at all. If the proxy requires user authentication, ## make sure to provide the credentials needed. @@ -118,6 +122,11 @@ neodymium.webDriver.keepBrowserOpen = false # eager : returns when DOMContentLoaded event was fired # none : returns immediately # +# .headless: A boolean propertey that defines if the browser should run in headless mode. Default value is false +# NOTE: Currently only implemented for Firefox and Chrome +# true: start browser in headless mode +# false: (default) start browser normal +# ################################################################################ # A local Chrome with a small window size browserprofile.Chrome_1024x768.name = Chrome 1024x768 diff --git a/pom.xml b/pom.xml index f6ee9c3c9..8e49b0606 100644 --- a/pom.xml +++ b/pom.xml @@ -67,8 +67,7 @@ 4 false - **/TestJunitCategoriesSuite.java - com/xceptance/neodymium/tests/** + com/xceptance/neodymium/tests/**/*Test.java diff --git a/src/main/java/com/xceptance/neodymium/MethodExecutionContext.java b/src/main/java/com/xceptance/neodymium/MethodExecutionContext.java deleted file mode 100644 index 92714e672..000000000 --- a/src/main/java/com/xceptance/neodymium/MethodExecutionContext.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.xceptance.neodymium; - -import org.junit.runner.Description; - -public class MethodExecutionContext -{ - private boolean runBeforeClass; - - private boolean runAfterClass; - - private Description runnerDescription; - - private Object testClassInstance; - - public boolean isRunBeforeClass() - { - return runBeforeClass; - } - - public void setRunBeforeClass(boolean runBeforeClass) - { - this.runBeforeClass = runBeforeClass; - } - - public boolean isRunAfterClass() - { - return runAfterClass; - } - - public void setRunAfterClass(boolean runAfterClass) - { - this.runAfterClass = runAfterClass; - } - - public Description getRunnerDescription() - { - return runnerDescription; - } - - public void setRunnerDescription(Description runnerDescription) - { - this.runnerDescription = runnerDescription; - } - - public Object getTestClassInstance() - { - return testClassInstance; - } - - public void setTestClassInstance(Object testClassInstance) - { - this.testClassInstance = testClassInstance; - } -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumBrowserRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumBrowserRunner.java deleted file mode 100644 index fa92a17d9..000000000 --- a/src/main/java/com/xceptance/neodymium/NeodymiumBrowserRunner.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.xceptance.neodymium; - -import java.lang.annotation.Annotation; -import java.net.MalformedURLException; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; -import org.junit.runner.Description; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.ParentRunner; -import org.junit.runners.model.InitializationError; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.firefox.FirefoxDriver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.codeborne.selenide.WebDriverRunner; -import com.xceptance.neodymium.multibrowser.Browser; -import com.xceptance.neodymium.multibrowser.BrowserRunnerHelper; -import com.xceptance.neodymium.multibrowser.WebDriverCache; -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.DriverServerPath; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.WebDriverProperties; -import com.xceptance.neodymium.util.Context; - -/** - * JUnit runner used to run testcases that are annotated with {@link Browser}. This class reads the annotation based - * configuration of {@link Browser} and executes the testcase multiple-times with different configurations. - * - * @author m.kaufmann - * @see Browser - */ -public class NeodymiumBrowserRunner extends ParentRunner -{ - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumBrowserRunner.class); - - /** - * The JUnit children of this runner. - */ - private final List browser = new LinkedList(); - - private WebDriver webdriver; - - private BrowserConfiguration browserConfig; - - private static final String SYSTEM_PROPERTY_BROWSERDEFINITION = "browserdefinition"; - - private static final String BROWSER_PROFILE_FILE = "./config/browser.properties"; - - /** - * Sets the test instance up. - */ - protected void setUpTest() - { - webdriver = null; - LOGGER.debug("Create browser for name: " + browserConfig.getName()); - try - { - // try to find appropriate web driver in cache before create a new instance - if (MultibrowserConfiguration.getInstance().getWebDriverProperties().reuseWebDriver()) - { - webdriver = WebDriverCache.instance.getRemoveWebDriver(browserConfig.getConfigTag()); - if (webdriver != null) - { - webdriver.manage().deleteAllCookies(); - } - } - - if (webdriver == null) - { - LOGGER.debug("Create new browser instance"); - webdriver = BrowserRunnerHelper.createWebdriver(browserConfig); - } - else - { - LOGGER.debug("Browser instance served from cache"); - } - } - catch (final MalformedURLException e) - { - throw new RuntimeException("An error occured during URL creation. See nested exception.", e); - } - if (webdriver != null) - { - // set browser window size - BrowserRunnerHelper.setBrowserWindowSize(browserConfig, webdriver); - WebDriverRunner.setWebDriver(webdriver); - Context.get().driver = webdriver; - Context.get().browserProfileName = browserConfig.getConfigTag(); - } - else - { - throw new RuntimeException("Could not create driver for browsertag: " + browserConfig.getConfigTag() + - ". Please check your browserconfigurations."); - } - } - - @Override - public void run(RunNotifier notifier) - { - setUpTest(); - } - - private NeodymiumBrowserRunner(Class testCaseClass, BrowserConfiguration browserConfig) throws InitializationError - { - super(testCaseClass); - this.browserConfig = browserConfig; - } - - public NeodymiumBrowserRunner(final Class testCaseClass) throws Throwable - { - super(testCaseClass); - - MultibrowserConfiguration multibrowserConfiguration = MultibrowserConfiguration.getInstance(); - - // that is like a dirty hack to provide testing ability - if (multibrowserConfiguration == null) - multibrowserConfiguration = MultibrowserConfiguration.getInstance(BROWSER_PROFILE_FILE); - - DriverServerPath driverServerPath = multibrowserConfiguration.getDriverServerPath(); - WebDriverProperties webDriverProperties = multibrowserConfiguration.getWebDriverProperties(); - - final Map parsedBrowserProperties = multibrowserConfiguration.getBrowserProfiles(); - - final String ieDriverPath = driverServerPath.getIeDriverPath(); - final String chromeDriverPath = driverServerPath.getChromeDriverPath(); - final String geckoDriverPath = driverServerPath.getFirefoxDriverPath(); - - // shall we run old school firefox? - final boolean firefoxLegacy = webDriverProperties.useFirefoxLegacy(); - System.setProperty(FirefoxDriver.SystemProperty.DRIVER_USE_MARIONETTE, Boolean.toString(!firefoxLegacy)); - - if (!StringUtils.isEmpty(ieDriverPath)) - { - System.setProperty("webdriver.ie.driver", ieDriverPath); - } - if (!StringUtils.isEmpty(chromeDriverPath)) - { - System.setProperty("webdriver.chrome.driver", chromeDriverPath); - } - if (!StringUtils.isEmpty(geckoDriverPath)) - { - System.setProperty("webdriver.gecko.driver", geckoDriverPath); - } - boolean foundTargetsAnnotation = false; - - // get test specific browser definitions (aka browser tag see browser.properties) - // could be one value or comma separated list of values - String browserDefinitionsProperty = System.getProperty(SYSTEM_PROPERTY_BROWSERDEFINITION, ""); - browserDefinitionsProperty = browserDefinitionsProperty.replaceAll("\\s", ""); - - List browserDefinitions = null; - - // parse test specific browser definitions - if (!StringUtils.isEmpty(browserDefinitionsProperty)) - { - browserDefinitions = Arrays.asList(browserDefinitionsProperty.split(",")); - } - - // Get annotations of test class. - final Annotation[] annotations = testCaseClass.getAnnotations(); - for (final Annotation annotation : annotations) - { - // only check Browser annotation with a list browser configuration tags - if (annotation instanceof Browser) - { - foundTargetsAnnotation = true; - - // remove duplicate targets by putting them into a set and get them back out - // use LinkedHashSet to preserve order of insertion - Set targetSet = new LinkedHashSet<>(); - targetSet.addAll(Arrays.asList(((Browser) annotation).value())); - final String[] targets = targetSet.toArray(new String[0]); - - for (final String target : targets) - { - // check if the annotated target is in the list of targets specified via system property - if (browserDefinitions != null && !browserDefinitions.contains(target)) - { - continue; - } - - final BrowserConfiguration foundBrowserConfiguration = parsedBrowserProperties.get(target); - if (foundBrowserConfiguration == null) - { - throw new IllegalArgumentException("Can not find browser configuration with tag: " + target); - } - - // create the JUnit children - browser.add(new NeodymiumBrowserRunner(testCaseClass, foundBrowserConfiguration)); - } - } - } - - if (!foundTargetsAnnotation) - throw new IllegalArgumentException("The class (" + testCaseClass.getSimpleName() + - ") does not have a required Browser annotation."); - } - - /** - * {@inheritDoc} - */ - @Override - public List getChildren() - { - return browser; - } - - /** - * {@inheritDoc} - */ - @Override - public Description getDescription() - { - return Description.createTestDescription(browserConfig.getName(), ""); - } - - public void teardown() - { - WebDriverProperties webDriverProperties = MultibrowserConfiguration.getInstance().getWebDriverProperties(); - if (webDriverProperties.reuseWebDriver()) - { - LOGGER.debug("Put browser into cache"); - WebDriverCache.instance.putWebDriver(browserConfig.getConfigTag(), webdriver); - } - else - { - if (!webDriverProperties.keepBrowserOpen() && webdriver != null) - { - LOGGER.debug("Teardown browser"); - webdriver.quit(); - } - } - Context.get().driver = null; - Context.get().browserProfileName = null; - } - - public static void quitCachedBrowser() - { - WebDriverProperties webDriverProperties = MultibrowserConfiguration.getInstance().getWebDriverProperties(); - if (!webDriverProperties.keepBrowserOpen()) - { - Collection allWebdriver = WebDriverCache.instance.getAllWebdriver(); - - for (WebDriver wd : allWebdriver) - { - try - { - LOGGER.debug("Quit web driver: " + wd.toString()); - wd.quit(); - } - catch (Exception e) - { - LOGGER.debug("Error on quitting web driver", e); - } - } - } - } - - @Override - protected Description describeChild(Runner child) - { - return null; - } - - @Override - protected void runChild(Runner child, RunNotifier notifier) - { - } - - /** - * Returns a name used to describe this Runner - */ - @Override - public String getName() - { - return browserConfig.getName(); - } -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumRunListener.java b/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunListener.java similarity index 87% rename from src/main/java/com/xceptance/neodymium/NeodymiumRunListener.java rename to src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunListener.java index 5e734f5b4..d9542bd6c 100644 --- a/src/main/java/com/xceptance/neodymium/NeodymiumRunListener.java +++ b/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunListener.java @@ -10,17 +10,18 @@ import org.slf4j.LoggerFactory; import com.codeborne.selenide.logevents.SelenideLogger; +import com.xceptance.neodymium.util.Context; import io.qameta.allure.Attachment; import io.qameta.allure.selenide.AllureSelenide; -public class NeodymiumRunListener extends RunListener +public class NeodymiumCucumberRunListener extends RunListener { - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumRunListener.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumCucumberRunListener.class); private List failures = new LinkedList<>(); - public NeodymiumRunListener() + public NeodymiumCucumberRunListener() { SelenideLogger.addListener("allure-selenide", new AllureSelenide()); } @@ -28,6 +29,7 @@ public NeodymiumRunListener() @Override public void testStarted(Description description) throws Exception { + Context.clearThreadContext(); LOGGER.debug("Test started: " + description.toString()); } diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunner.java index 5518441de..c272818ce 100644 --- a/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunner.java +++ b/src/main/java/com/xceptance/neodymium/NeodymiumCucumberRunner.java @@ -18,7 +18,8 @@ public NeodymiumCucumberRunner(Class clazz) throws InitializationError, IOExc public void run(RunNotifier notifier) { // we add our own run listener in order to attach screenshots taken by Selenide to the Allure report - notifier.addListener(new NeodymiumRunListener()); + // this also neccessary to clear the context between tests + notifier.addListener(new NeodymiumCucumberRunListener()); super.run(notifier); } } diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumDataRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumDataRunner.java deleted file mode 100644 index b1b12da2d..000000000 --- a/src/main/java/com/xceptance/neodymium/NeodymiumDataRunner.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.xceptance.neodymium; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.lang3.StringUtils; -import org.junit.runner.Description; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.ParentRunner; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.TestClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.xceptance.neodymium.testdata.TestDataUtils; -import com.xceptance.neodymium.util.Context; - -public class NeodymiumDataRunner extends ParentRunner -{ - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumDataRunner.class); - - private List children; - - public NeodymiumDataRunner(TestClass testClass, MethodExecutionContext methodExecutionContext) throws InitializationError - { - super(testClass.getJavaClass()); - List> dataSets; - Map packageTestData; - - children = new LinkedList<>(); - - try - { - dataSets = TestDataUtils.getDataSets(testClass.getJavaClass()); - packageTestData = TestDataUtils.getPackageTestData(testClass.getJavaClass()); - } - catch (Exception e) - { - throw new InitializationError(e); - } - - if (!dataSets.isEmpty() || !packageTestData.isEmpty()) - { - - if (!dataSets.isEmpty()) - { - // data sets found - for (int i = 0; i < dataSets.size(); i++) - { - children.add(new NeodymiumDataRunnerRunner(testClass.getJavaClass(), dataSets, i, packageTestData, - methodExecutionContext)); - } - } - else - { - // only package data, no data sets - children.add(new NeodymiumDataRunnerRunner(testClass.getJavaClass(), dataSets, -1, packageTestData, - methodExecutionContext)); - } - } - else - { - // we couldn't find any data sets - // throw an IllegalArgumentException that will be caught in NeodymiumRunner - throw new IllegalArgumentException(); - } - } - - @Override - protected List getChildren() - { - return children; - } - - @Override - protected Description describeChild(Runner child) - { - return ((NeodymiumDataRunnerRunner) child).getDescription(); - } - - @Override - protected void runChild(Runner child, RunNotifier notifier) - { - child.run(notifier); - } - - public class NeodymiumDataRunnerRunner extends Runner - { - - private Class testClass; - - private MethodExecutionContext methodExecutionContext; - - private int index; - - private Map testData; - - private int dataSetCount; - - public NeodymiumDataRunnerRunner(Class javaClass, List> dataSets, int index, - Map packageTestData, MethodExecutionContext methodExecutionContext) - { - this.index = index; - this.testClass = javaClass; - this.dataSetCount = dataSets.size(); - this.methodExecutionContext = methodExecutionContext; - - // these are the test data that will be injected into the test class - testData = new HashMap<>(); - // first put all package test data into the map - testData.putAll(packageTestData); - // if data sets are present then add them afterwards so they can overwrite package data - if (index >= 0) - { - for (Entry newDataEntry : dataSets.get(index).entrySet()) - { - // only log if a data set entry overwrites an package data entry - if (testData.containsKey(newDataEntry.getKey())) - { - LOGGER.debug(String.format("Data entry \"%s\" overwritten by data set #%d (old: \"%s\", new: \"%s\")", - newDataEntry.getKey(), index + 1, testData.get(newDataEntry.getKey()), - newDataEntry.getValue())); - } - testData.put(newDataEntry.getKey(), newDataEntry.getValue()); - } - - testData.putAll(dataSets.get(index)); - } - } - - @Override - public Description getDescription() - { - if (index >= 0) - { - // data sets and (maybe) package data - String testDatasetIndetifier = testData.get("ID"); - if (StringUtils.isBlank(testDatasetIndetifier)) - { - testDatasetIndetifier = "Data set"; - } - String displayName = String.format("%s %d / %d", testDatasetIndetifier, (index + 1), dataSetCount); - return Description.createSuiteDescription(displayName, testClass.getAnnotations()); - } - else - { - // only package data - return Description.createSuiteDescription("TestData", testClass.getAnnotations()); - } - } - - public boolean hasDataSets() - { - // used in NeodymiumRunner to determine if this runner should be visible in the runner list / JUnit view / test report - return (index >= 0); - } - - @Override - public void run(RunNotifier notifier) - { - try - { - Context.get().data.putAll(testData); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - - } -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumMethodRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumMethodRunner.java deleted file mode 100644 index 3722e831c..000000000 --- a/src/main/java/com/xceptance/neodymium/NeodymiumMethodRunner.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.xceptance.neodymium; - -import java.util.LinkedList; -import java.util.List; - -import org.junit.internal.AssumptionViolatedException; -import org.junit.runner.Description; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunNotifier; -import org.junit.runner.notification.StoppedByUserException; -import org.junit.runners.BlockJUnit4ClassRunner; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.MultipleFailureException; -import org.junit.runners.model.Statement; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NeodymiumMethodRunner extends BlockJUnit4ClassRunner -{ - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumMethodRunner.class); - - List methodToRun; - - private Object testInstance; - - private MethodExecutionContext methodExecutionContext; - - private NeodymiumMethodRunner(Class klass) throws InitializationError - { - super(klass); - } - - public NeodymiumMethodRunner(Class klass, FrameworkMethod method, MethodExecutionContext methodExecutionContext) - throws InitializationError - { - super(klass); - this.methodExecutionContext = methodExecutionContext; - methodToRun = new LinkedList<>(); - methodToRun.add(method); - } - - @Override - protected List getChildren() - { - return methodToRun; - } - - @Override - public void run(RunNotifier notifier) - { - testInstance = methodExecutionContext.getTestClassInstance(); - - NeodymiumRunListener runListener = new NeodymiumRunListener(); - try - { - RunNotifier subnotifier = new RunNotifier(); - subnotifier.addListener(runListener); - - Statement statement = childrenInvoker(subnotifier); - - if (methodExecutionContext.isRunBeforeClass()) - { - LOGGER.debug("Run before classes"); - statement = withBeforeClasses(statement); - } - - if (methodExecutionContext.isRunAfterClass()) - { - LOGGER.debug("Run after classes"); - statement = withAfterClasses(statement); - } - statement.evaluate(); - if (runListener.hasFailure()) - { - for (Failure failure : runListener.getFailures()) - { - notifier.fireTestFailure(new Failure(methodExecutionContext.getRunnerDescription(), failure.getException())); - LOGGER.debug("Execution failed", failure.getException()); - } - - } - } - catch (AssumptionViolatedException e) - { - notifier.fireTestAssumptionFailed(new Failure(methodExecutionContext.getRunnerDescription(), e)); - } - catch (StoppedByUserException e) - { - throw e; - } - catch (Throwable e) - { - List exceptionList = new LinkedList<>(); - if (e instanceof MultipleFailureException) - { - exceptionList = ((MultipleFailureException) e).getFailures(); - } - else - { - exceptionList.add(e); - } - - for (Throwable t : exceptionList) - { - notifier.fireTestFailure(new Failure(methodExecutionContext.getRunnerDescription(), t)); - } - } - } - - @Override - protected Object createTest() throws Exception - { - return testInstance; - } - - @Override - public Description getDescription() - { - FrameworkMethod method = getMethod(); - Description description = Description.createSuiteDescription(method.getName(), getRunnerAnnotations()); - return description; - } - - public FrameworkMethod getMethod() - { - return methodToRun.get(0); - } -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunner.java deleted file mode 100644 index cd6a82b64..000000000 --- a/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunner.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.xceptance.neodymium; - -import java.lang.reflect.Field; -import java.util.LinkedList; -import java.util.List; - -import org.junit.runner.Description; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.model.FrameworkField; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; -import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters; -import org.junit.runners.parameterized.TestWithParameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NeodymiumParameterRunner extends BlockJUnit4ClassRunnerWithParameters -{ - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumParameterRunner.class); - - private TestWithParameters test; - - private Object[] parameters; - - private Object testInstance; - - private MethodExecutionContext methodExecutionContext; - - public NeodymiumParameterRunner(TestWithParameters test, MethodExecutionContext methodExecutionContext) throws InitializationError - { - super(test); - this.test = test; - this.methodExecutionContext = methodExecutionContext; - parameters = test.getParameters().toArray(new Object[0]); - } - - @Override - public Object createTest() throws Exception - { - return super.createTest(); - } - - @Override - public Description getDescription() - { - return Description.createTestDescription(test.getTestClass().getClass(), test.getName()); - } - - @Override - public void run(RunNotifier notifier) - { - testInstance = methodExecutionContext.getTestClassInstance(); - - super.run(notifier); - try - { - injectTestParameter(); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - - @Override - protected String getName() - { - return test.getName(); - } - - @Override - protected List getChildren() - { - List dummy = new LinkedList<>(); - return dummy; - } - - private void injectTestParameter() throws Exception - { - List parameterFrameworkFields = getTestClass().getAnnotatedFields(Parameter.class); - LOGGER.debug("Found " + parameterFrameworkFields.size() + " parameter fields"); - if (parameterFrameworkFields.size() != parameters.length) - { - throw new Exception("Number of parameters (" + parameters.length + ") and " + // - "fields (" + parameterFrameworkFields.size() + ") " + // - "annotated with @Parameter must match!"); - } - - for (FrameworkField parameterFrameworkField : parameterFrameworkFields) - { - Field field = parameterFrameworkField.getField(); - int parameterIndex = field.getAnnotation(Parameter.class).value(); - - LOGGER.debug("Set parameter \"" + parameterFrameworkField.getName() + "\" to \"" + parameters[parameterIndex] + "\""); - setField(field, parameters[parameterIndex]); - } - } - - private void setField(Field field, Object value) - { - Class fieldType = field.getType(); - Class valueType; - if (value == null) - { - valueType = Void.class; - } - else - { - valueType = value.getClass(); - } - - // try to convert String values to appropriate target types - if (valueType == String.class) - { - try - { - if (fieldType == int.class || fieldType == Integer.class) - { - value = Integer.valueOf((String) value); - } - else if (fieldType == long.class || fieldType == Long.class) - { - value = Long.valueOf((String) value); - } - else if (fieldType == double.class || fieldType == Double.class) - { - value = Double.valueOf((String) value); - } - else if (fieldType == float.class || fieldType == Float.class) - { - value = Float.valueOf((String) value); - } - else if (fieldType == boolean.class || fieldType == Boolean.class) - { - value = Boolean.valueOf((String) value); - } - } - catch (Exception e) - { - throw new RuntimeException("An error occured during conversion of input string \"" + (String) value + "\" to type " + - fieldType.getName() + " for field \"" + field.getName() + "\"", e); - } - } - - try - { - field.set(testInstance, value); - } - catch (IllegalArgumentException e) - { - throw new RuntimeException("Could not set parameter of type " + valueType + " to field \"" + field.getName() + "\" of type " + - fieldType + ". Value: " + value); - } - catch (IllegalAccessException e) - { - throw new RuntimeException("Could not set parameter due to it is not public or it is final"); - } - } -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunnerFactory.java b/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunnerFactory.java deleted file mode 100644 index 62123edc3..000000000 --- a/src/main/java/com/xceptance/neodymium/NeodymiumParameterRunnerFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.xceptance.neodymium; - -import org.junit.runner.Runner; -import org.junit.runners.model.InitializationError; -import org.junit.runners.parameterized.ParametersRunnerFactory; -import org.junit.runners.parameterized.TestWithParameters; - -public class NeodymiumParameterRunnerFactory implements ParametersRunnerFactory -{ - - private MethodExecutionContext methodExecutionContext; - - public NeodymiumParameterRunnerFactory(MethodExecutionContext methodExecutionContext) - { - this.methodExecutionContext = methodExecutionContext; - } - - @Override - public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError - { - return new NeodymiumParameterRunner(test, methodExecutionContext); - } - -} diff --git a/src/main/java/com/xceptance/neodymium/NeodymiumRunner.java b/src/main/java/com/xceptance/neodymium/NeodymiumRunner.java index 67d3407f8..8465bbb2e 100644 --- a/src/main/java/com/xceptance/neodymium/NeodymiumRunner.java +++ b/src/main/java/com/xceptance/neodymium/NeodymiumRunner.java @@ -1,40 +1,27 @@ package com.xceptance.neodymium; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Set; +import java.util.Map; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.runner.Description; import org.junit.runner.RunWith; -import org.junit.runner.Runner; -import org.junit.runner.manipulation.Filter; -import org.junit.runner.manipulation.Filterable; -import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.JUnit4; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; -import org.junit.runners.ParentRunner; import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.RunnerBuilder; -import org.junit.runners.model.TestClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; -import com.xceptance.neodymium.NeodymiumDataRunner.NeodymiumDataRunnerRunner; -import com.xceptance.neodymium.multibrowser.Browser; +import com.xceptance.neodymium.module.EnhancedMethod; +import com.xceptance.neodymium.module.StatementBuilder; +import com.xceptance.neodymium.module.order.DefaultStatementRunOrder; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; +import com.xceptance.neodymium.util.Context; /** * This class executes {@link JUnit4} test classes (aka JUnit Runner) and adds several features to test execution e.g. @@ -77,454 +64,288 @@ * * @author m.kaufmann */ -public class NeodymiumRunner extends Runner implements Filterable +public class NeodymiumRunner extends BlockJUnit4ClassRunner { - private static final Logger LOGGER = LoggerFactory.getLogger(NeodymiumRunner.class); + public NeodymiumRunner(Class klass) throws InitializationError + { + super(klass); + } - List> testRunner = new LinkedList<>(); + public enum DescriptionMode + { + flat, + tree, + }; - private TestClass testClass; + private List computedTestMethods; - private Description testDescription; + private Map childDescriptions; - private MethodExecutionContext methodExecutionContext; + private Description globalTestDescription; - public NeodymiumRunner(Class testKlass, RunnerBuilder rb) throws Throwable - { - LOGGER.debug(testKlass.getCanonicalName()); - List> vectors = new LinkedList<>(); - testClass = new TestClass(testKlass); - List runners = new LinkedList<>(); - methodExecutionContext = new MethodExecutionContext(); - - // find test vectors - // scan for Browser and Parameters annotation - // later on we could add handler for any annotation that should influence test run - - // lookup Browser annotation - Browser browser = testClass.getAnnotation(Browser.class); - if (browser != null) - { - LOGGER.debug("Found browser annotation"); - runners.add(new NeodymiumBrowserRunner(testKlass)); - } + private Object testClassInstance; - // scan for JUnit Parameters - List parameterMethods = testClass.getAnnotatedMethods(Parameters.class); - if (parameterMethods.size() > 0) - { - LOGGER.debug("Found parameters annotation"); - setFinalStatic(Parameterized.class.getDeclaredField("DEFAULT_FACTORY"), - new NeodymiumParameterRunnerFactory(methodExecutionContext)); - runners.add(new Parameterized(testKlass)); - } - - try - { - runners.add(new NeodymiumDataRunner(testClass, methodExecutionContext)); - } - catch (IllegalArgumentException e) - { - // no test data found, proceed - } + @Override + protected Statement methodBlock(FrameworkMethod method) + { + // This will build a default JUnit statement which runs excactly one of the test methods including before/after + // methods. This call will also create the test class instance in which this method will be invoked. + Statement methodStatement = super.methodBlock(method); + // We need this particular test class instance for our own statements but we can not access it from here. + // We can get the instance by having createTest overridden, see implementation of createTest in this class as + // well as in BlockJUnit4ClassRunner. - // collect children of ParentRunner sub classes - doMagic(runners, vectors); + // At this point our createTest implementation was called and we have the testClassInstance - // create method runners that actually execute the methods annotated with @Test - List methodVector = new LinkedList<>(); - List annotatedMethods = testClass.getAnnotatedMethods(Test.class); - if (annotatedMethods.size() > 0) + if (method instanceof EnhancedMethod) { - LOGGER.debug("Found methods to run"); + EnhancedMethod m = (EnhancedMethod) method; + for (int i = m.getBuilder().size() - 1; i >= 0; i--) + { + StatementBuilder statementBuilder = m.getBuilder().get(i); + Object data = m.getData().get(i); + methodStatement = statementBuilder.createStatement(testClassInstance, methodStatement, data); + } } - else + else if (method instanceof FrameworkMethod) { - LOGGER.debug("No test methods found"); - throw new Exception("No runnable methods"); - } + // This could happen if there are plain test methods in the class with no data sets or test data defined. + // Also the SuppressDataSets annotation can degrade a method to an FrameworkMethod even if there is some + // test data or data sets. - for (FrameworkMethod method : annotatedMethods) - { - NeodymiumMethodRunner methodRunner = new NeodymiumMethodRunner(testKlass, method, methodExecutionContext); - LOGGER.debug("\t" + methodRunner.getDescription().getDisplayName()); - methodVector.add(methodRunner); + // It's fine, just make sure super.methodBlock is called with this method and return the resulting statement } - vectors.add(methodVector); - - testRunner = buildTestRunnerLists(vectors); - LOGGER.debug("Build " + testRunner.size() + " test runner"); + return methodStatement; + } - testDescription = createTestDescription(); + @Override + protected Object createTest() throws Exception + { + // Very important code which will be called from super's methodBlock function (see our methodBlock) + // The super's call creates the instance of the class to test which will be a new one for each method. + // Since we need this particular instance for our own statements we need to save it for us. + // Keep in mind that this method will be called for every method that will be returned from computeTestMethods. + // So there is not the one and only test class instance. Its one instance per method. + this.testClassInstance = super.createTest(); + return testClassInstance; } - // private List> regroupTests(List> testRunner, List> groupsToExecute, boolean - // matchAny) - // { - // Map>> testMethodsWithTestGroups = getTestMethodsWithCategories(); - // - // List> groupedRunner = new LinkedList<>(); - // - // for (List runners : testRunner) - // { - // FrameworkMethod method = null; - // // the last runner in the list should always be an NeodymiumMethodRunner - // // get this method - // Runner runner = runners.get(runners.size() - 1); - // if (runner instanceof NeodymiumMethodRunner) - // { - // method = ((NeodymiumMethodRunner) runner).getMethod(); - // } - // else - // { - // throw new RuntimeException("This shouldn't happen"); - // } - // - // if (testCategoryMatch(testMethodsWithTestGroups.get(method), groupsToExecute, matchAny)) - // { - // groupedRunner.add(runners); - // } - // } - // - // return groupedRunner; - // } - // - // private boolean testCategoryMatch(Set> annotatedGroups, List> groupsToExecute, boolean - // matchAny) - // { - // // if not matchAny then it's matchAll - // boolean match; - // if (matchAny) - // { - // match = false; - // } - // else - // { - // match = true; - // } - // for (Class annotatedGroup : annotatedGroups) - // { - // boolean executionGroupsContainsAnnotatedGroup = groupsToExecute.contains(annotatedGroup); - // if (matchAny) - // { - // match |= executionGroupsContainsAnnotatedGroup; - // } - // else - // { - // match &= executionGroupsContainsAnnotatedGroup; - // } - // } - // - // return match; - // } - // - // private Map>> getTestMethodsWithCategories() - // { - // Map>> testMethods = new HashMap<>(); - // - // Category classCategory = testClass.getAnnotation(Category.class); - // List> classCategories = new ArrayList<>(); - // if (classCategory != null) - // { - // classCategories = Arrays.asList(classCategory.value()); - // } - // - // // method grouping belongs only to test methods so check that first - // for (FrameworkMethod annotatedMethod : testClass.getAnnotatedMethods(Test.class)) - // { - // Category categoryAnnotation = annotatedMethod.getAnnotation(Category.class); - // - // Set> categories = new HashSet<>(); - // if (categoryAnnotation != null) - // { - // categories.addAll(Arrays.asList(categoryAnnotation.value())); - // } - // - // // add categories from class to every method - // categories.addAll(classCategories); - // // ensure that DefaultGroup is set for all methods that makes it easier afterwards - // categories.add(DefaultGroup.class); - // categories.remove(null); - // - // testMethods.put(annotatedMethod, categories); - // } - // - // return testMethods; - // } - - private void setFinalStatic(Field field, Object newValue) throws Exception + @Override + protected List computeTestMethods() { - field.setAccessible(true); + // Normally JUnit works with all methods that are annotated with @Test, see super's implementation + // But we override this function in order to do all the fancy stuff, like method multiplication and so on. + // So we basically start with the list of test methods and add and rearrange new one's to this list and JUnit + // will take this list and call us for each entry to create a statement which actually does all the stuff. + // Each entry of this list causes a call to methodBlock(). - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + // Since this method is called at least two times and is somewhat expensive, we cache the result + if (computedTestMethods != null) + return computedTestMethods; - field.set(null, newValue); - } + // That list will contain all methods that need to be run for the class + List testMethods = new LinkedList<>(); - private Description createTestDescription() - { - Description description = Description.createSuiteDescription(testClass.getJavaClass()); + // Statement run order defines the order of our own statements that will surround the default JUnit statement + // from methodBlock + List> statementRunOrder = new DefaultStatementRunOrder().getRunOrder(); - for (List runners : testRunner) + // super.computeTestMethods will return all methods that are annotated with @Test + for (FrameworkMethod testAnnotatedMethod : super.computeTestMethods()) { - List displayNames = new LinkedList<>(); - for (Runner runner : runners) + // these lists contain all the builders and data that will be responsible for a partiuclar method + List builderList = new LinkedList<>(); + List> builderDataList = new LinkedList<>(); + + // iterate over statements defined in the order + for (Class statementClass : statementRunOrder) { - Description runnerDescription = runner.getDescription(); - String displayName = ""; - if (runner instanceof NeodymiumParameterRunner) - { - displayName = ((NeodymiumParameterRunner) runner).getName(); - } - else if (runner instanceof BlockJUnit4ClassRunner) + // ask each statement builder if this method should be processed + // results in a list of parameters for this statement for method multiplication + // e.g. for @Browser("A") the data list will contain "A" + + StatementBuilder builder = StatementBuilder.instantiate(statementClass); + + List iterationData = null; + try { - displayName = runner.getDescription().getDisplayName(); + iterationData = builder.createIterationData(getTestClass(), testAnnotatedMethod); } - else if (runner instanceof NeodymiumDataRunnerRunner) + catch (Throwable e) { - NeodymiumDataRunnerRunner dataRunner = (NeodymiumDataRunnerRunner) runner; - if (dataRunner.hasDataSets()) - { - displayName = runnerDescription.getDisplayName(); - } - else - { - displayName = null; - } + throw new RuntimeException(e); } - else + + // Avoid empty entries in the list since its a hassle to deal with + if (iterationData != null && !iterationData.isEmpty()) { - displayName = runnerDescription.getDisplayName(); + // we save both, the builder instance as well as the "data" to run with + builderList.add(builder); + builderDataList.add(iterationData); } - - if (displayName != null) - displayNames.add(displayName); - } - - // necessary to preserve JUnit view feature which lead you to the test method on double click the entry - // https://github.com/eclipse/eclipse.jdt.ui/blob/0e4ddb8f4fd1d3c22748423acba36397e5f020e7/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/OpenTestAction.java#L108-L122 - Collections.reverse(displayNames); - - Set methodCategoryAnnotations = new HashSet<>(); - List annotatedMethods = testClass.getAnnotatedMethods(); - for (FrameworkMethod fm : annotatedMethods) - { - methodCategoryAnnotations.add(fm.getAnnotation(Category.class)); } - methodCategoryAnnotations.remove(null); - Description childDescription = Description.createTestDescription(testClass.getJavaClass(), String.join(" :: ", displayNames), - methodCategoryAnnotations.toArray(new Annotation[0])); - description.addChild(childDescription); + // This is the point where multiple test methods are computed for the current processed method. + testMethods.addAll(buildCrossProduct(testAnnotatedMethod.getMethod(), builderList, builderDataList)); } - return description; - } - - private List> buildTestRunnerLists(List> vectors) - { + // this list is now final for class execution so make it unmodifiable + computedTestMethods = Collections.unmodifiableList(testMethods); - List> runner = new LinkedList<>(); - runner.add(new LinkedList<>()); + // compute test descriptions + childDescriptions = new HashMap<>(); + globalTestDescription = createTestDescriptions(computedTestMethods); - // iterate over all vectors to build the cross product . Last vector should only consist of - // method runners - for (int i = vectors.size() - 1; i >= 0; i--) - { - List> newTestRunners = new LinkedList<>(); - for (Runner r : vectors.get(i)) - { - List> testRunnerCopy = deepCopy(runner); - for (List list : testRunnerCopy) - { - list.add(0, r); - } - newTestRunners.addAll(testRunnerCopy); - } - // overwrite previous list of runners - runner = newTestRunners; - } - - return runner; + return computedTestMethods; } - private List> deepCopy(List> original) + public Description createTestDescriptions(List methods) { - List> copy = new LinkedList<>(); - for (List entry : original) + switch (Context.get().configuration.junitViewMode()) { - copy.add(new LinkedList<>(entry)); - } + case flat: + return createFlatTestDescription(methods); - return copy; + case tree: + default: + return createHierarchicalTestDescription(methods); + } } - @SuppressWarnings("unchecked") - private void doMagic(List runners, List> vectors) - throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException + private Description createHierarchicalTestDescription(List methods) { - // due to the mostly used protected modifier of getChildren method we have to do some magic here + Description hierarchicalDescription = Description.createSuiteDescription(getTestClass().getJavaClass()); - for (Runner runner : runners) + for (FrameworkMethod method : methods) { - if (runner instanceof ParentRunner) + Description currentLevel = hierarchicalDescription; + if (method instanceof EnhancedMethod) { - Method m = runner.getClass().getDeclaredMethod("getChildren"); - if (m.getName().equals("getChildren")) + EnhancedMethod enhancedMethod = (EnhancedMethod) method; + List statementBuilder = enhancedMethod.getBuilder(); + List builderData = enhancedMethod.getData(); + + for (int i = 0; i < statementBuilder.size(); i++) { - if (!m.isAccessible()) + StatementBuilder builder = statementBuilder.get(i); + String categoryName = builder.getCategoryName(builderData.get(i)); + + // check if hierarchical description has a child with that description + ArrayList currentLevelChildren = currentLevel.getChildren(); + boolean found = false; + for (Description currentLevelChild : currentLevelChildren) { - m.setAccessible(true); + if (categoryName.equals(currentLevelChild.getDisplayName())) + { + found = true; + currentLevel = currentLevelChild; + break; + } } - List childs = (List) m.invoke(runner); - LOGGER.debug(runner.getClass().getSimpleName() + " added " + childs.size() + " childs"); - for (Runner r : childs) + // create one if it's missing and set the new one as the current level, then dig deeper + if (!found) { - LOGGER.debug("\t" + r.getDescription().getDisplayName()); + Description newChild = Description.createSuiteDescription(categoryName); + currentLevel.addChild(newChild); + currentLevel = newChild; } - vectors.add(childs); } + // finally add the test method to lowest level + currentLevel.addChild(describeChild(method)); } else { - LOGGER.debug(runner.getClass().getCanonicalName()); - List child = new LinkedList<>(); - child.add(runner); - vectors.add(child); + // it's just a default JUnit method, just add it as child + hierarchicalDescription.addChild(describeChild(method)); } } + + return hierarchicalDescription; } - @Override - public void run(RunNotifier notifier) + private Description createFlatTestDescription(List methods) { - LOGGER.debug("Run " + testRunner.size() + " tests"); - for (int i = 0; i < testRunner.size(); i++) - { - LOGGER.debug("Run test " + (i + 1) + "/" + testRunner.size()); - boolean firstIteration = (i == 0) ? true : false; - boolean lastIteration = (i == testRunner.size() - 1) ? true : false; + Description flatDescription = Description.createSuiteDescription(getTestClass().getJavaClass()); - List runners = testRunner.get(i); - Description description = testDescription.getChildren().get(Math.min(i, Math.max(0, testDescription.getChildren().size() - 1))); + for (FrameworkMethod method : methods) + { + flatDescription.addChild(describeChild(method)); + } - if (checkIgnored(runners)) - { - LOGGER.debug("Test ignored"); - notifier.fireTestIgnored(description); - } - else - { - Object classInstance; - try - { - classInstance = testClass.getOnlyConstructor().newInstance(); - } - catch (Exception e) - { - throw new RuntimeException(e); - } + return flatDescription; + } - NeodymiumBrowserRunner browserRunner = null; - notifier.fireTestStarted(description); - Failure testFailure = null; + @Override + protected Description describeChild(FrameworkMethod method) + { + return childDescriptions.computeIfAbsent(method, (m) -> { + return Description.createTestDescription(getTestClass().getJavaClass(), m.getName()); + }); + } - for (int r = 0; r < runners.size(); r++) - { - Runner runner = runners.get(r); + @Override + protected void runChild(FrameworkMethod method, RunNotifier notifier) + { + // clear the context before next child run + Context.clearThreadContext(); + super.runChild(method, notifier); + } - if (runner instanceof NeodymiumBrowserRunner) - { - // remember browser runner to close the web driver after test - browserRunner = (NeodymiumBrowserRunner) runner; - } + private List buildCrossProduct(Method method, List builderList, List> builderDataList) + { + List resultingMethods = new LinkedList<>(); + recursiveBuildCrossProduct(method, builderList, builderDataList, 0, resultingMethods, null); + return resultingMethods; + } - methodExecutionContext.setRunBeforeClass(firstIteration); - methodExecutionContext.setRunAfterClass(lastIteration); - methodExecutionContext.setRunnerDescription(description); - methodExecutionContext.setTestClassInstance(classInstance); + private void recursiveBuildCrossProduct(Method method, List builderList, List> builderDataList, + int currentIndex, List resultingMethods, EnhancedMethod actualFrameworkMethod) + { + if (builderList.isEmpty()) + { + // if there is no enclosing statement involved we handle it as single method call + resultingMethods.add(new FrameworkMethod(method)); + } + else + { + StatementBuilder builder = builderList.get(currentIndex); + List builderData = builderDataList.get(currentIndex); - LOGGER.debug("Execute runner " + runner.getClass().getSimpleName()); - try - { - runner.run(notifier); - } - catch (Throwable e) - { - LOGGER.debug("Test failed", e); - // mark test as failed and try the next one - testFailure = new Failure(description, e); - notifier.fireTestFailure(testFailure); - break; - } + for (Object data : builderData) + { + EnhancedMethod newMethod = new EnhancedMethod(method); + if (actualFrameworkMethod != null) + { + newMethod.getBuilder().addAll(actualFrameworkMethod.getBuilder()); + newMethod.getData().addAll(actualFrameworkMethod.getData()); } - if (testFailure == null) - LOGGER.debug("Test passed"); + newMethod.getBuilder().add(builder); + newMethod.getData().add(data); - if (browserRunner != null) + if (currentIndex < builderList.size() - 1) { - browserRunner.teardown(); + recursiveBuildCrossProduct(method, builderList, builderDataList, currentIndex + 1, resultingMethods, newMethod); + } + else + { + resultingMethods.add(newMethod); } - notifier.fireTestFinished(description); - } - } - } - - private boolean checkIgnored(List runners) - { - for (Runner runner : runners) - { - if (runner instanceof NeodymiumMethodRunner) - { - NeodymiumMethodRunner methodRunner = (NeodymiumMethodRunner) runner; - return (methodRunner.getChildren().get(0).getAnnotation(Ignore.class) != null); } } - - return false; } @Override public Description getDescription() { - return testDescription; + return globalTestDescription; } @Override - public void filter(Filter filter) throws NoTestsRemainException + protected String testName(FrameworkMethod method) { - // this method will be called by surefire and gradle among others - // any include/exclude groups defined in maven or gradle build process result in an filter object - LOGGER.debug("Filter type: " + filter.getClass()); - LOGGER.debug("Runner size before filter: " + testRunner.size()); - - List> newTestRunner = new LinkedList<>(); - - for (List runners : testRunner) - { - try - { - NeodymiumMethodRunner runner = (NeodymiumMethodRunner) runners.get(runners.size() - 1); - filter.apply(runner); - newTestRunner.add(runners); - } - catch (NoTestsRemainException e) - { - // doesn't matter - } - } - - testRunner = newTestRunner; - - // groupsToExecute.add(DefaultGroup.class); - // testRunner = regroupTests(testRunner, groupsToExecute, true); - testDescription = createTestDescription(); - - LOGGER.debug("Runner size after filter: " + testRunner.size()); + return method.getName(); } } diff --git a/src/main/java/com/xceptance/neodymium/groups/DefaultGroup.java b/src/main/java/com/xceptance/neodymium/groups/DefaultGroup.java deleted file mode 100644 index 4b5f7e424..000000000 --- a/src/main/java/com/xceptance/neodymium/groups/DefaultGroup.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.xceptance.neodymium.groups; - -public interface DefaultGroup -{ - -} diff --git a/src/main/java/com/xceptance/neodymium/module/EnhancedMethod.java b/src/main/java/com/xceptance/neodymium/module/EnhancedMethod.java new file mode 100644 index 000000000..d7445db64 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/EnhancedMethod.java @@ -0,0 +1,113 @@ +package com.xceptance.neodymium.module; + +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; + +public class EnhancedMethod extends FrameworkMethod +{ + private List data = new LinkedList<>(); + + private List builder = new LinkedList<>(); + + public EnhancedMethod(Method method) + { + super(method); + } + + public List getData() + { + return data; + } + + public void setData(List data) + { + this.data = data; + } + + public List getBuilder() + { + return builder; + } + + public void setBuilder(List builder) + { + this.builder = builder; + } + + @Override + public String getName() + { + StringBuilder nameBuilder = new StringBuilder(250); + nameBuilder.append(super.getName()); + for (int i = builder.size() - 1; i >= 0; i--) + { + StatementBuilder statementBuilder = builder.get(i); + nameBuilder.append(" :: "); + nameBuilder.append(statementBuilder.getTestName(data.get(i))); + } + + return nameBuilder.toString(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((builder == null) ? 0 : builder.hashCode()); + result = prime * result + ((data == null) ? 0 : data.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!super.equals(obj)) + { + return false; + } + if (!(obj instanceof EnhancedMethod)) + { + return false; + } + EnhancedMethod other = (EnhancedMethod) obj; + if (builder == null) + { + if (other.builder != null) + { + return false; + } + } + else if (!builder.equals(other.builder)) + { + return false; + } + if (data == null) + { + if (other.data != null) + { + return false; + } + } + else if (!data.equals(other.data)) + { + return false; + } + return true; + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/StatementBuilder.java b/src/main/java/com/xceptance/neodymium/module/StatementBuilder.java new file mode 100644 index 000000000..39c6dcce8 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/StatementBuilder.java @@ -0,0 +1,109 @@ +package com.xceptance.neodymium.module; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Repeatable; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; + +public abstract class StatementBuilder extends Statement +{ + public abstract List createIterationData(TestClass testClass, FrameworkMethod method) throws Throwable; + + public abstract StatementBuilder createStatement(Object testClassInstance, Statement next, Object parameter); + + public abstract String getTestName(Object data); + + public abstract String getCategoryName(Object data); + + public static T instantiate(Class clazz) + { + try + { + return clazz.newInstance(); + } + catch (InstantiationException e) + { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException(e); + } + } + + public static List getAnnotations(AnnotatedElement object, Class annotationClass) + { + List annotations = new LinkedList<>(); + if (object == null || annotationClass == null) + { + return annotations; + } + + // check if the annotation is repeatable + Repeatable repeatingAnnotation = annotationClass.getAnnotation(Repeatable.class); + Annotation annotation = (repeatingAnnotation == null) ? null : object.getAnnotation(repeatingAnnotation.value()); + + if (annotation != null) + { + try + { + annotations.addAll(Arrays.asList((T[]) annotation.getClass().getMethod("value").invoke(annotation))); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + else + { + T anno = object.getAnnotation(annotationClass); + if (anno != null) + { + annotations.add(anno); + } + } + + return annotations; + } + + public static List getDeclaredAnnotations(AnnotatedElement object, Class annotationClass) + { + List annotations = new LinkedList<>(); + if (object == null || annotationClass == null) + { + return annotations; + } + + // check if the annotation is repeatable + Repeatable repeatingAnnotation = annotationClass.getAnnotation(Repeatable.class); + Annotation annotation = (repeatingAnnotation == null) ? null : object.getDeclaredAnnotation(repeatingAnnotation.value()); + + if (annotation != null) + { + try + { + annotations.addAll(Arrays.asList((T[]) annotation.getClass().getMethod("value").invoke(annotation))); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + else + { + T anno = object.getDeclaredAnnotation(annotationClass); + if (anno != null) + { + annotations.add(anno); + } + } + + return annotations; + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/order/DefaultStatementRunOrder.java b/src/main/java/com/xceptance/neodymium/module/order/DefaultStatementRunOrder.java new file mode 100644 index 000000000..e4200f20e --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/order/DefaultStatementRunOrder.java @@ -0,0 +1,15 @@ +package com.xceptance.neodymium.module.order; + +import com.xceptance.neodymium.module.statement.browser.BrowserStatement; +import com.xceptance.neodymium.module.statement.parameter.ParameterStatement; +import com.xceptance.neodymium.module.statement.testdata.TestdataStatement; + +public class DefaultStatementRunOrder extends StatementRunOrder +{ + public DefaultStatementRunOrder() + { + runOrder.add(BrowserStatement.class); + runOrder.add(ParameterStatement.class); + runOrder.add(TestdataStatement.class); + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/order/StatementRunOrder.java b/src/main/java/com/xceptance/neodymium/module/order/StatementRunOrder.java new file mode 100644 index 000000000..ae21c0f97 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/order/StatementRunOrder.java @@ -0,0 +1,16 @@ +package com.xceptance.neodymium.module.order; + +import java.util.LinkedList; +import java.util.List; + +import com.xceptance.neodymium.module.StatementBuilder; + +public class StatementRunOrder +{ + protected List> runOrder = new LinkedList<>(); + + public List> getRunOrder() + { + return runOrder; + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/browser/BrowserStatement.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/BrowserStatement.java new file mode 100644 index 000000000..f92f399ef --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/BrowserStatement.java @@ -0,0 +1,342 @@ +package com.xceptance.neodymium.module.statement.browser; + +import java.net.MalformedURLException; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.codeborne.selenide.Configuration; +import com.codeborne.selenide.WebDriverRunner; +import com.xceptance.neodymium.module.StatementBuilder; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.BrowserRunnerHelper; +import com.xceptance.neodymium.module.statement.browser.multibrowser.SuppressBrowsers; +import com.xceptance.neodymium.module.statement.browser.multibrowser.WebDriverCache; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.DriverServerPath; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.WebDriverProperties; +import com.xceptance.neodymium.util.Context; + +public class BrowserStatement extends StatementBuilder +{ + public static Logger LOGGER = LoggerFactory.getLogger(BrowserStatement.class); + + private Statement next; + + private String browserTag; + + Set browser = new LinkedHashSet<>(); + + private static final String SYSTEM_PROPERTY_BROWSERDEFINITION = "browserdefinition"; + + private static final String BROWSER_PROFILE_FILE = "./config/browser.properties"; + + private List browserDefinitions = new LinkedList<>(); + + private MultibrowserConfiguration multibrowserConfiguration = MultibrowserConfiguration.getInstance(); + + private WebDriver webdriver; + + public BrowserStatement() + { + // that is like a dirty hack to provide testing ability + if (multibrowserConfiguration == null) + multibrowserConfiguration = MultibrowserConfiguration.getInstance(BROWSER_PROFILE_FILE); + + DriverServerPath driverServerPath = multibrowserConfiguration.getDriverServerPath(); + WebDriverProperties webDriverProperties = multibrowserConfiguration.getWebDriverProperties(); + + final String ieDriverPath = driverServerPath.getIeDriverPath(); + final String chromeDriverPath = driverServerPath.getChromeDriverPath(); + final String geckoDriverPath = driverServerPath.getFirefoxDriverPath(); + + // shall we run old school firefox? + final boolean firefoxLegacy = webDriverProperties.useFirefoxLegacy(); + System.setProperty(FirefoxDriver.SystemProperty.DRIVER_USE_MARIONETTE, Boolean.toString(!firefoxLegacy)); + + if (!StringUtils.isEmpty(ieDriverPath)) + { + System.setProperty("webdriver.ie.driver", ieDriverPath); + } + if (!StringUtils.isEmpty(chromeDriverPath)) + { + System.setProperty("webdriver.chrome.driver", chromeDriverPath); + } + if (!StringUtils.isEmpty(geckoDriverPath)) + { + System.setProperty("webdriver.gecko.driver", geckoDriverPath); + } + + // get test specific browser definitions (aka browser tag see browser.properties) + // could be one value or comma separated list of values + String browserDefinitionsProperty = System.getProperty(SYSTEM_PROPERTY_BROWSERDEFINITION, ""); + browserDefinitionsProperty = browserDefinitionsProperty.replaceAll("\\s", ""); + + // parse test specific browser definitions + if (!StringUtils.isEmpty(browserDefinitionsProperty)) + { + browserDefinitions.addAll(Arrays.asList(browserDefinitionsProperty.split(","))); + } + } + + public BrowserStatement(Statement next, String parameter) + { + this.next = next; + this.browserTag = parameter; + } + + @Override + public void evaluate() throws Throwable + { + boolean testFailed = false; + + LOGGER.debug("setup browser: " + browserTag); + setUpTest(browserTag); + try + { + next.evaluate(); + } + catch (Throwable t) + { + testFailed = true; + throw t; + } + finally + { + teardown(testFailed); + } + } + + /** + * Sets the test instance up. + * + * @param browserTag + * name of the browser corresponding to the browser.properties + */ + public void setUpTest(String browserTag) + { + webdriver = null; + this.browserTag = browserTag; + LOGGER.debug("Create browser for name: " + browserTag); + BrowserConfiguration browserConfiguration = multibrowserConfiguration.getBrowserProfiles().get(browserTag); + + try + { + // try to find appropriate web driver in cache before create a new instance + if (MultibrowserConfiguration.getInstance().getWebDriverProperties().reuseWebDriver()) + { + webdriver = WebDriverCache.instance.getRemoveWebDriver(browserConfiguration.getConfigTag()); + if (webdriver != null) + { + webdriver.manage().deleteAllCookies(); + } + } + + if (webdriver == null) + { + LOGGER.debug("Create new browser instance"); + webdriver = BrowserRunnerHelper.createWebdriver(browserConfiguration); + } + else + { + LOGGER.debug("Browser instance served from cache"); + } + } + catch (final MalformedURLException e) + { + throw new RuntimeException("An error occured during URL creation. See nested exception.", e); + } + if (webdriver != null) + { + // set browser window size + BrowserRunnerHelper.setBrowserWindowSize(browserConfiguration, webdriver); + WebDriverRunner.setWebDriver(webdriver); + Context.get().driver = webdriver; + Context.get().browserProfileName = browserConfiguration.getConfigTag(); + + // set our default timeout + Configuration.timeout = Context.get().configuration.timeout(); + Configuration.collectionsTimeout = Configuration.timeout * 2; + } + else + { + throw new RuntimeException("Could not create driver for browsertag: " + browserConfiguration.getConfigTag() + + ". Please check your browserconfigurations."); + } + } + + public void teardown(boolean testFailed) + { + WebDriverProperties webDriverProperties = multibrowserConfiguration.getWebDriverProperties(); + Context context = Context.get(); + BrowserConfiguration browserConfiguration = multibrowserConfiguration.getBrowserProfiles().get(context.browserProfileName); + + if (testFailed && webDriverProperties.keepBrowserOpenOnFailure() && !browserConfiguration.isHeadless()) + { + // test failed and we want to leave the browser instance open + // don't quit the webdriver, just remove references + LOGGER.debug("Keep browser open"); + context.driver = null; + context.browserProfileName = null; + return; + } + + if (webDriverProperties.reuseWebDriver()) + { + LOGGER.debug("Put browser into cache"); + WebDriverCache.instance.putWebDriver(browserTag, webdriver); + } + else + { + if (browserConfiguration.isHeadless() || !webDriverProperties.keepBrowserOpen()) + { + LOGGER.debug("Teardown browser"); + if (webdriver != null) + webdriver.quit(); + } + } + context.driver = null; + context.browserProfileName = null; + } + + public static void quitCachedBrowser() + { + WebDriverProperties webDriverProperties = MultibrowserConfiguration.getInstance().getWebDriverProperties(); + if (!webDriverProperties.keepBrowserOpen()) + { + Collection allWebdriver = WebDriverCache.instance.getAllWebdriver(); + + for (WebDriver wd : allWebdriver) + { + try + { + LOGGER.debug("Quit web driver: " + wd.toString()); + wd.quit(); + } + catch (Exception e) + { + LOGGER.debug("Error on quitting web driver", e); + } + } + } + } + + @Override + public List createIterationData(TestClass testClass, FrameworkMethod method) + { + // get the @Browser annotation from the method to run as well as from the enclosing class + // if it doesn't exist check the class for a @Browser annotation + List methodBrowserAnnotations = getAnnotations(method.getMethod(), Browser.class); + List classBrowserAnnotations = findClassBrowserAnnotation(testClass.getJavaClass()); + List methodSuppressBrowserAnnotations = getAnnotations(method.getMethod(), SuppressBrowsers.class); + List classSuppressBrowserAnnotations = getAnnotations(testClass.getJavaClass(), SuppressBrowsers.class); + + if (!methodSuppressBrowserAnnotations.isEmpty()) + { + // method is marked to suppress browser + return new LinkedList<>(); + } + + if (!classSuppressBrowserAnnotations.isEmpty() && methodBrowserAnnotations.isEmpty()) + { + // class is marked to suppress browsers and there is no override on the method + return new LinkedList<>(); + } + + // so there might be a browser suppress on the class but there is at least one override on the method + List browserAnnotations = new LinkedList<>(); + + // add all browser annotations from the method + browserAnnotations.addAll(methodBrowserAnnotations); + + // if the class doesn't have suppress and method doesn't have any overrides then add them too + if (classSuppressBrowserAnnotations.isEmpty() && methodBrowserAnnotations.isEmpty()) + { + browserAnnotations.addAll(classBrowserAnnotations); + } + + for (Browser b : browserAnnotations) + { + browser.add(b.value()); + } + + Map parsedBrowserProperties = multibrowserConfiguration.getBrowserProfiles(); + List iterations = new LinkedList<>(); + for (String browserTag : browser) + { + // check if the annotated target is in the list of targets specified via system property + if (browserDefinitions != null && !browserDefinitions.isEmpty() && !browserDefinitions.contains(browserTag)) + { + continue; + } + + final BrowserConfiguration foundBrowserConfiguration = parsedBrowserProperties.get(browserTag); + if (foundBrowserConfiguration == null) + { + throw new IllegalArgumentException("Can not find browser configuration with tag: " + browserTag); + } + + // create the JUnit children + iterations.add(browserTag); + } + + return iterations; + } + + public List findClassBrowserAnnotation(Class clazz) + { + // this function is used to find the first (!) @Browser annotation on class level in the hierarchy + // furthermore its not the first but also the first that doesn't have @SuppressBrowsers annotated + + if (clazz == null) + return new LinkedList<>(); + + // check class for browser annotation + // if class has browser annotation and no suppress browsers its fine, else take the super class and check again + List browserAnnotations = getDeclaredAnnotations(clazz, Browser.class); + List suppressBrowsersAnnotations = getDeclaredAnnotations(clazz, SuppressBrowsers.class); + + if (!suppressBrowsersAnnotations.isEmpty() || browserAnnotations.isEmpty()) + { + return findClassBrowserAnnotation(clazz.getSuperclass()); + } + else + { + return browserAnnotations; + } + + } + + @Override + public StatementBuilder createStatement(Object testClassInstance, Statement next, Object parameter) + { + return new BrowserStatement(next, (String) parameter); + } + + @Override + public String getTestName(Object data) + { + return MessageFormat.format("Browser {0}", (String) data); + } + + @Override + public String getCategoryName(Object data) + { + return getTestName(data); + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browser.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browser.java new file mode 100644 index 000000000..1933c979f --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browser.java @@ -0,0 +1,28 @@ +package com.xceptance.neodymium.module.statement.browser.multibrowser; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotate a class or method with {@link Browser} and add as annotation value a list of test targets (browsertag). + * These browsertags refer to browser profiles that are configured in browser.properties located in config folder. See + * Multi-browser-support for + * examples on the github wiki. + * + * @author m.kaufmann + */ +@Retention(RetentionPolicy.RUNTIME) +@Target( + { + ElementType.TYPE, ElementType.METHOD + }) +@Inherited +@Repeatable(Browsers.class) +public @interface Browser +{ + String value(); +} diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/BrowserRunnerHelper.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/BrowserRunnerHelper.java similarity index 94% rename from src/main/java/com/xceptance/neodymium/multibrowser/BrowserRunnerHelper.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/BrowserRunnerHelper.java index 518a6dc70..b445889ee 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/BrowserRunnerHelper.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/BrowserRunnerHelper.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser; +package com.xceptance.neodymium.module.statement.browser.multibrowser; import java.io.File; import java.net.MalformedURLException; @@ -36,12 +36,12 @@ import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.RemoteWebDriver; -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.DriverServerPath; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.ProxyConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.TestEnvironment; -import com.xceptance.neodymium.multibrowser.configuration.WebDriverProperties; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.DriverServerPath; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.ProxyConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.TestEnvironment; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.WebDriverProperties; public final class BrowserRunnerHelper { @@ -207,6 +207,7 @@ private static FirefoxBinary createFirefoxBinary(final String pathToBrowser) * if Selenium grid is * used */ + @SuppressWarnings("unchecked") public static WebDriver createWebdriver(final BrowserConfiguration config) throws MalformedURLException { final DesiredCapabilities capabilities = config.getCapabilities(); @@ -276,6 +277,7 @@ public static WebDriver createWebdriver(final BrowserConfiguration config) throw { options.setBinary(pathToBrowser); } + options.setHeadless(config.isHeadless()); return new ChromeDriver(options); } @@ -284,6 +286,7 @@ else if (firefoxBrowsers.contains(browserName)) FirefoxOptions firefoxOptions = new FirefoxOptions(); firefoxOptions.setBinary(createFirefoxBinary(driverServerPath.getFirefoxBrowserPath())); firefoxOptions.merge(capabilities); + firefoxOptions.setHeadless(config.isHeadless()); return new FirefoxDriver(firefoxOptions); } diff --git a/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browsers.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browsers.java new file mode 100644 index 000000000..1f65b1de0 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/Browsers.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.module.statement.browser.multibrowser; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target( + { + TYPE, METHOD + }) +@Inherited +public @interface Browsers +{ + Browser[] value(); +} diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/ProxyHttpClient.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/ProxyHttpClient.java similarity index 88% rename from src/main/java/com/xceptance/neodymium/multibrowser/ProxyHttpClient.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/ProxyHttpClient.java index 1182914da..b7b918109 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/ProxyHttpClient.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/ProxyHttpClient.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser; +package com.xceptance.neodymium.module.statement.browser.multibrowser; import java.net.URL; diff --git a/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/SuppressBrowsers.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/SuppressBrowsers.java new file mode 100644 index 000000000..f5e22a811 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/SuppressBrowsers.java @@ -0,0 +1,17 @@ +package com.xceptance.neodymium.module.statement.browser.multibrowser; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target( + { + TYPE, METHOD + }) +public @interface SuppressBrowsers +{ + +} diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCache.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCache.java similarity index 98% rename from src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCache.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCache.java index 16a92648f..6372d0017 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCache.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCache.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser; +package com.xceptance.neodymium.module.statement.browser.multibrowser; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCacheCleanupHook.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCacheCleanupHook.java similarity index 63% rename from src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCacheCleanupHook.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCacheCleanupHook.java index 1a6a1679c..0244e18d7 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverCacheCleanupHook.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverCacheCleanupHook.java @@ -1,9 +1,9 @@ -package com.xceptance.neodymium.multibrowser; +package com.xceptance.neodymium.module.statement.browser.multibrowser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.xceptance.neodymium.NeodymiumBrowserRunner; +import com.xceptance.neodymium.module.statement.browser.BrowserStatement; public class WebDriverCacheCleanupHook extends Thread { @@ -14,6 +14,6 @@ public class WebDriverCacheCleanupHook extends Thread public void run() { LOGGER.debug("All tests finished. Quit cached browser"); - NeodymiumBrowserRunner.quitCachedBrowser(); + BrowserStatement.quitCachedBrowser(); } } diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverFactory.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverFactory.java similarity index 81% rename from src/main/java/com/xceptance/neodymium/multibrowser/WebDriverFactory.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverFactory.java index 5eb7fe36f..938f30c13 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/WebDriverFactory.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/WebDriverFactory.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser; +package com.xceptance.neodymium.module.statement.browser.multibrowser; import java.net.MalformedURLException; import java.util.Map; @@ -7,10 +7,10 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.DriverServerPath; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.WebDriverProperties; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.DriverServerPath; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.WebDriverProperties; public class WebDriverFactory { diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfiguration.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfiguration.java similarity index 84% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfiguration.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfiguration.java index e503c9f9c..ee713d060 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfiguration.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfiguration.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import org.openqa.selenium.remote.DesiredCapabilities; @@ -21,6 +21,8 @@ public class BrowserConfiguration private int browserHeight; + private boolean headless; + public String getConfigTag() { return browserTag; @@ -80,4 +82,14 @@ protected void setBrowserHeight(int browserHeight) { this.browserHeight = browserHeight; } + + public boolean isHeadless() + { + return headless; + } + + public void setHeadless(boolean headless) + { + this.headless = headless; + } } diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfigurationMapper.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfigurationMapper.java similarity index 95% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfigurationMapper.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfigurationMapper.java index baca29e8e..4eda7797e 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/BrowserConfigurationMapper.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/BrowserConfigurationMapper.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import java.util.HashMap; import java.util.Map; @@ -29,6 +29,8 @@ public class BrowserConfigurationMapper private static final String PAGE_LOAD_STRATEGY = "pageLoadStrategy"; + private static final String HEADLESS = "headless"; + // appium specific propertys private static final String APPIUM_VERSION = "appiumVersion"; @@ -173,6 +175,11 @@ else if ("safari".equals(emulatedBrowser)) if (!StringUtils.isEmpty(pageLoadStrategy)) capabilities.setCapability("pageLoadStrategy", pageLoadStrategy); + // headless + String headless = o.get(HEADLESS); + if (!StringUtils.isEmpty(headless)) + r.setHeadless(Boolean.valueOf(headless)); + capabilities.setCapability("name", o.get("name")); r.setCapabilities(capabilities); r.setConfigTag(o.get("browserTag")); diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/DriverServerPath.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/DriverServerPath.java similarity index 92% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/DriverServerPath.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/DriverServerPath.java index d71af4a9f..904b5ff1a 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/DriverServerPath.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/DriverServerPath.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import org.aeonbits.owner.Config; import org.aeonbits.owner.Config.Sources; diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/MultibrowserConfiguration.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/MultibrowserConfiguration.java similarity index 95% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/MultibrowserConfiguration.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/MultibrowserConfiguration.java index b63a05ebc..0e75aece5 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/MultibrowserConfiguration.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/MultibrowserConfiguration.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import java.io.File; import java.io.FileInputStream; @@ -166,14 +166,14 @@ public static MultibrowserConfiguration getInstance() */ public static MultibrowserConfiguration getInstance(String configFile) { - MultibrowserConfiguration configuration = CONFIGURATIONS.get(configFile); + return CONFIGURATIONS.computeIfAbsent(configFile, (file) -> { + return new MultibrowserConfiguration(file); + }); + } - if (configuration == null) - { - configuration = new MultibrowserConfiguration(configFile); - CONFIGURATIONS.put(configFile, configuration); - } - return configuration; + public static void clearAllInstances() + { + CONFIGURATIONS.clear(); } public DriverServerPath getDriverServerPath() diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/ProxyConfiguration.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/ProxyConfiguration.java similarity index 88% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/ProxyConfiguration.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/ProxyConfiguration.java index fabb0396f..4cef4b8db 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/ProxyConfiguration.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/ProxyConfiguration.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import org.aeonbits.owner.Config; import org.aeonbits.owner.Config.Sources; diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/TestEnvironment.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/TestEnvironment.java similarity index 87% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/TestEnvironment.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/TestEnvironment.java index ee4d46a12..ffda75a1a 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/TestEnvironment.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/TestEnvironment.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import java.util.Properties; diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/WebDriverProperties.java b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/WebDriverProperties.java similarity index 77% rename from src/main/java/com/xceptance/neodymium/multibrowser/configuration/WebDriverProperties.java rename to src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/WebDriverProperties.java index 9224e5534..841a57fd0 100644 --- a/src/main/java/com/xceptance/neodymium/multibrowser/configuration/WebDriverProperties.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/browser/multibrowser/configuration/WebDriverProperties.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.multibrowser.configuration; +package com.xceptance.neodymium.module.statement.browser.multibrowser.configuration; import org.aeonbits.owner.Config; import org.aeonbits.owner.Config.Sources; @@ -28,4 +28,8 @@ public interface WebDriverProperties extends Config @Key("neodymium.webDriver.keepBrowserOpen") @DefaultValue("false") public boolean keepBrowserOpen(); + + @Key("neodymium.webDriver.keepBrowserOpenOnFailure") + @DefaultValue("false") + public boolean keepBrowserOpenOnFailure(); } diff --git a/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatement.java b/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatement.java new file mode 100644 index 000000000..70ffc7eff --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatement.java @@ -0,0 +1,223 @@ +package com.xceptance.neodymium.module.statement.parameter; + +import java.lang.reflect.Field; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xceptance.neodymium.module.StatementBuilder; + +public class ParameterStatement extends StatementBuilder +{ + public static Logger LOGGER = LoggerFactory.getLogger(ParameterStatement.class); + + private Statement next; + + private ParameterStatementData statementData; + + private Object testClassInstance; + + public ParameterStatement(Statement next, ParameterStatementData parameter, Object testClassInstance) + { + this.next = next; + this.statementData = parameter; + this.testClassInstance = testClassInstance; + } + + public ParameterStatement() + { + } + + @Override + public void evaluate() throws Throwable + { + injectTestParameter(); + next.evaluate(); + } + + @SuppressWarnings("unchecked") + @Override + public List createIterationData(TestClass testClass, FrameworkMethod method) throws Exception + { + List parametersMethods = testClass.getAnnotatedMethods(Parameters.class); + Iterable parameter = null; + + for (FrameworkMethod parametersMethod : parametersMethods) + { + if (parametersMethod.isPublic() && parametersMethod.isStatic()) + { + // take the first public static method. invoke it and use the result as parameter + try + { + Object parametersResult = parametersMethod.invokeExplosively(null); + if (parametersResult instanceof Iterable) + { + parameter = (Iterable) parametersResult; + } + else if (parametersResult instanceof Object[]) + { + parameter = Arrays.asList((Object[]) parametersResult); + } + else + { + String msg = MessageFormat.format("{0}.{1}() must return an Iterable of arrays.", + testClass.getJavaClass().getName(), parametersMethod.getName()); + throw new Exception(msg); + } + break; + } + catch (Throwable e) + { + throw new RuntimeException(e); + } + } + } + + if (!parametersMethods.isEmpty() && parameter == null) + { + throw new Exception("No public static parameters method on class " + testClass.getJavaClass().getCanonicalName()); + } + + List parameterFrameworkFields = testClass.getAnnotatedFields(Parameter.class); + LOGGER.debug("Found " + parameterFrameworkFields.size() + " parameter fields"); + + List iterations = new LinkedList<>(); + + if (parameter != null) + { + int parameterSetCounter = 0; + for (Object para : parameter) + { + Object[] p; + if (para instanceof Object[]) + { + p = (Object[]) para; + } + else + { + p = new Object[] + { + para + }; + } + + iterations.add(new ParameterStatementData(parameterSetCounter, p, parameterFrameworkFields)); + parameterSetCounter++; + } + } + + return iterations; + } + + private void injectTestParameter() throws Exception + { + int parameterFieldCount = statementData.getParameterFrameworkFields().size(); + Object[] parameter = statementData.getParameter(); + + if (parameterFieldCount != parameter.length) + { + throw new Exception("Number of parameters (" + parameter.length + ") and " + // + "fields (" + parameterFieldCount + ") " + // + "annotated with @Parameter must match!"); + } + + for (FrameworkField parameterFrameworkField : statementData.getParameterFrameworkFields()) + { + Field field = parameterFrameworkField.getField(); + int parameterIndex = field.getAnnotation(Parameter.class).value(); + + LOGGER.debug("Set parameter \"" + parameterFrameworkField.getName() + "\" to \"" + parameter[parameterIndex] + "\""); + setField(field, parameter[parameterIndex]); + } + } + + private void setField(Field field, Object value) + { + Class fieldType = field.getType(); + Class valueType; + if (value == null) + { + valueType = Void.class; + } + else + { + valueType = value.getClass(); + } + + // try to convert String values to appropriate target types + if (valueType == String.class) + { + try + { + if (fieldType == int.class || fieldType == Integer.class) + { + value = Integer.valueOf((String) value); + } + else if (fieldType == long.class || fieldType == Long.class) + { + value = Long.valueOf((String) value); + } + else if (fieldType == double.class || fieldType == Double.class) + { + value = Double.valueOf((String) value); + } + else if (fieldType == float.class || fieldType == Float.class) + { + value = Float.valueOf((String) value); + } + else if (fieldType == boolean.class || fieldType == Boolean.class) + { + value = Boolean.valueOf((String) value); + } + } + catch (Exception e) + { + throw new RuntimeException("An error occured during conversion of input string \"" + (String) value + "\" to type " + + fieldType.getName() + " for field \"" + field.getName() + "\"", e); + } + } + + try + { + field.set(testClassInstance, value); + } + catch (IllegalArgumentException e) + { + throw new RuntimeException("Could not set parameter of type " + valueType + " to field \"" + field.getName() + "\" of type " + + fieldType + ". Value: " + value); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not set parameter due to it is not public or it is final"); + } + } + + @Override + public StatementBuilder createStatement(Object testClassInstance, Statement next, Object parameter) + { + return new ParameterStatement(next, (ParameterStatementData) parameter, testClassInstance); + } + + @Override + public String getTestName(Object data) + { + ParameterStatementData p = (ParameterStatementData) data; + return "[" + p.getParameterIndex() + "]"; + } + + @Override + public String getCategoryName(Object data) + { + return getTestName(data); + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatementData.java b/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatementData.java new file mode 100644 index 000000000..301d457f6 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/parameter/ParameterStatementData.java @@ -0,0 +1,41 @@ +package com.xceptance.neodymium.module.statement.parameter; + +import java.util.List; + +import org.junit.runners.model.FrameworkField; + +public class ParameterStatementData +{ + private int parameterIndex; + + private Object[] parameter; + + private List parameterFrameworkFields; + + public ParameterStatementData(int parameterIndex, Object[] parameter, List parameterFrameworkFields) + { + this.parameterIndex = parameterIndex; + this.parameter = parameter; + this.parameterFrameworkFields = parameterFrameworkFields; + } + + public int getParameterIndex() + { + return parameterIndex; + } + + public Object[] getParameter() + { + return parameter; + } + + public List getParameterFrameworkFields() + { + return parameterFrameworkFields; + } + + public void setParameterFrameworkFields(List parameterFrameworkFields) + { + this.parameterFrameworkFields = parameterFrameworkFields; + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSet.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSet.java new file mode 100644 index 000000000..5aa3752ab --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSet.java @@ -0,0 +1,35 @@ +package com.xceptance.neodymium.module.statement.testdata; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * This annotation can be used to limit and override data set execution for an entire class or at the same time for a + * single method. + *

+ * The value defines the index of the data set that has to be force used for the class or method. + *

+ * Default is 0 which will not have any effect on execution unless there is a {@link SuppressDataSets} annotation + * involved. In case a class is annotated with {@link SuppressDataSets} and a test method is annotated @DataSet() + * or @DataSet(0) then it will override suppression and enforce the method to run with all data sets + *

+ * Any number above zero will enforce execution with only that data set. First data set would be equal to 1 and so on. + * + * @author m.kaufmann + */ +@Retention(RUNTIME) +@Target( + { + TYPE, METHOD + }) +@Repeatable(DataSets.class) +public @interface DataSet +{ + int value() default 0; + + String id() default ""; +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSets.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSets.java new file mode 100644 index 000000000..9f12da029 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/DataSets.java @@ -0,0 +1,22 @@ +package com.xceptance.neodymium.module.statement.testdata; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Do not use this annotation. This annoation is just the wrapper for repeated {@link DataSet} annotations. + * + * @author m.kaufmann + */ +@Retention(RUNTIME) +@Target( + { + TYPE, METHOD + }) +public @interface DataSets +{ + DataSet[] value(); +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/testdata/SuppressDataSets.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/SuppressDataSets.java new file mode 100644 index 000000000..b26c18b68 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/SuppressDataSets.java @@ -0,0 +1,24 @@ +package com.xceptance.neodymium.module.statement.testdata; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * This annotation can be used to suppress automatic test case multiplication for + * data sets and test data. + * + * @author m.kaufmann + * @see DataSet + */ +@Retention(RUNTIME) +@Target( + { + TYPE, METHOD + }) +public @interface SuppressDataSets +{ + +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatement.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatement.java new file mode 100644 index 000000000..3ab6d6410 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatement.java @@ -0,0 +1,308 @@ +package com.xceptance.neodymium.module.statement.testdata; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.xceptance.neodymium.module.StatementBuilder; +import com.xceptance.neodymium.module.statement.testdata.util.TestDataUtils; +import com.xceptance.neodymium.util.Context; + +public class TestdataStatement extends StatementBuilder +{ + private static final String TEST_ID = "testId"; + + public static Logger LOGGER = LoggerFactory.getLogger(TestdataStatement.class); + + private Statement next; + + Map testData; + + public TestdataStatement(Statement next, TestdataStatementData parameter) + { + this.next = next; + + int currentDataSetIndex = parameter.getIndex(); + + testData = new HashMap<>(); + testData.putAll(parameter.getPackageTestData()); + + if (currentDataSetIndex >= 0) + { + for (Entry newDataEntry : parameter.getDataSet().entrySet()) + { + // only log if a data set entry overwrites an package data entry + if (testData.containsKey(newDataEntry.getKey())) + { + LOGGER.debug(String.format("Data entry \"%s\" overwritten by data set #%d (old: \"%s\", new: \"%s\")", + newDataEntry.getKey(), currentDataSetIndex + 1, testData.get(newDataEntry.getKey()), + newDataEntry.getValue())); + } + testData.put(newDataEntry.getKey(), newDataEntry.getValue()); + } + } + + } + + public TestdataStatement() + { + } + + @Override + public void evaluate() throws Throwable + { + Context.get().data.putAll(testData); + next.evaluate(); + } + + @Override + public List createIterationData(TestClass testClass, FrameworkMethod method) + { + List> dataSets; + Map packageTestData; + try + { + dataSets = TestDataUtils.getDataSets(testClass.getJavaClass()); + } + catch (FileNotFoundException e) + { + throw new RuntimeException(e); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + packageTestData = TestDataUtils.getPackageTestData(testClass.getJavaClass()); + + List iterations = new LinkedList<>(); + if (!dataSets.isEmpty() || !packageTestData.isEmpty()) + { + if (!dataSets.isEmpty()) + { + // data sets found + for (int i = 0; i < dataSets.size(); i++) + { + iterations.add(new TestdataStatementData(dataSets.get(i), packageTestData, i, dataSets.size())); + } + } + else + { + // only package data, no data sets + iterations.add(new TestdataStatementData(new HashMap<>(), packageTestData, -1, -1)); + } + } + else + { + // we couldn't find any data sets + } + iterations = processOverrides(testClass, method, iterations); + iterations = processDuplicates(iterations); + + return iterations; + } + + private List processDuplicates(List iterations) + { + // since the user can decide to annotate the same data set several times to the same function we need to care + // about the duplicates. First of all we need to clone those objects, then we need to set a special index which + // will be later used to distinguish them in the run + + // this map contains the counter for the new index + HashMap iterationIndexMap = new HashMap<>(); + List fixedIterations = new LinkedList<>(); + + for (Object object : iterations) + { + if (!fixedIterations.contains(object)) + { + // no duplicate, just add it + fixedIterations.add(object); + } + else + { + // now the funny part, we encountered an duplicated object + + // always set the first occurance of an object to 1 + TestdataStatementData existingObject = (TestdataStatementData) object; + existingObject.setIterationIndex(1); + + // set the counter for this object to 1 + iterationIndexMap.computeIfAbsent(object, (o) -> { + return 1; + }); + + // increment the counter every time we visit with the same object + Integer newIndex = iterationIndexMap.computeIfPresent(object, (o, index) -> { + return (index + 1); + }); + + // important: we clone that object + TestdataStatementData clonedObject = new TestdataStatementData((TestdataStatementData) object); + // set the "iteration" index to the new cloned object + clonedObject.setIterationIndex(newIndex); + // add it to the list + fixedIterations.add(clonedObject); + } + } + + return fixedIterations; + } + + private List processOverrides(TestClass testClass, FrameworkMethod method, List iterations) + { + SuppressDataSets methodSuppress = method.getAnnotation(SuppressDataSets.class); + if (methodSuppress != null) + { + // the test method is marked to suppress data sets + return new LinkedList<>(); + } + + SuppressDataSets classSuppress = testClass.getAnnotation(SuppressDataSets.class); + List methodDataSetAnnotations = getAnnotations(method.getMethod(), DataSet.class); + + if (methodDataSetAnnotations.isEmpty() && classSuppress != null) + { + // class is marked to suppress data sets and there is no overriding DataSet on the method + return new LinkedList<>(); + } + + List dataSetAnnotations = new LinkedList<>(); + + // at this point neither the class nor the method could have data sets supressed + List classDataSetAnnotations = getAnnotations(testClass.getJavaClass(), DataSet.class); + if (!methodDataSetAnnotations.isEmpty()) + { + dataSetAnnotations = methodDataSetAnnotations; + } + else if (!classDataSetAnnotations.isEmpty()) + { + dataSetAnnotations = classDataSetAnnotations; + } + + if (dataSetAnnotations.isEmpty()) + { + // so there is nothing to suppress and nothing to override. Go ahead with all data sets + return iterations; + } + + // we've gathered some instructions to override + + List fixedIterations = new LinkedList<>(); + for (DataSet dataSet : dataSetAnnotations) + { + int dataSetIndex = dataSet.value(); + String dataSetId = dataSet.id(); + + // take dataSetId (testId) if its set + if (dataSetId != null && dataSetId.trim().length() > 0) + { + // search the dataset + boolean found = false; + for (Object object : iterations) + { + TestdataStatementData o = (TestdataStatementData) object; + String testId = o.getDataSet().get(TEST_ID); + if (dataSetId.equals(testId)) + { + fixedIterations.add(object); + found = true; + break; + } + } + if (!found) + { + String msg = MessageFormat.format("Method ''{0}'' is marked to be run with data set testId ''{1}'', but could not find that data set", + method.getName(), dataSetId); + throw new IllegalArgumentException(msg); + } + } + else + { + // use index + if (dataSetIndex <= 0) + { + // add all data sets + fixedIterations.addAll(iterations); + } + else + { + if (dataSetIndex > iterations.size()) + { + String msg = MessageFormat.format("Method ''{0}'' is marked to be run with data set index {1}, but there are only {2}", + method.getName(), dataSetIndex, iterations.size()); + throw new IllegalArgumentException(msg); + } + else + { + fixedIterations.add(iterations.get(dataSetIndex - 1)); + } + } + } + } + return fixedIterations; + } + + @Override + public StatementBuilder createStatement(Object testClassInstance, Statement next, Object parameter) + { + return new TestdataStatement(next, (TestdataStatementData) parameter); + } + + @Override + public String getTestName(Object data) + { + String testname = getCategoryName(data); + TestdataStatementData parameter = (TestdataStatementData) data; + + if (parameter.getIterationIndex() > 0) + { + testname += MessageFormat.format(", run #{0}", parameter.getIterationIndex()); + } + + return testname; + } + + @Override + public String getCategoryName(Object data) + { + TestdataStatementData parameter = (TestdataStatementData) data; + Map testData = new HashMap<>(); + testData.putAll(parameter.getPackageTestData()); + testData.putAll(parameter.getDataSet()); + + String testname; + if (parameter.getIndex() >= 0) + { + // data sets and (maybe) package data + String testDatasetIndetifier = testData.get(TEST_ID); + if (StringUtils.isBlank(testDatasetIndetifier)) + { + testDatasetIndetifier = "Data set"; + } + + // replace paranthesis because https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512 + // "Any text in parentheses is assumed to be the name of the class in which the test is defined." + testDatasetIndetifier = testDatasetIndetifier.replaceAll("\\(", "[").replaceAll("\\)", "]"); + + testname = String.format("%s %d / %d", testDatasetIndetifier, (parameter.getIndex() + 1), parameter.getSize()); + } + else + { + // only package data + testname = "TestData"; + } + return testname; + } +} diff --git a/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatementData.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatementData.java new file mode 100644 index 000000000..5e753f901 --- /dev/null +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/TestdataStatementData.java @@ -0,0 +1,75 @@ +package com.xceptance.neodymium.module.statement.testdata; + +import java.util.HashMap; +import java.util.Map; + +public class TestdataStatementData +{ + + private Map dataSet; + + private Map packageTestData; + + private int index; + + private int size; + + private int iterationIndex; + + public TestdataStatementData(Map dataSet, Map packageTestData, int index, int size) + { + this.dataSet = dataSet; + this.packageTestData = packageTestData; + this.index = index; + this.size = size; + this.iterationIndex = 0; + } + + public TestdataStatementData(TestdataStatementData another) + { + if (another.dataSet != null) + { + this.dataSet = new HashMap<>(); + this.dataSet.putAll(another.dataSet); + } + + if (another.packageTestData != null) + { + this.packageTestData = new HashMap<>(); + this.packageTestData.putAll(another.packageTestData); + } + this.size = another.size; + this.index = another.index; + this.iterationIndex = another.iterationIndex; + } + + public Map getDataSet() + { + return dataSet; + } + + public Map getPackageTestData() + { + return packageTestData; + } + + public int getIndex() + { + return index; + } + + public int getSize() + { + return size; + } + + public int getIterationIndex() + { + return iterationIndex; + } + + public void setIterationIndex(int iterationIndex) + { + this.iterationIndex = iterationIndex; + } +} diff --git a/src/main/java/com/xceptance/neodymium/testdata/CsvFileReader.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/CsvFileReader.java similarity index 95% rename from src/main/java/com/xceptance/neodymium/testdata/CsvFileReader.java rename to src/main/java/com/xceptance/neodymium/module/statement/testdata/util/CsvFileReader.java index 01e212dce..c722a98ec 100644 --- a/src/main/java/com/xceptance/neodymium/testdata/CsvFileReader.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/CsvFileReader.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.testdata; +package com.xceptance.neodymium.module.statement.testdata.util; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/com/xceptance/neodymium/testdata/JsonFileReader.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/JsonFileReader.java similarity index 97% rename from src/main/java/com/xceptance/neodymium/testdata/JsonFileReader.java rename to src/main/java/com/xceptance/neodymium/module/statement/testdata/util/JsonFileReader.java index dda0d901c..550accbda 100644 --- a/src/main/java/com/xceptance/neodymium/testdata/JsonFileReader.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/JsonFileReader.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.testdata; +package com.xceptance.neodymium.module.statement.testdata.util; import java.io.BufferedInputStream; import java.io.File; diff --git a/src/main/java/com/xceptance/neodymium/testdata/PropertyFileReader.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/PropertyFileReader.java similarity index 96% rename from src/main/java/com/xceptance/neodymium/testdata/PropertyFileReader.java rename to src/main/java/com/xceptance/neodymium/module/statement/testdata/util/PropertyFileReader.java index d1550ea16..9c1d12bc5 100644 --- a/src/main/java/com/xceptance/neodymium/testdata/PropertyFileReader.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/PropertyFileReader.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.testdata; +package com.xceptance.neodymium.module.statement.testdata.util; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/com/xceptance/neodymium/testdata/TestDataUtils.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/TestDataUtils.java similarity index 99% rename from src/main/java/com/xceptance/neodymium/testdata/TestDataUtils.java rename to src/main/java/com/xceptance/neodymium/module/statement/testdata/util/TestDataUtils.java index 4ee7d5ed5..bfed9435f 100644 --- a/src/main/java/com/xceptance/neodymium/testdata/TestDataUtils.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/TestDataUtils.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.testdata; +package com.xceptance.neodymium.module.statement.testdata.util; import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/com/xceptance/neodymium/testdata/XmlFileReader.java b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/XmlFileReader.java similarity index 97% rename from src/main/java/com/xceptance/neodymium/testdata/XmlFileReader.java rename to src/main/java/com/xceptance/neodymium/module/statement/testdata/util/XmlFileReader.java index e80a8c009..22e104024 100644 --- a/src/main/java/com/xceptance/neodymium/testdata/XmlFileReader.java +++ b/src/main/java/com/xceptance/neodymium/module/statement/testdata/util/XmlFileReader.java @@ -1,4 +1,4 @@ -package com.xceptance.neodymium.testdata; +package com.xceptance.neodymium.module.statement.testdata.util; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/com/xceptance/neodymium/multibrowser/Browser.java b/src/main/java/com/xceptance/neodymium/multibrowser/Browser.java deleted file mode 100644 index 1278e0d8a..000000000 --- a/src/main/java/com/xceptance/neodymium/multibrowser/Browser.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xceptance.neodymium.multibrowser; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotate a class with {@link Browser} and add as annotation value a list of test targets. These targets refer to - * browser profiles (browsertag) that are configured in browser.properties located in config folder. - * - * @author m.kaufmann - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -public @interface Browser -{ - String[] value(); -} diff --git a/src/main/java/com/xceptance/neodymium/util/Configuration.java b/src/main/java/com/xceptance/neodymium/util/Configuration.java index 3ac467f24..1efc25fa5 100644 --- a/src/main/java/com/xceptance/neodymium/util/Configuration.java +++ b/src/main/java/com/xceptance/neodymium/util/Configuration.java @@ -7,6 +7,8 @@ import org.aeonbits.owner.Config.Sources; import org.aeonbits.owner.Mutable; +import com.xceptance.neodymium.NeodymiumRunner.DescriptionMode; + @LoadPolicy(LoadType.MERGE) @Sources( { @@ -126,4 +128,7 @@ public interface Configuration extends Mutable @DefaultValue("+-#$%%&.;,_") public String dataUtilsPasswordSpecialChars(); + @Key("junit.viewmode") + @DefaultValue("tree") + public DescriptionMode junitViewMode(); } diff --git a/src/main/java/com/xceptance/neodymium/util/DataUtils.java b/src/main/java/com/xceptance/neodymium/util/DataUtils.java index 27080f55a..2e44eb82a 100644 --- a/src/main/java/com/xceptance/neodymium/util/DataUtils.java +++ b/src/main/java/com/xceptance/neodymium/util/DataUtils.java @@ -91,6 +91,27 @@ public static String asString(String key) return value; } + /** + * Get a test data value as string or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link String} if the key was found else defaultValue + */ + public static String asString(String key, String defaultValue) + { + try + { + return asString(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } + } + /** * Get a test data value as int * @@ -102,7 +123,28 @@ public static String asString(String key) */ public static int asInt(String key) { - return Integer.valueOf(asString(key)).intValue(); + return Integer.parseInt(asString(key)); + } + + /** + * Get a test data value as int or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link int} if the key was found else defaultValue + */ + public static int asInt(String key, int defaultValue) + { + try + { + return asInt(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } } /** @@ -116,7 +158,28 @@ public static int asInt(String key) */ public static long asLong(String key) { - return Long.valueOf(asString(key)).longValue(); + return Long.parseLong(asString(key)); + } + + /** + * Get a test data value as long or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link long} if the key was found else defaultValue + */ + public static long asLong(String key, long defaultValue) + { + try + { + return asLong(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } } /** @@ -130,7 +193,28 @@ public static long asLong(String key) */ public static double asDouble(String key) { - return Double.valueOf(asString(key)).doubleValue(); + return Double.parseDouble(asString(key)); + } + + /** + * Get a test data value as double or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link double} if the key was found else defaultValue + */ + public static double asDouble(String key, double defaultValue) + { + try + { + return asDouble(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } } /** @@ -144,7 +228,28 @@ public static double asDouble(String key) */ public static float asFloat(String key) { - return Float.valueOf(asString(key)).floatValue(); + return Float.parseFloat(asString(key)); + } + + /** + * Get a test data value as float or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link float} if the key was found else defaultValue + */ + public static float asFloat(String key, float defaultValue) + { + try + { + return asFloat(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } } /** @@ -158,6 +263,27 @@ public static float asFloat(String key) */ public static boolean asBool(String key) { - return Boolean.valueOf(asString(key)).booleanValue(); + return Boolean.parseBoolean(asString(key)); + } + + /** + * Get a test data value as boolean or default value if it couldn't be found + * + * @param key + * Name of test data key + * @param defaultValue + * a value that will be returned if the key was not found + * @return {@link boolean} if the key was found else defaultValue + */ + public static boolean asBool(String key, boolean defaultValue) + { + try + { + return asBool(key); + } + catch (IllegalArgumentException e) + { + return defaultValue; + } } } diff --git a/src/main/java/com/xceptance/neodymium/util/Driver.java b/src/main/java/com/xceptance/neodymium/util/Driver.java index 69f3e18cd..477107f46 100644 --- a/src/main/java/com/xceptance/neodymium/util/Driver.java +++ b/src/main/java/com/xceptance/neodymium/util/Driver.java @@ -1,76 +1,43 @@ package com.xceptance.neodymium.util; -import java.net.MalformedURLException; +import java.util.function.Supplier; -import org.openqa.selenium.WebDriver; +import com.xceptance.neodymium.module.statement.browser.BrowserStatement; -import com.codeborne.selenide.WebDriverRunner; -import com.xceptance.neodymium.multibrowser.WebDriverCache; -import com.xceptance.neodymium.multibrowser.WebDriverFactory; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.WebDriverProperties; +import cucumber.api.Scenario; public class Driver { - private static final String BROWSER_PROFILE_FILE = "./config/browser.properties"; - - public static void setUp(final String browserProfileName) + private static ThreadLocal browserStatement = ThreadLocal.withInitial(new Supplier() { - // try to find appropriate web driver in cache before creating a new instance - WebDriver driver = null; - - MultibrowserConfiguration multibrowserConfiguration = MultibrowserConfiguration.getInstance(); - if (multibrowserConfiguration == null) - multibrowserConfiguration = MultibrowserConfiguration.getInstance(BROWSER_PROFILE_FILE); - - if (multibrowserConfiguration.getWebDriverProperties().reuseWebDriver()) + @Override + public BrowserStatement get() { - driver = WebDriverCache.instance.getRemoveWebDriver(browserProfileName); + return new BrowserStatement(); } - // nothing in the cache or nothing set yet - if (driver == null) - { - try - { - driver = WebDriverFactory.create(browserProfileName); - } - catch (MalformedURLException e) - { - throw new RuntimeException(e); - } - WebDriverRunner.setWebDriver(driver); - } - else - { - // ok, clean reused driver - driver.manage().deleteAllCookies(); - } + }); - // clear Context for every browser instance - Context.clearThreadContext(); + public static void setUp(final String browserProfileName) + { - // keep in globally - Context.get().driver = driver; - Context.get().browserProfileName = browserProfileName; + browserStatement.get().setUpTest(browserProfileName); } - public static void tearDown() + /** + * @param scenario + * Scenario is a Cucumber API class that can be gathered in hooks via dependency injection + * + *
+     *            @cucumber.api.java.After(order = 100)
+     *            public void tearDown(Scenario scenario)
+     *            {
+     *                Driver.tearDown(scenario);
+     *            }
+     *            
+ **/ + public static void tearDown(Scenario scenario) { - WebDriverProperties webDriverProperties = MultibrowserConfiguration.getInstance().getWebDriverProperties(); - if (webDriverProperties.reuseWebDriver()) - { - WebDriverCache.instance.putWebDriver(Context.get().browserProfileName, Context.get().driver); - } - else - { - if (!webDriverProperties.keepBrowserOpen() && Context.get().driver != null) - { - Context.get().driver.quit(); - } - } - - Context.get().driver = null; - Context.get().browserProfileName = null; + browserStatement.get().teardown(scenario.isFailed()); } } diff --git a/src/test/com/xceptance/xlt/ai/Test_Image_OneElement.network b/src/test/com/xceptance/xlt/ai/Test_Image_OneElement.network new file mode 100644 index 000000000..a737e46f4 Binary files /dev/null and b/src/test/com/xceptance/xlt/ai/Test_Image_OneElement.network differ diff --git a/src/test/java/com/xceptance/neodymium/test/visual/ai/Test_Image_OneElement.network b/src/test/java/com/xceptance/neodymium/test/visual/ai/Test_Image_OneElement.network new file mode 100644 index 000000000..02ae6cc55 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/test/visual/ai/Test_Image_OneElement.network differ diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/EmptyBrowser.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/EmptyBrowser.java deleted file mode 100644 index 1a15d9cb5..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/browser/EmptyBrowser.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xceptance.neodymium.testclasses.browser; - -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; - -@RunWith(NeodymiumRunner.class) -@Browser( - { - "" - }) -public class EmptyBrowser -{ -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/NoBrowserTag.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/NoBrowserTag.java deleted file mode 100644 index b5a4f8008..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/browser/NoBrowserTag.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.xceptance.neodymium.testclasses.browser; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; - -@RunWith(NeodymiumRunner.class) -@Browser({}) -public class NoBrowserTag -{ - @Test - public void test() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/TestBrowser.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/TestBrowser.java deleted file mode 100644 index a635bf767..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/browser/TestBrowser.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xceptance.neodymium.testclasses.browser; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; - -@RunWith(NeodymiumRunner.class) -@Browser( - { - "test" - }) -public class TestBrowser -{ - @Test - public void test() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressed.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressed.java new file mode 100644 index 000000000..2f3759eed --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressed.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.SuppressBrowsers; + +@RunWith(NeodymiumRunner.class) +@Browser("chrome") +@SuppressBrowsers +public class ClassBrowserSuppressed +{ + @Test + public void first() throws Exception + { + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressedNoBrowserAnnotation.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressedNoBrowserAnnotation.java new file mode 100644 index 000000000..a92a51dfe --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/ClassBrowserSuppressedNoBrowserAnnotation.java @@ -0,0 +1,17 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.SuppressBrowsers; + +@SuppressBrowsers +@RunWith(NeodymiumRunner.class) +public class ClassBrowserSuppressedNoBrowserAnnotation +{ + @Test + public void first() throws Exception + { + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/EmptyBrowser.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/EmptyBrowser.java new file mode 100644 index 000000000..d8b74fdca --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/EmptyBrowser.java @@ -0,0 +1,20 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@RunWith(NeodymiumRunner.class) +@Browser("") +public class EmptyBrowser +{ + + @Test + public void testName() throws Exception + { + Assert.fail(); + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/OneClassBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/OneClassBrowserOneMethod.java new file mode 100644 index 000000000..96059e5ba --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/OneClassBrowserOneMethod.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@RunWith(NeodymiumRunner.class) +@Browser("chrome") +public class OneClassBrowserOneMethod +{ + @Test + public void first() + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoClassBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoClassBrowserOneMethod.java new file mode 100644 index 000000000..125cfe15e --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoClassBrowserOneMethod.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@RunWith(NeodymiumRunner.class) +@Browser("chrome") +@Browser("firefox") +public class TwoClassBrowserOneMethod +{ + @Test + public void first() + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoSameClassBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoSameClassBrowserOneMethod.java new file mode 100644 index 000000000..ebcd19ffd --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/classonly/TwoSameClassBrowserOneMethod.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.browser.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@RunWith(NeodymiumRunner.class) +@Browser("chrome") +@Browser("chrome") +public class TwoSameClassBrowserOneMethod +{ + @Test + public void first() + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/MethodBrowserSuppressNoBrowserAnnotation.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/MethodBrowserSuppressNoBrowserAnnotation.java new file mode 100644 index 000000000..886f2871a --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/MethodBrowserSuppressNoBrowserAnnotation.java @@ -0,0 +1,17 @@ +package com.xceptance.neodymium.testclasses.browser.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.SuppressBrowsers; + +@RunWith(NeodymiumRunner.class) +public class MethodBrowserSuppressNoBrowserAnnotation +{ + @Test + @SuppressBrowsers + public void first() throws Exception + { + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/OneBrowserOneMethodBrowserSuppressed.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/OneBrowserOneMethodBrowserSuppressed.java new file mode 100644 index 000000000..1645061f0 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/methodonly/OneBrowserOneMethodBrowserSuppressed.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.browser.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.SuppressBrowsers; + +@RunWith(NeodymiumRunner.class) +public class OneBrowserOneMethodBrowserSuppressed +{ + @Test + @Browser("chrome") + @SuppressBrowsers + public void first() throws Exception + { + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/browser/mixed/ClassAndMethodSameBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/browser/mixed/ClassAndMethodSameBrowserOneMethod.java new file mode 100644 index 000000000..0cab5c419 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/browser/mixed/ClassAndMethodSameBrowserOneMethod.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.browser.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@Browser("chrome") +@RunWith(NeodymiumRunner.class) +public class ClassAndMethodSameBrowserOneMethod +{ + @Browser("chrome") + @Test + public void first() throws Exception + { + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.csv b/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.java b/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.java new file mode 100644 index 000000000..23f3edc62 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/ContextGetsCleared.java @@ -0,0 +1,33 @@ +package com.xceptance.neodymium.testclasses.context; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; +import com.xceptance.neodymium.module.statement.testdata.SuppressDataSets; +import com.xceptance.neodymium.util.Context; + +@RunWith(NeodymiumRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ContextGetsCleared +{ + @Test + @DataSet + public void test1() throws Exception + { + // there is one data set -> key1 = val1 + Assert.assertEquals("val1", Context.dataValue("key1")); + } + + @Test + @SuppressDataSets + public void test2() throws Exception + { + // supressing data sets makes sure we dont + Assert.assertNull(Context.dataValue("key1")); + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/DefaultSelenideTimeoutCheck.java b/src/test/java/com/xceptance/neodymium/testclasses/context/DefaultSelenideTimeoutCheck.java new file mode 100644 index 000000000..939fa8379 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/DefaultSelenideTimeoutCheck.java @@ -0,0 +1,31 @@ +package com.xceptance.neodymium.testclasses.context; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import com.codeborne.selenide.Configuration; +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; + +@RunWith(NeodymiumRunner.class) +@Browser("headless_chrome") +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class DefaultSelenideTimeoutCheck +{ + @Test + public void test1() throws Exception + { + Configuration.timeout = 1234; + Configuration.collectionsTimeout = 1234; + } + + @Test + public void test2() throws Exception + { + Assert.assertEquals(3000, Configuration.timeout); + Assert.assertEquals(6000, Configuration.collectionsTimeout); + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/ContextGetCleared.feature b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/ContextGetCleared.feature new file mode 100644 index 000000000..dac69d528 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/ContextGetCleared.feature @@ -0,0 +1,13 @@ +Feature: Context data get cleared + + Scenario: Change timeout + Given Change timeout to 4000 + + Scenario: Assert resettet timeout + Given Assert timeout of 3000 + + Scenario: Change collection timeout + Given Change default collection timeout to 1234 + + Scenario: Assert resettet collection timeout + Given Assert collection timeout of 6000 diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextGetsCleared.java b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextGetsCleared.java new file mode 100644 index 000000000..bca22ccb9 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextGetsCleared.java @@ -0,0 +1,14 @@ +package com.xceptance.neodymium.testclasses.context.cucumbercontextclear; + +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumCucumberRunner; + +import cucumber.api.CucumberOptions; + +@RunWith(NeodymiumCucumberRunner.class) +@CucumberOptions(features = "src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear", + glue = "com/xceptance/neodymium/testclasses/context/cucumbercontextclear") +public class CucumberContextGetsCleared +{ +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextSteps.java b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextSteps.java new file mode 100644 index 000000000..b17851565 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/context/cucumbercontextclear/CucumberContextSteps.java @@ -0,0 +1,58 @@ +package com.xceptance.neodymium.testclasses.context.cucumbercontextclear; + +import org.junit.Assert; + +import com.xceptance.neodymium.util.Configuration; +import com.xceptance.neodymium.util.Context; +import com.xceptance.neodymium.util.Driver; + +import cucumber.api.Scenario; +import cucumber.api.java.After; +import cucumber.api.java.Before; +import cucumber.api.java.en.Given; + +public class CucumberContextSteps +{ + @Before + public void beforeTest() + { + // setup browser since we set our selenide defaults only if a browser is involved + Driver.setUp("headless_chrome"); + } + + @After(order = 100) + public void teardown(Scenario scenario) + { + Driver.tearDown(scenario); + } + + @Given("Change timeout to 4000") + public void testAndChangeDefaultTimeout() + { + Configuration configuration = Context.get().configuration; + Assert.assertEquals(3000, configuration.timeout()); + + configuration.setProperty("selenide.timeout", "4000"); + Assert.assertEquals(4000, configuration.timeout()); + } + + @Given("Assert timeout of 3000") + public void testDefaultTimeout() + { + Configuration configuration = Context.get().configuration; + Assert.assertEquals(3000, configuration.timeout()); + } + + @Given("Change default collection timeout to 1234") + public void testAndChangeDefaultCollectionTimeout() + { + com.codeborne.selenide.Configuration.collectionsTimeout = 1234; + Assert.assertEquals(1234, com.codeborne.selenide.Configuration.collectionsTimeout); + } + + @Given("Assert collection timeout of 6000") + public void testDefaultCollectionTimeout() + { + Assert.assertEquals(6000, com.codeborne.selenide.Configuration.collectionsTimeout); + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.csv new file mode 100644 index 000000000..ae1f4cfac --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.csv @@ -0,0 +1 @@ +key1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.java new file mode 100644 index 000000000..c3cb57f12 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueEmptyDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet() +public class ClassDefaultValueEmptyDataSets +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueNoDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueNoDataSets.java new file mode 100644 index 000000000..2440b67fc --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueNoDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet() +public class ClassDefaultValueNoDataSets +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.java new file mode 100644 index 000000000..22f09f4bd --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueOneDataSet.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet() +public class ClassDefaultValueOneDataSet +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.java new file mode 100644 index 000000000..b9203ebd7 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassDefaultValueTwoDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet() +public class ClassDefaultValueTwoDataSets +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.java new file mode 100644 index 000000000..148a3f21e --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassExplicitDefaultValueTwoDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet(0) +public class ClassExplicitDefaultValueTwoDataSets +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.java new file mode 100644 index 000000000..3ea0a1d6b --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/classonly/ClassMultipleSameDataSet.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.data.override.classonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +@DataSet(1) +@DataSet(1) +public class ClassMultipleSameDataSet +{ + @Test + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.csv new file mode 100644 index 000000000..ae1f4cfac --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.csv @@ -0,0 +1 @@ +key1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.java new file mode 100644 index 000000000..be943b1ce --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultEmptyDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodDefaultEmptyDataSets +{ + @Test + @DataSet + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultNoDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultNoDataSets.java new file mode 100644 index 000000000..137716527 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultNoDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodDefaultNoDataSets +{ + @Test + @DataSet + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.java new file mode 100644 index 000000000..a0a3f99f8 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultOneDataSet.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodDefaultOneDataSet +{ + @Test + @DataSet + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.java new file mode 100644 index 000000000..3bea804ec --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodDefaultTwoDataSet.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodDefaultTwoDataSet +{ + @Test + @DataSet + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.java new file mode 100644 index 000000000..c6fc204eb --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodExplicitDefaultTwoDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodExplicitDefaultTwoDataSets +{ + @Test + @DataSet(0) + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.java new file mode 100644 index 000000000..a82f450a0 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/methodonly/MethodMultipleSameDataSet.java @@ -0,0 +1,19 @@ +package com.xceptance.neodymium.testclasses.data.override.methodonly; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class MethodMultipleSameDataSet +{ + @Test + @DataSet(1) + @DataSet(1) + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.java new file mode 100644 index 000000000..a0b933d16 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ClassWithoutTwoMethodsOneForced.java @@ -0,0 +1,26 @@ +package com.xceptance.neodymium.testclasses.data.override.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; +import com.xceptance.neodymium.module.statement.testdata.SuppressDataSets; + +@RunWith(NeodymiumRunner.class) +@SuppressDataSets +public class ClassWithoutTwoMethodsOneForced +{ + @Test + @DataSet(1) + public void test1() throws Exception + { + + } + + @Test + public void test2() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ForceOfNoneDataSets.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ForceOfNoneDataSets.java new file mode 100644 index 000000000..105ccdcf6 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/ForceOfNoneDataSets.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.testclasses.data.override.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class ForceOfNoneDataSets +{ + @Test + @DataSet(2) + public void test1() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.java new file mode 100644 index 000000000..56ec76008 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OneDataSetTwoMethodsOneWithout.java @@ -0,0 +1,24 @@ +package com.xceptance.neodymium.testclasses.data.override.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.SuppressDataSets; + +@RunWith(NeodymiumRunner.class) +public class OneDataSetTwoMethodsOneWithout +{ + @Test + public void test1() throws Exception + { + + } + + @Test + @SuppressDataSets + public void test2() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.csv new file mode 100644 index 000000000..600a3b138 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.csv @@ -0,0 +1,2 @@ +key1 +val1 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/FailingMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.java similarity index 52% rename from src/test/java/com/xceptance/neodymium/testclasses/method/FailingMethod.java rename to src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.java index 555ad4a59..9c2e61b00 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/FailingMethod.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/OnlyImplicitOneDataSet.java @@ -1,17 +1,16 @@ -package com.xceptance.neodymium.testclasses.method; +package com.xceptance.neodymium.testclasses.data.override.mixed; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import com.xceptance.neodymium.NeodymiumRunner; @RunWith(NeodymiumRunner.class) -public class FailingMethod +public class OnlyImplicitOneDataSet { @Test - public void fail() + public void test1() throws Exception { - Assert.fail(); + } } diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.java new file mode 100644 index 000000000..7b834bc1c --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneForced.java @@ -0,0 +1,24 @@ +package com.xceptance.neodymium.testclasses.data.override.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.DataSet; + +@RunWith(NeodymiumRunner.class) +public class TwoDataSetsTwoMethodsOneForced +{ + @Test + public void test1() throws Exception + { + + } + + @Test + @DataSet(1) + public void test2() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.csv b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.csv new file mode 100644 index 000000000..cef447744 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.csv @@ -0,0 +1,3 @@ +key1 +val1 +val2 \ No newline at end of file diff --git a/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.java b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.java new file mode 100644 index 000000000..32f0dae00 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/data/override/mixed/TwoDataSetsTwoMethodsOneWithout.java @@ -0,0 +1,24 @@ +package com.xceptance.neodymium.testclasses.data.override.mixed; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.module.statement.testdata.SuppressDataSets; + +@RunWith(NeodymiumRunner.class) +public class TwoDataSetsTwoMethodsOneWithout +{ + @Test + public void test1() throws Exception + { + + } + + @Test + @SuppressDataSets + public void test2() throws Exception + { + + } +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/datautils/DataUtilsTests.java b/src/test/java/com/xceptance/neodymium/testclasses/datautils/DataUtilsTests.java new file mode 100644 index 000000000..982662920 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/testclasses/datautils/DataUtilsTests.java @@ -0,0 +1,275 @@ +package com.xceptance.neodymium.testclasses.datautils; + +import java.text.MessageFormat; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.xceptance.neodymium.NeodymiumRunner; +import com.xceptance.neodymium.util.Context; +import com.xceptance.neodymium.util.DataUtils; + +@RunWith(NeodymiumRunner.class) +public class DataUtilsTests +{ + private static final String NIL = "not in list"; + + @Test + public void testAsString() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("value", "value"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asString(null); + }); + expectIAE(() -> { + DataUtils.asString("nullValue"); + }); + expectIAE(() -> { + DataUtils.asString(""); + }); + expectIAE(() -> { + DataUtils.asString(NIL); + }); + + Assert.assertEquals("", DataUtils.asString("empty")); + Assert.assertEquals("value", DataUtils.asString("value")); + + Assert.assertEquals(null, DataUtils.asString(null, null)); + Assert.assertEquals(null, DataUtils.asString("", null)); + Assert.assertEquals(null, DataUtils.asString("nullValue", null)); + Assert.assertEquals(null, DataUtils.asString(NIL, null)); + + } + + @Test + public void testAsInt() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("positiveValue", "3"); + data.put("negativeValue", "-3"); + data.put("zeroValue", "0"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asInt(null); + }); + expectIAE(() -> { + DataUtils.asInt("nullValue"); + }); + expectIAE(() -> { + DataUtils.asInt(""); + }); + expectIAE(() -> { + DataUtils.asInt(NIL); + }); + + expectNFE(() -> { + DataUtils.asInt("empty"); + }); + + Assert.assertEquals(3, DataUtils.asInt("positiveValue")); + Assert.assertEquals(-3, DataUtils.asInt("negativeValue")); + Assert.assertEquals(0, DataUtils.asInt("zeroValue")); + + Assert.assertEquals(3, DataUtils.asInt(null, 3)); + Assert.assertEquals(3, DataUtils.asInt("", 3)); + Assert.assertEquals(3, DataUtils.asInt("nullValue", 3)); + Assert.assertEquals(3, DataUtils.asInt(NIL, 3)); + } + + @Test + public void testAsLong() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("positiveValue", "3"); + data.put("negativeValue", "-3"); + data.put("zeroValue", "0"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asLong(null); + }); + expectIAE(() -> { + DataUtils.asLong("nullValue"); + }); + expectIAE(() -> { + DataUtils.asLong(""); + }); + expectIAE(() -> { + DataUtils.asLong(NIL); + }); + + expectNFE(() -> { + DataUtils.asLong("empty"); + }); + + Assert.assertEquals(3, DataUtils.asLong("positiveValue")); + Assert.assertEquals(-3, DataUtils.asLong("negativeValue")); + Assert.assertEquals(0, DataUtils.asLong("zeroValue")); + + Assert.assertEquals(3, DataUtils.asLong(null, 3)); + Assert.assertEquals(3, DataUtils.asLong("", 3)); + Assert.assertEquals(3, DataUtils.asLong("nullValue", 3)); + Assert.assertEquals(3, DataUtils.asLong(NIL, 3)); + } + + @Test + public void testAsFloat() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("positiveValue", "3.3f"); + data.put("negativeValue", "-3.3"); + data.put("zeroValue", ".0"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asFloat(null); + }); + expectIAE(() -> { + DataUtils.asFloat("nullValue"); + }); + expectIAE(() -> { + DataUtils.asFloat(""); + }); + expectIAE(() -> { + DataUtils.asFloat(NIL); + }); + + expectNFE(() -> { + DataUtils.asFloat("empty"); + }); + + Assert.assertEquals(3.3, DataUtils.asFloat("positiveValue"), 0.000001); + Assert.assertEquals(-3.3, DataUtils.asFloat("negativeValue"), 0.000001); + Assert.assertEquals(0, DataUtils.asFloat("zeroValue"), 0.000001); + + Assert.assertEquals(3, DataUtils.asFloat(null, 3), 0.000001); + Assert.assertEquals(3, DataUtils.asFloat("", 3), 0.000001); + Assert.assertEquals(3, DataUtils.asFloat("nullValue", 3), 0.000001); + Assert.assertEquals(3, DataUtils.asFloat(NIL, 3), 0.000001); + } + + @Test + public void testAsDouble() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("positiveValue", "3.3d"); + data.put("negativeValue", "-3.3"); + data.put("zeroValue", ".0"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asDouble(null); + }); + expectIAE(() -> { + DataUtils.asDouble("nullValue"); + }); + expectIAE(() -> { + DataUtils.asDouble(""); + }); + expectIAE(() -> { + DataUtils.asDouble(NIL); + }); + + expectNFE(() -> { + DataUtils.asDouble("empty"); + }); + + Assert.assertEquals(3.3, DataUtils.asDouble("positiveValue"), 0.000001); + Assert.assertEquals(-3.3, DataUtils.asDouble("negativeValue"), 0.000001); + Assert.assertEquals(0, DataUtils.asDouble("zeroValue"), 0.000001); + + Assert.assertEquals(3, DataUtils.asDouble(null, 3), 0.000001); + Assert.assertEquals(3, DataUtils.asDouble("", 3), 0.000001); + Assert.assertEquals(3, DataUtils.asDouble("nullValue", 3), 0.000001); + Assert.assertEquals(3, DataUtils.asDouble(NIL, 3), 0.000001); + } + + @Test + public void testAsBoolean() throws Exception + { + Map data = Context.get().data; + data.clear(); + data.put("nullValue", null); + data.put("empty", ""); + data.put("positiveValue", "true"); + data.put("negativeValue", "FaLsE"); + + // expect IllegalArgumentException + expectIAE(() -> { + DataUtils.asBool(null); + }); + expectIAE(() -> { + DataUtils.asBool("nullValue"); + }); + expectIAE(() -> { + DataUtils.asBool(""); + }); + expectIAE(() -> { + DataUtils.asBool(NIL); + }); + + Assert.assertEquals(false, DataUtils.asBool("empty")); + Assert.assertEquals(true, DataUtils.asBool("positiveValue")); + Assert.assertEquals(false, DataUtils.asBool("negativeValue")); + + Assert.assertEquals(true, DataUtils.asBool(null, true)); + Assert.assertEquals(true, DataUtils.asBool("", true)); + Assert.assertEquals(true, DataUtils.asBool("nullValue", true)); + Assert.assertEquals(true, DataUtils.asBool(NIL, true)); + } + + private void expectIAE(Runnable function) + { + expectException(function, IllegalArgumentException.class); + } + + private void expectNFE(Runnable function) + { + expectException(function, NumberFormatException.class); + } + + private void expectException(Runnable function, Class expectedException) + { + Throwable caughtException = null; + + try + { + function.run(); + } + catch (Throwable e) + { + caughtException = e; + } + + String caughtExeptionName = "no exception!"; + if (caughtException != null) + caughtExeptionName = caughtException.getClass().toString(); + + if (caughtException == null || caughtException.getClass() != expectedException) + { + Assert.fail(MessageFormat.format("Expected exception {0} but caught {1}", expectedException.toString(), caughtExeptionName)); + } + } + +} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/BeforeAndAfter.java b/src/test/java/com/xceptance/neodymium/testclasses/method/BeforeAndAfter.java deleted file mode 100644 index 7716879e8..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/BeforeAndAfter.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import java.util.LinkedList; -import java.util.List; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runners.MethodSorters; - -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class BeforeAndAfter -{ - public static List TRACE = new LinkedList<>(); - - @BeforeClass - public static void beforeClass() - { - TRACE.add("beforeClass"); - } - - @Before - public void beforeMethod() - { - TRACE.add("beforeMethod"); - } - - @After - public void afterMethod() - { - TRACE.add("afterMethod"); - } - - @AfterClass - public static void afterClass() - { - TRACE.add("afterClass"); - } - - @Test - public void first() - { - TRACE.add("first"); - } - - @Test - public void second() - { - TRACE.add("second"); - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsCheckedException.java b/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsCheckedException.java deleted file mode 100644 index dacbd8f75..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsCheckedException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; - -@RunWith(NeodymiumRunner.class) -public class ConstructorThrowsCheckedException -{ - public ConstructorThrowsCheckedException() throws Throwable - { - throw new Exception("construction failed"); - } - - @Test - public void test() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsError.java b/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsError.java deleted file mode 100644 index ac1fc7b91..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/ConstructorThrowsError.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; - -@RunWith(NeodymiumRunner.class) -public class ConstructorThrowsError -{ - public ConstructorThrowsError() throws Exception - { - throw new Error(); - } - - @Test - public void test() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/IgnoredClass.java b/src/test/java/com/xceptance/neodymium/testclasses/method/IgnoredClass.java deleted file mode 100644 index 5d8d33197..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/IgnoredClass.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; - -@RunWith(NeodymiumRunner.class) -@Ignore -public class IgnoredClass -{ - @Test - public void test() - { - Assert.fail(); - } - - @Test - @Ignore - public void ignoredTestMethod() - { - Assert.fail(); - } - - public void foo() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/NoTestMethods.java b/src/test/java/com/xceptance/neodymium/testclasses/method/NoTestMethods.java deleted file mode 100644 index ef2902757..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/NoTestMethods.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import org.junit.Ignore; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; - -@RunWith(NeodymiumRunner.class) -public class NoTestMethods -{ - public void foo() - { - - } - - @Ignore - public void bar() - { - - } -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/method/TestAndIgnoreAnnotation.java b/src/test/java/com/xceptance/neodymium/testclasses/method/TestAndIgnoreAnnotation.java deleted file mode 100644 index 1cbd00489..000000000 --- a/src/test/java/com/xceptance/neodymium/testclasses/method/TestAndIgnoreAnnotation.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xceptance.neodymium.testclasses.method; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.xceptance.neodymium.NeodymiumRunner; - -@RunWith(NeodymiumRunner.class) -public class TestAndIgnoreAnnotation -{ - // only methods annotated with test should be called - // ignoring a class or method should override any test annotation - - public void noTestMethod() - { - Assert.fail(); - } - - @Test - public void testMethod() - { - } - - @Ignore - public void ignoredMethod() - { - Assert.fail(); - } - - @Test - @Ignore - public void ignoredTestMethod() - { - Assert.fail(); - } - -} diff --git a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserOneMethod.java index 7ee87cbfa..bff221b05 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserOneMethod.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserOneMethod.java @@ -4,7 +4,7 @@ import org.junit.runner.RunWith; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; @RunWith(NeodymiumRunner.class) @Browser("first_browser") diff --git a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserTwoMethods.java b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserTwoMethods.java index 7dd7329b9..f885a8d84 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserTwoMethods.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/OneBrowserTwoMethods.java @@ -4,7 +4,7 @@ import org.junit.runner.RunWith; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; @RunWith(NeodymiumRunner.class) @Browser("first_browser") diff --git a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserOneMethod.java b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserOneMethod.java index 0a3f1eb1c..412cef290 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserOneMethod.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserOneMethod.java @@ -4,13 +4,11 @@ import org.junit.runner.RunWith; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; @RunWith(NeodymiumRunner.class) -@Browser( - { - "first_browser", "second_browser" - }) +@Browser("first_browser") +@Browser("second_browser") public class TwoBrowserOneMethod { @Test diff --git a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserTwoMethods.java b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserTwoMethods.java index 09e49b2f1..3a42178c6 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserTwoMethods.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/multiplication/browser/TwoBrowserTwoMethods.java @@ -4,13 +4,11 @@ import org.junit.runner.RunWith; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.Browser; +import com.xceptance.neodymium.module.statement.browser.multibrowser.Browser; @RunWith(NeodymiumRunner.class) -@Browser( - { - "first_browser", "second_browser" - }) +@Browser("first_browser") +@Browser("second_browser") public class TwoBrowserTwoMethods { @Test diff --git a/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversion.java b/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversion.java index 68039cb19..369ec3fb9 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversion.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversion.java @@ -10,7 +10,7 @@ import org.junit.runners.Parameterized.Parameters; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; @RunWith(NeodymiumRunner.class) public class GeneratorAutoTypeConversion diff --git a/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversionCanNotHandleArbitraryTypes.java b/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversionCanNotHandleArbitraryTypes.java index 616511db1..3d15907e0 100644 --- a/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversionCanNotHandleArbitraryTypes.java +++ b/src/test/java/com/xceptance/neodymium/testclasses/parameter/GeneratorAutoTypeConversionCanNotHandleArbitraryTypes.java @@ -9,7 +9,7 @@ import org.junit.runners.Parameterized.Parameters; import com.xceptance.neodymium.NeodymiumRunner; -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; @RunWith(NeodymiumRunner.class) public class GeneratorAutoTypeConversionCanNotHandleArbitraryTypes diff --git a/src/test/java/com/xceptance/neodymium/tests/BrowserMultiplicationTest.java b/src/test/java/com/xceptance/neodymium/tests/BrowserMultiplicationTest.java index 4faaa9920..9a86700b3 100644 --- a/src/test/java/com/xceptance/neodymium/tests/BrowserMultiplicationTest.java +++ b/src/test/java/com/xceptance/neodymium/tests/BrowserMultiplicationTest.java @@ -8,14 +8,16 @@ import java.util.Map; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; import com.xceptance.neodymium.testclasses.multiplication.browser.OneBrowserOneMethod; import com.xceptance.neodymium.testclasses.multiplication.browser.OneBrowserTwoMethods; import com.xceptance.neodymium.testclasses.multiplication.browser.TwoBrowserOneMethod; import com.xceptance.neodymium.testclasses.multiplication.browser.TwoBrowserTwoMethods; +import com.xceptance.neodymium.util.Context; public class BrowserMultiplicationTest extends NeodymiumTest { @@ -31,7 +33,15 @@ public static void beforeClass() throws IOException tempConfigFile = File.createTempFile("browser", "", new File("./config/")); writeMapToPropertiesFile(properties, tempConfigFile); - MultibrowserConfiguration multibrowserConfiguration = MultibrowserConfiguration.getInstance(tempConfigFile.getPath()); + // this line is important as we initialize the config from the temporary file we created above + MultibrowserConfiguration.clearAllInstances(); + MultibrowserConfiguration.getInstance(tempConfigFile.getPath()); + } + + @Before + public void setJUnitViewModeFlat() + { + Context.get().configuration.setProperty("junit.viewmode", "flat"); } @AfterClass @@ -56,7 +66,7 @@ public void testOneBrowserOneMethod() throws Throwable { String[] expected = new String[] { - "first :: (first browser)" + "first :: Browser first_browser" }; checkDescription(OneBrowserOneMethod.class, expected); } @@ -66,8 +76,8 @@ public void testOneBrowserTwoMethods() throws Throwable { String[] expected = new String[] { - "first :: (first browser)", // - "second :: (first browser)" + "first :: Browser first_browser", // + "second :: Browser first_browser" }; checkDescription(OneBrowserTwoMethods.class, expected); } @@ -77,8 +87,8 @@ public void testTwoBrowserOneMethod() throws Throwable { String[] expected = new String[] { - "first :: (first browser)", // - "first :: (second browser)" + "first :: Browser first_browser", // + "first :: Browser second_browser" }; checkDescription(TwoBrowserOneMethod.class, expected); } @@ -88,10 +98,10 @@ public void testTwoBrowserTwoMethods() throws Throwable { String[] expected = new String[] { - "first :: (first browser)", // - "first :: (second browser)", // - "second :: (first browser)", // - "second :: (second browser)" + "first :: Browser first_browser", // + "first :: Browser second_browser", // + "second :: Browser first_browser", // + "second :: Browser second_browser" }; checkDescription(TwoBrowserTwoMethods.class, expected); } diff --git a/src/test/java/com/xceptance/neodymium/tests/BrowserStatementTest.java b/src/test/java/com/xceptance/neodymium/tests/BrowserStatementTest.java new file mode 100644 index 000000000..90fcc2e36 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/BrowserStatementTest.java @@ -0,0 +1,185 @@ +package com.xceptance.neodymium.tests; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration; +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.testclasses.browser.classonly.ClassBrowserSuppressed; +import com.xceptance.neodymium.testclasses.browser.classonly.ClassBrowserSuppressedNoBrowserAnnotation; +import com.xceptance.neodymium.testclasses.browser.classonly.EmptyBrowser; +import com.xceptance.neodymium.testclasses.browser.classonly.OneClassBrowserOneMethod; +import com.xceptance.neodymium.testclasses.browser.classonly.TwoClassBrowserOneMethod; +import com.xceptance.neodymium.testclasses.browser.classonly.TwoSameClassBrowserOneMethod; +import com.xceptance.neodymium.testclasses.browser.methodonly.MethodBrowserSuppressNoBrowserAnnotation; +import com.xceptance.neodymium.testclasses.browser.methodonly.OneBrowserOneMethodBrowserSuppressed; +import com.xceptance.neodymium.testclasses.browser.mixed.ClassAndMethodSameBrowserOneMethod; +import com.xceptance.neodymium.util.Context; + +public class BrowserStatementTest extends NeodymiumTest +{ + private static MultibrowserConfiguration browserConfig; + + @Before + public void setJUnitViewModeFlat() + { + Context.get().configuration.setProperty("junit.viewmode", "flat"); + } + + @BeforeClass + public static void beforeClass() throws IOException + { + Map properties = new HashMap<>(); + + properties.put("browserprofile.chrome.name", "Google Chrome"); + properties.put("browserprofile.chrome.browser", "chrome"); + properties.put("browserprofile.chrome.testEnvironment", "local"); + + properties.put("browserprofile.firefox.name", "Mozilla Firefox"); + properties.put("browserprofile.firefox.browser", "firefox"); + + File tempConfigFile = File.createTempFile("browser", "", new File("./config/")); + tempFiles.add(tempConfigFile); + writeMapToPropertiesFile(properties, tempConfigFile); + + MultibrowserConfiguration.clearAllInstances(); + browserConfig = MultibrowserConfiguration.getInstance(tempConfigFile.getPath()); + } + + @Test + public void testEmptyBrowser() + { + // an empty browser tag (@Browser({""})) should raise an error + Result result = JUnitCore.runClasses(EmptyBrowser.class); + checkFail(result, 1, 0, 1, "java.lang.IllegalArgumentException: Can not find browser configuration with tag: "); + } + + @Test + public void testTestBrowser() throws Throwable + { + // one test method and one browser annotated on class + String[] expected = new String[] + { + "first :: Browser chrome" + }; + checkDescription(OneClassBrowserOneMethod.class, expected); + } + + @Test + public void testClassBrowserSuppressed() throws Throwable + { + // + String[] expected = new String[] + { + "first" + }; + checkDescription(ClassBrowserSuppressed.class, expected); + } + + @Test + public void testTwoClassBrowserOneMethod() throws Throwable + { + String[] expected = new String[] + { + "first :: Browser chrome", "first :: Browser firefox" + }; + checkDescription(TwoClassBrowserOneMethod.class, expected); + } + + @Test + public void testTwoSameClassBrowserOneMethod() throws Throwable + { + // two browser annotated on class, both have same value + String[] expected = new String[] + { + "first :: Browser chrome" + }; + checkDescription(TwoSameClassBrowserOneMethod.class, expected); + } + + @Test + public void testClassAndMethodSameBrowserOneMethod() throws Throwable + { + // same browser annotated on class and method + String[] expected = new String[] + { + "first :: Browser chrome" + }; + checkDescription(ClassAndMethodSameBrowserOneMethod.class, expected); + } + + @Test + public void testClassBrowserSuppressedNoBrowserAnnotation() throws Throwable + { + // no browser definition but browser suppressed on class + String[] expected = new String[] + { + "first" + }; + checkDescription(ClassBrowserSuppressedNoBrowserAnnotation.class, expected); + } + + @Test + public void testName() throws Throwable + { + // no browser definition but browser suppressed on method + String[] expected = new String[] + { + "first" + }; + checkDescription(MethodBrowserSuppressNoBrowserAnnotation.class, expected); + } + + @Test + public void testOneBrowserOneMethodBrowserSuppressed() throws Throwable + { + // a browser definition on a method and a suppress browser + String[] expected = new String[] + { + "first" + }; + checkDescription(OneBrowserOneMethodBrowserSuppressed.class, expected); + } + + @Test + public void testMultibrowserConfiguration() throws Throwable + { + // define one chrome browser then validate the parsed multi-browser configuration + // TODO: we need more of this tests... + Map browserProfiles = browserConfig.getBrowserProfiles(); + // Assert.assertEquals(1, browserProfiles.size()); + + checkChrome(browserProfiles.get("chrome")); + checkFirefox(browserProfiles.get("firefox")); + } + + public void checkChrome(BrowserConfiguration config) + { + Assert.assertNotNull(config); + Assert.assertEquals("chrome", config.getConfigTag()); + Assert.assertEquals("Google Chrome", config.getName()); + Assert.assertEquals("local", config.getTestEnvironment()); + DesiredCapabilities testCapabilities = config.getCapabilities(); + Assert.assertEquals("chrome", testCapabilities.getBrowserName()); + } + + public void checkFirefox(BrowserConfiguration config) + { + Assert.assertNotNull(config); + Assert.assertEquals("firefox", config.getConfigTag()); + Assert.assertEquals("Mozilla Firefox", config.getName()); + Assert.assertEquals(null, config.getTestEnvironment()); + DesiredCapabilities testCapabilities = config.getCapabilities(); + Assert.assertEquals("firefox", testCapabilities.getBrowserName()); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/ContextTest.java b/src/test/java/com/xceptance/neodymium/tests/ContextTest.java new file mode 100644 index 000000000..070585177 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/ContextTest.java @@ -0,0 +1,62 @@ +package com.xceptance.neodymium.tests; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; + +import com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.MultibrowserConfiguration; +import com.xceptance.neodymium.testclasses.context.ContextGetsCleared; +import com.xceptance.neodymium.testclasses.context.DefaultSelenideTimeoutCheck; +import com.xceptance.neodymium.testclasses.context.cucumbercontextclear.CucumberContextGetsCleared; + +public class ContextTest extends NeodymiumTest +{ + private static File tempConfigFile; + + @BeforeClass + public static void beforeClass() throws IOException + { + Map properties = new HashMap<>(); + + properties.put("browserprofile.headless_chrome.name", "Headless Google Chrome"); + properties.put("browserprofile.headless_chrome.browser", "chrome"); + properties.put("browserprofile.headless_chrome.headless", "true"); + + tempConfigFile = File.createTempFile("browser", "", new File("./config/")); + tempFiles.add(tempConfigFile); + writeMapToPropertiesFile(properties, tempConfigFile); + + MultibrowserConfiguration.clearAllInstances(); + MultibrowserConfiguration.getInstance(tempConfigFile.getPath()); + } + + @Test + public void testContextGetCleared() throws Exception + { + // test that NeodymiumRunner clears the context before each run + Result result = JUnitCore.runClasses(ContextGetsCleared.class); + checkPass(result, 2, 0, 0); + } + + @Test + public void testCucumberContextGetsCleared() throws Exception + { + // test that NeodymiumCucumberRunListener clears the context before each run + Result result = JUnitCore.runClasses(CucumberContextGetsCleared.class); + checkPass(result, 4, 0, 0); + } + + @Test + public void testDefaultSelenideTimeoutCheck() throws Exception + { + Result result = JUnitCore.runClasses(DefaultSelenideTimeoutCheck.class); + checkPass(result, 2, 0, 0); + } + +} diff --git a/src/test/java/com/xceptance/neodymium/tests/DataUtilTest.java b/src/test/java/com/xceptance/neodymium/tests/DataUtilTest.java new file mode 100644 index 000000000..9aa606af1 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/DataUtilTest.java @@ -0,0 +1,18 @@ +package com.xceptance.neodymium.tests; + +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; + +import com.xceptance.neodymium.testclasses.datautils.DataUtilsTests; + +public class DataUtilTest extends NeodymiumTest +{ + @Test + public void testDataUtils() throws Exception + { + // test the data utils + Result result = JUnitCore.runClasses(DataUtilsTests.class); + checkPass(result, 6, 0, 0); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/MultiplicationTest.java b/src/test/java/com/xceptance/neodymium/tests/MultiplicationTest.java index 0c1c5682d..aab208209 100644 --- a/src/test/java/com/xceptance/neodymium/tests/MultiplicationTest.java +++ b/src/test/java/com/xceptance/neodymium/tests/MultiplicationTest.java @@ -1,5 +1,6 @@ package com.xceptance.neodymium.tests; +import org.junit.Before; import org.junit.Test; import com.xceptance.neodymium.testclasses.multiplication.TwoMethods; @@ -22,9 +23,17 @@ import com.xceptance.neodymium.testclasses.multiplication.parameteranddataset.TwoDataSetsTwoParameterSetsOneMethod; import com.xceptance.neodymium.testclasses.multiplication.parameteranddataset.TwoDataSetsTwoParameterSetsTwoMethods; import com.xceptance.neodymium.testclasses.multiplication.pkgdata.PackageDataDoNotAffectMethodMultiplication; +import com.xceptance.neodymium.util.Context; public class MultiplicationTest extends NeodymiumTest { + + @Before + public void setJUnitViewModeFlat() + { + Context.get().configuration.setProperty("junit.viewmode", "flat"); + } + ////////////////// // Methods only // ////////////////// @@ -72,7 +81,7 @@ public void testPackageDataDoNotAffectMethodMultiplication() throws Throwable // two methods, package test data do not affect multiplication String[] expected = new String[] { - "first", "second" + "first :: TestData", "second :: TestData" }; checkDescription(PackageDataDoNotAffectMethodMultiplication.class, expected); diff --git a/src/test/java/com/xceptance/neodymium/tests/NeodymiumBrowserRunnerTest.java b/src/test/java/com/xceptance/neodymium/tests/NeodymiumBrowserRunnerTest.java deleted file mode 100644 index 4888979c9..000000000 --- a/src/test/java/com/xceptance/neodymium/tests/NeodymiumBrowserRunnerTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.xceptance.neodymium.tests; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration; -import com.xceptance.neodymium.multibrowser.configuration.MultibrowserConfiguration; -import com.xceptance.neodymium.testclasses.browser.EmptyBrowser; -import com.xceptance.neodymium.testclasses.browser.NoBrowserTag; - -public class NeodymiumBrowserRunnerTest extends NeodymiumTest -{ - // holds files that will be deleted in @After method - static List tempFiles = new LinkedList<>(); - - private static MultibrowserConfiguration browserConfig; - - @BeforeClass - public static void beforeClass() throws IOException - { - Map properties = new HashMap<>(); - - properties.put("browserprofile.chrome.name", "Google Chrome"); - properties.put("browserprofile.chrome.browser", "chrome"); - properties.put("browserprofile.chrome.testEnvironment", "local"); - - properties.put("browserprofile.firefox.name", "Mozilla Firefox"); - properties.put("browserprofile.firefox.browser", "firefox"); - - File tempConfigFile = File.createTempFile("browser", "", new File("./config/")); - tempFiles.add(tempConfigFile); - writeMapToPropertiesFile(properties, tempConfigFile); - - browserConfig = MultibrowserConfiguration.getInstance(tempConfigFile.getPath()); - - } - - @Test - public void testEmptyBrowserTag() - { - // an empty @Browser({}) annotation shouldn't raise an error and shouldn't invoke a method - Result result = JUnitCore.runClasses(NoBrowserTag.class); - checkPass(result, 0, 0, 0); - } - - @Test - public void testEmptyBrowser() - { - // an empty browser tag (@Browser({""})) should raise an error - Result result = JUnitCore.runClasses(EmptyBrowser.class); - checkFail(result, 1, 0, 1, "Can not find browser configuration with tag: "); - } - - @Test - public void testMultibrowserConfiguration() throws Throwable - { - // define one chrome browser then validate the parsed multi-browser configuration - // TODO: we need more of this tests... - Map browserProfiles = browserConfig.getBrowserProfiles(); - // Assert.assertEquals(1, browserProfiles.size()); - - checkChrome(browserProfiles.get("chrome")); - checkFirefox(browserProfiles.get("firefox")); - } - - public void checkChrome(BrowserConfiguration config) - { - Assert.assertNotNull(config); - Assert.assertEquals("chrome", config.getConfigTag()); - Assert.assertEquals("Google Chrome", config.getName()); - Assert.assertEquals("local", config.getTestEnvironment()); - DesiredCapabilities testCapabilities = config.getCapabilities(); - Assert.assertEquals("chrome", testCapabilities.getBrowserName()); - } - - public void checkFirefox(BrowserConfiguration config) - { - Assert.assertNotNull(config); - Assert.assertEquals("firefox", config.getConfigTag()); - Assert.assertEquals("Mozilla Firefox", config.getName()); - Assert.assertEquals(null, config.getTestEnvironment()); - DesiredCapabilities testCapabilities = config.getCapabilities(); - Assert.assertEquals("firefox", testCapabilities.getBrowserName()); - } - - @AfterClass - public static void cleanUp() - { - for (File f : tempFiles) - { - if (f.exists()) - { - try - { - Files.delete(f.toPath()); - } - catch (Exception e) - { - System.out.println(MessageFormat.format("couldn''t delete temporary file: ''{0}'' caused by {1}", f.getAbsolutePath(), - e)); - } - } - } - } -} diff --git a/src/test/java/com/xceptance/neodymium/tests/NeodymiumDataRunnerTest.java b/src/test/java/com/xceptance/neodymium/tests/NeodymiumDataRunnerTest.java deleted file mode 100644 index 81eceadbe..000000000 --- a/src/test/java/com/xceptance/neodymium/tests/NeodymiumDataRunnerTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.xceptance.neodymium.tests; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; - -import com.xceptance.neodymium.testclasses.data.inheritance.child.PackageTestDataInheritance; -import com.xceptance.neodymium.testclasses.data.inheritance.child.grandchild.GrandChildPackageTestDataInheritance; -import com.xceptance.neodymium.testclasses.data.inheritance.child.grandchild.set.DataSetOverridesPackageData; -import com.xceptance.neodymium.testclasses.data.pkg.csv.CanReadPackageDataCSV; -import com.xceptance.neodymium.testclasses.data.pkg.json.CanReadPackageDataJson; -import com.xceptance.neodymium.testclasses.data.pkg.properties.CanReadPackageDataProperties; -import com.xceptance.neodymium.testclasses.data.pkg.xml.CanReadPackageDataXML; -import com.xceptance.neodymium.testclasses.data.set.csv.CanReadDataSetCSV; -import com.xceptance.neodymium.testclasses.data.set.json.CanReadDataSetJson; -import com.xceptance.neodymium.testclasses.data.set.properties.CanReadDataSetProperties; -import com.xceptance.neodymium.testclasses.data.set.xml.CanReadDataSetXML; -import com.xceptance.neodymium.util.Context; - -public class NeodymiumDataRunnerTest extends NeodymiumTest -{ - - @Before - public void beforeTest() - { - // we need to clear the context before test starts because all of the tests are running in the same thread and - // the context holds data based on the current thread. since data sets and package data is also stored in the - // context this data would never be updated - Context.clearThreadContext(); - } - - @Test - public void testCanReadPackageDataCSV() - { - // test package test data csv is read - Result result = JUnitCore.runClasses(CanReadPackageDataCSV.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadPackageDataJson() - { - // test package test data json is read - Result result = JUnitCore.runClasses(CanReadPackageDataJson.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadPackageDataProperties() - { - // test package test data properties is read - Result result = JUnitCore.runClasses(CanReadPackageDataProperties.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadPackageDataXML() - { - // test package test data xml is read - Result result = JUnitCore.runClasses(CanReadPackageDataXML.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadDataSetCSV() - { - // test data set csv is read - Result result = JUnitCore.runClasses(CanReadDataSetCSV.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadDataSetJson() - { - // test data set json is read - Result result = JUnitCore.runClasses(CanReadDataSetJson.class); - checkPass(result, 1, 0, 0); - } - - /** - * This test is ignored because property files are a fairly bad data set storage. We first need to decide what a - * propper layout would be. Maybe property files will be not supported for data sets but yaml instead. - */ - @Test - @Ignore - public void testCanReadDataSetProperties() - { - // test data set properties is read - Result result = JUnitCore.runClasses(CanReadDataSetProperties.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testCanReadDataSetXML() - { - // test data set xml is read - Result result = JUnitCore.runClasses(CanReadDataSetXML.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testPackageTestDataInheritance() - { - // test inheritacne of package test data - Result result = JUnitCore.runClasses(PackageTestDataInheritance.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testGrandChildPackageTestDataInheritance() - { - // test multiple inheritance of package test data - Result result = JUnitCore.runClasses(GrandChildPackageTestDataInheritance.class); - checkPass(result, 1, 0, 0); - } - - @Test - public void testDataSetOverridesPackageData() - { - // test that data set overrides package test data - Result result = JUnitCore.runClasses(DataSetOverridesPackageData.class); - checkPass(result, 1, 0, 0); - } -} diff --git a/src/test/java/com/xceptance/neodymium/tests/NeodymiumMethodRunnerTest.java b/src/test/java/com/xceptance/neodymium/tests/NeodymiumMethodRunnerTest.java deleted file mode 100644 index 46b2692b0..000000000 --- a/src/test/java/com/xceptance/neodymium/tests/NeodymiumMethodRunnerTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.xceptance.neodymium.tests; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; - -import com.xceptance.neodymium.testclasses.method.BeforeAndAfter; -import com.xceptance.neodymium.testclasses.method.ConstructorThrowsCheckedException; -import com.xceptance.neodymium.testclasses.method.ConstructorThrowsError; -import com.xceptance.neodymium.testclasses.method.FailingMethod; -import com.xceptance.neodymium.testclasses.method.IgnoredClass; -import com.xceptance.neodymium.testclasses.method.NoTestMethods; -import com.xceptance.neodymium.testclasses.method.TestAndIgnoreAnnotation; - -public class NeodymiumMethodRunnerTest extends NeodymiumTest -{ - @Test - public void testNoTestMethod() - { - // test there is nothing when no test method was found - Result result = JUnitCore.runClasses(NoTestMethods.class); - checkFail(result, 1, 0, 1, "No runnable methods"); - } - - @Test - public void testTestAndIgnoreAnnotation() - { - // test that NeodymiumRunner handles @Test and @Ignore correctly - Result result = JUnitCore.runClasses(TestAndIgnoreAnnotation.class); - checkPass(result, 1, 1, 0); - } - - @Test - public void testIgnoredClass() - { - // no method should be invoked in an ignored class - Result result = JUnitCore.runClasses(IgnoredClass.class); - checkPass(result, 0, 1, 0); - } - - @Test - public void testMethodFailing() - { - // test that a failing method fails the test - Result result = JUnitCore.runClasses(FailingMethod.class); - checkFail(result, 1, 0, 1, null); - } - - @Test - public void testConstructorThrowsCheckedException() - { - // test that the test fails if the constructor throws an exception - Result result = JUnitCore.runClasses(ConstructorThrowsCheckedException.class); - checkFail(result, 0, 0, 1, "java.lang.reflect.InvocationTargetException"); - } - - @Test - public void testConstructorThrowsError() - { - // test that the test fails if the constructor throws an error - Result result = JUnitCore.runClasses(ConstructorThrowsError.class); - checkFail(result, 0, 0, 1, "java.lang.reflect.InvocationTargetException"); - } - - @Test - public void testBeforeAndAfter() - { - // test @Before, @After, @BeforeClass, @AfterClass - Result result = JUnitCore.runClasses(BeforeAndAfter.class); - checkPass(result, 2, 0, 0); - String[] expected = new String[] - { - "beforeClass", // - "beforeMethod", // - "first", // - "afterMethod", // - "beforeMethod", // - "second", // - "afterMethod", // - "afterClass" - }; - String[] trace = BeforeAndAfter.TRACE.toArray(new String[0]); - Assert.assertArrayEquals(expected, trace); - } - -} diff --git a/src/test/java/com/xceptance/neodymium/tests/NeodymiumTest.java b/src/test/java/com/xceptance/neodymium/tests/NeodymiumTest.java index 2765b94ca..43385894e 100644 --- a/src/test/java/com/xceptance/neodymium/tests/NeodymiumTest.java +++ b/src/test/java/com/xceptance/neodymium/tests/NeodymiumTest.java @@ -2,10 +2,15 @@ import java.io.File; import java.io.FileOutputStream; +import java.nio.file.Files; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import org.junit.AfterClass; import org.junit.Assert; import org.junit.runner.Description; import org.junit.runner.Result; @@ -15,6 +20,30 @@ public abstract class NeodymiumTest { + + // holds files that will be deleted in @After method + static List tempFiles = new LinkedList<>(); + + @AfterClass + public static void cleanUp() + { + for (File f : tempFiles) + { + if (f.exists()) + { + try + { + Files.delete(f.toPath()); + } + catch (Exception e) + { + System.out.println(MessageFormat.format("couldn''t delete temporary file: ''{0}'' caused by {1}", f.getAbsolutePath(), + e)); + } + } + } + } + public void check(Result result, boolean expectedSuccessful, int expectedRunCount, int expectedIgnoreCount, int expectedFailCount, String expectedFailureMessage) { @@ -58,7 +87,7 @@ public void checkDescription(Description testDescription, String[] expectedTestD public void checkDescription(Class clazz, String[] expectedTestDescription) throws Throwable { - checkDescription(new NeodymiumRunner(clazz, null).getDescription(), expectedTestDescription); + checkDescription(new NeodymiumRunner(clazz).getDescription(), expectedTestDescription); } /** diff --git a/src/test/java/com/xceptance/neodymium/tests/NeodymiumParameterRunnerTest.java b/src/test/java/com/xceptance/neodymium/tests/ParameterStatementTest.java similarity index 76% rename from src/test/java/com/xceptance/neodymium/tests/NeodymiumParameterRunnerTest.java rename to src/test/java/com/xceptance/neodymium/tests/ParameterStatementTest.java index 4f2f38573..8bce0fde8 100644 --- a/src/test/java/com/xceptance/neodymium/tests/NeodymiumParameterRunnerTest.java +++ b/src/test/java/com/xceptance/neodymium/tests/ParameterStatementTest.java @@ -18,7 +18,7 @@ import com.xceptance.neodymium.testclasses.parameter.NonStaticGeneratorVoidReturn; import com.xceptance.neodymium.testclasses.parameter.ParameterFieldButNoGenerator; -public class NeodymiumParameterRunnerTest extends NeodymiumTest +public class ParameterStatementTest extends NeodymiumTest { @Test public void testParameterFieldWithoutGenerator() @@ -33,7 +33,8 @@ public void testNonStaticGeneratorVoidReturn() { // test a non static generator Result result = JUnitCore.runClasses(NonStaticGeneratorVoidReturn.class); - checkFail(result, 1, 0, 1, "No public static parameters method on class " + NonStaticGeneratorVoidReturn.class.getCanonicalName()); + checkFail(result, 1, 0, 1, "java.lang.Exception: No public static parameters method on class " + + NonStaticGeneratorVoidReturn.class.getCanonicalName()); } @Test @@ -41,7 +42,8 @@ public void testGeneratorVoidReturn() { // test generator void return type Result result = JUnitCore.runClasses(GeneratorVoidReturn.class); - checkFail(result, 1, 0, 1, GeneratorVoidReturn.class.getCanonicalName() + ".createData() must return an Iterable of arrays."); + checkFail(result, 1, 0, 1, "java.lang.RuntimeException: java.lang.Exception: " + GeneratorVoidReturn.class.getCanonicalName() + + ".createData() must return an Iterable of arrays."); } @Test @@ -49,7 +51,8 @@ public void testGeneratorObjectReturn() { // test generator returning object is not accidently castet to correct type Result result = JUnitCore.runClasses(GeneratorObjectReturn.class); - checkFail(result, 1, 0, 1, GeneratorObjectReturn.class.getCanonicalName() + ".createData() must return an Iterable of arrays."); + checkFail(result, 1, 0, 1, "java.lang.RuntimeException: java.lang.Exception: " + GeneratorObjectReturn.class.getCanonicalName() + + ".createData() must return an Iterable of arrays."); } @Test @@ -65,7 +68,7 @@ public void testGeneratorTooFewElements() { // one test iteration with two parameter fields, but just one data set Result result = JUnitCore.runClasses(GeneratorTooFewElements.class); - checkFail(result, 1, 0, 1, "java.lang.Exception: Number of parameters (1) and fields (2) annotated with @Parameter must match!"); + checkFail(result, 1, 0, 1, "Number of parameters (1) and fields (2) annotated with @Parameter must match!"); } @Test @@ -73,7 +76,7 @@ public void testGeneratorTooMuchElements() { // one test iteration with one data field, but two data sets Result result = JUnitCore.runClasses(GeneratorTooMuchElements.class); - checkFail(result, 1, 0, 1, "java.lang.Exception: Number of parameters (2) and fields (1) annotated with @Parameter must match!"); + checkFail(result, 1, 0, 1, "Number of parameters (2) and fields (1) annotated with @Parameter must match!"); } @Test @@ -90,7 +93,7 @@ public void testGeneratorAutoTypeConversionCanNotHandleArbitraryTypes() // test that auto type conversion from string to an arbitrary type fails Result result = JUnitCore.runClasses(GeneratorAutoTypeConversionCanNotHandleArbitraryTypes.class); checkFail(result, 1, 0, 1, - "java.lang.RuntimeException: Could not set parameter of type class java.lang.String to field \"browser\" of type class com.xceptance.neodymium.multibrowser.configuration.BrowserConfiguration. Value: a string can not be parsed to an arbitrary type"); + "Could not set parameter of type class java.lang.String to field \"browser\" of type class com.xceptance.neodymium.module.statement.browser.multibrowser.configuration.BrowserConfiguration. Value: a string can not be parsed to an arbitrary type"); } @Test @@ -106,7 +109,7 @@ public void testGeneratorCanNotSetFinalField() { // test that a final field can not be set Result result = JUnitCore.runClasses(GeneratorCanNotSetFinalField.class); - checkFail(result, 1, 0, 1, "java.lang.RuntimeException: Could not set parameter due to it is not public or it is final"); + checkFail(result, 1, 0, 1, "Could not set parameter due to it is not public or it is final"); } @Test @@ -114,7 +117,7 @@ public void testGeneratorCanNotSetPrivateSField() { // test that a private field can not be set Result result = JUnitCore.runClasses(GeneratorCanNotSetPrivateField.class); - checkFail(result, 1, 0, 1, "java.lang.RuntimeException: Could not set parameter due to it is not public or it is final"); + checkFail(result, 1, 0, 1, "Could not set parameter due to it is not public or it is final"); } @Test @@ -122,7 +125,6 @@ public void testGeneratorAutoTypeConversionFailsOnWrongInputData() { // test that auto type conversion from string fails if string content can not match Result result = JUnitCore.runClasses(GeneratorAutoTypeConversionFailsOnWrongInputData.class); - checkFail(result, 1, 0, 1, - "java.lang.RuntimeException: An error occured during conversion of input string \"true\" to type double for field \"aDouble\""); + checkFail(result, 1, 0, 1, "An error occured during conversion of input string \"true\" to type double for field \"aDouble\""); } } diff --git a/src/test/java/com/xceptance/neodymium/tests/TestDataStatementTest.java b/src/test/java/com/xceptance/neodymium/tests/TestDataStatementTest.java new file mode 100644 index 000000000..3e2de3dfd --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/TestDataStatementTest.java @@ -0,0 +1,357 @@ +package com.xceptance.neodymium.tests; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; + +import com.xceptance.neodymium.testclasses.data.inheritance.child.PackageTestDataInheritance; +import com.xceptance.neodymium.testclasses.data.inheritance.child.grandchild.GrandChildPackageTestDataInheritance; +import com.xceptance.neodymium.testclasses.data.inheritance.child.grandchild.set.DataSetOverridesPackageData; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassDefaultValueEmptyDataSets; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassDefaultValueNoDataSets; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassDefaultValueOneDataSet; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassDefaultValueTwoDataSets; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassExplicitDefaultValueTwoDataSets; +import com.xceptance.neodymium.testclasses.data.override.classonly.ClassMultipleSameDataSet; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodDefaultEmptyDataSets; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodDefaultNoDataSets; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodDefaultOneDataSet; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodDefaultTwoDataSet; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodExplicitDefaultTwoDataSets; +import com.xceptance.neodymium.testclasses.data.override.methodonly.MethodMultipleSameDataSet; +import com.xceptance.neodymium.testclasses.data.override.mixed.ClassWithoutTwoMethodsOneForced; +import com.xceptance.neodymium.testclasses.data.override.mixed.ForceOfNoneDataSets; +import com.xceptance.neodymium.testclasses.data.override.mixed.OneDataSetTwoMethodsOneWithout; +import com.xceptance.neodymium.testclasses.data.override.mixed.OnlyImplicitOneDataSet; +import com.xceptance.neodymium.testclasses.data.override.mixed.TwoDataSetsTwoMethodsOneForced; +import com.xceptance.neodymium.testclasses.data.override.mixed.TwoDataSetsTwoMethodsOneWithout; +import com.xceptance.neodymium.testclasses.data.pkg.csv.CanReadPackageDataCSV; +import com.xceptance.neodymium.testclasses.data.pkg.json.CanReadPackageDataJson; +import com.xceptance.neodymium.testclasses.data.pkg.properties.CanReadPackageDataProperties; +import com.xceptance.neodymium.testclasses.data.pkg.xml.CanReadPackageDataXML; +import com.xceptance.neodymium.testclasses.data.set.csv.CanReadDataSetCSV; +import com.xceptance.neodymium.testclasses.data.set.json.CanReadDataSetJson; +import com.xceptance.neodymium.testclasses.data.set.properties.CanReadDataSetProperties; +import com.xceptance.neodymium.testclasses.data.set.xml.CanReadDataSetXML; +import com.xceptance.neodymium.util.Context; + +public class TestDataStatementTest extends NeodymiumTest +{ + @Before + public void setJUnitViewModeFlat() + { + Context.get().configuration.setProperty("junit.viewmode", "flat"); + } + + @Test + public void testCanReadPackageDataCSV() + { + // test package test data csv is read + Result result = JUnitCore.runClasses(CanReadPackageDataCSV.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadPackageDataJson() + { + // test package test data json is read + Result result = JUnitCore.runClasses(CanReadPackageDataJson.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadPackageDataProperties() + { + // test package test data properties is read + Result result = JUnitCore.runClasses(CanReadPackageDataProperties.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadPackageDataXML() + { + // test package test data xml is read + Result result = JUnitCore.runClasses(CanReadPackageDataXML.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadDataSetCSV() + { + // test data set csv is read + Result result = JUnitCore.runClasses(CanReadDataSetCSV.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadDataSetJson() + { + // test data set json is read + Result result = JUnitCore.runClasses(CanReadDataSetJson.class); + checkPass(result, 1, 0, 0); + } + + /** + * This test is ignored because property files are a fairly bad data set storage. We first need to decide what a + * propper layout would be. Maybe property files will be not supported for data sets but yaml instead. + */ + @Test + @Ignore + public void testCanReadDataSetProperties() + { + // test data set properties is read + Result result = JUnitCore.runClasses(CanReadDataSetProperties.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testCanReadDataSetXML() + { + // test data set xml is read + Result result = JUnitCore.runClasses(CanReadDataSetXML.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testPackageTestDataInheritance() + { + // test inheritacne of package test data + Result result = JUnitCore.runClasses(PackageTestDataInheritance.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testGrandChildPackageTestDataInheritance() + { + // test multiple inheritance of package test data + Result result = JUnitCore.runClasses(GrandChildPackageTestDataInheritance.class); + checkPass(result, 1, 0, 0); + } + + @Test + public void testDataSetOverridesPackageData() + { + // test that data set overrides package test data + Result result = JUnitCore.runClasses(DataSetOverridesPackageData.class); + checkPass(result, 1, 0, 0); + } + + /////////////////////// + // Testdata override // + /////////////////////// + + // Class level override + + @Test + public void testClassDefaultValueNoDataSets() throws Throwable + { + // No data set file and @Testdata() on class + String[] expected = new String[] + { + "test1" + }; + checkDescription(ClassDefaultValueNoDataSets.class, expected); + } + + @Test + public void testClassDefaultValueEmptyDataSets() throws Throwable + { + // Empty data sets (only one key but no value) and @Testdata() on class + String[] expected = new String[] + { + "test1" + }; + checkDescription(ClassDefaultValueEmptyDataSets.class, expected); + } + + @Test + public void testClassDefaultValueOneDataSet() throws Throwable + { + // One data set and @Testdata() on class + String[] expected = new String[] + { + "test1 :: Data set 1 / 1" + }; + checkDescription(ClassDefaultValueOneDataSet.class, expected); + } + + @Test + public void testClassDefaultValueTwoDataSets() throws Throwable + { + // Two data sets and @Testdata() on class + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2" + }; + checkDescription(ClassDefaultValueTwoDataSets.class, expected); + } + + @Test + public void testClassExplicitDefaultValueTwoDataSets() throws Throwable + { + // Two data sets and explicit @Testdata(-1) on class + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2" + }; + checkDescription(ClassExplicitDefaultValueTwoDataSets.class, expected); + } + + @Test + public void testClassMultipleSameDataSet() throws Throwable + { + // One data set which is enforced on the class to perform two executions + String[] expected = new String[] + { + "test1 :: Data set 1 / 1, run #1", // + "test1 :: Data set 1 / 1, run #2" + }; + checkDescription(ClassMultipleSameDataSet.class, expected); + } + + // Method level override + + @Test + public void testMethodDefaultEmptyDataSets() throws Throwable + { + // Empty data sets (only one key but no value) and @Testdata() on method + String[] expected = new String[] + { + "test1" + }; + checkDescription(MethodDefaultEmptyDataSets.class, expected); + } + + @Test + public void testMethodDefaultNoDataSets() throws Throwable + { + // No data set file and @Testdata on method + String[] expected = new String[] + { + "test1" + }; + checkDescription(MethodDefaultNoDataSets.class, expected); + } + + @Test + public void testMethodDefaultOneDataSet() throws Throwable + { + // One data set and @Testdata on method + String[] expected = new String[] + { + "test1 :: Data set 1 / 1" + }; + checkDescription(MethodDefaultOneDataSet.class, expected); + } + + @Test + public void testMethodDefaultTwoDataSet() throws Throwable + { + // Two data sets and @Testdata on method + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2" + }; + checkDescription(MethodDefaultTwoDataSet.class, expected); + } + + @Test + public void testMethodExplicitDefaultTwoDataSets() throws Throwable + { + // Two data sets and explicit @Testdata(-1) on method + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2" + }; + checkDescription(MethodExplicitDefaultTwoDataSets.class, expected); + } + + @Test + public void testMethodMultipleSameDataSet() throws Throwable + { + // One data set, one method, method enforced to run data set twice + String[] expected = new String[] + { + "test1 :: Data set 1 / 1, run #1", // + "test1 :: Data set 1 / 1, run #2" + }; + checkDescription(MethodMultipleSameDataSet.class, expected); + } + + // mixed tests + + @Test + public void testOneDataSetTwoMethodsOneWithout() throws Throwable + { + // One data set, two methods, one method with @Testdata(0) + String[] expected = new String[] + { + "test1 :: Data set 1 / 1", // + "test2" + }; + checkDescription(OneDataSetTwoMethodsOneWithout.class, expected); + } + + @Test + public void testTwoDataSetsTwoMethodsOneWithout() throws Throwable + { + // One data set, two methods, one method with @Testdata(0) + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2", // + "test2" + }; + checkDescription(TwoDataSetsTwoMethodsOneWithout.class, expected); + } + + @Test + public void testTwoDataSetsTwoMethodsOneForced() throws Throwable + { + // One data set, two methods, one method with @Testdata(0) + String[] expected = new String[] + { + "test1 :: Data set 1 / 2", // + "test1 :: Data set 2 / 2", // + "test2 :: Data set 1 / 2" + }; + checkDescription(TwoDataSetsTwoMethodsOneForced.class, expected); + } + + @Test + public void testClassWithoutTwoMethodsOneForced() throws Throwable + { + // One data set, two methods, one method with @Testdata(0) + String[] expected = new String[] + { + "test1 :: Data set 1 / 1", // + "test2" + }; + checkDescription(ClassWithoutTwoMethodsOneForced.class, expected); + } + + @Test + public void testForceOfNoneDataSets() throws Exception + { + Result result = JUnitCore.runClasses(ForceOfNoneDataSets.class); + checkFail(result, 1, 0, 1, + "java.lang.IllegalArgumentException: Method 'test1' is marked to be run with data set index 2, but there are only 0"); + } + + @Test + public void testOnlyImplicitOneDataSet() throws Throwable + { + String[] expected = new String[] + { + "test1 :: Data set 1 / 1", // + }; + checkDescription(OnlyImplicitOneDataSet.class, expected); + } + +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/AbstractVisualAssertTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/ai/AbstractVisualAssertTest.java new file mode 100644 index 000000000..130cacbdb --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/ai/AbstractVisualAssertTest.java @@ -0,0 +1,29 @@ +package com.xceptance.neodymium.tests.visual.ai; + +import java.io.File; + +import org.junit.AfterClass; + +public abstract class AbstractVisualAssertTest +{ + + protected static final String propertiesFilePath = "config" + File.separator + "ai.properties"; + + protected static final String testFolderPath = "src" + File.separator + + "test" + File.separator + + "java" + File.separator + + "com" + File.separator + + "xceptance" + File.separator + + "neodymium" + File.separator + + "tests" + File.separator + + "visual" + File.separator + + "ai" + File.separator; + + protected static String networkPath; + + @AfterClass + public static void tearDown() + { + new File(networkPath).delete(); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Image_OneElement/Untitled1.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Image_OneElement/Untitled1.png new file mode 100644 index 000000000..639de22dc Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Image_OneElement/Untitled1.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 100 - Women's Wedges _ Shoes I Cole _ - http___www.colehaan.com_womens-shoes-wedges.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 100 - Women's Wedges _ Shoes I Cole _ - http___www.colehaan.com_womens-shoes-wedges.png new file mode 100644 index 000000000..b0512e8c1 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 100 - Women's Wedges _ Shoes I Cole _ - http___www.colehaan.com_womens-shoes-wedges.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 101 - Women's Handbags _ Tote & Crossbod_ - http___www.colehaan.com_womens-handbags.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 101 - Women's Handbags _ Tote & Crossbod_ - http___www.colehaan.com_womens-handbags.png new file mode 100644 index 000000000..86ad8468c Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 101 - Women's Handbags _ Tote & Crossbod_ - http___www.colehaan.com_womens-handbags.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 102 - Women's Hobos & _ - http___www.colehaan.com_womens-handbags-satchels-shoulder.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 102 - Women's Hobos & _ - http___www.colehaan.com_womens-handbags-satchels-shoulder.png new file mode 100644 index 000000000..50247b254 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 102 - Women's Hobos & _ - http___www.colehaan.com_womens-handbags-satchels-shoulder.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 103 - Women's Leather & _ - http___www.colehaan.com_womens-accessories-product-care.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 103 - Women's Leather & _ - http___www.colehaan.com_womens-accessories-product-care.png new file mode 100644 index 000000000..dec0d6fc5 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 103 - Women's Leather & _ - http___www.colehaan.com_womens-accessories-product-care.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 104 - Men's Bags _ Bags & Wallets I Cole Haan - http___www.colehaan.com_mens-bags.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 104 - Men's Bags _ Bags & Wallets I Cole Haan - http___www.colehaan.com_mens-bags.png new file mode 100644 index 000000000..6ba51e12f Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 104 - Men's Bags _ Bags & Wallets I Cole Haan - http___www.colehaan.com_mens-bags.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png new file mode 100644 index 000000000..11382b723 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png new file mode 100644 index 000000000..1d20460bd Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png new file mode 100644 index 000000000..3875dac63 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 96 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 96 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png new file mode 100644 index 000000000..89124e9cd Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 96 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 97 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 97 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png new file mode 100644 index 000000000..acf475426 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 97 - Women's ZEROGRAND Collection I Col_ - http___www.colehaan.com_womens-zerogrand.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 98 - New Shoes _ Women's Heel_ - http___www.colehaan.com_womens-whats-new-new-shoes.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 98 - New Shoes _ Women's Heel_ - http___www.colehaan.com_womens-whats-new-new-shoes.png new file mode 100644 index 000000000..0d4618be9 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 98 - New Shoes _ Women's Heel_ - http___www.colehaan.com_womens-whats-new-new-shoes.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 99 - Women's Ballet Flats _ _ - http___www.colehaan.com_womens-shoes-ballets-wedges.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 99 - Women's Ballet Flats _ _ - http___www.colehaan.com_womens-shoes-ballets-wedges.png new file mode 100644 index 000000000..a586fa0f0 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_ESF/FireShot Capture 99 - Women's Ballet Flats _ _ - http___www.colehaan.com_womens-shoes-ballets-wedges.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png new file mode 100644 index 000000000..11382b723 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png new file mode 100644 index 000000000..1d20460bd Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 106 - Men's Wallets & Card Case_ - http___www.colehaan.com_mens-accessories-wallets.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png new file mode 100644 index 000000000..3875dac63 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OIC/FireShot Capture 107 - Womens 2.ZEROGRAND Collection I _ - http___www.colehaan.com_womens-2zerogrand.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OICV/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OICV/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png new file mode 100644 index 000000000..11382b723 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/ai/Test_Images_OICV/FireShot Capture 105 - New Markdowns _ Mens Sale S_ - http___www.colehaan.com_mens-sale-newmarkdowns.png differ diff --git a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_ExactSameFolder.java b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorExactSameFolderTest.java similarity index 89% rename from src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_ExactSameFolder.java rename to src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorExactSameFolderTest.java index a581dc65d..0e5116596 100644 --- a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_ExactSameFolder.java +++ b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorExactSameFolderTest.java @@ -15,12 +15,10 @@ // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -package com.xceptance.neodymium.visual.ai.test; +package com.xceptance.neodymium.tests.visual.ai; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.net.URL; import java.util.ArrayList; import org.junit.BeforeClass; @@ -36,38 +34,29 @@ * * @author tvolkmann */ -public class Validator_ExactSameFolder +public class ValidatorExactSameFolderTest extends AbstractVisualAssertTest { + private final static String testFolderName = "Test_Images_ESF"; + @BeforeClass public static void setup() { - URL location = NetworkTrainer.class.getProtectionDomain().getCodeSource().getLocation(); - File file = new File(location.getPath()).getParentFile(); - - // /xlt-visual-assert/config - String propertieFile = file.toString() + File.separator + "config" + File.separator + "ai.properties"; - - // /xlt-visual-assert/src/test/com/xceptance/xlt/ai - String testFolderPath = file.toString() + File.separator + "src" + File.separator + - "test" + File.separator + "com" + File.separator + "xceptance" + - File.separator + "xlt" + File.separator + "ai" + File.separator; - // images for the Exact-Same-Folder (ESF) test - String testFolderName = "Test_Images_ESF"; - String completteFolderName = testFolderPath + testFolderName; + String completeFolderName = testFolderPath + testFolderName; String[] argTR = { - completteFolderName, + completeFolderName, testFolderPath, - propertieFile, + propertiesFilePath, testFolderName }; + networkPath = completeFolderName + ".network"; String[] argTE = { - completteFolderName + ".network", - completteFolderName + networkPath, + completeFolderName }; NetworkTrainer.main(argTR); diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneElementTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneElementTest.java new file mode 100644 index 000000000..f23978ca5 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneElementTest.java @@ -0,0 +1,51 @@ +package com.xceptance.neodymium.tests.visual.ai; + +import static org.junit.Assert.assertTrue; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.xceptance.neodymium.visual.ai.NetworkTester; +import com.xceptance.neodymium.visual.ai.NetworkTrainer; + +public class ValidatorOneElementTest extends AbstractVisualAssertTest +{ + private final static String testFolderName = "Test_Image_OneElement"; + + @BeforeClass + public static void setup() + { + // image with one group + String completeFolderName = testFolderPath + testFolderName; + + String[] argTR = + { + completeFolderName, + testFolderPath, + propertiesFilePath, + testFolderName + }; + + networkPath = completeFolderName + ".network"; + String[] argTE = + { + completeFolderName + ".network", + completeFolderName + }; + + NetworkTrainer.main(argTR); + NetworkTester.main(argTE); + } + + @Test + public void foundOneElement() + { + assertTrue(NetworkTrainer.im.getCurator().get(0).getMetricCurator().metricList.size() == 1); + } + + @Test + public void checkAverageMetric() + { + assertTrue(NetworkTester.an.getAverageMetric().size() == 1); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneImageContainedTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneImageContainedTest.java new file mode 100644 index 000000000..3a352e435 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/ai/ValidatorOneImageContainedTest.java @@ -0,0 +1,174 @@ +// Copyright 2017 Thomas Volkmann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +// and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package com.xceptance.neodymium.tests.visual.ai; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.xceptance.neodymium.visual.ai.NetworkTester; +import com.xceptance.neodymium.visual.ai.NetworkTrainer; +import com.xceptance.neodymium.visual.ai.image.AverageMetric; +import com.xceptance.neodymium.visual.ai.image.ImageStatistics; +import com.xceptance.neodymium.visual.ai.image.Metric; +import com.xceptance.neodymium.visual.ai.image.MetricCurator; +import com.xceptance.neodymium.visual.ai.image.PatternHelper; + +public class ValidatorOneImageContainedTest extends AbstractVisualAssertTest +{ + + private final static String testFolderName = "Test_Images_OIC"; + + private final static String testFolderNameValidation = "Test_Images_OICV"; + + @BeforeClass + public static void setup() + { + // images for the Exact-Same-Folder (ESF) test + String completeFolderName = testFolderPath + testFolderName; + String completeFolderNameValidation = testFolderPath + testFolderNameValidation; + + String[] argTR = + { + completeFolderName, + testFolderPath, + propertiesFilePath, + testFolderName + }; + + networkPath = completeFolderName + ".network"; + String[] argTE = + { + networkPath, + completeFolderNameValidation + }; + + NetworkTrainer.main(argTR); + NetworkTester.main(argTE); + } + + @Test + public void CreateTrainerAndTester() + { + assertTrue(NetworkTrainer.an != null); + assertTrue(NetworkTrainer.im != null); + + assertTrue(NetworkTester.an != null); + assertTrue(NetworkTester.im != null); + } + + @Test + public void ImageGroupsComparator() + { + for (int index = 0; index < NetworkTrainer.im.getCurator().size(); ++index) + { + MetricCurator trainerMetricCurator = NetworkTrainer.im.getCurator().get(index).getMetricCurator(); + MetricCurator testerMetricListCurator = NetworkTester.im.getCurator().get(0).getMetricCurator(); + + if (trainerMetricCurator.getTagName().equals(testerMetricListCurator.getTagName())) + { + assertTrue(trainerMetricCurator.metricList.size() == testerMetricListCurator.metricList.size()); + for (int ind = 0; ind < trainerMetricCurator.metricList.size(); ++ind) + { + Metric trainerMetric = trainerMetricCurator.metricList.get(ind); + Metric testerMetric = testerMetricListCurator.metricList.get(ind); + + assertTrue(trainerMetric.getGroupSize() == testerMetric.getGroupSize()); + assertTrue(trainerMetric.getBoundingBoxDistance() == testerMetric.getBoundingBoxDistance()); + + ImageStatistics trainerImageStatistic = trainerMetric.getImageStatistic(); + if (trainerImageStatistic != null) + { + ImageStatistics testerImageStatistic = testerMetric.getImageStatistic(); + assertTrue(trainerImageStatistic.getHistogramBlue().getMean() == testerImageStatistic.getHistogramBlue().getMean()); + assertTrue(trainerImageStatistic.getHistogramRed().getMean() == testerImageStatistic.getHistogramRed().getMean()); + assertTrue(trainerImageStatistic.getHistogramGreen().getMean() == testerImageStatistic.getHistogramGreen().getMean()); + } + } + } + } + } + + @Test + public void NetworkAverageMetric() + { + assertTrue(NetworkTrainer.an.getInputsCount() == NetworkTester.an.getInputsCount()); + assertTrue(NetworkTrainer.an.getAverageMetric().keySet().size() == NetworkTester.an.getAverageMetric().keySet().size()); + + int size = NetworkTrainer.an.getAverageMetric().keySet().size(); + + for (int index = 0; index < size; ++index) + { + AverageMetric trainerMetric = NetworkTrainer.an.getAverageMetric().get(index); + AverageMetric testerMetric = NetworkTester.an.getAverageMetric().get(index); + + assertTrue(trainerMetric.getAverageGroupSize() == testerMetric.getAverageGroupSize()); + assertTrue(trainerMetric.getAverageBoundingBoxSize() == testerMetric.getAverageBoundingBoxSize()); + assertTrue(trainerMetric.getAverageHistogramRedMean() == testerMetric.getAverageHistogramRedMean()); + assertTrue(trainerMetric.getAverageHistogramGreenMean() == testerMetric.getAverageHistogramGreenMean()); + assertTrue(trainerMetric.getAverageHistogramBlueMean() == testerMetric.getAverageHistogramBlueMean()); + } + } + + @Test + public void ActivationNetworkParameter() + { + assertTrue(NetworkTrainer.an.getLayer().inputsCount == NetworkTester.an.getLayer().inputsCount); + assertTrue(NetworkTrainer.an.getLayer().getActivationNeuron().getInputCount() == NetworkTester.an.getLayer().getActivationNeuron().getInputCount()); + assertTrue(NetworkTrainer.an.threshold == NetworkTester.an.getLayer().getActivationNeuron().getThreshold()); + assertTrue(NetworkTrainer.an.getLayer().getActivationNeuron().getWeight() == NetworkTester.an.getLayer().getActivationNeuron().getWeight()); + } + + @Test + public void PatternCalculatedResult() + { + ArrayList pattHelpTrainer = NetworkTrainer.im.updateInternalPattern(NetworkTrainer.im.getAverageMetric(), + NetworkTrainer.im.getCurator()); + ArrayList pattHelpTester = NetworkTester.im.updateInternalPattern(NetworkTester.im.getAverageMetric(), NetworkTester.im.getCurator()); + int recognized = 0; + + for (int index = 0; index < pattHelpTrainer.size(); ++index) + { + System.out.println(NetworkTrainer.an.checkForRecognitionAsString(pattHelpTrainer.get(index).getPatternList()) + " " + + NetworkTester.an.checkForRecognitionAsString(pattHelpTester.get(0).getPatternList())); + if (NetworkTester.an.checkForRecognitionAsString(pattHelpTrainer.get(index).getPatternList()) + .equals(NetworkTester.an.checkForRecognitionAsString(pattHelpTester.get(0).getPatternList()))) + { + ++recognized; + } + } + assertTrue(recognized == 1); + } + + @Test + public void CompareNeuronWeights() + { + assertTrue(NetworkTrainer.an.neurons.size() == NetworkTester.an.getLayer().getActivationNeuron().getNeurons().size()); + + int size = NetworkTester.an.getLayer().getActivationNeuron().getNeurons().size(); + + for (int index = 0; index < size; ++index) + { + assertTrue(NetworkTester.an.getLayer().getActivationNeuron().getNeurons().get(index).getWeight() == NetworkTrainer.an.neurons.get(index) + .getWeight()); + } + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/ImageTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/ImageTest.java new file mode 100644 index 000000000..95a6c729a --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/ImageTest.java @@ -0,0 +1,143 @@ +package com.xceptance.neodymium.tests.visual.pixel; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import org.apache.commons.lang3.ClassUtils; + +public abstract class ImageTest +{ + protected File resolveFile(final String name) + { + final String path = ClassUtils.getPackageName(this.getClass()).replace(".", "/"); + return new File("src/test/java/" + path + "/" + name); + } + + protected BufferedImage load(final File f) + { + try + { + return ImageIO.read(f); + } + catch (final IOException e) + { + throw new RuntimeException("File " + f.getAbsolutePath() + " not found!", e); + } + } + + private void write(final BufferedImage image, final String type, final File file) + { + try + { + ImageIO.write(image, type, file); + } + catch (final IOException e) + { + throw new RuntimeException(e); + } + } + + protected void write(final BufferedImage image, final String fileName) + { + write(image, "PNG", new File(fileName)); + } + + protected void writeToTmp(final BufferedImage image, final String fileName) + { + write(image, "PNG", new File(new File(System.getProperty("java.io.tmpdir")), fileName)); + } + + protected BufferedImage load(final String f) + { + return load(resolveFile(f)); + } + + protected boolean imageEqual(final BufferedImage img1, final BufferedImage img2) + { + if (img1 == null && img2 == null) + return true; + + if (img1 == null || img2 == null) + return false; + + for (int x = 0; x < img1.getWidth(); x++) + { + for (int y = 0; y < img1.getHeight(); y++) + { + // if the RGB values of 2 pixels differ + if (img1.getRGB(x, y) != img2.getRGB(x, y)) + { + return false; + } + } + } + + return true; + } + + protected BufferedImage createTestImageGradient(final Color startColor, final int r, final int g, final int b) throws IOException + { + final BufferedImage img = new BufferedImage(300, 13, BufferedImage.TYPE_INT_RGB); + + // white + final Graphics graphics = img.getGraphics(); + graphics.setColor(Color.WHITE); + graphics.fillRect(0, 0, img.getWidth(), img.getHeight()); + graphics.dispose(); + + int sR = startColor.getRed(); + int sG = startColor.getGreen(); + int sB = startColor.getBlue(); + + for (int w = 1; w < img.getWidth(); w = w + 3) + { + sR = sR + r; + sG = sG + g; + sB = sB + b; + + if (sR > 255 || sB > 255 || sG > 255) + { + break; + } + + img.setRGB(w, 7, new Color(sR, sG, sB).getRGB()); + } + + return img; + } + + protected BufferedImage createTestImage2DGradient(final Color startColor, final Color constant) throws IOException + { + final BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + + img.setRGB(0, 0, startColor.getRGB()); + + for (int w = 0; w < img.getWidth(); w++) + { + for (int h = 0; h < img.getWidth(); h++) + { + int color = 0; + if (constant == Color.RED) + { + color = new Color(0, w, h).getRGB(); + } + else if (constant == Color.GREEN) + { + color = new Color(w, 0, h).getRGB(); + } + else if (constant == Color.BLUE) + { + color = new Color(w, h, 0).getRGB(); + } + img.setRGB(w, h, color); + } + } + return img; + } + +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/TestComparator.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/TestComparator.java new file mode 100644 index 000000000..86a609ec2 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/TestComparator.java @@ -0,0 +1,129 @@ +package com.xceptance.neodymium.tests.visual.pixel; + +import java.awt.image.BufferedImage; +import java.text.MessageFormat; + +import org.junit.Assert; + +import com.xceptance.neodymium.visual.image.algorithm.ComparisonAlgorithm; +import com.xceptance.neodymium.visual.image.algorithm.ExactMatch; +import com.xceptance.neodymium.visual.image.util.ImageComparison; +import com.xceptance.neodymium.visual.image.util.MaskImage; +import com.xceptance.neodymium.visual.image.util.RectangleMask; + +public class TestComparator extends ImageTest +{ + private final RectangleMask differenceMarker; + + private final ComparisonAlgorithm algorithm; + + private ImageComparison comperator; + + private MaskImage masker; + + private BufferedImage referenceImage; + + private BufferedImage comparisonImage; + + private int markingSizeY; + + private int markingSizeX; + + public TestComparator() + { + this.algorithm = new ExactMatch(); + this.differenceMarker = new RectangleMask(10, 10); + } + + public TestComparator(final ComparisonAlgorithm algorithm, final RectangleMask differenceMarker, final int markingSizeX, final int markingSizeY) + { + this.algorithm = algorithm; + this.differenceMarker = differenceMarker; + this.markingSizeX = markingSizeX; + this.markingSizeY = markingSizeY; + } + + public TestComparator match(final String referenceImageFile) + { + return match(load(referenceImageFile)); + } + + public TestComparator match(final BufferedImage referenceImage) + { + this.referenceImage = referenceImage; + masker = new MaskImage(this.referenceImage); + + return this; + } + + public TestComparator to(final String comparisonImageFile) + { + return to(load(comparisonImageFile)); + } + + public TestComparator to(final BufferedImage comparisonImage) + { + this.comparisonImage = comparisonImage; + comperator = new ImageComparison(referenceImage); + + return this; + } + + public TestComparator isEqual() + { + Assert.assertTrue(comperator.isEqual(comparisonImage, masker, algorithm)); + return this; + } + + public TestComparator isNotEqual() + { + Assert.assertFalse(comperator.isEqual(comparisonImage, masker, algorithm)); + return this; + } + + public TestComparator train(final String trainImageFile) + { + return train(load(trainImageFile)); + } + + public TestComparator train(final BufferedImage trainImage) + { + masker.train(trainImage, algorithm, differenceMarker); + return this; + } + + public TestComparator hasMarking(final String markingFile) + { + return hasMarking(load(markingFile)); + } + + public TestComparator hasMarking(final BufferedImage marking) + { + final BufferedImage comperatorDifference = comperator.getMarkedImageWithBoxes(markingSizeX, markingSizeY); + + final long now = System.currentTimeMillis(); + writeToTmp(comperatorDifference, MessageFormat.format("actual.{0}.png", String.valueOf(now))); + writeToTmp(marking, MessageFormat.format("expected.{0}.png", String.valueOf(now))); + Assert.assertTrue(imageEqual(comperatorDifference, marking)); + + return this; + } + + public TestComparator hasNoMarking() + { + final BufferedImage comperatorDifference = comperator.getMarkedImageWithBoxes(markingSizeX, markingSizeY); + Assert.assertNull(comperatorDifference); + + return this; + } + + public MaskImage getMasker() + { + return masker; + } + + public ImageComparison getComperator() + { + return comperator; + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/ColorFuzzyTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/ColorFuzzyTest.java new file mode 100644 index 000000000..3e1cd8c4f --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/ColorFuzzyTest.java @@ -0,0 +1,161 @@ +package com.xceptance.neodymium.tests.visual.pixel.colorfuzzy; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.xceptance.neodymium.tests.visual.pixel.ImageTest; +import com.xceptance.neodymium.tests.visual.pixel.TestComparator; +import com.xceptance.neodymium.visual.image.algorithm.ColorFuzzy; +import com.xceptance.neodymium.visual.image.algorithm.ComparisonAlgorithm; +import com.xceptance.neodymium.visual.image.util.RectangleMask; + +public class ColorFuzzyTest extends ImageTest +{ + + ComparisonAlgorithm a = new ColorFuzzy(0.1); + + // how should a difference maSked during training + RectangleMask m = new RectangleMask(10, 10); + + // how difference should maRked in difference file + int mX = 10; + + int mY = 10; + + TestComparator T; + + @Before + public void setup() + { + T = new TestComparator(a, m, mX, mY); + } + + /** + * Test default, no difference + * + * @throws IOException + */ + @Test + public void sameSimple() + { + T.match("colorfuzzy/blank.png").to("colorfuzzy/blank.png").isEqual(); + } + + /** + * Test default, no difference + * + * @throws IOException + */ + @Test + public void samePhoto() + { + T.match("colorfuzzy/photo.png").to("colorfuzzy/photo.png").isEqual(); + } + + /** + * Test default, one pixel diff + * + * @throws IOException + */ + @Test + public void onePixelDifferenceBlack() + { + T.match("colorfuzzy/white-35x35.png").to("colorfuzzy/white-35x35-1pixel-1x1.png").isNotEqual() + .hasMarking("colorfuzzy/onePixelDifferenceBlack.png"); + } + + /** + * Test default, difference close to being a problem s + * + * @throws IOException + */ + @Test + public void grayIncreasingDefaultEqual() throws IOException + { + final BufferedImage b = createTestImageGradient(Color.BLACK, 5, 5, 5); + final BufferedImage c = createTestImageGradient(new Color(25, 25, 25), 5, 5, 5); + T.match(b).to(c).isEqual(); + } + + /** + * Test color difference 1 that should not trigger anything + * + * @throws IOException + */ + @Test + public void grayIncreasingDefaultEqual_Color10() throws IOException + { + final BufferedImage b = createTestImageGradient(Color.BLACK, 5, 5, 5); + final BufferedImage c = createTestImageGradient(new Color(50, 50, 91), 5, 5, 5); + + T = new TestComparator(new ColorFuzzy(1.0), m, mX, mY); + + T.match(b).to(c).isEqual(); + } + + /** + * Test with color difference 0, hence it is always different enough + * + * @throws IOException + */ + @Test + public void grayIncreasingDefaultNotEqual_Color00() throws IOException + { + final BufferedImage b = createTestImageGradient(Color.BLACK, 5, 5, 5); + final BufferedImage c = createTestImageGradient(new Color(25, 25, 25), 5, 5, 5); + + T = new TestComparator(new ColorFuzzy(0.0), m, 3, 3); + + T.match(b).to(c).isNotEqual().hasMarking("colorfuzzy/grayIncreasingDefaultNotEqual_Color00.png"); + } + + /** + * Test default, we have a difference that is enough to trigger something + * + * @throws IOException + */ + @Test + public void grayIncreasingDefaultNotEqual() throws IOException + { + final BufferedImage b = createTestImageGradient(Color.BLACK, 5, 5, 5); + final BufferedImage c = createTestImageGradient(new Color(30, 30, 30), 5, 5, 5); + + T = new TestComparator(a, m, 3, 3); + + T.match(b).to(c).isNotEqual().hasMarking("colorfuzzy/grayIncreasingDefaultNotEqual.png"); + } + + /** + * Test default, we have a difference that is enough to trigger something + * + * @throws IOException + */ + @Test + public void gradient2DBlack_Color01() throws IOException + { + final BufferedImage b = createTestImage2DGradient(Color.BLACK, Color.BLUE); + + T = new TestComparator(a, m, 1, 1); + + T.match(b).to("colorfuzzy/black-256x256.png").isNotEqual().hasMarking("colorfuzzy/gradient2DBlack_Color01.png"); + } + + /** + * Test default, we have a difference that is enough to trigger something + * + * @throws IOException + */ + @Test + public void gradient2DBlack_Color05() throws IOException + { + final BufferedImage b = createTestImage2DGradient(Color.BLACK, Color.BLUE); + + T = new TestComparator(new ColorFuzzy(0.5), m, 1, 1); + + T.match(b).to("colorfuzzy/black-256x256.png").isNotEqual().hasMarking("colorfuzzy/gradient2DBlack_Color05.png"); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/black-256x256.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/black-256x256.png new file mode 100644 index 000000000..77dd265d4 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/black-256x256.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/blank.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/blank.png new file mode 100644 index 000000000..50a8c57f2 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/blank.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color01.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color01.png new file mode 100644 index 000000000..e58f395ba Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color01.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color05.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color05.png new file mode 100644 index 000000000..f19631f0d Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DBlack_Color05.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_2_Color05.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_2_Color05.png new file mode 100644 index 000000000..3f49c3ab9 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_2_Color05.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_Color05.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_Color05.png new file mode 100644 index 000000000..d59504099 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/gradient2DRed_Color05.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual.png new file mode 100644 index 000000000..76d72e006 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual_Color00.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual_Color00.png new file mode 100644 index 000000000..62d7c93e6 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/grayIncreasingDefaultNotEqual_Color00.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/onePixelDifferenceBlack.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/onePixelDifferenceBlack.png new file mode 100644 index 000000000..bb96614de Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/onePixelDifferenceBlack.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/photo.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/photo.png new file mode 100644 index 000000000..1a23d7a5e Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/photo.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/red-256x256.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/red-256x256.png new file mode 100644 index 000000000..32cce87d2 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/red-256x256.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35-1pixel-1x1.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35-1pixel-1x1.png new file mode 100644 index 000000000..533bc41b9 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35-1pixel-1x1.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35.png new file mode 100644 index 000000000..a559cbe11 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/colorfuzzy/white-35x35.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/ExactMatchTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/ExactMatchTest.java new file mode 100644 index 000000000..ffd6469a5 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/ExactMatchTest.java @@ -0,0 +1,80 @@ +package com.xceptance.neodymium.tests.visual.pixel.exact; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.xceptance.neodymium.tests.visual.pixel.ImageTest; +import com.xceptance.neodymium.tests.visual.pixel.TestComparator; +import com.xceptance.neodymium.visual.image.algorithm.ComparisonAlgorithm; +import com.xceptance.neodymium.visual.image.algorithm.ExactMatch; +import com.xceptance.neodymium.visual.image.util.RectangleMask; + +public class ExactMatchTest extends ImageTest +{ + ComparisonAlgorithm a = new ExactMatch(); + + // how should a difference maSked during training + RectangleMask m = new RectangleMask(10, 10); + + // how difference should maRked in difference file + int mX = 10; + + int mY = 10; + + TestComparator T; + + @Before + public void setup() + { + T = new TestComparator(a, m, mX, mY); + } + + // TODO find reason for failure + @Test + @Ignore + public void blank() + { + T.match("exact/blank.png").to("exact/blank.png").isEqual().hasNoMarking(); + } + + // TODO find reason for failure + @Test + @Ignore + public void photo() + { + T.match("exact/photo.png").to("exact/photo.png").isEqual().hasNoMarking(); + } + + // TODO find reason for failure + @Test + @Ignore + public void photoSameButDifferentFile() + { + T.match("exact/photo.png").to("exact/photo2.png").isEqual().hasNoMarking(); + } + + @Test + public void noMatchPixelDiff() + { + T.match("exact/blank.png").to("exact/oneblackpixel.png").isNotEqual().hasMarking("exact/noMatchPixelDiff.png"); + } + + @Test + public void noMatchDifferentSize() + { + T.match("exact/photo.png").to("exact/photo-205x205.png").isNotEqual().hasMarking("exact/photo-205x205-MaskExpected.png"); + } + + @Test + public void noMatchDifferentSizeReversed() + { + T.match("exact/photo-205x205.png").to("exact/photo.png").isNotEqual().hasMarking("exact/photo-205x205-ReversedMaskExpected.png"); + } + + @Test + public void noMatchNegated() + { + T.match("exact/blank.png").to("exact/negated-blank.png").isNotEqual().hasMarking("exact/negated-MaskExpected.png"); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/blank.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/blank.png new file mode 100644 index 000000000..50a8c57f2 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/blank.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-MaskExpected.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-MaskExpected.png new file mode 100644 index 000000000..7b188de6d Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-MaskExpected.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-blank.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-blank.png new file mode 100644 index 000000000..92bd13473 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/negated-blank.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/noMatchPixelDiff.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/noMatchPixelDiff.png new file mode 100644 index 000000000..ab8c552d0 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/noMatchPixelDiff.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/oneblackpixel.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/oneblackpixel.png new file mode 100644 index 000000000..34628ddd9 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/oneblackpixel.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-MaskExpected.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-MaskExpected.png new file mode 100644 index 000000000..2495dddd5 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-MaskExpected.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-ReversedMaskExpected.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-ReversedMaskExpected.png new file mode 100644 index 000000000..f9fc5f6ae Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205-ReversedMaskExpected.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205.png new file mode 100644 index 000000000..94659ee35 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo-205x205.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo.png new file mode 100644 index 000000000..1a23d7a5e Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo2.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo2.png new file mode 100644 index 000000000..1a23d7a5e Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/exact/photo2.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/FuzzyTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/FuzzyTest.java new file mode 100644 index 000000000..eeeef71b5 --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/FuzzyTest.java @@ -0,0 +1,206 @@ +package com.xceptance.neodymium.tests.visual.pixel.fuzzy; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.xceptance.neodymium.tests.visual.pixel.ImageTest; +import com.xceptance.neodymium.tests.visual.pixel.TestComparator; +import com.xceptance.neodymium.visual.image.algorithm.ComparisonAlgorithm; +import com.xceptance.neodymium.visual.image.algorithm.PixelFuzzy; +import com.xceptance.neodymium.visual.image.util.RectangleMask; + +public class FuzzyTest extends ImageTest +{ + ComparisonAlgorithm a = new PixelFuzzy(0.1, 0.1, 10); + + // how should a difference maSked during training + RectangleMask m = new RectangleMask(10, 10); + + // how difference should maRked in difference file + int mX = 10; + + int mY = 10; + + TestComparator T; + + @Before + public void setup() + { + T = new TestComparator(a, m, mX, mY); + } + + /** + * Test default, no difference + * + * @throws IOException + */ + @Test + public void sameSimple() + { + T.match("fuzzy/blank.png").to("fuzzy/blank.png").isEqual(); + } + + /** + * Test default, no difference + * + * @throws IOException + */ + @Test + public void samePhoto() + { + T.match("fuzzy/photo.png").to("fuzzy/photo.png").isEqual(); + } + + /** + * Test default, no difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_10of100() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-10diff.png").isEqual(); + } + + /** + * Test default, difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_11of100() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-11diff.png").isNotEqual().hasMarking("fuzzy/diffPixel_01_11of100.png"); + } + + /** + * Test default, color difference limit not reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_10of100_colorUnderLimit() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-10diff-colorUnderLimit.png").isEqual(); + } + + /** + * Test default, no difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_11of100_colorUnderLimit() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-11diff-colorUnderLimit.png").isEqual(); + } + + /** + * Test default, no difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_100of100_colorUnderLimit() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-100diff-colorUnderLimit.png").isEqual(); + } + + /** + * Test default, no difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_100of100_colorUnderLimit_10of100_over() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-100of100_colorUnderLimit_10of100_over.png").isEqual(); + } + + /** + * Test default, no difference limit reached + * + * @throws IOException + */ + @Test + public void diffPixel_01_100of100_colorUnderLimit_11of100_over() + { + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-100of100_colorUnderLimit_11of100_over.png").isNotEqual(); + } + + /** + * Test no tolerance + * + * @throws IOException + */ + @Test + public void pixel_00_color_00() + { + T = new TestComparator(new PixelFuzzy(0, 0, 10), m, mX, mY); + + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10.png").isEqual(); + } + + /** + * Test no tolerance, one pixel diff + * + * @throws IOException + */ + @Test + public void pixel_00_color_00_1_pixeldiff() + { + T = new TestComparator(new PixelFuzzy(0, 0, 10), m, mX, mY); + + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-1diff-coloroverlimit.png").isNotEqual(); + } + + /** + * Test no tolerance, one pixel diff, very low diff + * + * @throws IOException + */ + @Test + public void pixel_00_color_00_1_pixeldiff_low_color() + { + T = new TestComparator(new PixelFuzzy(0, 0, 10), m, mX, mY); + + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-1diff-colordiffverylowlimit.png").isNotEqual(); + } + + /** + * Test more tolerance but on a smaller area + * + * @throws IOException + */ + @Test + public void pixel_02_color_02_dimension_3_noDifference() + { + T = new TestComparator(new PixelFuzzy(0.1, 0.1, 10), m, 3, 3); + + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10.png").isEqual(); + } + + /** + * Test more tolerance but on a smaller area + * + * @throws IOException + */ + @Test + public void pixel_02_color_02_dimension_3_difference_1_pixel() + { + // 0.9 pixels diff + T = new TestComparator(new PixelFuzzy(0.1, 0.1, 3), m, mX, mY); + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-1pixel.png").isNotEqual(); + + // 1/9 pixels diff + T = new TestComparator(new PixelFuzzy(0.11, 0.1, 3), m, mX, mY); + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-1pixel.png").isNotEqual(); + + // > 1/9 pixels diff + T = new TestComparator(new PixelFuzzy(0.12, 0.1, 3), m, mX, mY); + T.match("fuzzy/white-10x10.png").to("fuzzy/white-10x10-1pixel.png").isEqual(); + + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/blank.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/blank.png new file mode 100644 index 000000000..50a8c57f2 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/blank.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/diffPixel_01_11of100.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/diffPixel_01_11of100.png new file mode 100644 index 000000000..5e0ab3891 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/diffPixel_01_11of100.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/photo.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/photo.png new file mode 100644 index 000000000..1a23d7a5e Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/photo.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100diff-colorUnderLimit.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100diff-colorUnderLimit.png new file mode 100644 index 000000000..b8de1e3af Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100diff-colorUnderLimit.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_10of100_over.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_10of100_over.png new file mode 100644 index 000000000..25f03ad40 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_10of100_over.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_11of100_over.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_11of100_over.png new file mode 100644 index 000000000..8ce5f59ec Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-100of100_colorUnderLimit_11of100_over.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff-colorUnderLimit.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff-colorUnderLimit.png new file mode 100644 index 000000000..3b9bcba21 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff-colorUnderLimit.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff.png new file mode 100644 index 000000000..2f8b5b86a Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-10diff.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff-colorUnderLimit.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff-colorUnderLimit.png new file mode 100644 index 000000000..660339dbc Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff-colorUnderLimit.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff.png new file mode 100644 index 000000000..000b674dc Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-11diff.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-colordiffverylowlimit.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-colordiffverylowlimit.png new file mode 100644 index 000000000..c86072d57 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-colordiffverylowlimit.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-coloroverlimit.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-coloroverlimit.png new file mode 100644 index 000000000..22280dcfa Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1diff-coloroverlimit.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1pixel.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1pixel.png new file mode 100644 index 000000000..25e17ca25 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10-1pixel.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10.png new file mode 100644 index 000000000..1f8ca901d Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/fuzzy/white-10x10.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/MarkTest.java b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/MarkTest.java new file mode 100644 index 000000000..5b08f044b --- /dev/null +++ b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/MarkTest.java @@ -0,0 +1,128 @@ +package com.xceptance.neodymium.tests.visual.pixel.mark; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.xceptance.neodymium.tests.visual.pixel.ImageTest; +import com.xceptance.neodymium.tests.visual.pixel.TestComparator; +import com.xceptance.neodymium.visual.image.algorithm.ColorFuzzy; +import com.xceptance.neodymium.visual.image.algorithm.ComparisonAlgorithm; +import com.xceptance.neodymium.visual.image.algorithm.ExactMatch; +import com.xceptance.neodymium.visual.image.util.RectangleMask; + +public class MarkTest extends ImageTest +{ + ComparisonAlgorithm a = new ColorFuzzy(0.1); + + // how should a difference maSked during training + RectangleMask m = new RectangleMask(10, 10); + + // how difference should maRked in difference file + int mX = 10; + + int mY = 10; + + TestComparator T; + + @Before + public void setup() + { + T = new TestComparator(a, m, mX, mY); + } + + /** + * Test default marking + * + * @throws IOException + */ + @Test + public void pixel0x0() + { + T.match("mark/white-35x35.png").to("mark/white-35x35-1pixel-0x0.png").isNotEqual().hasMarking("mark/pixel0x0.png"); + } + + /** + * Test default marking, one pixel in + * + * @throws IOException + */ + @Test + public void pixel1x1() + { + T.match("mark/white-35x35.png").to("mark/white-35x35-1pixel-1x1.png").isNotEqual().hasMarking("mark/pixel1x1.png"); + } + + /** + * Test default marking, four pixels of all corners + * + * @throws IOException + */ + @Test + public void pixels10x10() + { + T.match("mark/white-35x35.png").to("mark/white-35x35-4pixels-10x10.png").isNotEqual().hasMarking("mark/pixels10x10.png"); + } + + /** + * Pixels in corners and one in the middle, shows smaller rectangles due to image size not being a total of 10. + * + * @throws IOException + */ + @Test + public void fivePixelsSmallerRect() + { + T.match("mark/white-35x35.png").to("mark/white-35x35-5pixels.png").isNotEqual().hasMarking("mark/fivePixelsSmallerRect.png"); + } + + /** + * Pixels in corners and one in the middle, shows smaller rectangles due to image size not being a total of 10. + * + * @throws IOException + */ + @Test + public void fivePixelsMark5x5() + { + T = new TestComparator(new ExactMatch(), m, 5, 5); + T.match("mark/white-35x35.png").to("mark/white-35x35-5pixels.png").isNotEqual().hasMarking("mark/fivePixelsMark5x5.png"); + } + + /** + * Pixels in corners and one in the middle, mark every pixel + * + * @throws IOException + */ + @Test + public void markPixelsOnly() + { + T = new TestComparator(new ExactMatch(), m, 1, 1); + T.match("mark/white-35x35.png").to("mark/white-35x35-5pixels.png").isNotEqual().hasMarking("mark/markPixelsOnly.png"); + } + + /** + * Pixels in corners and one in the middle, shows smaller rectangles due to image size not being a total of 10 and + * not square + * + * @throws IOException + */ + @Test + public void markNonSquare() + { + T = new TestComparator(new ExactMatch(), m, 5, 3); + T.match("mark/white-35x35.png").to("mark/white-35x35-5pixels.png").isNotEqual().hasMarking("mark/markNonSquare.png"); + } + + /** + * Pixels in corners and one in the middle, shows smaller rectangles due to image size not being a total of 10 and + * not square but very small + * + * @throws IOException + */ + @Test + public void markNonSquareClosed() + { + T = new TestComparator(new ExactMatch(), m, 2, 2); + T.match("mark/white-35x35.png").to("mark/white-35x35-5pixels.png").isNotEqual().hasMarking("mark/markNonSquareClosed.png"); + } +} diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsMark5x5.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsMark5x5.png new file mode 100644 index 000000000..5cab7cbcc Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsMark5x5.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsSmallerRect.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsSmallerRect.png new file mode 100644 index 000000000..7628729a4 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/fivePixelsSmallerRect.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquare.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquare.png new file mode 100644 index 000000000..0cdf75d3d Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquare.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquareClosed.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquareClosed.png new file mode 100644 index 000000000..12b2508f7 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markNonSquareClosed.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markPixelsOnly.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markPixelsOnly.png new file mode 100644 index 000000000..aed142a3f Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/markPixelsOnly.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel0x0.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel0x0.png new file mode 100644 index 000000000..be4619410 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel0x0.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel1x1.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel1x1.png new file mode 100644 index 000000000..bb96614de Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixel1x1.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixels10x10.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixels10x10.png new file mode 100644 index 000000000..be4619410 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/pixels10x10.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-0x0.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-0x0.png new file mode 100644 index 000000000..79e571230 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-0x0.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-1x1.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-1x1.png new file mode 100644 index 000000000..533bc41b9 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-1pixel-1x1.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-4pixels-10x10.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-4pixels-10x10.png new file mode 100644 index 000000000..8f9732d84 Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-4pixels-10x10.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-5pixels.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-5pixels.png new file mode 100644 index 000000000..3b70e67ed Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35-5pixels.png differ diff --git a/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35.png b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35.png new file mode 100644 index 000000000..9420ed22e Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/tests/visual/pixel/mark/white-35x35.png differ diff --git a/src/test/java/com/xceptance/neodymium/visual/ai/Test_Image_OneElement.network b/src/test/java/com/xceptance/neodymium/visual/ai/Test_Image_OneElement.network new file mode 100644 index 000000000..98914bfcb Binary files /dev/null and b/src/test/java/com/xceptance/neodymium/visual/ai/Test_Image_OneElement.network differ diff --git a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneElement.java b/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneElement.java deleted file mode 100644 index 35eb02ee8..000000000 --- a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneElement.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.xceptance.neodymium.visual.ai.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.net.URL; - -import org.junit.BeforeClass; -import org.junit.Test; - -import com.xceptance.neodymium.visual.ai.NetworkTester; -import com.xceptance.neodymium.visual.ai.NetworkTrainer; - -public class Validator_OneElement -{ - @BeforeClass - public static void setup() - { - URL location = NetworkTrainer.class.getProtectionDomain().getCodeSource().getLocation(); - File file = new File(location.getPath()).getParentFile(); - - // /xlt-visual-assert/config - String propertieFile = file.toString() + File.separator + "config" + File.separator + "ai.properties"; - - // /xlt-visual-assert/src/test/com/xceptance/xlt/ai - String testFolderPath = file.toString() + File.separator + "src" + File.separator + - "test" + File.separator + "com" + File.separator + "xceptance" + - File.separator + "xlt" + File.separator + "ai" + File.separator; - - // image with one group - String testFolderName = "Test_Image_OneElement"; - String completteFolderName = testFolderPath + testFolderName; - - String[] argTR = - { - completteFolderName, - testFolderPath, - propertieFile, - testFolderName - }; - - String[] argTE = - { - completteFolderName + ".network", - completteFolderName - }; - - NetworkTrainer.main(argTR); - NetworkTester.main(argTE); - } - - @Test - public void foundOneElement() - { - assertTrue(NetworkTrainer.im.getCurator().get(0).getMetricCurator().metricList.size() == 1); - } - - @Test - public void checkAverageMetric() - { - assertTrue(NetworkTester.an.getAverageMetric().size() == 1); - } -} diff --git a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneImageContained.java b/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneImageContained.java deleted file mode 100644 index fa7b8fbcb..000000000 --- a/src/test/java/com/xceptance/neodymium/visual/ai/test/Validator_OneImageContained.java +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2017 Thomas Volkmann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -// and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package com.xceptance.neodymium.visual.ai.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.net.URL; -import java.util.ArrayList; - -import org.junit.BeforeClass; -import org.junit.Test; - -import com.xceptance.neodymium.visual.ai.NetworkTester; -import com.xceptance.neodymium.visual.ai.NetworkTrainer; -import com.xceptance.neodymium.visual.ai.image.PatternHelper; - -public class Validator_OneImageContained -{ - @BeforeClass - public static void setup() - { - URL location = NetworkTrainer.class.getProtectionDomain().getCodeSource().getLocation(); - File file = new File(location.getPath()).getParentFile(); - - // /xlt-visual-assert/config - String propertieFile = file.toString() + File.separator + "config" + File.separator + "ai.properties"; - - // /xlt-visual-assert/src/test/com/xceptance/xlt/ai - String testFolderPath = file.toString() + File.separator + "src" + File.separator + - "test" + File.separator + "com" + File.separator + "xceptance" + - File.separator + "xlt" + File.separator + "ai" + File.separator; - - // images for the Exact-Same-Folder (ESF) test - String testFolderName = "Test_Images_OIC"; - String testFolderNameValidation = "Test_Images_OICV"; - String completteFolderName = testFolderPath + testFolderName; - String completeFolderNameValidation = testFolderPath + testFolderNameValidation; - - String[] argTR = - { - completteFolderName, - testFolderPath, - propertieFile, - testFolderName - }; - - String[] argTE = - { - completteFolderName + ".network", - completeFolderNameValidation - }; - - NetworkTrainer.main(argTR); - NetworkTester.main(argTE); - } - - @Test - public void CreateTrainerAndTester() - { - assertTrue(NetworkTrainer.an != null); - assertTrue(NetworkTrainer.im != null); - - assertTrue(NetworkTester.an != null); - assertTrue(NetworkTester.im != null); - } - - @Test - public void ImageGroupsComparator() - { - for (int index = 0; index < NetworkTrainer.im.getCurator().size(); ++index) - { - if (NetworkTrainer.im.getCurator().get(index).getMetricCurator().getTagName() - .equals(NetworkTester.im.getCurator().get(0).getMetricCurator().getTagName())) - { - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.size() == NetworkTester.im.getCurator().get(0).getMetricCurator().metricList.size()); - for (int ind = 0; ind < NetworkTrainer.im.getCurator().get(index).getMetricCurator().metricList.size(); ++ind) - { - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.get(ind) - .getGroupSize() == NetworkTester.im.getCurator().get(0) - .getMetricCurator().metricList.get(ind) - .getGroupSize()); - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.get(ind) - .getBoundingBoxDistance() == NetworkTester.im.getCurator().get(0) - .getMetricCurator().metricList.get(ind) - .getBoundingBoxDistance()); - if (NetworkTrainer.im.getCurator().get(index).getMetricCurator().metricList.get(ind).getImageStatistic() != null) - { - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.get(ind).getImageStatistic() - .getHistogramBlue() - .getMean() == NetworkTester.im.getCurator().get(0) - .getMetricCurator().metricList.get(ind) - .getImageStatistic() - .getHistogramBlue() - .getMean()); - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.get(ind).getImageStatistic() - .getHistogramRed() - .getMean() == NetworkTester.im.getCurator().get(0) - .getMetricCurator().metricList.get(ind) - .getImageStatistic() - .getHistogramRed() - .getMean()); - assertTrue(NetworkTrainer.im.getCurator().get(index) - .getMetricCurator().metricList.get(ind).getImageStatistic() - .getHistogramGreen() - .getMean() == NetworkTester.im.getCurator().get(0) - .getMetricCurator().metricList.get(ind) - .getImageStatistic() - .getHistogramGreen() - .getMean()); - } - } - } - } - } - - @Test - public void NetworkAverageMetric() - { - assertTrue(NetworkTrainer.an.getInputsCount() == NetworkTester.an.getInputsCount()); - assertTrue(NetworkTrainer.an.getAverageMetric().keySet().size() == NetworkTester.an.getAverageMetric().keySet().size()); - - int size = NetworkTrainer.an.getAverageMetric().keySet().size(); - - for (int index = 0; index < size; ++index) - { - assertTrue(NetworkTrainer.an.getAverageMetric().get(index).getAverageGroupSize() == NetworkTester.an.getAverageMetric().get(index) - .getAverageGroupSize()); - assertTrue(NetworkTrainer.an.getAverageMetric().get(index).getAverageBoundingBoxSize() == NetworkTester.an.getAverageMetric().get(index) - .getAverageBoundingBoxSize()); - assertTrue(NetworkTrainer.an.getAverageMetric().get(index).getAverageHistogramRedMean() == NetworkTester.an.getAverageMetric().get(index) - .getAverageHistogramRedMean()); - assertTrue(NetworkTrainer.an.getAverageMetric().get(index).getAverageHistogramGreenMean() == NetworkTester.an.getAverageMetric().get(index) - .getAverageHistogramGreenMean()); - assertTrue(NetworkTrainer.an.getAverageMetric().get(index).getAverageHistogramBlueMean() == NetworkTester.an.getAverageMetric().get(index) - .getAverageHistogramBlueMean()); - } - } - - @Test - public void ActivationNetworkParameter() - { - assertTrue(NetworkTrainer.an.getLayer().inputsCount == NetworkTester.an.getLayer().inputsCount); - assertTrue(NetworkTrainer.an.getLayer().getActivationNeuron().getInputCount() == NetworkTester.an.getLayer().getActivationNeuron().getInputCount()); - assertTrue(NetworkTrainer.an.threshold == NetworkTester.an.getLayer().getActivationNeuron().getThreshold()); - assertTrue(NetworkTrainer.an.getLayer().getActivationNeuron().getWeight() == NetworkTester.an.getLayer().getActivationNeuron().getWeight()); - } - - @Test - public void PatternCalculatedResult() - { - ArrayList patternListTrainer = NetworkTrainer.im.updateInternalPattern(NetworkTrainer.im.getAverageMetric(), - NetworkTrainer.im.getCurator()); - ArrayList patternListTester = NetworkTester.im.updateInternalPattern(NetworkTester.im.getAverageMetric(), NetworkTester.im.getCurator()); - int recognized = 0; - - for (int index = 0; index < patternListTrainer.size(); ++index) - { - System.out.println(NetworkTester.an.checkForRecognitionAsString(patternListTrainer.get(index).getPatternList()) + " " - + NetworkTester.an.checkForRecognitionAsString(patternListTester.get(0).getPatternList())); - if (NetworkTester.an.checkForRecognitionAsString(patternListTrainer.get(index).getPatternList()).equals( - NetworkTester.an.checkForRecognitionAsString(patternListTester.get(0) - .getPatternList()))) - { - ++recognized; - } - } - assertTrue(recognized == 1); - } - - @Test - public void CompareNeuronWeights() - { - assertTrue(NetworkTrainer.an.neurons.size() == NetworkTester.an.getLayer().getActivationNeuron().getNeurons().size()); - - int size = NetworkTester.an.getLayer().getActivationNeuron().getNeurons().size(); - - for (int index = 0; index < size; ++index) - { - assertTrue(NetworkTester.an.getLayer().getActivationNeuron().getNeurons().get(index).getWeight() == NetworkTrainer.an.neurons.get(index) - .getWeight()); - } - } -}