diff --git a/src/main/java/io/jenkins/plugins/util/AgentFileVisitor.java b/src/main/java/io/jenkins/plugins/util/AgentFileVisitor.java index b1e94e93..d5fef049 100644 --- a/src/main/java/io/jenkins/plugins/util/AgentFileVisitor.java +++ b/src/main/java/io/jenkins/plugins/util/AgentFileVisitor.java @@ -42,7 +42,9 @@ public abstract class AgentFileVisitor private final String filePattern; private final String encoding; private final boolean followSymbolicLinks; + private final boolean errorOnEmptyFiles; private final FileSystemFacade fileSystemFacade; + private static final String EMPTY_FILE = "Skipping file '%s' because it's empty"; /** * Creates a new instance of {@link AgentFileVisitor}. @@ -52,20 +54,22 @@ public abstract class AgentFileVisitor * @param encoding * encoding of the files to parse * @param followSymbolicLinks - * if the scanner should traverse symbolic links + * determines whether the visitor should traverse symbolic links + * @param errorOnEmptyFiles + * determines whether the visitor should log errors if a file is empty */ - protected AgentFileVisitor(final String filePattern, final String encoding, final boolean followSymbolicLinks) { - this(filePattern, encoding, followSymbolicLinks, new FileSystemFacade()); + protected AgentFileVisitor(final String filePattern, final String encoding, final boolean followSymbolicLinks, final boolean errorOnEmptyFiles) { + this(filePattern, encoding, followSymbolicLinks, errorOnEmptyFiles, new FileSystemFacade()); } @VisibleForTesting - AgentFileVisitor(final String filePattern, final String encoding, final boolean followSymbolicLinks, - final FileSystemFacade fileSystemFacade) { + AgentFileVisitor(final String filePattern, final String encoding, final boolean followSymbolicLinks, final boolean errorOnEmptyFiles, final FileSystemFacade fileSystemFacade) { super(); this.filePattern = filePattern; this.encoding = encoding; this.followSymbolicLinks = followSymbolicLinks; + this.errorOnEmptyFiles = errorOnEmptyFiles; this.fileSystemFacade = fileSystemFacade; } @@ -98,7 +102,12 @@ private List scanFiles(final File workspace, final String[] fileNames, final log.logError("Skipping file '%s' because Jenkins has no permission to read the file", fileName); } else if (fileSystemFacade.isEmpty(file)) { - log.logError("Skipping file '%s' because it's empty", fileName); + if (errorOnEmptyFiles) { + log.logError(EMPTY_FILE, fileName); + } + else { + log.logInfo(EMPTY_FILE, fileName); + } } else { results.add(processFile(file, new CharsetValidation().getCharset(encoding), log)); diff --git a/src/test/java/io/jenkins/plugins/util/AgentFileVisitorTest.java b/src/test/java/io/jenkins/plugins/util/AgentFileVisitorTest.java index c6175c52..6307f767 100644 --- a/src/test/java/io/jenkins/plugins/util/AgentFileVisitorTest.java +++ b/src/test/java/io/jenkins/plugins/util/AgentFileVisitorTest.java @@ -38,7 +38,7 @@ class AgentFileVisitorTest extends SerializableTest { @CsvSource({"true, enabled", "false, disabled"}) @ParameterizedTest(name = "{index} => followSymbolicLinks={0}, message={1}") void shouldReportErrorOnEmptyResults(final boolean followLinks, final String message) { - StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, + StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, true, createFileSystemFacade(followLinks)); FileVisitorResult actualResult = scanner.invoke(workspace, null); @@ -57,7 +57,7 @@ void shouldReportErrorOnEmptyResults(final boolean followLinks, final String mes @CsvSource({"true, enabled", "false, disabled"}) @ParameterizedTest(name = "{index} => followSymbolicLinks={0}, message={1}") void shouldReturnSingleResult(final boolean followLinks, final String message) { - StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, + StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, true, createFileSystemFacade(followLinks, "/one.txt")); FileVisitorResult actualResult = scanner.invoke(workspace, null); @@ -75,7 +75,7 @@ void shouldReturnSingleResult(final boolean followLinks, final String message) { @CsvSource({"true, enabled", "false, disabled"}) @ParameterizedTest(name = "{index} => followSymbolicLinks={0}, message={1}") void shouldReturnMultipleResults(final boolean followLinks, final String message) { - StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, + StringScanner scanner = new StringScanner(PATTERN, "UTF-8", followLinks, true, createFileSystemFacade(followLinks, "/one.txt", "/two.txt")); FileVisitorResult actualResult = scanner.invoke(workspace, null); @@ -91,20 +91,20 @@ void shouldReturnMultipleResults(final boolean followLinks, final String message } @Test - @DisplayName("Should handle empty or forbidden files") - void shouldReturnMultipleResults() { + @DisplayName("Should log error for empty or forbidden files") + void shouldLogErrorForEmptyAndForbiddenFiles() { FileSystemFacade fileSystemFacade = createFileSystemFacade(true, "/one.txt", "/two.txt", "empty.txt", "not-readable.txt"); Path empty = workspace.toPath().resolve("empty.txt"); when(fileSystemFacade.resolve(workspace, "empty.txt")).thenReturn(empty); - when(fileSystemFacade.isNotReadable(empty)).thenReturn(true); + when(fileSystemFacade.isEmpty(empty)).thenReturn(true); Path notReadable = workspace.toPath().resolve("not-readable.txt"); when(fileSystemFacade.resolve(workspace, "not-readable.txt")).thenReturn(notReadable); - when(fileSystemFacade.isEmpty(notReadable)).thenReturn(true); + when(fileSystemFacade.isNotReadable(notReadable)).thenReturn(true); - StringScanner scanner = new StringScanner(PATTERN, "UTF-8", true, + StringScanner scanner = new StringScanner(PATTERN, "UTF-8", true, true, fileSystemFacade); FileVisitorResult actualResult = scanner.invoke(workspace, null); @@ -116,8 +116,33 @@ void shouldReturnMultipleResults() { "Successfully processed file '/two.txt'"); assertThat(actualResult.hasErrors()).isTrue(); assertThat(actualResult.getLog().getErrorMessages()).containsExactly("Errors during parsing", - "Skipping file 'empty.txt' because Jenkins has no permission to read the file", - "Skipping file 'not-readable.txt' because it's empty"); + "Skipping file 'empty.txt' because it's empty", + "Skipping file 'not-readable.txt' because Jenkins has no permission to read the file"); + } + + @Test + @DisplayName("Should skip logging of errors when parsing empty files") + void shouldSkipLoggingOfErrorsForEmptyFiles() { + FileSystemFacade fileSystemFacade = createFileSystemFacade(true, + "/one.txt", "/two.txt", "empty.txt"); + + Path empty = workspace.toPath().resolve("empty.txt"); + when(fileSystemFacade.resolve(workspace, "empty.txt")).thenReturn(empty); + when(fileSystemFacade.isEmpty(empty)).thenReturn(true); + + StringScanner scanner = new StringScanner(PATTERN, "UTF-8", true, false, + fileSystemFacade); + + FileVisitorResult actualResult = scanner.invoke(workspace, null); + assertThat(actualResult.getResults()).containsExactly(CONTENT + 1, CONTENT + 2); + assertThat(actualResult.getLog().getInfoMessages()).contains( + "Searching for all files in '/absolute/path' that match the pattern '**/*.txt'", + "-> found 3 files", + "Successfully processed file '/one.txt'", + "Successfully processed file '/two.txt'", + "Skipping file 'empty.txt' because it's empty"); + assertThat(actualResult.hasErrors()).isFalse(); + assertThat(actualResult.getLog().getErrorMessages()).isEmpty(); } private FileSystemFacade createFileSystemFacade(final boolean followLinks, final String... files) { @@ -131,7 +156,7 @@ private FileSystemFacade createFileSystemFacade(final boolean followLinks, final @Override protected StringScanner createSerializable() { - return new StringScanner(PATTERN, "UTF-8", true, createFileSystemFacade(true)); + return new StringScanner(PATTERN, "UTF-8", true, true, createFileSystemFacade(true)); } static class StringScanner extends AgentFileVisitor { @@ -139,8 +164,8 @@ static class StringScanner extends AgentFileVisitor { private int counter = 1; @VisibleForTesting - protected StringScanner(final String filePattern, final String encoding, final boolean followSymbolicLinks, final FileSystemFacade fileSystemFacade) { - super(filePattern, encoding, followSymbolicLinks, fileSystemFacade); + protected StringScanner(final String filePattern, final String encoding, final boolean followSymbolicLinks, final boolean errorOnEmptyFiles, final FileSystemFacade fileSystemFacade) { + super(filePattern, encoding, followSymbolicLinks, errorOnEmptyFiles, fileSystemFacade); } @Override