diff --git a/pom.xml b/pom.xml
index d07ee66..7dd76ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,6 +101,13 @@
1.10.17
test
+
+ org.esa.snap
+ snap-runtime
+ ${snap.test.version}
+ test-jar
+ test
+
@@ -220,6 +227,19 @@
test
test-jar
+
+ org.esa.snap
+ snap-ndvi
+ ${project.version}
+ test
+
+
+ org.esa.snap
+ snap-ndvi
+ ${project.version}
+ test
+ test-jar
+
@@ -523,6 +543,19 @@
test
test-jar
+
+ org.esa.s2tbx
+ s2tbx-radiometric-indices
+ ${s2tbx.test.version}
+ test
+
+
+ org.esa.s2tbx
+ s2tbx-radiometric-indices
+ ${s2tbx.test.version}
+ test
+ test-jar
+
diff --git a/src/test/java/org/esa/snap/dataio/ProductReaderAcceptanceTest.java b/src/test/java/org/esa/snap/dataio/ProductReaderAcceptanceTest.java
index 4d4aa34..4e9f3bb 100644
--- a/src/test/java/org/esa/snap/dataio/ProductReaderAcceptanceTest.java
+++ b/src/test/java/org/esa/snap/dataio/ProductReaderAcceptanceTest.java
@@ -72,7 +72,7 @@ public class ProductReaderAcceptanceTest {
private static final String PROPERTYNAME_FAIL_ON_MISSING_DATA = "snap.reader.tests.failOnMissingData";
private static final String PROPERTYNAME_FAIL_ON_INTENDED = "snap.reader.tests.failOnMultipleIntendedReaders";
private static final String PROPERTYNAME_LOG_FILE_PATH = "snap.reader.tests.log.file";
- private static final String PROPERTYNAME_CASS_NAME = "snap.reader.tests.class.name";
+ private static final String PROPERTYNAME_CLASS_NAME = "snap.reader.tests.class.name";
private static final boolean FAIL_ON_MISSING_DATA = Boolean.parseBoolean(System.getProperty(PROPERTYNAME_FAIL_ON_MISSING_DATA, "true"));
private static final String INDENT = "\t";
private static final ProductList testProductList = new ProductList();
@@ -471,7 +471,7 @@ private static void loadProductReaderTestDefinitions() throws IOException {
final Iterable readerPlugIns = SystemUtils.loadServices(ProductReaderPlugIn.class);
testDefinitionList = new TestDefinitionList();
- final String className = System.getProperty(PROPERTYNAME_CASS_NAME);
+ final String className = System.getProperty(PROPERTYNAME_CLASS_NAME);
for (ProductReaderPlugIn readerPlugIn : readerPlugIns) {
final Class extends ProductReaderPlugIn> readerPlugInClass = readerPlugIn.getClass();
diff --git a/src/test/java/org/esa/snap/dataio/RunProductReaderTest.java b/src/test/java/org/esa/snap/dataio/RunProductReaderTest.java
new file mode 100644
index 0000000..18eab8c
--- /dev/null
+++ b/src/test/java/org/esa/snap/dataio/RunProductReaderTest.java
@@ -0,0 +1,305 @@
+package org.esa.snap.dataio;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.esa.s2tbx.dataio.gdal.GDALLibraryInstaller;
+import org.esa.snap.core.dataio.ProductReader;
+import org.esa.snap.core.dataio.ProductReaderPlugIn;
+import org.esa.snap.core.datamodel.Product;
+import org.esa.snap.core.util.SystemUtils;
+import org.esa.snap.dataio.netcdf.NetCdfActivator;
+import org.esa.snap.jp2.reader.OpenJPEGLibraryInstaller;
+import org.esa.snap.runtime.LogUtils4Tests;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static org.junit.Assert.fail;
+
+public class RunProductReaderTest {
+
+ private static final Logger logger = Logger.getLogger(RunProductReaderTest.class.getName());
+
+ private static final String PROPERTY_NAME_FAIL_ON_MISSING_DATA = "snap.reader.tests.failOnMissingData";
+ private static final String PROPERTY_NAME_DATA_DIR = "snap.reader.tests.data.dir";
+ private static final String PROPERTY_NAME_CASS_NAME = "snap.reader.tests.class.name";
+ private static final String PROPERTY_NAME_PRODUCT_IDS = "snap.reader.tests.product.ids";
+
+ private static List testDefinitionList;
+ private static File dataRootDir;
+ private static boolean isFailOnMissingData;
+
+ private ErrorCollector errorCollector = new ErrorCollector();
+
+ public RunProductReaderTest() {
+ }
+
+ @BeforeClass
+ public static void initialize() throws Exception {
+ LogUtils4Tests.initLogger();
+
+ String dataDirPropertyValue = System.getProperty(PROPERTY_NAME_DATA_DIR);
+ if (dataDirPropertyValue == null) {
+ fail("The test data property '"+PROPERTY_NAME_DATA_DIR+"' representing the folder which contains the source products is not set.");
+ }
+
+ String readerPlugInClassNameToTest = System.getProperty(PROPERTY_NAME_CASS_NAME);
+ String productIdsToTest = System.getProperty(PROPERTY_NAME_PRODUCT_IDS);
+ String failOnMissingData = System.getProperty(PROPERTY_NAME_FAIL_ON_MISSING_DATA);
+
+ if (logger.isLoggable(Level.FINE)) {
+ StringBuilder message = new StringBuilder();
+ message.append("Input test parameters: data folder path: ")
+ .append(dataDirPropertyValue)
+ .append(", reader plugin class: ")
+ .append(readerPlugInClassNameToTest)
+ .append(", product ids: ")
+ .append(productIdsToTest)
+ .append(", fail on missing data: ")
+ .append(failOnMissingData)
+ .append(".");
+ logger.log(Level.FINE, message.toString());
+ }
+
+ dataRootDir = new File(dataDirPropertyValue);
+ if (!dataRootDir.exists()) {
+ fail("The path '" + dataDirPropertyValue+"' representing the folder which contains the source products does not exist.");
+ }
+ if (!dataRootDir.isDirectory()) {
+ fail("The path '" + dataDirPropertyValue+"' exists and it does not denote a folder.");
+ }
+
+ isFailOnMissingData = true;
+ if (failOnMissingData != null) {
+ isFailOnMissingData = Boolean.parseBoolean(failOnMissingData);
+ }
+
+ SystemUtils.init3rdPartyLibs(RunProductReaderTest.class);
+
+ if (!isFailOnMissingData) {
+ logger.warning("Tests will not fail if test data is missing!");
+ }
+
+ testDefinitionList = loadProductReaderTestDefinitions(readerPlugInClassNameToTest, productIdsToTest);
+
+ OpenJPEGLibraryInstaller.install();
+ GDALLibraryInstaller.install();
+ NetCdfActivator.activate();
+ }
+
+ /**
+ * The required parameters to run the method:
+ * -Dsnap.reader.tests.data.dir=\\CV-DEV-SRV01\Satellite_Imagery\TestingJUnitFiles
+ *
+ * Optional parameters:
+ * -Dsnap.reader.tests.class.name=org.esa.s2tbx.dataio.muscate.MuscateProductReaderPlugin
+ * -Dsnap.reader.tests.product.ids=MUSCATE-Zip-31TFK,MUSCATE-v18,MUSCATE-v20
+ * -Dsnap.reader.tests.failOnMissingData=false
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testReadIntendedProductContent() throws IOException {
+ logger.info("Test product content for " + testDefinitionList.size() + " reader plugins.");
+
+ for (int k=0; k 0) {
+ logger.info(""); // write an empty line
+ }
+ final List intendedProductIds = testDefinition.getDecodableProductIds();
+ String readerPluginClassName = testDefinition.getProductReaderPlugin().getClass().getSimpleName();
+
+ logger.info("Test products content: reader plugin class: " + readerPluginClassName+ ", product count: " + intendedProductIds.size()+".");
+
+ for (String productId : intendedProductIds) {
+ TestProduct foundTestProduct = null;
+ for (TestProduct testProduct : testDefinition.getAllProducts()) {
+ if (testProduct.getId().equalsIgnoreCase(productId)) {
+ foundTestProduct = testProduct;
+ break;
+ }
+ }
+ if (foundTestProduct == null) {
+ String message = "The test product with id '"+ productId+"' does not exist.";
+ if (isFailOnMissingData) {
+ fail(message);
+ } else {
+ logger.info(message);
+ }
+ } else if (foundTestProduct.exists()) {
+ logger.info("Start testing the product content: reader plugin class: " + readerPluginClassName+ ", product id: " + foundTestProduct.getId()+", product relative path: " + foundTestProduct.getRelativePath()+".");
+
+ long startTime = System.currentTimeMillis();
+
+ final File testProductFile = new File(dataRootDir, foundTestProduct.getRelativePath());
+
+ long startTimeReadProduct = System.currentTimeMillis();
+
+ final ProductReader productReader = testDefinition.getProductReaderPlugin().createReaderInstance();
+ final Product product = productReader.readProductNodes(testProductFile, null);
+ if (product == null) {
+ String message = "The product can not be read from file '" + testProductFile.getAbsolutePath()+"' does not exist.";
+ if (isFailOnMissingData) {
+ fail(message);
+ } else {
+ logger.log(Level.SEVERE, message);
+ }
+ } else {
+ try {
+ if (logger.isLoggable(Level.FINE)) {
+ double elapsedSecondsReadProduct = (System.currentTimeMillis() - startTimeReadProduct) / 1000.0d;
+ StringBuilder message = new StringBuilder();
+ message.append("Finish reading the product id: ")
+ .append(foundTestProduct.getId())
+ .append(", relative path: ")
+ .append(foundTestProduct.getRelativePath())
+ .append(", reader class: ")
+ .append(productReader.getClass().getName())
+ .append(", size: ")
+ .append(product.getSceneRasterWidth())
+ .append("x")
+ .append(product.getSceneRasterHeight())
+ .append(", elapsed time: ")
+ .append(elapsedSecondsReadProduct)
+ .append(" seconds.");
+ logger.log(Level.FINE, message.toString());
+ }
+
+ assertExpectedContent(testDefinition, foundTestProduct, product);
+ } catch (Throwable t) {
+ errorCollector.addError(new Throwable("[" + productId + "] " + t.getMessage(), t));
+ } finally {
+ product.dispose();
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ double elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000.0d;
+ StringBuilder message = new StringBuilder();
+ message.append("Finish testing the product content id: ")
+ .append(foundTestProduct.getId())
+ .append(", relative path: ")
+ .append(foundTestProduct.getRelativePath())
+ .append(", elapsed time: ")
+ .append(elapsedSeconds)
+ .append(" seconds.");
+ logger.log(Level.FINE, message.toString());
+ }
+ }
+ } else {
+ logger.info("The test product with id '"+ foundTestProduct.getId()+"' is missing from the disc.");
+ }
+ }
+ }
+ }
+
+ private static void assertExpectedContent(TestDefinition testDefinition, TestProduct testProduct, Product product) {
+ final ExpectedContent expectedContent = testDefinition.getExpectedContent(testProduct.getId());
+ if (expectedContent == null) {
+ String message = "No expected content for product id '" + testProduct.getId()+"'.";
+ if (isFailOnMissingData) {
+ fail(message);
+ } else {
+ logger.log(Level.SEVERE, message);
+ }
+ } else {
+ long startTime = System.currentTimeMillis();
+
+ final ContentAssert contentAssert = new ContentAssert(expectedContent, testProduct.getId(), product);
+ contentAssert.assertProductContent();
+
+ if (logger.isLoggable(Level.FINE)) {
+ double elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000.0d;
+ StringBuilder message = new StringBuilder();
+ message.append("Finish testing expected content: product id: ")
+ .append(testProduct.getId())
+ .append(", relative path: ")
+ .append(testProduct.getRelativePath())
+ .append(", elapsed time: ")
+ .append(elapsedSeconds)
+ .append(" seconds.");
+ logger.log(Level.FINE, message.toString());
+ }
+ }
+ }
+
+ private static List loadProductReaderTestDefinitions(String readerPlugInClassNameToTest, String productIdsToTest) throws IOException {
+ final ObjectMapper mapper = new ObjectMapper();
+ final Iterable readerPlugIns = SystemUtils.loadServices(ProductReaderPlugIn.class);
+
+ String[] productIds = null;
+ if (productIdsToTest != null) {
+ productIds = productIdsToTest.split(",");
+ if (productIds.length == 0) {
+ throw new IllegalArgumentException("The product ids array is empty.");
+ } else {
+ for (int k=0; k testDefinitionList = new ArrayList<>();
+ for (ProductReaderPlugIn readerPlugIn : readerPlugIns) {
+ final Class extends ProductReaderPlugIn> readerPlugInClass = readerPlugIn.getClass();
+ if (readerPlugInClassNameToTest != null && !readerPlugInClass.getName().startsWith(readerPlugInClassNameToTest)) {
+ continue;
+ }
+
+ final String path = readerPlugInClass.getName().replace(".", "/");
+ final String dataResourceName = "/" + path + "-data.json";
+ final URL dataResource = readerPlugInClass.getResource(dataResourceName);
+ if (dataResource == null) {
+ logger.warning("The reader plugin class '"+readerPlugInClass.getSimpleName() + "' does not define test data.");
+ continue;
+ }
+
+ final ProductList productList = mapper.readValue(dataResource, ProductList.class);
+
+ final TestDefinition testDefinition = new TestDefinition();
+ testDefinition.setProductReaderPlugin(readerPlugIn);
+ for (TestProduct testProduct : productList.getAll()) {
+ boolean canTestProduct;
+ if (productIds == null) {
+ canTestProduct = true;
+ } else {
+ canTestProduct = false;
+ for (int k=0; k gptGraphParameters) throws Exception {
@@ -327,34 +358,34 @@ public void write(int b) {
}
}
- private static void assertExpectedContent(Product product, ExpectedContent expectedContent, String productId) throws IOException {
- ContentAssert contentAssert = new ContentAssert(expectedContent, productId, product);
- contentAssert.assertProductContent();
- }
+ private static void assertExpectedContent(File testFile, InputGraphData inputGraphData, String outputNameValue, Product product, ExpectedContent expectedContent) {
+ StringBuilder assertMessagePrefix = new StringBuilder();
+ assertMessagePrefix.append("Test file '")
+ .append(testFile.getName())
+ .append("', id '")
+ .append(inputGraphData.getId())
+ .append("', output name '")
+ .append(outputNameValue)
+ .append("': ");
- private static void initLogger() throws Exception {
- // Suppress ugly (and harmless) JAI error messages saying that a JAI is going to continue in pure Java mode.
- System.setProperty("com.sun.media.jai.disableMediaLib", "true"); // disable native libraries for JAI
-
- logger = Logger.getLogger(ProductReaderAcceptanceTest.class.getSimpleName());
- removeRootLogHandler();
- ConsoleHandler consoleHandler = new ConsoleHandler();
- consoleHandler.setFormatter(new CustomLogFormatter());
- logger.addHandler(consoleHandler);
- String logFilePath = System.getProperty(PROPERTY_NAME_LOG_FILE_PATH);
- if (logFilePath != null) {
- File logFile = new File(logFilePath);
- FileOutputStream fos = new FileOutputStream(logFile);
- StreamHandler streamHandler = new StreamHandler(fos, new CustomLogFormatter());
- logger.addHandler(streamHandler);
- }
- }
+ long startTime = System.currentTimeMillis();
+
+ ContentAssert contentAssert = new ContentAssert(expectedContent, assertMessagePrefix.toString(), product);
+ contentAssert.assertProductContent();
- private static void removeRootLogHandler() {
- Logger rootLogger = LogManager.getLogManager().getLogger("");
- Handler[] handlers = rootLogger.getHandlers();
- for (Handler handler : handlers) {
- rootLogger.removeHandler(handler);
+ if (logger.isLoggable(Level.FINE)) {
+ double elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000.0d;
+ StringBuilder message = new StringBuilder();
+ message.append("Finish testing expected content: file: ")
+ .append(testFile.getName())
+ .append(", id: ")
+ .append(inputGraphData.getId())
+ .append(", output name: ")
+ .append(outputNameValue)
+ .append(", elapsed time: ")
+ .append(elapsedSeconds)
+ .append(" seconds.");
+ logger.log(Level.FINE, message.toString());
}
}
@@ -378,29 +409,6 @@ private static void validateFileOnDisk(File fileToValidate) throws FileNotFoundE
}
}
- private static class CustomLogFormatter extends Formatter {
-
- private final static String LINE_SEPARATOR = System.getProperty("line.separator", "\r\n");
-
- @Override
- public synchronized String format(LogRecord record) {
- StringBuilder sb = new StringBuilder();
- String message = formatMessage(record);
- sb.append(record.getLevel().getName());
- sb.append(": ");
- sb.append(message);
- sb.append(LINE_SEPARATOR);
- if (record.getThrown() != null) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- record.getThrown().printStackTrace(pw);
- pw.close();
- sb.append(sw.toString());
- }
- return sb.toString();
- }
- }
-
private static class InputGraphData {
private String id;