package org.fluentlenium.adapter;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.experimental.Delegate;
import org.fluentlenium.configuration.ConfigurationProperties.DriverLifecycle;
import org.openqa.selenium.WebDriver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
/**
* A singleton container for all running {@link SharedWebDriver} in the JVM.
*/
public enum SharedWebDriverContainer {
/**
* Singleton
*/
INSTANCE;
@Delegate
private final Impl impl = new Impl();
private final SharedWebDriverContainerShutdownHook shutdownHook; // NOPMD SingularField
/**
* Creates a new Shared WebDriver Container.
*/
SharedWebDriverContainer() {
shutdownHook = new SharedWebDriverContainerShutdownHook("SharedWebDriverContainerShutdownHook");
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
@EqualsAndHashCode
@AllArgsConstructor
private static class ClassAndTestName {
private Class<?> testClass;
private String testName;
}
/**
* Shared web driver container singleton implementation.
*/
static class Impl {
private SharedWebDriver jvmDriver;
private final Map<Class<?>, SharedWebDriver> classDrivers = new HashMap<>();
private final Map<ClassAndTestName, SharedWebDriver> methodDrivers = new HashMap<>();
/**
* Get an existing or create a new shared driver for the given test, with the given shared driver
* lifecycle strategy.
*
* @param webDriverFactory Supplier supplying new WebDriver instances
* @param testClass Test class
* @param testName Test name
* @param driverLifecycle shared driver lifecycle
* @param <T> type of test
* @return shared web driver
*/
public <T> SharedWebDriver getOrCreateDriver(Supplier<WebDriver> webDriverFactory, Class<T> testClass, String testName,
DriverLifecycle driverLifecycle) {
synchronized (this) {
SharedWebDriver driver = getDriver(testClass, testName, driverLifecycle);
if (driver == null) {
driver = createDriver(webDriverFactory, testClass, testName, driverLifecycle);
registerDriver(driver);
}
return driver;
}
}
private <T> SharedWebDriver createDriver(Supplier<WebDriver> webDriverFactory, Class<T> testClass, String testName,
DriverLifecycle driverLifecycle) {
WebDriver webDriver = webDriverFactory.get();
return new SharedWebDriver(webDriver, testClass, testName, driverLifecycle);
}
private void registerDriver(SharedWebDriver driver) {
switch (driver.getDriverLifecycle()) {
case JVM:
jvmDriver = driver;
break;
case CLASS:
classDrivers.put(driver.getTestClass(), driver);
break;
case METHOD:
default:
methodDrivers.put(new ClassAndTestName(driver.getTestClass(), driver.getTestName()), driver);
break;
}
}
/**
* Get the current driver for given test class.
*
* @param testClass test class
* @param testName test name
* @param driverLifecycle driver lifecycle
* @param <T> type of test class
* @return shared WebDriver
*/
public <T> SharedWebDriver getDriver(Class<T> testClass, String testName, DriverLifecycle driverLifecycle) {
synchronized (this) {
switch (driverLifecycle) {
case JVM:
return jvmDriver;
case CLASS:
return classDrivers.get(testClass);
case METHOD:
default:
return methodDrivers.get(new ClassAndTestName(testClass, testName));
}
}
}
/**
* Quit an existing shared driver.
*
* @param driver Shared WebDriver
*/
public void quit(SharedWebDriver driver) {
synchronized (this) {
switch (driver.getDriverLifecycle()) {
case JVM:
if (jvmDriver == driver) { // NOPMD CompareObjectsWithEquals
if (jvmDriver.getDriver() != null) {
jvmDriver.getDriver().quit();
}
jvmDriver = null;
}
break;
case CLASS:
SharedWebDriver classDriver = classDrivers.remove(driver.getTestClass());
if (classDriver == driver && classDriver.getDriver() != null) { // NOPMD CompareObjectsWithEquals
classDriver.getDriver().quit();
}
break;
case METHOD:
default:
SharedWebDriver testDriver = methodDrivers
.remove(new ClassAndTestName(driver.getTestClass(), driver.getTestName()));
if (testDriver == driver && testDriver.getDriver() != null) { // NOPMD CompareObjectsWithEquals
testDriver.getDriver().quit();
}
break;
}
}
}
/**
* Get all WebDriver of this container.
*
* @return List of {@link SharedWebDriver}
*/
public List<SharedWebDriver> getAllDrivers() {
List<SharedWebDriver> drivers = new ArrayList<>();
synchronized (this) {
if (jvmDriver != null) {
drivers.add(jvmDriver);
}
for (SharedWebDriver classDriver : classDrivers.values()) {
drivers.add(classDriver);
}
for (SharedWebDriver testDriver : methodDrivers.values()) {
drivers.add(testDriver);
}
}
return Collections.unmodifiableList(drivers);
}
/**
* Get all shared WebDriver of this container for a given test class.
*
* @param testClass test class
* @return list of shared WebDriver
*/
public List<SharedWebDriver> getTestClassDrivers(Class<?> testClass) {
List<SharedWebDriver> drivers = new ArrayList<>();
synchronized (this) {
SharedWebDriver classDriver = classDrivers.get(testClass);
if (classDriver != null) {
drivers.add(classDriver);
}
for (SharedWebDriver testDriver : methodDrivers.values()) {
if (testDriver.getTestClass() == testClass) {
drivers.add(testDriver);
}
}
return Collections.unmodifiableList(drivers);
}
}
/**
* Quit all shared web driver.
*/
public void quitAll() {
synchronized (this) {
if (jvmDriver != null) {
jvmDriver.getDriver().quit();
jvmDriver = null;
}
Iterator<SharedWebDriver> classDriversIterator = classDrivers.values().iterator();
while (classDriversIterator.hasNext()) {
classDriversIterator.next().getDriver().quit();
classDriversIterator.remove();
}
Iterator<SharedWebDriver> testDriversIterator = methodDrivers.values().iterator();
while (testDriversIterator.hasNext()) {
testDriversIterator.next().getDriver().quit();
testDriversIterator.remove();
}
}
}
}
}