This is an automated email from the ASF dual-hosted git repository.

estrauss pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/systemds.git


The following commit(s) were added to refs/heads/main by this push:
     new c4e7e466bc [SYSTEMDS-3842] Improve test coverage of API components: 
DMLScript & DMLOptions
c4e7e466bc is described below

commit c4e7e466bc55e39569881bf36b4b88beb016dff0
Author: e-strauss <lathan...@gmx.de>
AuthorDate: Wed Apr 16 13:08:40 2025 +0200

    [SYSTEMDS-3842] Improve test coverage of API components: DMLScript & 
DMLOptions
    
    Closes #2241.
---
 src/main/java/org/apache/sysds/api/DMLOptions.java |  82 ++---
 .../apache/sysds/hops/codegen/SpoofCompiler.java   |   2 +-
 .../test/component/misc/CLIOptionsParserTest.java  | 195 +++++++++++
 .../sysds/test/component/misc/DMLScriptTest.java   | 364 +++++++++++++++++++++
 src/test/resources/conf/invalid-codegen-conf.xml   |  23 ++
 src/test/resources/conf/invalid-gpu-conf.xml       |  22 ++
 .../resources/conf/invalid-shadow-buffer1-conf.xml |  23 ++
 .../resources/conf/invalid-shadow-buffer2-conf.xml |  23 ++
 src/test/resources/conf/shadow-buffer-conf.xml     |  23 ++
 9 files changed, 716 insertions(+), 41 deletions(-)

