loadLines(String filename) throws IOException {
- return loadLines(filename, null);
+ /**
+ * Add a command line argument, each argument must be set separately one by one.
+ *
+ * ${basedir}
in argument will be replaced by value of {@link #getBasedir()} during execution.
+ *
+ * @param cliArgument an argument to add
+ */
+ public void addCliArgument(String cliArgument) {
+ cliArguments.add(cliArgument);
}
- @Override
- public List loadFile(String basedir, String filename, boolean hasCommand) throws VerificationException {
- return super.loadFile(basedir, filename, hasCommand);
+ /**
+ * Add a command line arguments, each argument must be set separately one by one.
+ *
+ * ${basedir}
in argument will be replaced by value of {@link #getBasedir()} during execution.
+ *
+ * @param cliArguments an arguments list to add
+ */
+ public void addCliArguments(String... cliArguments) {
+ Collections.addAll(this.cliArguments, cliArguments);
}
- @Override
- public List loadFile(File file, boolean hasCommand) throws VerificationException {
- return super.loadFile(file, hasCommand);
+ public Properties getSystemProperties() {
+ return systemProperties;
}
- public File filterFile(String srcPath, String dstPath) throws IOException {
- return filterFile(srcPath, dstPath, (String) null);
+ public void setEnvironmentVariable(String key, String value) {
+ if (value != null) {
+ environmentVariables.put(key, value);
+ } else {
+ environmentVariables.remove(key);
+ }
}
- public File filterFile(String srcPath, String dstPath, Map filterMap) throws IOException {
- return super.filterFile(srcPath, dstPath, null, filterMap);
+ public String getBasedir() {
+ return basedir.toString();
+ }
+
+ public void setLogFileName(String logFileName) {
+ if (logFileName == null || logFileName.isEmpty()) {
+ throw new IllegalArgumentException("log file name unspecified");
+ }
+ this.logFileName = logFileName;
+ this.logFile = this.basedir.resolve(this.logFileName);
+ }
+
+ public void setAutoclean(boolean autoClean) {
+ this.autoClean = autoClean;
+ }
+
+ public void setForkJvm(boolean forkJvm) {
+ this.forkJvm = forkJvm;
+ }
+
+ public void setHandleLocalRepoTail(boolean handleLocalRepoTail) {
+ this.handleLocalRepoTail = handleLocalRepoTail;
+ }
+
+ public String getLocalRepository() {
+ return getLocalRepositoryWithSettings(null);
+ }
+
+ public String getLocalRepositoryWithSettings(String settingsXml) {
+ String outerHead = System.getProperty("maven.repo.local", "").trim();
+ if (!outerHead.isEmpty()) {
+ return outerHead;
+ } else if (settingsXml != null) {
+ // when invoked with settings.xml, the file must be resolved from basedir (as Maven does)
+ // but we should not use basedir, as it may contain extensions.xml or a project, that Maven will eagerly
+ // load, and may fail, as it would need more (like CI friendly versioning, etc).
+ // if given, it must exist
+ Path settingsFile = basedir.resolve(settingsXml).toAbsolutePath().normalize();
+ if (!Files.isRegularFile(settingsFile)) {
+ throw new IllegalArgumentException("settings xml does not exist: " + settingsXml);
+ }
+ return executorHelper.localRepository(executorHelper
+ .executorRequest()
+ .cwd(tempBasedir)
+ .userHomeDirectory(userHomeDirectory)
+ .argument("-s")
+ .argument(settingsFile.toString()));
+ } else {
+ return executorHelper.localRepository(
+ executorHelper.executorRequest().cwd(tempBasedir).userHomeDirectory(userHomeDirectory));
+ }
+ }
+
+ private String getLogContents(Path logFile) {
+ try {
+ return Files.readString(logFile);
+ } catch (IOException e) {
+ return "(Error reading log contents: " + e.getMessage() + ")";
+ }
+ }
+
+ public String getLogFileName() {
+ return logFileName;
+ }
+
+ public Path getLogFile() {
+ return logFile;
+ }
+
+ public void verifyErrorFreeLog() throws VerificationException {
+ List lines = loadFile(logFile.toFile(), false);
+
+ for (String line : lines) {
+ // A hack to keep stupid velocity resource loader errors from triggering failure
+ if (stripAnsi(line).contains("[ERROR]") && !isVelocityError(line)) {
+ throw new VerificationException("Error in execution: " + line);
+ }
+ }
}
/**
@@ -82,10 +389,6 @@ public class Verifier extends org.apache.maven.shared.verifier.Verifier {
verifyTextNotInLog(loadLogLines(), text);
}
- public long textOccurrencesInLog(String text) throws IOException {
- return textOccurencesInLog(loadLogLines(), text);
- }
-
public static void verifyTextNotInLog(List lines, String text) throws VerificationException {
if (textOccurencesInLog(lines, text) > 0) {
throw new VerificationException("Text found in log: " + text);
@@ -98,11 +401,625 @@ public class Verifier extends org.apache.maven.shared.verifier.Verifier {
}
}
+ public long textOccurrencesInLog(String text) throws IOException {
+ return textOccurencesInLog(loadLogLines(), text);
+ }
+
public static long textOccurencesInLog(List lines, String text) {
return lines.stream().filter(line -> stripAnsi(line).contains(text)).count();
}
- public void execute() throws VerificationException {
- super.execute();
+ /**
+ * Checks whether the specified line is just an error message from Velocity. Especially old versions of Doxia employ
+ * a very noisy Velocity instance.
+ *
+ * @param line The log line to check, must not be null
.
+ * @return true
if the line appears to be a Velocity error, false
otherwise.
+ */
+ private static boolean isVelocityError(String line) {
+ return line.contains("VM_global_library.vm") || line.contains("VM #") && line.contains("macro");
+ }
+
+ /**
+ * Throws an exception if the text is not present in the log.
+ *
+ * @param text the text to assert present
+ * @throws VerificationException if text is not found in log
+ */
+ public void verifyTextInLog(String text) throws VerificationException {
+ List lines = loadFile(logFile.toFile(), false);
+
+ boolean result = false;
+ for (String line : lines) {
+ if (stripAnsi(line).contains(text)) {
+ result = true;
+ break;
+ }
+ }
+ if (!result) {
+ throw new VerificationException("Text not found in log: " + text);
+ }
+ }
+
+ public static String stripAnsi(String msg) {
+ return msg.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", "");
+ }
+
+ public Properties loadProperties(String filename) throws VerificationException {
+ Properties properties = new Properties();
+
+ File propertiesFile = new File(getBasedir(), filename);
+ try (FileInputStream fis = new FileInputStream(propertiesFile)) {
+ properties.load(fis);
+ } catch (IOException e) {
+ throw new VerificationException("Error reading properties file", e);
+ }
+
+ return properties;
+ }
+
+ /**
+ * Loads the (non-empty) lines of the specified text file.
+ *
+ * @param filename The path to the text file to load, relative to the base directory, must not be null
.
+ * @param encoding The character encoding of the file, may be null
or empty to use the platform default
+ * encoding.
+ * @return The list of (non-empty) lines from the text file, can be empty but never null
.
+ * @throws IOException If the file could not be loaded.
+ * @since 1.2
+ */
+ public List loadLines(String filename, String encoding) throws IOException {
+ List lines = new ArrayList<>();
+ try (BufferedReader reader = getReader(filename, encoding)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (!line.isEmpty()) {
+ lines.add(line);
+ }
+ }
+ }
+ return lines;
+ }
+
+ private BufferedReader getReader(String filename, String encoding) throws IOException {
+ File file = new File(getBasedir(), filename);
+ if (encoding != null && !encoding.isEmpty()) {
+ return Files.newBufferedReader(file.toPath(), Charset.forName(encoding));
+ } else {
+ return Files.newBufferedReader(file.toPath());
+ }
+ }
+
+ public List loadFile(String basedir, String filename, boolean hasCommand) throws VerificationException {
+ return loadFile(new File(basedir, filename), hasCommand);
+ }
+
+ public List loadFile(File file, boolean hasCommand) throws VerificationException {
+ List lines = new ArrayList<>();
+
+ if (file.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ String line = reader.readLine();
+
+ while (line != null) {
+ line = line.trim();
+
+ if (!line.startsWith("#") && !line.isEmpty()) {
+ lines.addAll(replaceArtifacts(line, hasCommand));
+ }
+ line = reader.readLine();
+ }
+ } catch (IOException e) {
+ throw new VerificationException(e);
+ }
+ }
+
+ return lines;
+ }
+
+ public String loadLogContent() throws IOException {
+ return Files.readString(getLogFile());
+ }
+
+ public List loadLogLines() throws IOException {
+ return loadLines(getLogFileName());
+ }
+
+ public List loadLines(String filename) throws IOException {
+ return loadLines(filename, null);
+ }
+
+ private static final String MARKER = "${artifact:";
+
+ private List replaceArtifacts(String line, boolean hasCommand) {
+ int index = line.indexOf(MARKER);
+ if (index >= 0) {
+ String newLine = line.substring(0, index);
+ index = line.indexOf("}", index);
+ if (index < 0) {
+ throw new IllegalArgumentException("line does not contain ending artifact marker: '" + line + "'");
+ }
+ String artifact = line.substring(newLine.length() + MARKER.length(), index);
+
+ newLine += getArtifactPath(artifact);
+ newLine += line.substring(index + 1);
+
+ List l = new ArrayList<>();
+ l.add(newLine);
+
+ int endIndex = newLine.lastIndexOf('/');
+
+ String command = null;
+ String filespec;
+ if (hasCommand) {
+ int startIndex = newLine.indexOf(' ');
+
+ command = newLine.substring(0, startIndex);
+
+ filespec = newLine.substring(startIndex + 1, endIndex);
+ } else {
+ filespec = newLine;
+ }
+
+ File dir = new File(filespec);
+ addMetadataToList(dir, hasCommand, l, command);
+ addMetadataToList(dir.getParentFile(), hasCommand, l, command);
+
+ return l;
+ } else {
+ return Collections.singletonList(line);
+ }
+ }
+
+ private static void addMetadataToList(File dir, boolean hasCommand, List l, String command) {
+ if (dir.exists() && dir.isDirectory()) {
+ String[] files = dir.list(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.startsWith("maven-metadata") && name.endsWith(".xml");
+ }
+ });
+
+ for (String file : files) {
+ if (hasCommand) {
+ l.add(command + " " + new File(dir, file).getPath());
+ } else {
+ l.add(new File(dir, file).getPath());
+ }
+ }
+ }
+ }
+
+ private String getArtifactPath(String artifact) {
+ StringTokenizer tok = new StringTokenizer(artifact, ":");
+ if (tok.countTokens() != 4) {
+ throw new IllegalArgumentException("Artifact must have 4 tokens: '" + artifact + "'");
+ }
+
+ String[] a = new String[4];
+ for (int i = 0; i < 4; i++) {
+ a[i] = tok.nextToken();
+ }
+
+ String groupId = a[0];
+ String artifactId = a[1];
+ String version = a[2];
+ String ext = a[3];
+ return getArtifactPath(groupId, artifactId, version, ext);
+ }
+
+ public String getArtifactPath(String groupId, String artifactId, String version, String ext) {
+ return getArtifactPath(groupId, artifactId, version, ext, null);
+ }
+
+ /**
+ * Returns the absolute path to the artifact denoted by groupId, artifactId, version, extension and classifier.
+ *
+ * @param gid The groupId, must not be null.
+ * @param aid The artifactId, must not be null.
+ * @param version The version, must not be null.
+ * @param ext The extension, must not be null.
+ * @param classifier The classifier, may be null to be omitted.
+ * @return the absolute path to the artifact denoted by groupId, artifactId, version, extension and classifier,
+ * never null.
+ */
+ public String getArtifactPath(String gid, String aid, String version, String ext, String classifier) {
+ if (classifier != null && classifier.isEmpty()) {
+ classifier = null;
+ }
+ if ("maven-plugin".equals(ext)) {
+ ext = "jar";
+ } else if ("coreit-artifact".equals(ext)) {
+ ext = "jar";
+ classifier = "it";
+ } else if ("test-jar".equals(ext)) {
+ ext = "jar";
+ classifier = "tests";
+ }
+
+ String gav;
+ if (classifier != null) {
+ gav = gid + ":" + aid + ":" + ext + ":" + classifier + ":" + version;
+ } else {
+ gav = gid + ":" + aid + ":" + ext + ":" + version;
+ }
+ return getLocalRepository()
+ + File.separator
+ + executorHelper.artifactPath(executorHelper.executorRequest(), gav, null);
+ }
+
+ public List getArtifactFileNameList(String org, String name, String version, String ext) {
+ List files = new ArrayList<>();
+ String artifactPath = getArtifactPath(org, name, version, ext);
+ File dir = new File(artifactPath);
+ files.add(artifactPath);
+ addMetadataToList(dir, false, files, null);
+ addMetadataToList(dir.getParentFile(), false, files, null);
+ return files;
+ }
+
+ /**
+ * Gets the path to the local artifact metadata. Note that the method does not check whether the returned path
+ * actually points to existing metadata.
+ *
+ * @param gid The group id, must not be null
.
+ * @param aid The artifact id, must not be null
.
+ * @param version The artifact version, may be null
.
+ * @return The (absolute) path to the local artifact metadata, never null
.
+ */
+ public String getArtifactMetadataPath(String gid, String aid, String version) {
+ return getArtifactMetadataPath(gid, aid, version, "maven-metadata.xml");
+ }
+
+ /**
+ * Gets the path to a file in the local artifact directory. Note that the method does not check whether the returned
+ * path actually points to an existing file.
+ *
+ * @param gid The group id, must not be null
.
+ * @param aid The artifact id, may be null
.
+ * @param version The artifact version, may be null
.
+ * @param filename The filename to use, must not be null
.
+ * @return The (absolute) path to the local artifact metadata, never null
.
+ */
+ public String getArtifactMetadataPath(String gid, String aid, String version, String filename) {
+ return getArtifactMetadataPath(gid, aid, version, filename, null);
+ }
+
+ /**
+ * Gets the path to a file in the local artifact directory. Note that the method does not check whether the returned
+ * path actually points to an existing file.
+ *
+ * @param gid The group id, must not be null
.
+ * @param aid The artifact id, may be null
.
+ * @param version The artifact version, may be null
.
+ * @param filename The filename to use, must not be null
.
+ * @param repoId The remote repository ID from where metadata originate, may be null
.
+ * @return The (absolute) path to the local artifact metadata, never null
.
+ */
+ public String getArtifactMetadataPath(String gid, String aid, String version, String filename, String repoId) {
+ String gav;
+ if (gid != null) {
+ gav = gid + ":";
+ } else {
+ gav = ":";
+ }
+ if (aid != null) {
+ gav += aid + ":";
+ } else {
+ gav += ":";
+ }
+ if (version != null) {
+ gav += version + ":";
+ } else {
+ gav += ":";
+ }
+ gav += filename;
+ return getLocalRepository()
+ + File.separator
+ + executorHelper.metadataPath(executorHelper.executorRequest(), gav, repoId);
+ }
+
+ /**
+ * Gets the path to the local artifact metadata. Note that the method does not check whether the returned path
+ * actually points to existing metadata.
+ *
+ * @param gid The group id, must not be null
.
+ * @param aid The artifact id, must not be null
.
+ * @return The (absolute) path to the local artifact metadata, never null
.
+ */
+ public String getArtifactMetadataPath(String gid, String aid) {
+ return getArtifactMetadataPath(gid, aid, null);
+ }
+
+ public void deleteArtifact(String org, String name, String version, String ext) throws IOException {
+ List files = getArtifactFileNameList(org, name, version, ext);
+ for (String fileName : files) {
+ FileUtils.forceDelete(new File(fileName));
+ }
+ }
+
+ /**
+ * Deletes all artifacts in the specified group id from the local repository.
+ *
+ * @param gid The group id whose artifacts should be deleted, must not be null
.
+ * @throws IOException If the artifacts could not be deleted.
+ * @since 1.2
+ */
+ public void deleteArtifacts(String gid) throws IOException {
+ String mdPath = executorHelper.metadataPath(executorHelper.executorRequest(), gid, null);
+ Path dir = Paths.get(getLocalRepository()).resolve(mdPath).getParent();
+ FileUtils.deleteDirectory(dir.toFile());
+ }
+
+ /**
+ * Deletes all artifacts in the specified g:a:v from the local repository.
+ *
+ * @param gid The group id whose artifacts should be deleted, must not be null
.
+ * @param aid The artifact id whose artifacts should be deleted, must not be null
.
+ * @param version The (base) version whose artifacts should be deleted, must not be null
.
+ * @throws IOException If the artifacts could not be deleted.
+ * @since 1.3
+ */
+ public void deleteArtifacts(String gid, String aid, String version) throws IOException {
+ requireNonNull(gid, "gid is null");
+ requireNonNull(aid, "aid is null");
+ requireNonNull(version, "version is null");
+
+ String mdPath =
+ executorHelper.metadataPath(executorHelper.executorRequest(), gid + ":" + aid + ":" + version, null);
+ Path dir = Paths.get(getLocalRepository()).resolve(mdPath).getParent();
+ FileUtils.deleteDirectory(dir.toFile());
+ }
+
+ /**
+ * Deletes the specified directory.
+ *
+ * @param path The path to the directory to delete, relative to the base directory, must not be null
.
+ * @throws IOException If the directory could not be deleted.
+ * @since 1.2
+ */
+ public void deleteDirectory(String path) throws IOException {
+ FileUtils.deleteDirectory(new File(getBasedir(), path));
+ }
+
+ public File filterFile(String srcPath, String dstPath) throws IOException {
+ return filterFile(srcPath, dstPath, (String) null);
+ }
+
+ public File filterFile(String srcPath, String dstPath, Map filterMap) throws IOException {
+ return filterFile(srcPath, dstPath, null, filterMap);
+ }
+
+ /**
+ * Filters a text file by replacing some user-defined tokens.
+ * This method is equivalent to:
+ *
+ *
+ * filterFile( srcPath, dstPath, fileEncoding, verifier.newDefaultFilterMap() )
+ *
+ *
+ * @param srcPath The path to the input file, relative to the base directory, must not be
+ * null
.
+ * @param dstPath The path to the output file, relative to the base directory and possibly equal to the
+ * input file, must not be null
.
+ * @param fileEncoding The file encoding to use, may be null
or empty to use the platform's default
+ * encoding.
+ * @return The path to the filtered output file, never null
.
+ * @throws IOException If the file could not be filtered.
+ * @since 2.0
+ */
+ public File filterFile(String srcPath, String dstPath, String fileEncoding) throws IOException {
+ return filterFile(srcPath, dstPath, fileEncoding, newDefaultFilterMap());
+ }
+
+ /**
+ * Filters a text file by replacing some user-defined tokens.
+ *
+ * @param srcPath The path to the input file, relative to the base directory, must not be
+ * null
.
+ * @param dstPath The path to the output file, relative to the base directory and possibly equal to the
+ * input file, must not be null
.
+ * @param fileEncoding The file encoding to use, may be null
or empty to use the platform's default
+ * encoding.
+ * @param filterMap The mapping from tokens to replacement values, must not be null
.
+ * @return The path to the filtered output file, never null
.
+ * @throws IOException If the file could not be filtered.
+ * @since 1.2
+ */
+ public File filterFile(String srcPath, String dstPath, String fileEncoding, Map filterMap)
+ throws IOException {
+ Charset charset = fileEncoding != null ? Charset.forName(fileEncoding) : StandardCharsets.UTF_8;
+ File srcFile = new File(getBasedir(), srcPath);
+ String data = Files.readString(srcFile.toPath(), charset);
+
+ for (Map.Entry entry : filterMap.entrySet()) {
+ data = StringUtils.replace(data, entry.getKey(), entry.getValue());
+ }
+
+ File dstFile = new File(getBasedir(), dstPath);
+ //noinspection ResultOfMethodCallIgnored
+ dstFile.getParentFile().mkdirs();
+ Files.writeString(dstFile.toPath(), data, charset);
+
+ return dstFile;
+ }
+
+ /**
+ * Gets a new copy of the default filter map. These default filter map, contains the tokens "@basedir@" and
+ * "@baseurl@" to the test's base directory and its base file:
URL, respectively.
+ *
+ * @return The (modifiable) map with the default filter map, never null
.
+ * @since 2.0
+ */
+ public Map newDefaultFilterMap() {
+ Map filterMap = new HashMap<>();
+
+ Path basedir = Paths.get(getBasedir()).toAbsolutePath();
+ filterMap.put("@basedir@", basedir.toString());
+ filterMap.put("@baseurl@", basedir.toUri().toASCIIString());
+
+ return filterMap;
+ }
+
+ /**
+ * Verifies that the given file exists.
+ *
+ * @param file the path of the file to check
+ * @throws VerificationException in case the given file does not exist
+ */
+ public void verifyFilePresent(String file) throws VerificationException {
+ verifyFilePresence(file, true);
+ }
+
+ /**
+ * Verifies that the given file does not exist.
+ *
+ * @param file the path of the file to check
+ * @throws VerificationException if the given file exists
+ */
+ public void verifyFileNotPresent(String file) throws VerificationException {
+ verifyFilePresence(file, false);
+ }
+
+ private void verifyArtifactPresence(boolean wanted, String groupId, String artifactId, String version, String ext)
+ throws VerificationException {
+ List files = getArtifactFileNameList(groupId, artifactId, version, ext);
+ for (String fileName : files) {
+ verifyFilePresence(fileName, wanted);
+ }
+ }
+
+ /**
+ * Verifies that the artifact given through its Maven coordinates exists.
+ *
+ * @param groupId the groupId of the artifact (must not be null)
+ * @param artifactId the artifactId of the artifact (must not be null)
+ * @param version the version of the artifact (must not be null)
+ * @param ext the extension of the artifact (must not be null)
+ * @throws VerificationException if the given artifact does not exist
+ */
+ public void verifyArtifactPresent(String groupId, String artifactId, String version, String ext)
+ throws VerificationException {
+ verifyArtifactPresence(true, groupId, artifactId, version, ext);
+ }
+
+ /**
+ * Verifies that the artifact given through its Maven coordinates does not exist.
+ *
+ * @param groupId the groupId of the artifact (must not be null)
+ * @param artifactId the artifactId of the artifact (must not be null)
+ * @param version the version of the artifact (must not be null)
+ * @param ext the extension of the artifact (must not be null)
+ * @throws VerificationException if the given artifact exists
+ */
+ public void verifyArtifactNotPresent(String groupId, String artifactId, String version, String ext)
+ throws VerificationException {
+ verifyArtifactPresence(false, groupId, artifactId, version, ext);
+ }
+
+ private void verifyFilePresence(String filePath, boolean wanted) throws VerificationException {
+ if (filePath.contains("!/")) {
+ Path basedir = Paths.get(getBasedir()).toAbsolutePath();
+ String urlString = "jar:" + basedir.toUri().toASCIIString() + "/" + filePath;
+
+ InputStream is = null;
+ try {
+ URL url = new URL(urlString);
+
+ is = url.openStream();
+
+ if (is == null) {
+ if (wanted) {
+ throw new VerificationException("Expected JAR resource was not found: " + filePath);
+ }
+ } else {
+ if (!wanted) {
+ throw new VerificationException("Unwanted JAR resource was found: " + filePath);
+ }
+ }
+ } catch (MalformedURLException e) {
+ throw new VerificationException("Error looking for JAR resource", e);
+ } catch (IOException e) {
+ if (wanted) {
+ throw new VerificationException("Error looking for JAR resource: " + filePath);
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ } else {
+ File expectedFile = new File(filePath);
+
+ // NOTE: On Windows, a path with a leading (back-)slash is relative to the current drive
+ if (!expectedFile.isAbsolute() && !expectedFile.getPath().startsWith(File.separator)) {
+ expectedFile = new File(getBasedir(), filePath);
+ }
+
+ if (filePath.indexOf('*') > -1) {
+ File parent = expectedFile.getParentFile();
+
+ if (!parent.exists()) {
+ if (wanted) {
+ throw new VerificationException(
+ "Expected file pattern was not found: " + expectedFile.getPath());
+ }
+ } else {
+ String shortNamePattern = expectedFile.getName().replaceAll("\\*", ".*");
+
+ String[] candidates = parent.list();
+
+ boolean found = false;
+
+ if (candidates != null) {
+ for (String candidate : candidates) {
+ if (candidate.matches(shortNamePattern)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found && wanted) {
+ throw new VerificationException(
+ "Expected file pattern was not found: " + expectedFile.getPath());
+ } else if (found && !wanted) {
+ throw new VerificationException("Unwanted file pattern was found: " + expectedFile.getPath());
+ }
+ }
+ } else {
+ if (!expectedFile.exists()) {
+ if (wanted) {
+ throw new VerificationException("Expected file was not found: " + expectedFile.getPath());
+ }
+ } else {
+ if (!wanted) {
+ throw new VerificationException("Unwanted file was found: " + expectedFile.getPath());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Verifies that the artifact given by its Maven coordinates exists and contains the given content.
+ *
+ * @param groupId the groupId of the artifact (must not be null)
+ * @param artifactId the artifactId of the artifact (must not be null)
+ * @param version the version of the artifact (must not be null)
+ * @param ext the extension of the artifact (must not be null)
+ * @param content the expected content
+ * @throws IOException if reading from the artifact fails
+ * @throws VerificationException if the content of the artifact differs
+ */
+ public void verifyArtifactContent(String groupId, String artifactId, String version, String ext, String content)
+ throws IOException, VerificationException {
+ String fileName = getArtifactPath(groupId, artifactId, version, ext);
+ if (!content.equals(FileUtils.fileRead(fileName))) {
+ throw new VerificationException("Content of " + fileName + " does not equal " + content);
+ }
}
}
diff --git a/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/AnsiSupport.java b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/VerificationException.java
similarity index 58%
rename from its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/AnsiSupport.java
rename to its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/VerificationException.java
index 27de46ba99..628981b73f 100644
--- a/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/AnsiSupport.java
+++ b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/VerificationException.java
@@ -16,29 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.maven.it;
+package org.apache.maven.shared.verifier;
/**
- * Basic Ansi support: can't use Ansi because IT is executed in separate classloader.
+ * @author Jason van Zyl
*/
-class AnsiSupport {
- private static final String ESC = String.valueOf((char) 27) + '[';
-
- private static final String NORMAL = ESC + "0;39m";
-
- static String success(String msg) {
- return ESC + "1;32m" + msg + NORMAL;
+public class VerificationException extends Exception {
+ public VerificationException(String message) {
+ super(message);
}
- static String warning(String msg) {
- return ESC + "1;33m" + msg + NORMAL;
+ public VerificationException(Throwable cause) {
+ super(cause);
}
- static String error(String msg) {
- return ESC + "1;31m" + msg + NORMAL;
- }
-
- static String bold(String msg) {
- return ESC + "1m" + msg + NORMAL;
+ public VerificationException(String message, Throwable cause) {
+ super(message, cause);
}
}
diff --git a/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/util/ResourceExtractor.java b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/util/ResourceExtractor.java
new file mode 100644
index 0000000000..2172b9439f
--- /dev/null
+++ b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/shared/verifier/util/ResourceExtractor.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.shared.verifier.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * TODO this can be replaced with plexus-archiver
+ */
+public class ResourceExtractor {
+
+ public static File simpleExtractResources(Class> cl, String resourcePath) throws IOException {
+ String tempDirPath = System.getProperty("maven.test.tmpdir", System.getProperty("java.io.tmpdir"));
+ File tempDir = new File(tempDirPath);
+
+ File testDir = new File(tempDir, resourcePath);
+
+ FileUtils.deleteDirectory(testDir);
+
+ testDir = extractResourcePath(cl, resourcePath, tempDir, false);
+ return testDir;
+ }
+
+ public static File extractResourcePath(String resourcePath, File dest) throws IOException {
+ return extractResourcePath(ResourceExtractor.class, resourcePath, dest);
+ }
+
+ public static File extractResourcePath(Class> cl, String resourcePath, File dest) throws IOException {
+ return extractResourcePath(cl, resourcePath, dest, false);
+ }
+
+ public static File extractResourcePath(Class> cl, String resourcePath, File tempDir, boolean alwaysExtract)
+ throws IOException {
+ File dest = new File(tempDir, resourcePath);
+ return extractResourceToDestination(cl, resourcePath, dest, alwaysExtract);
+ }
+
+ public static File extractResourceToDestination(
+ Class> cl, String resourcePath, File destination, boolean alwaysExtract) throws IOException {
+ URL url = cl.getResource(resourcePath);
+ if (url == null) {
+ throw new IllegalArgumentException("Resource not found: " + resourcePath);
+ }
+ if ("jar".equalsIgnoreCase(url.getProtocol())) {
+ File jarFile = getJarFileFromUrl(url);
+ extractResourcePathFromJar(cl, jarFile, resourcePath, destination);
+ } else {
+ try {
+ File resourceFile = new File(new URI(url.toExternalForm()));
+ if (!alwaysExtract) {
+ return resourceFile;
+ }
+ if (resourceFile.isDirectory()) {
+ FileUtils.copyDirectoryStructure(resourceFile, destination);
+ } else {
+ FileUtils.copyFile(resourceFile, destination);
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Couldn't convert URL to File:" + url, e);
+ }
+ }
+ return destination;
+ }
+
+ private static void extractResourcePathFromJar(Class> cl, File jarFile, String resourcePath, File dest)
+ throws IOException {
+ ZipFile z = new ZipFile(jarFile, ZipFile.OPEN_READ);
+ String zipStyleResourcePath = resourcePath.substring(1) + "/";
+ ZipEntry ze = z.getEntry(zipStyleResourcePath);
+ if (ze != null) {
+ // DGF If it's a directory, then we need to look at all the entries
+ for (Enumeration extends ZipEntry> entries = z.entries(); entries.hasMoreElements(); ) {
+ ze = entries.nextElement();
+ if (ze.getName().startsWith(zipStyleResourcePath)) {
+ String relativePath = ze.getName().substring(zipStyleResourcePath.length());
+ File destFile = new File(dest, relativePath);
+ if (ze.isDirectory()) {
+ destFile.mkdirs();
+ } else {
+ try (FileOutputStream fos = new FileOutputStream(destFile)) {
+ z.getInputStream(ze).transferTo(fos);
+ } finally {
+ z.close();
+ }
+ }
+ }
+ }
+ } else {
+ try (FileOutputStream fos = new FileOutputStream(dest)) {
+ cl.getResourceAsStream(resourcePath).transferTo(fos);
+ } finally {
+ z.close();
+ }
+ }
+ }
+
+ private static File getJarFileFromUrl(URL url) {
+ if (!"jar".equalsIgnoreCase(url.getProtocol())) {
+ throw new IllegalArgumentException("This is not a Jar URL:" + url.toString());
+ }
+ String resourceFilePath = url.getFile();
+ int index = resourceFilePath.indexOf("!");
+ if (index == -1) {
+ throw new RuntimeException("Bug! " + url.toExternalForm() + " does not have a '!'");
+ }
+ String jarFileURI = resourceFilePath.substring(0, index);
+ try {
+ File jarFile = new File(new URI(jarFileURI));
+ return jarFile;
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Bug! URI failed to parse: " + jarFileURI, e);
+ }
+ }
+}
diff --git a/its/pom.xml b/its/pom.xml
index fb242752f0..ae5cbdd8a4 100644
--- a/its/pom.xml
+++ b/its/pom.xml
@@ -23,7 +23,7 @@ under the License.
org.apache.maven
maven
- 4.0.0-beta-6-SNAPSHOT
+ 4.0.0-rc-2-SNAPSHOT
org.apache.maven.its
@@ -73,7 +73,7 @@ under the License.
- 4.0.0-beta-6-SNAPSHOT
+ 4.0.0-rc-2-SNAPSHOT
3.15.1