-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added an extended ResourceReader that can retrieve test resource file…
…s that aren't tightly coupled to the default file naming schemes
- Loading branch information
1 parent
048495b
commit 432688e
Showing
9 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
134 changes: 134 additions & 0 deletions
134
src/main/java/emissary/util/io/GreedyResourceReader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package emissary.util.io; | ||
|
||
import org.apache.commons.io.FilenameUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.net.URL; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
import static org.apache.commons.lang3.StringUtils.isNotBlank; | ||
import static org.apache.commons.lang3.StringUtils.substringBeforeLast; | ||
|
||
/** | ||
* A {@link ResourceReader} extended to find data files based purely on their location, ignoring the default naming | ||
* convention used by the {@link ResourceReader#findDataResourcesFor(Class)} method. | ||
* <p> | ||
* This class is primarily used to find payload files for Identification tests that can benefit from more | ||
* content-representative file names. | ||
* </p> | ||
*/ | ||
public class GreedyResourceReader extends ResourceReader { | ||
private static final Logger logger = LoggerFactory.getLogger(GreedyResourceReader.class); | ||
|
||
public static final String PAYLOADS_FOLDER = "payloads"; | ||
public static final String ANSWERS_FOLDER = "answers"; | ||
|
||
public static final Predicate<String> IS_XML_FILE = filename -> "xml".equals(FilenameUtils.getExtension(filename)); | ||
|
||
/** | ||
* Returns the project-relative paths of test files for the specified test class. The files should be underneath a | ||
* "payloads" subdirectory of the test class directory. Additional subdirectories can exist within the payloads | ||
* directory itself, and any files found within will be included in the results. | ||
* | ||
* @param c test class for which to perform the search | ||
* @return list of project-relative test file paths | ||
*/ | ||
public List<String> findAllPayloadFilesFor(Class<?> c) { | ||
URL url = this.which(c); | ||
if (url == null || !url.getProtocol().equals("file")) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<String> results = new ArrayList<>(findAllFilesUnderClassNameSubDir(c, url, PAYLOADS_FOLDER)); | ||
Collections.sort(results); | ||
return results; | ||
} | ||
|
||
/** | ||
* Returns the project-relative paths of test files for the specified test class. The files should be underneath a | ||
* "payloads" subdirectory of the test class directory. Additional subdirectories can exist within the payloads | ||
* directory itself, and any files found within will be included in the results. | ||
* | ||
* @param c test class for which to perform the search | ||
* @return list of project-relative test file paths | ||
*/ | ||
public List<String> findAllAnswerFilesFor(Class<?> c) { | ||
URL url = this.which(c); | ||
if (url == null || !url.getProtocol().equals("file")) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<String> results = findAllFilesUnderClassNameSubDir(c, url, ANSWERS_FOLDER, IS_XML_FILE); | ||
Collections.sort(results); | ||
return results; | ||
} | ||
|
||
/** | ||
* Finds all files beneath the specified subdirectory of the test class resource folder | ||
* | ||
* @param c test class for which the resource files exist | ||
* @param url location from which the classLoader looded the test class | ||
* @param subDirName subdirectory that contains the files | ||
* @return List of test resource file paths | ||
*/ | ||
private List<String> findAllFilesUnderClassNameSubDir(Class<?> c, URL url, final String subDirName) { | ||
return findAllFilesUnderClassNameSubDir(c, url, subDirName, StringUtils::isNotBlank); | ||
} | ||
|
||
/** | ||
* Finds the files beneath a given test class resource folder, filtered by a provided {@link Predicate<String>} | ||
* | ||
* @param c test class for which the resource files exist | ||
* @param url location from which the classLoader loaded the test class | ||
* @param subDirName subdirectory that contains the files | ||
* @param fileFilter Predicate used to filter the list of discovered files | ||
* @return List of test resource file paths | ||
*/ | ||
private List<String> findAllFilesUnderClassNameSubDir(Class<?> c, URL url, final String subDirName, final Predicate<String> fileFilter) { | ||
String classNameInPathFormat = getResourceName(c); | ||
Path subDir = Path.of(getFullPathOfTestClassResourceFolder(url, c), subDirName); | ||
File testClassDir = subDir.toFile(); | ||
if (testClassDir.exists() && testClassDir.isDirectory()) { | ||
try (Stream<Path> theList = Files.walk(testClassDir.toPath())) { | ||
return theList.filter(Files::isRegularFile) | ||
.map(testClassDir.toPath()::relativize) | ||
.map(filePath -> classNameInPathFormat + "/" + subDirName + "/" + filePath) | ||
.filter(fileFilter::test) | ||
.collect(Collectors.toList()); | ||
|
||
} catch (IOException e) { | ||
logger.debug("Failed to retrieve files for class {}", c.getName(), e); | ||
} | ||
} | ||
|
||
return Collections.emptyList(); | ||
} | ||
|
||
/** | ||
* Gets the absolute path of a test class runtime resource folder | ||
* | ||
* @param url URL from which the ClassLoader loaded the test class | ||
* @param c test class | ||
* @return test class folder path | ||
*/ | ||
protected String getFullPathOfTestClassResourceFolder(URL url, Class<?> c) { | ||
String classNameInPathFormat = getResourceName(c); | ||
if (url.getPath().contains(CLASS_SUFFIX)) { | ||
// return the URL minus the ".class" suffix | ||
return StringUtils.substringBeforeLast(url.getPath(), CLASS_SUFFIX); | ||
} | ||
|
||
return StringUtils.join(url.getPath(), "/", classNameInPathFormat); | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/test/java/emissary/util/io/GreedyResourceReaderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package emissary.util.io; | ||
|
||
import emissary.test.core.junit5.UnitTest; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
|
||
public class GreedyResourceReaderTest extends UnitTest { | ||
|
||
|
||
@Test | ||
void testPayloadFileLocation() { | ||
|
||
// files in the "payloads" subdirectory should be found as resources | ||
List<String> testFileNames = Arrays.asList("payloads/File1.txt", "payloads/subdir/sample.md"); | ||
// Non-payload.txt is in the test class directory, but not beneath its "payloads" subdirectory | ||
final String NON_PAYLOAD = "Non-payload.txt"; | ||
|
||
GreedyResourceReader grr = new GreedyResourceReader(); | ||
String testClassDir = grr.getResourceName(this.getClass()); | ||
|
||
List<String> resources = grr.findAllPayloadFilesFor(this.getClass()); | ||
assertNotNull(resources, "Resources must not be null"); | ||
assertEquals(testFileNames.size(), resources.size(), "All data resources not found"); | ||
|
||
testFileNames.stream() | ||
.map(t -> Path.of(testClassDir, t)) | ||
.forEach(p -> assertTrue(resources.contains(p.toString()))); | ||
|
||
assertFalse(resources.contains(Path.of(testClassDir, NON_PAYLOAD).toString())); | ||
|
||
for (String rez : resources) { | ||
try (InputStream is = grr.getResourceAsStream(rez)) { | ||
assertNotNull(is, "Failed to open " + rez); | ||
} catch (IOException e) { | ||
fail("Failed to open " + rez, e); | ||
} | ||
} | ||
} | ||
|
||
|
||
@Test | ||
void testAnswerFileLocation() { | ||
|
||
// files in the "payloads" subdirectory should be found as resources | ||
List<String> testAnswerFileNames = Arrays.asList("answers/File1.txt.xml", "answers/subdir/sample.md.xml"); | ||
|
||
// files that should NOT be detected as "answer" files based on their locations | ||
List<String> misplacedAnswerFileNames = Arrays.asList("Non-answer.xml", "answers/README"); | ||
|
||
GreedyResourceReader grr = new GreedyResourceReader(); | ||
String testClassDir = grr.getResourceName(this.getClass()); | ||
|
||
List<String> answerFiles = grr.findAllAnswerFilesFor(this.getClass()); | ||
assertNotNull(answerFiles, "Resources must not be null"); | ||
assertEquals(testAnswerFileNames.size(), answerFiles.size(), "Not all answer files not found"); | ||
|
||
testAnswerFileNames.stream() | ||
.map(t -> Path.of(testClassDir, t)) | ||
.forEach(p -> assertTrue(answerFiles.contains(p.toString()))); | ||
|
||
misplacedAnswerFileNames.stream() | ||
.map(t -> Path.of(testClassDir, t)) | ||
.forEach(p -> assertFalse(answerFiles.contains(p.toString()))); | ||
|
||
|
||
for (String file : answerFiles) { | ||
try (InputStream is = grr.getResourceAsStream(file)) { | ||
assertNotNull(is, "Failed to open " + file); | ||
} catch (IOException e) { | ||
fail("Failed to open " + file, e); | ||
} | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/Non-answer.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<root>file is in wrong directory</root> |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/Non-payload.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ignore me |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/answers/File1.txt.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<root>ignore the file content</root> |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/answers/README
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
not an answer file |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/answers/subdir/sample.md.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<root>ignore the file content</root> |
1 change: 1 addition & 0 deletions
1
src/test/resources/emissary/util/io/GreedyResourceReaderTest/payloads/File1.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Ignore the content |
1 change: 1 addition & 0 deletions
1
...t/resources/emissary/util/io/GreedyResourceReaderTest/payloads/subdir/sample.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
## this is a sample file |