diff --git a/src/main/java/org/apache/sysds/api/DMLOptions.java 
b/src/main/java/org/apache/sysds/api/DMLOptions.java
index a289b29bcd..763ac7b938 100644
--- a/src/main/java/org/apache/sysds/api/DMLOptions.java
+++ b/src/main/java/org/apache/sysds/api/DMLOptions.java
@@ -141,34 +141,32 @@ public class DMLOptions {
                        String lineageTypes[] = line.getOptionValues("lineage");
                        if (lineageTypes != null) {
                                for (String lineageType : lineageTypes) {
-                                       if (lineageType != null){
-                                               if 
(lineageType.equalsIgnoreCase("dedup"))
-                                                       
dmlOptions.lineage_dedup = lineageType.equalsIgnoreCase("dedup");
-                                               else if 
(lineageType.equalsIgnoreCase("reuse_full")
-                                                       || 
lineageType.equalsIgnoreCase("reuse"))
-                                                       dmlOptions.linReuseType 
= ReuseCacheType.REUSE_FULL;
-                                               else if 
(lineageType.equalsIgnoreCase("reuse_partial"))
-                                                       dmlOptions.linReuseType 
= ReuseCacheType.REUSE_PARTIAL;
-                                               else if 
(lineageType.equalsIgnoreCase("reuse_multilevel"))
-                                                       dmlOptions.linReuseType 
= ReuseCacheType.REUSE_MULTILEVEL;
-                                               else if 
(lineageType.equalsIgnoreCase("reuse_hybrid"))
-                                                       dmlOptions.linReuseType 
= ReuseCacheType.REUSE_HYBRID;
-                                               else if 
(lineageType.equalsIgnoreCase("none"))
-                                                       dmlOptions.linReuseType 
= ReuseCacheType.NONE;
-                                               else if 
(lineageType.equalsIgnoreCase("policy_lru"))
-                                                       
dmlOptions.linCachePolicy = LineageCachePolicy.LRU;
-                                               else if 
(lineageType.equalsIgnoreCase("policy_costnsize"))
-                                                       
dmlOptions.linCachePolicy = LineageCachePolicy.COSTNSIZE;
-                                               else if 
(lineageType.equalsIgnoreCase("policy_dagheight"))
-                                                       
dmlOptions.linCachePolicy = LineageCachePolicy.DAGHEIGHT;
-                                               else if 
(lineageType.equalsIgnoreCase("estimate"))
-                                                       
dmlOptions.lineage_estimate = lineageType.equalsIgnoreCase("estimate");
-                                               else if 
(lineageType.equalsIgnoreCase("debugger"))
-                                                       
dmlOptions.lineage_debugger = lineageType.equalsIgnoreCase("debugger");         
                                        
-                                               else
-                                                       throw new 
org.apache.commons.cli.ParseException(
-                                                               "Invalid 
argument specified for -lineage option: " + lineageType);
-                                       }
+                                       if 
(lineageType.equalsIgnoreCase("dedup"))
+                                               dmlOptions.lineage_dedup = 
lineageType.equalsIgnoreCase("dedup");
+                                       else if 
(lineageType.equalsIgnoreCase("reuse_full")
+                                               || 
lineageType.equalsIgnoreCase("reuse"))
+                                               dmlOptions.linReuseType = 
ReuseCacheType.REUSE_FULL;
+                                       else if 
(lineageType.equalsIgnoreCase("reuse_partial"))
+                                               dmlOptions.linReuseType = 
ReuseCacheType.REUSE_PARTIAL;
+                                       else if 
(lineageType.equalsIgnoreCase("reuse_multilevel"))
+                                               dmlOptions.linReuseType = 
ReuseCacheType.REUSE_MULTILEVEL;
+                                       else if 
(lineageType.equalsIgnoreCase("reuse_hybrid"))
+                                               dmlOptions.linReuseType = 
ReuseCacheType.REUSE_HYBRID;
+                                       else if 
(lineageType.equalsIgnoreCase("none"))
+                                               dmlOptions.linReuseType = 
ReuseCacheType.NONE;
+                                       else if 
(lineageType.equalsIgnoreCase("policy_lru"))
+                                               dmlOptions.linCachePolicy = 
LineageCachePolicy.LRU;
+                                       else if 
(lineageType.equalsIgnoreCase("policy_costnsize"))
+                                               dmlOptions.linCachePolicy = 
LineageCachePolicy.COSTNSIZE;
+                                       else if 
(lineageType.equalsIgnoreCase("policy_dagheight"))
+                                               dmlOptions.linCachePolicy = 
LineageCachePolicy.DAGHEIGHT;
+                                       else if 
(lineageType.equalsIgnoreCase("estimate"))
+                                               dmlOptions.lineage_estimate = 
true;
+                                       else if 
(lineageType.equalsIgnoreCase("debugger"))
+                                               dmlOptions.lineage_debugger = 
true;
+                                       else
+                                               throw new 
org.apache.commons.cli.ParseException(
+                                                       "Invalid argument 
specified for -lineage option: " + lineageType);
                                }
                        }
                }
@@ -186,13 +184,11 @@ public class DMLOptions {
                }
                if (line.hasOption("exec")){
                        String execMode = line.getOptionValue("exec");
-                       if (execMode != null){
-                               if (execMode.equalsIgnoreCase("singlenode")) 
dmlOptions.execMode = ExecMode.SINGLE_NODE;
-                               else if (execMode.equalsIgnoreCase("hybrid")) 
dmlOptions.execMode = ExecMode.HYBRID;
-                               else if (execMode.equalsIgnoreCase("spark")) 
dmlOptions.execMode = ExecMode.SPARK;
-                               else throw new 
org.apache.commons.cli.ParseException("Invalid argument specified for -exec 
option, must be one of [hadoop, singlenode, hybrid, HYBRID, spark]");
-                       }
-               }
+                       if (execMode.equalsIgnoreCase("singlenode")) 
dmlOptions.execMode = ExecMode.SINGLE_NODE;
+                       else if (execMode.equalsIgnoreCase("hybrid")) 
dmlOptions.execMode = ExecMode.HYBRID;
+                       else if (execMode.equalsIgnoreCase("spark")) 
dmlOptions.execMode = ExecMode.SPARK;
+                       else throw new 
org.apache.commons.cli.ParseException("Invalid argument specified for -exec 
option, must be one of [hadoop, singlenode, hybrid, HYBRID, spark]");
+       }
                if (line.hasOption("explain")) {
                        dmlOptions.explainType = ExplainType.RUNTIME;
                        String explainType = line.getOptionValue("explain");
@@ -222,7 +218,7 @@ public class DMLOptions {
                dmlOptions.statsNGrams = line.hasOption("ngrams");
                if (dmlOptions.statsNGrams){
                        String[] nGramArgs = line.getOptionValues("ngrams");
-                       if (nGramArgs.length >= 2) {
+                       if (nGramArgs != null && nGramArgs.length >= 2) {
                                try {
                                        String[] nGramSizeSplit = 
nGramArgs[0].split(",");
                                        dmlOptions.statsNGramSizes = new 
int[nGramSizeSplit.length];
@@ -273,11 +269,17 @@ public class DMLOptions {
 
                if (line.hasOption("fedMonitoring")) {
                        dmlOptions.fedMonitoring= true;
-                       dmlOptions.fedMonitoringPort = 
Integer.parseInt(line.getOptionValue("fedMonitoring"));
+                       String port = line.getOptionValue("fedMonitoring");
+                       if(port != null)
+                               dmlOptions.fedMonitoringPort = 
Integer.parseInt(port);
+                       else
+                               throw new 
org.apache.commons.cli.ParseException("No port [integer] specified for 
-fedMonitoring option");
                }
 
                if (line.hasOption("fedMonitoringAddress")) {
                        dmlOptions.fedMonitoringAddress = 
line.getOptionValue("fedMonitoringAddress");
+                       if(dmlOptions.fedMonitoringAddress == null)
+                               throw new 
org.apache.commons.cli.ParseException("No address [String] specified for 
-fedMonitoringAddress option");
                }
 
                if (line.hasOption("f")){
@@ -326,7 +328,7 @@ public class DMLOptions {
                        OptimizerUtils.FEDERATED_COMPILATION = true;
                        dmlOptions.federatedCompilation = true;
                        String[] fedCompSpecs = 
line.getOptionValues("federatedCompilation");
-                       if ( fedCompSpecs != null && fedCompSpecs.length > 0 ){
+                       if (fedCompSpecs != null){
                                for ( String spec : fedCompSpecs ){
                                        String[] specPair = spec.split("=");
                                        if (specPair.length != 2){
@@ -370,8 +372,8 @@ public class DMLOptions {
                        .withDescription("monitors and reports summary 
execution statistics; heavy hitter <count> is 10 unless overridden; default 
off")
                        .hasOptionalArg().create("stats");
                Option ngramsOpt = OptionBuilder//.withArgName("ngrams")
-                       .withDescription("monitors and reports the most 
occurring n-grams; -ngrams <comma separated n's> <topK>")
-                       .hasOptionalArgs(2).create("ngrams");
+                       .withDescription("monitors and reports the most 
occurring n-grams; -ngrams <comma separated n's> <topK> <boolean lineage>")
+                       .hasOptionalArgs(3).create("ngrams");
                Option fedStatsOpt = OptionBuilder.withArgName("count")
                        .withDescription("monitors and reports summary 
execution statistics of federated workers; heavy hitter <count> is 10 unless 
overridden; default off")
                        .hasOptionalArg().create("fedStats");
diff --git a/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java 
b/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java
index c0e1a2a320..34329ca64d 100644
--- a/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java
+++ b/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java
@@ -223,7 +223,7 @@ public class SpoofCompiler {
                        else {
                                local_tmp = System.getProperty("user.dir") + 
"/src/main".replace("/", File.separator);
                        }
-                       
+                       // TODO: Code is unreachable here
                        if(generator == GeneratorAPI.CUDA) {
                                // init GPUs with jCuda to avoid double 
initialization problems
                                GPUContextPool.initializeGPU();
diff --git 
a/src/test/java/org/apache/sysds/test/component/misc/CLIOptionsParserTest.java 
b/src/test/java/org/apache/sysds/test/component/misc/CLIOptionsParserTest.java
index 3e6239b5e4..ec8843440a 100644
--- 
a/src/test/java/org/apache/sysds/test/component/misc/CLIOptionsParserTest.java
+++ 
b/src/test/java/org/apache/sysds/test/component/misc/CLIOptionsParserTest.java
@@ -24,6 +24,9 @@ import java.util.Map;
 import org.apache.commons.cli.AlreadySelectedException;
 import org.apache.commons.cli.MissingOptionException;
 import org.apache.commons.cli.ParseException;
+import org.apache.sysds.hops.OptimizerUtils;
+import org.apache.sysds.runtime.instructions.fed.FEDInstruction;
+import org.apache.sysds.runtime.lineage.LineageCacheConfig;
 import org.junit.Assert;
 import org.junit.Test;
 import org.apache.sysds.api.DMLOptions;
@@ -31,6 +34,8 @@ import org.apache.sysds.common.Types.ExecMode;
 import org.apache.sysds.runtime.lineage.LineageCacheConfig.ReuseCacheType;
 import org.apache.sysds.utils.Explain;
 
+import static org.apache.sysds.api.DMLOptions.parseCLArguments;
+
 @net.jcip.annotations.NotThreadSafe
 public class CLIOptionsParserTest {
 
@@ -162,6 +167,7 @@ public class CLIOptionsParserTest {
                Assert.assertEquals(ReuseCacheType.REUSE_PARTIAL, 
o.linReuseType);
                Assert.assertEquals(false, o.lineage_dedup);
        }
+
        @Test
        public void testLineageReuseH() throws Exception {
                String cl = "systemds -f test.dml -lineage reuse_hybrid";
@@ -450,4 +456,193 @@ public class CLIOptionsParserTest {
                Map<String, String> m = o.argVals;
                Assert.assertEquals("'def'", m.get("$abc"));
        }
+
+       @Test
+       public void parseCLArgumentsLineageDAGHEIGHTTest() throws 
ParseException {
+               String[] args = new String[]{"-f", "test", "-lineage", 
"policy_dagheight"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.lineage && opts.linCachePolicy == 
LineageCacheConfig.LineageCachePolicy.DAGHEIGHT);
+       }
+
+       @Test
+       public void parseCLIArgumentsLineageEstimateTest() throws 
ParseException {
+               String[] args = new String[]{"-f", "test", "-lineage", 
"estimate"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.lineage && opts.lineage_estimate);
+       }
+
+       @Test
+       public void parseCLArgumentsGPUTest() throws ParseException {
+               String[] args = new String[]{"-f", "test", "-gpu",};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.gpu);
+       }
+
+       @Test
+       public void parseCLArgumentsInvalidExplainTest() throws ParseException {
+               String[] args = new String[]{"-f", "test","-explain","XYZ"};
+               try {
+                       parseCLArguments(args);
+               } catch (ParseException e) {
+                       assert e.getMessage().equals("Invalid argument 
specified for -hops option, must be one of [hops, runtime, recompile_hops, 
recompile_runtime, codegen, codegen_recompile]");
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsExplainCodegenRecompileTest() throws 
ParseException {
+               String[] args = new String[]{"-f", 
"test","-explain","codegen_recompile"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertEquals(opts.explainType, 
Explain.ExplainType.CODEGEN_RECOMPILE);
+       }
+
+       @Test
+       public void parseCLArgumentsNGramsTest1() throws ParseException {
+               String[] args = new String[]{"-f", "test", "-ngrams",};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.statsNGrams);
+       }
+
+       @Test
+       public void parseCLArgumentsNGramsTest2() throws ParseException {
+               String[] args =  new String[]{"-f", "test", "-ngrams","1"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.statsNGrams);
+       }
+
+       @Test
+       public void parseCLArgumentsNGramsTest3() throws ParseException {
+               String[] args = new String[]{"-f", "test", 
"-ngrams","1","1","FALSE"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.statsNGrams);
+               Assert.assertEquals(opts.statsNGramSizes[0], 1);
+               Assert.assertEquals(opts.statsTopKNGrams, 1);
+               Assert.assertFalse(opts.statsNGramsUseLineage);
+       }
+
+       @Test
+       public void parseCLArgumentsNGramsTest4() throws ParseException {
+               String[] args = new String[]{"-f", "test", "-ngrams","1,3","1"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.statsNGrams);
+               Assert.assertEquals(opts.statsNGramSizes[0], 1);
+               Assert.assertEquals(opts.statsNGramSizes[1], 3);
+               Assert.assertEquals(opts.statsTopKNGrams, 1);
+               Assert.assertTrue(opts.statsNGramsUseLineage);
+       }
+
+       @Test
+       public void parseCLArgumentsNGramsTest5() throws ParseException {
+               String[] args = new String[]{"-f", "test","-ngrams","1,2","b"};
+               try {
+                       parseCLArguments(args);
+               } catch (ParseException e) {
+                       assert e.getMessage().equals("Invalid argument 
specified for -ngrams option, must be a valid integer");
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsFEDStatsTest1() throws ParseException {
+               String[] args = new String[]{"-f", "test", "-fedStats",};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.fedStats);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDStatsTest2() throws ParseException {
+               String[] args = new String[]{"-f", "test", "-fedStats", "21"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.fedStats);
+               Assert.assertEquals(21, opts.fedStatsCount);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDStatsTest3() {
+               String[] args = new String[]{"-f", "test", "-fedStats", "xyz"};
+               try {
+                       parseCLArguments(args);
+               } catch (ParseException e) {
+                       assert e.getMessage().equals("Invalid argument 
specified for -fedStats option, must be a valid integer");
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsFEDMonitoringTest1() {
+               String[] args = new String[]{"-fedMonitoring"};
+               try {
+                       parseCLArguments(args);
+               } catch (ParseException e) {
+                       assert e.getMessage().equals("No port [integer] 
specified for -fedMonitoring option");
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsFEDMonitoringTest2() {
+               String[] args = new String[]{"-fedMonitoring","21", 
"-fedMonitoringAddress"};
+               try {
+                       parseCLArguments(args);
+               } catch (ParseException e) {
+                       assert e.getMessage().equals("No address [String] 
specified for -fedMonitoringAddress option");
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsFEDMonitoringTest3() throws ParseException {
+               String[] args = new String[]{"-fedMonitoring", "21"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.fedMonitoring);
+               Assert.assertEquals(21, opts.fedMonitoringPort);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDMonitoringTest4() throws ParseException {
+               String[] args = new String[]{"-fedMonitoring", "21", 
"-fedMonitoringAddress", "xyz"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.fedMonitoring);
+               Assert.assertEquals(21, opts.fedMonitoringPort);
+               Assert.assertEquals("xyz", opts.fedMonitoringAddress);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDCompilationTest1() throws ParseException 
{
+               String[] args = new String[]{"-f", "test", 
"-federatedCompilation"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.federatedCompilation);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDCompilationTest2() throws ParseException 
{
+               String[] args = new String[]{"-f", "test", 
"-federatedCompilation", "1=NONE"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.federatedCompilation);
+               Assert.assertEquals(OptimizerUtils.FEDERATED_SPECS.get(1), 
FEDInstruction.FederatedOutput.NONE);
+       }
+
+       @Test
+       public void parseCLArgumentsFEDCompilationTest3() {
+               String[] args = new String[]{"-f","test", 
"-federatedCompilation","1=n=n"};
+               try {
+                       parseCLArguments(args);
+                       throw new AssertionError("Test should have resulted in 
Exception");
+               } catch (ParseException e){
+                       Assert.assertEquals("Invalid argument specified for 
-federatedCompilation option, must be a list of space separated K=V pairs, 
where K is a line number of the DML script and V is a federated output 
value",e.getMessage());
+               }
+       }
+
+       @Test
+       public void parseCLArgumentsFEDNoRuntimeConversionTest() throws 
ParseException {
+               String[] args = new String[]{"-f", "test", 
"-noFedRuntimeConversion"};
+               DMLOptions opts = parseCLArguments(args);
+               Assert.assertTrue(opts.noFedRuntimeConversion);
+       }
+
+       @Test
+       public void testDMLOptionToString() throws ParseException {
+               String cl = "systemds -f test.dml -exec spark";
+               String[] args = cl.split(" ");
+               DMLOptions o = DMLOptions.parseCLArguments(args);
+               String oString = o.toString();
+               Assert.assertTrue(oString.contains("script='null'"));
+               Assert.assertTrue(oString.contains("filePath='test.dml'"));
+               Assert.assertTrue(oString.contains("execMode=SPARK"));
+       }
 }
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/sysds/test/component/misc/DMLScriptTest.java 
b/src/test/java/org/apache/sysds/test/component/misc/DMLScriptTest.java
new file mode 100644
index 0000000000..5b5483823a
--- /dev/null
+++ b/src/test/java/org/apache/sysds/test/component/misc/DMLScriptTest.java
@@ -0,0 +1,364 @@
+/*
+ * 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.sysds.test.component.misc;
+
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.sysds.api.DMLOptions;
+import org.apache.sysds.api.DMLScript;
+import org.apache.sysds.parser.LanguageException;
+import org.apache.sysds.test.LoggingUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static org.apache.sysds.api.DMLScript.executeScript;
+import static org.apache.sysds.api.DMLScript.readDMLScript;
+
+@net.jcip.annotations.NotThreadSafe
+public class DMLScriptTest {
+
+    @Test
+    public void executeDMLScriptParsingExceptionTest() throws IOException {
+        // Create a ListAppender to capture log messages
+        final LoggingUtils.TestAppender appender = LoggingUtils.overwrite();
+        try {
+            Logger.getLogger(DMLScript.class).setLevel(Level.DEBUG);
+
+            String[] args = new String[]{"-f", "test","-explain","XYZ"};
+            Assert.assertFalse(executeScript(args));
+
+            final List<LoggingEvent> log = LoggingUtils.reinsert(appender);
+            Assert.assertEquals(log.get(0).getMessage(), "Parsing Exception 
Invalid argument specified for -hops option, must be one of [hops, runtime, 
recompile_hops, recompile_runtime, codegen, codegen_recompile]");
+        } finally {
+            LoggingUtils.reinsert(appender);
+        }
+    }
+
+    @Test
+    public void executeDMLScriptAlreadySelectedExceptionTest() throws 
IOException {
+        final LoggingUtils.TestAppender appender = LoggingUtils.overwrite();
+        try {
+            Logger.getLogger(DMLScript.class).setLevel(Level.DEBUG);
+
+            String[] args = new String[]{"-f", "test", "-clean"};
+            Assert.assertFalse(executeScript(args));
+
+            final List<LoggingEvent> log = LoggingUtils.reinsert(appender);
+            Assert.assertEquals(log.get(0).getMessage(), "Mutually exclusive 
options were selected. The option 'clean' was specified but an option from this 
group has already been selected: 'f'");
+        } finally {
+            LoggingUtils.reinsert(appender);
+        }
+    }
+
+    @Test
+    public void executeDMLHelpTest() throws IOException {
+        String[] args = new String[]{"-help"};
+        Assert.assertTrue(executeScript(args));
+    }
+
+    @Test
+    public void executeDMLCleanTest() throws IOException {
+        String[] args = new String[]{"-clean"};
+        Assert.assertTrue(executeScript(args));
+    }
+
+    @Test
+    public void executeDMLfedMonitoringTest() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+
+        try {
+            String[] args = new String[]{"-fedMonitoring", "1"};
+            Future<?> future = executor.submit(() -> executeScript(args));
+
+            try {
+                future.get(10, TimeUnit.SECONDS); // Wait for up to 10 seconds
+            } catch (TimeoutException e) {
+                future.cancel(true); // Cancel if timeout occurs
+                System.out.println("Test fedMonitoring was forcefully 
terminated after 10s.");
+            } catch (Exception e) {
+                future.cancel(true); // Cancel in case of any other failure
+                throw new RuntimeException("Test execution failed", e);
+            }
+        } finally {
+            executor.shutdownNow();
+        }
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void executeDMLfedMonitoringAddressTest1() throws Throwable {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        try {
+            String[] args = new 
String[]{"-f","src/test/scripts/usertest/helloWorld.dml","-fedMonitoringAddress",
+                    "http://localhost:8080"};
+            Future<?> future = executor.submit(() -> executeScript(args));
+            try {
+                future.get(10, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                future.cancel(true);
+                System.out.println("Test fedMonitoring was forcefully 
terminated after 10s.");
+            } catch (Exception e) {
+                future.cancel(true);
+                throw e.getCause();
+            }
+        } finally {
+            executor.shutdownNow();
+            DMLScript.MONITORING_ADDRESS = null;
+        }
+    }
+
+    @Test
+    public void executeDMLfedMonitoringAddressTest2() throws Throwable {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        try {
+            String[] args = new 
String[]{"-f","src/test/scripts/usertest/helloWorld.dml","-fedMonitoringAddress",
+                    "https://example.com"};
+            Future<?> future = executor.submit(() -> executeScript(args));
+            try {
+                future.get(10, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                future.cancel(true);
+                System.out.println("Test fedMonitoring was forcefully 
terminated after 10s.");
+            } catch (Exception e) {
+                future.cancel(true);
+                throw e.getCause();
+            }
+        } finally {
+            executor.shutdownNow();
+            DMLScript.MONITORING_ADDRESS = null;
+        }
+    }
+
+    @Test
+    public void executeDMLWithScriptTest() throws IOException {
+        String cl = "systemds -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        final PrintStream originalOut = System.out;
+        final ByteArrayOutputStream outputStreamCaptor = new 
ByteArrayOutputStream();
+
+        System.setOut(new PrintStream(outputStreamCaptor));
+        try{
+            Assert.assertTrue(executeScript(args));
+            Assert.assertEquals("hello", 
outputStreamCaptor.toString().split(System.lineSeparator())[0]);
+        } finally {
+            System.setOut(originalOut);
+        }
+    }
+
+    @Test(expected = LanguageException.class)
+    public void readDMLWithNoScriptTest() throws IOException {
+        readDMLScript(false, null);
+    }
+
+    @Test(expected = LanguageException.class)
+    public void readDMLWithNoFilepathTest() throws IOException {
+        readDMLScript(true, null);
+    }
+
+    @Test(expected = IOException.class)
+    public void readDMLWrongHDFSPathTest1() throws IOException {
+        readDMLScript(true, "hdfs:/namenodehost/test.txt");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void readDMLWrongHDFSPathTes2t() throws IOException {
+        readDMLScript(true, "hdfs://namenodehost/test.txt");
+    }
+
+    @Test(expected = IOException.class)
+    public void readDMLWrongGPFSPathTest() throws IOException {
+        readDMLScript(true, "gpfs:/namenodehost/test.txt");
+    }
+
+    @Test
+    public void setActiveAMTest(){
+        DMLScript.setActiveAM();
+        try {
+
+            Assert.assertTrue(DMLScript.isActiveAM());
+        } finally {
+            DMLScript._activeAM = false;
+        }
+    }
+
+    @Test
+    public void runDMLScriptMainLanguageExceptionTest(){
+        String cl = "systemds -debug -s \"printx('hello')\"";
+        String[] args = cl.split(" ");
+        final PrintStream originalErr = System.err;
+
+        try {
+            final ByteArrayOutputStream outputStreamCaptor = new 
ByteArrayOutputStream();
+            System.setErr(new PrintStream(outputStreamCaptor));
+            DMLScript.main(args);
+            System.setErr(originalErr);
+            
Assert.assertTrue(outputStreamCaptor.toString().split(System.lineSeparator())[0]
+                    .startsWith("org.apache.sysds.parser.LanguageException: 
ERROR: [line 1:0] -> printx('hello') -- function printx is undefined"));
+        } finally {
+            System.setErr(originalErr);
+        }
+
+    }
+
+    @Test
+    public void runDMLScriptMainDMLRuntimeExceptionTest(){
+        String cl = "systemds -s 
\"F=as.frame(matrix(1,1,1));spec=\"{ids:true,recod:[1]}\";" +
+                "M=transformapply(target=F,spec=spec,meta=F);print(M[1,1]) \"";
+        String[] args = cl.split(" ");
+
+        final PrintStream originalOut = System.out;
+        try {
+            final ByteArrayOutputStream outputStreamCaptor = new 
ByteArrayOutputStream();
+            System.setOut(new PrintStream(outputStreamCaptor));
+            DMLScript.main(args);
+            System.setOut(originalOut);
+            String[] lines = 
outputStreamCaptor.toString().split(System.lineSeparator());
+            for (int i = 0; i < lines.length; i++) {
+                if(lines[i].startsWith("An Error Occurred :")){
+                    for (int j = 0; j < 4; j++) {
+                        Assert.assertTrue(lines[i + 1 + 
j].trim().startsWith("DMLRuntimeException"));
+                    }
+                    break;
+                }
+            }
+        } finally {
+            System.setOut(originalOut);
+        }
+
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void executeDMLWithScriptInvalidConfTest1() throws IOException {
+        String cl = "systemds -config 
src/test/resources/conf/invalid-gpu-conf.xml -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        executeScript(args);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void executeDMLWithScriptInvalidConfTest2() throws IOException {
+        String cl = "systemds -config 
src/test/resources/conf/invalid-shadow-buffer1-conf.xml -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        executeScript(args);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void executeDMLWithScriptInvalidConfTest3() throws IOException {
+        String cl = "systemds -config 
src/test/resources/conf/invalid-shadow-buffer2-conf.xml -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        executeScript(args);
+    }
+
+    @Test
+    public void executeDMLWithScriptValidCodegenConfTest() throws IOException {
+        String cl = "systemds -config 
src/test/resources/conf/invalid-codegen-conf.xml -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        executeScript(args);
+    }
+
+    @Test
+    public void executeDMLWithScriptShadowBufferWarnTest() throws IOException {
+        String cl = "systemds -config 
src/test/resources/conf/shadow-buffer-conf.xml -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        DMLScript.EVICTION_SHADOW_BUFFER_CURR_BYTES =1000000000L;
+
+        final PrintStream originalOut = System.out;
+        try {
+            final ByteArrayOutputStream outputStreamCaptor = new 
ByteArrayOutputStream();
+            System.setOut(new PrintStream(outputStreamCaptor));
+            executeScript(args);
+            System.setOut(originalOut);
+            String[] lines = 
outputStreamCaptor.toString().split(System.lineSeparator());
+            Assert.assertTrue(lines[0].startsWith("WARN: Cannot use the shadow 
buffer due to potentially cached GPU objects. Current shadow buffer size (in 
bytes)"));
+        } finally {
+            System.setOut(originalOut);
+        }
+    }
+
+    @Test
+    public void executeDMLWithScriptAndInfoTest() throws IOException {
+        String cl = "systemds -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+        Logger.getLogger(DMLScript.class).setLevel(Level.INFO);
+        final LoggingUtils.TestAppender appender = LoggingUtils.overwrite();
+        try {
+            Assert.assertTrue(executeScript(args));
+            final List<LoggingEvent> log = LoggingUtils.reinsert(appender);
+            try {
+                int i = log.get(0).getMessage().toString().startsWith("Low 
memory budget") ? 1 : 0;
+                
Assert.assertTrue(log.get(i++).getMessage().toString().startsWith("BEGIN DML 
run"));
+                
Assert.assertTrue(log.get(i).getMessage().toString().startsWith("Process id"));
+            } catch (Error e) {
+                System.out.println("ERROR while evaluating INFO logs: ");
+                for (LoggingEvent loggingEvent : log) {
+                    System.out.println(loggingEvent.getMessage());
+                }
+                throw e;
+            }
+
+        } finally {
+            LoggingUtils.reinsert(appender);
+        }
+    }
+
+    @Test
+    public void executeDMLWithScriptAndDebugTest() throws IOException {
+        // have to run sequentially, to avoid concurrent call to 
Logger.getLogger(DMLScript.class)
+        String cl = "systemds -s \"print('hello')\"";
+        String[] args = cl.split(" ");
+
+        Logger.getLogger(DMLScript.class).setLevel(Level.DEBUG);
+        final LoggingUtils.TestAppender appender2 = LoggingUtils.overwrite();
+        try{
+            Assert.assertTrue(executeScript(args));
+            final List<LoggingEvent> log = LoggingUtils.reinsert(appender2);
+            try {
+                int i = log.get(0).getMessage().toString().startsWith("Low 
memory budget") ? 2 : 1;
+                
Assert.assertTrue(log.get(i++).getMessage().toString().startsWith("BEGIN DML 
run"));
+                
Assert.assertTrue(log.get(i++).getMessage().toString().startsWith("DML 
script"));
+                
Assert.assertTrue(log.get(i).getMessage().toString().startsWith("Process id"));
+            } catch (Error e){
+                for (LoggingEvent loggingEvent : log) {
+                    System.out.println(loggingEvent.getMessage());
+                }
+                throw e;
+            }
+        } finally {
+            LoggingUtils.reinsert(appender2);
+        }
+    }
+
+    @Test
+    public void createDMLScriptInstance(){
+        DMLScript script = new DMLScript();
+        Assert.assertTrue(script != null);
+    }
+}
diff --git a/src/test/resources/conf/invalid-codegen-conf.xml 
b/src/test/resources/conf/invalid-codegen-conf.xml
new file mode 100644
index 0000000000..df1be48365
--- /dev/null
+++ b/src/test/resources/conf/invalid-codegen-conf.xml
@@ -0,0 +1,23 @@
+<!--
+ * 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.
+-->
+
+<root>
+    <sysds.codegen.enabled>true</sysds.codegen.enabled>
+    <sysds.codegen.api>CUDA</sysds.codegen.api>
+</root>
diff --git a/src/test/resources/conf/invalid-gpu-conf.xml 
b/src/test/resources/conf/invalid-gpu-conf.xml
new file mode 100644
index 0000000000..28a7f595c7
--- /dev/null
+++ b/src/test/resources/conf/invalid-gpu-conf.xml
@@ -0,0 +1,22 @@
+<!--
+ * 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.
+-->
+
+<root>
+    <sysds.gpu.memory.util.factor>-1</sysds.gpu.memory.util.factor>
+</root>
diff --git a/src/test/resources/conf/invalid-shadow-buffer1-conf.xml 
b/src/test/resources/conf/invalid-shadow-buffer1-conf.xml
new file mode 100644
index 0000000000..6574d3c1ac
--- /dev/null
+++ b/src/test/resources/conf/invalid-shadow-buffer1-conf.xml
@@ -0,0 +1,23 @@
+<!--
+ * 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.
+-->
+
+<root>
+    <sysds.floating.point.precision>single</sysds.floating.point.precision>
+    
<sysds.gpu.eviction.shadow.bufferSize>2</sysds.gpu.eviction.shadow.bufferSize>
+</root>
diff --git a/src/test/resources/conf/invalid-shadow-buffer2-conf.xml 
b/src/test/resources/conf/invalid-shadow-buffer2-conf.xml
new file mode 100644
index 0000000000..33203bb255
--- /dev/null
+++ b/src/test/resources/conf/invalid-shadow-buffer2-conf.xml
@@ -0,0 +1,23 @@
+<!--
+ * 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.
+-->
+
+<root>
+    <sysds.floating.point.precision>single</sysds.floating.point.precision>
+    
<sysds.gpu.eviction.shadow.bufferSize>-1</sysds.gpu.eviction.shadow.bufferSize>
+</root>
diff --git a/src/test/resources/conf/shadow-buffer-conf.xml 
b/src/test/resources/conf/shadow-buffer-conf.xml
new file mode 100644
index 0000000000..ddc32be334
--- /dev/null
+++ b/src/test/resources/conf/shadow-buffer-conf.xml
@@ -0,0 +1,23 @@
+<!--
+ * 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.
+-->
+
+<root>
+    <sysds.floating.point.precision>single</sysds.floating.point.precision>
+    
<sysds.gpu.eviction.shadow.bufferSize>0.01</sysds.gpu.eviction.shadow.bufferSize>
+</root>


Reply via email to