com.lazerycode.selenium.SeleniumServerMojo Maven / Gradle / Ivy
Show all versions of driver-binary-downloader-maven-plugin Show documentation
package com.lazerycode.selenium;
import com.lazerycode.selenium.download.DownloadHandler;
import com.lazerycode.selenium.repository.*;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.resource.ResourceManager;
import org.codehaus.plexus.resource.loader.FileResourceCreationException;
import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import static com.lazerycode.selenium.repository.FileRepository.buildDownloadableFileRepository;
import static com.lazerycode.selenium.repository.OperatingSystem.getOperatingSystem;
import static com.lazerycode.selenium.repository.SystemArchitecture.getCurrentSystemArcitecture;
/**
* Selenium Standalone Server Maven Plugin
*
* @author Mark Collin
*/
@Mojo(name = "selenium", defaultPhase = LifecyclePhase.TEST_COMPILE)
@SuppressWarnings({"UnusedDeclaration"})
public class SeleniumServerMojo extends AbstractMojo {
/**
* Root directory where the standalone server file structure will be created and files will be saved
* <rootStandaloneServerDirectory>${project.basedir}/src/test/resources/webdriver/binaries</rootStandaloneServerDirectory>
*/
@Parameter(defaultValue = "${project.basedir}/src/test/resources/webdriver/binaries")
protected File rootStandaloneServerDirectory;
/**
* Directory where downloaded standalone executable zip files will be saved
* <downloadedZipFileDirectory>${project.basedir}/src/test/resources/webdriver/compressed_files</downloadedZipFileDirectory>
*/
@Parameter(defaultValue = "${project.basedir}/src/test/resources/webdriver/compressed_files")
protected File downloadedZipFileDirectory;
/**
* Path to the XML RepositoryMap
* <xmlRepositoryMap>${project.basedir}/src/test/resources/RepositoryMap.xml</xmlRepositoryMap>
*/
@Parameter
protected String customRepositoryMap;
/**
* Only get drivers that are compatible with the operating system running the plugin
* <onlyGetDriversForHostOperatingSystem>true</onlyGetDriversForHostOperatingSystem>
* If set to false this will download binary executables for all operating systems
*/
@Parameter(defaultValue = "true")
protected boolean onlyGetDriversForHostOperatingSystem;
/**
* The Operating systems you would like to download a standalone executable for
* <operatingSystems>
* <windows>true</windows>
* <linux>true</linux>
* <mac>true</mac>
* </operatingSystems>
* Unknown operating systems will cause an error to be thrown, only use the options shown above.
* WARNINGif onlyGetDriversForHostOperatingSystem is true, this will be ignored!
*/
@Parameter
protected Map operatingSystems;
/**
* Force download of 32 bit standalone executable
.
* <thirtyTwoBitBinaries>true</thirtyTwoBitBinaries>
*/
@Parameter(defaultValue = "false")
protected boolean thirtyTwoBitBinaries;
/**
* Force download of 64 bit standalone executable
* <sixtyFourBitBinaries>true</sixtyFourBitBinaries>
*/
@Parameter(defaultValue = "false")
protected boolean sixtyFourBitBinaries;
/**
* Force download of arm standalone executable
.
* <armBinaries>true</armBinaries>
*/
@Parameter(defaultValue = "false")
protected boolean armBinaries;
/**
* Only get the latest version of each standalone executable in RepositoryMap.xml
* <onlyGetLatestVersions>true</onlyGetLatestVersions>
* If set to false this will download all versions specified in the RepositoryMap.xml
* This will be ignored if specific executable versions have been specified
*/
@Parameter(defaultValue = "true")
protected boolean onlyGetLatestVersions;
/**
* A map of driver standalone versions to download
* <getSpecificExecutableVersions>
* <googlechrome>19</googlechrome>
* <internetexplorer>2.21.0</internetexplorer>
* </getSpecificExecutableVersions>
* Unrecognised browser names/versions will be ignored by default
*/
@Parameter
protected Map getSpecificExecutableVersions;
/**
* Throw an exception if any of the specified standalone versions do not exist in the repository map
*
* <throwExceptionIfSpecifiedVersionIsNotFound>false</throwExceptionIfSpecifiedVersionIsNotFound>
*
* This will cause a MojoFailureException to be thrown if any specific executable versions that have been specified do not exist in the RepositoryMap.xml
*/
@Parameter(defaultValue = "false")
protected boolean throwExceptionIfSpecifiedVersionIsNotFound;
/**
* Number of times to retry the file download of each executable
* <fileDownloadRetryAttempts>1</fileDownloadRetryAttempts>
*/
@Parameter(defaultValue = "1")
protected int fileDownloadRetryAttempts;
/**
* the number of milliseconds until this method will timeout if no connection could be established to remote file location
* <fileDownloadConnectTimeout>15000</fileDownloadConnectTimeout>
*/
@Parameter(defaultValue = "15000")
protected int fileDownloadConnectTimeout;
/**
* the number of milliseconds until this method will timeout if if no data could be read from remote file location
* <fileDownloadReadTimeout>15000</fileDownloadReadTimeout>
*/
@Parameter(defaultValue = "15000")
protected int fileDownloadReadTimeout;
/**
* If the environmental variables http.proxyHost, and http.proxyPort are set they will be used for http/https calls
* <useSystemProxy>true</useSystemProxy>
*/
@Parameter(defaultValue = "true")
protected boolean useSystemProxy;
/**
* Force the plugin to overwrite any files that have already been extracted from a valid zip file
* <overwriteFilesThatExist>false</overwriteFilesThatExist>
* crc checks are not performed on files that have been extracted from valid zips, they are assumed to be valid.
* This will force the plugin to extract everything from valid zips again and overwrite any existing files.
* This does not clean out old files, it only writes new files over the top of existing ones.
*/
@Parameter(defaultValue = "false")
protected boolean overwriteFilesThatExist;
/**
* Enable the file hash check for downloaded files
* <checkFileHashes>false</checkFileHashes>
* Setting this to false will skip all hash checks on downloaded files, this is not recommended.
* If you do not check the file hash there is no guarantee that the downloaded file is the correct file
*/
@Parameter(defaultValue = "true")
protected boolean checkFileHashes;
@Parameter(defaultValue = "${project}", required = true, readonly = true)
protected MavenProject project;
@Component
private ResourceManager locator;
protected InputStream xmlRepositoryMap = null;
private static final Logger LOG = Logger.getLogger(SeleniumServerMojo.class);
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
BasicConfigurator.configure(new MavenLoggerLog4jBridge(getLog()));
LOG.info(" ");
LOG.info("--------------------------------------------------------");
LOG.info(" DOWNLOADING SELENIUM STAND-ALONE EXECUTABLE BINARIES...");
LOG.info("--------------------------------------------------------");
LOG.info(" ");
setRepositoryMapFile();
if (fileDownloadRetryAttempts < 1) {
LOG.warn("Invalid number of retry attempts specified, defaulting to '1'...");
fileDownloadRetryAttempts = 1;
}
Map selectedOperatingSystems = new HashMap();
LOG.info("Only get drivers for current Operating System: " + this.onlyGetDriversForHostOperatingSystem);
//Calculate operating systems
Set osTypeList = new HashSet();
if (onlyGetDriversForHostOperatingSystem || null == operatingSystems || operatingSystems.size() < 1) {
LOG.info("Getting drivers for current operating system only.");
osTypeList = OperatingSystem.getCurrentOperatingSystemAsAHashSet();
} else {
for (Map.Entry os : this.operatingSystems.entrySet()) {
if (os.getValue().toLowerCase().equals("true")) {
osTypeList.add(getOperatingSystem(os.getKey()));
}
}
}
//Calculate system architecture
if (!thirtyTwoBitBinaries && !sixtyFourBitBinaries && !armBinaries) {
//TODO clean this up, maybe pass in a list of valid architectures later on
if (getCurrentSystemArcitecture().equals(SystemArchitecture.ARCHITECTURE_64_BIT)) {
sixtyFourBitBinaries = true;
} else if (getCurrentSystemArcitecture().equals(SystemArchitecture.ARCHITECTURE_ARM)) {
armBinaries = true;
} else {
thirtyTwoBitBinaries = true;
}
}
DriverMap driverRepository;
XMLParser parser = new XMLParser(xmlRepositoryMap, osTypeList, getSpecificExecutableVersions, thirtyTwoBitBinaries, sixtyFourBitBinaries);
try {
DownloadHandler standaloneExecutableDownloader = new DownloadHandler(
this.rootStandaloneServerDirectory,
this.downloadedZipFileDirectory,
this.fileDownloadRetryAttempts,
this.fileDownloadConnectTimeout,
this.fileDownloadReadTimeout,
buildDownloadableFileRepository(parser.getAllNodesInScope(), thirtyTwoBitBinaries, sixtyFourBitBinaries, armBinaries),
this.overwriteFilesThatExist,
this.checkFileHashes,
this.useSystemProxy,
this.onlyGetLatestVersions);
driverRepository = standaloneExecutableDownloader.ensureStandaloneExecutableFilesExist();
} catch (IOException e) {
throw new MojoExecutionException("Failed to download all of the standalone executables: " + e.getLocalizedMessage());
} catch (URISyntaxException e) {
throw new MojoExecutionException("Invalid URI detected: " + e.getLocalizedMessage());
} catch (XPathExpressionException | JAXBException rethrow) {
throw new MojoExecutionException(rethrow.getMessage());
}
setSystemProperties(driverRepository);
LOG.info(" ");
LOG.info("--------------------------------------------------------");
LOG.info("SELENIUM STAND-ALONE EXECUTABLE DOWNLOADS COMPLETE");
LOG.info("--------------------------------------------------------");
LOG.info(" ");
}
/**
* Set the system property webdriver.*.driver for the latest revision of each binary extracted.
*
* @param driverRepository map of drivers that system properties will be set for
*/
protected void setSystemProperties(DriverMap driverRepository) {
ArrayList driverContextsForCurrentOperatingSystem = driverRepository.getDriverContextsForCurrentOperatingSystem();
if (driverContextsForCurrentOperatingSystem.size() == 0) {
LOG.warn("No driver contexts detected for the current operating system, no maven properties set!");
}
for (DriverContext driverContext : driverContextsForCurrentOperatingSystem) {
DriverDetails driverDetails = driverRepository.getDetailsForLatestVersionOfDriverContext(driverContext);
LOG.info("Setting maven property - ${" + driverContext.getBinaryTypeForContext().getDriverSystemProperty() + "} = " + driverDetails.extractedLocation);
project.getProperties().setProperty(driverContext.getBinaryTypeForContext().getDriverSystemProperty(), driverDetails.extractedLocation);
}
}
private File getRepositoryMapFile(String customRepositoryMap) {
File repositoryMap;
try {
repositoryMap = locator.getResourceAsFile(customRepositoryMap);
} catch (ResourceNotFoundException | FileResourceCreationException e) {
LOG.info("Unable to find the specified custom repository map in dependencies, attempting to use value as a file path...");
LOG.info(" ");
repositoryMap = new File(customRepositoryMap);
}
return repositoryMap;
}
/**
* Set the RepositoryMap used to get file information.
* If the supplied map is invalid it will default to the pre-packaged one here.
*
* @throws MojoExecutionException
*/
private void setRepositoryMapFile() throws MojoExecutionException {
if (this.customRepositoryMap != null && !this.customRepositoryMap.isEmpty()) {
File repositoryMap = getRepositoryMapFile(this.customRepositoryMap);
if (repositoryMap.exists()) {
checkRepositoryMapIsValid(repositoryMap);
try {
this.xmlRepositoryMap = repositoryMap.toURI().toURL().openStream();
} catch (IOException ioe) {
throw new MojoExecutionException(ioe.getLocalizedMessage());
}
} else {
throw new MojoExecutionException("Repository map '" + repositoryMap.getAbsolutePath() + "' does not exist");
}
}
if (this.xmlRepositoryMap == null) {
this.xmlRepositoryMap = this.getClass().getResourceAsStream("/RepositoryMap.xml");
}
}
/**
* Validate any custom repository maps that are supplied against the xsd.
* Throw an error and stop if it is not valid.
* Assume it doesn't exist if we get an IOError and fall back to default file.
*
* @throws MojoExecutionException thrown if customRepositoryMap is not valid
*/
protected void checkRepositoryMapIsValid(File repositoryMap) throws MojoExecutionException {
URL schemaFile = this.getClass().getResource("/RepositoryMap.xsd");
Source xmlFile = new StreamSource(repositoryMap);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(xmlFile);
LOG.info("Repository map '" + xmlFile.getSystemId() + "' is valid");
LOG.info(" ");
} catch (SAXException | IOException ex) {
throw new MojoExecutionException(repositoryMap.getName() + " is not valid: " + ex.getLocalizedMessage());
}
}
}