From 2db85738d25def778d2f9d05db20b6c5e56d82ae Mon Sep 17 00:00:00 2001 From: e-strauss Date: Wed, 5 Mar 2025 14:14:55 +0100 Subject: [PATCH] [SYSTEMDS-3842] Improve test coverage of API components: DMLScript & DMLOptions --- .../java/org/apache/sysds/api/DMLOptions.java | 82 ++-- .../sysds/hops/codegen/SpoofCompiler.java | 2 +- .../component/misc/CLIOptionsParserTest.java | 195 ++++++++++ .../test/component/misc/DMLScriptTest.java | 364 ++++++++++++++++++ .../resources/conf/invalid-codegen-conf.xml | 23 ++ src/test/resources/conf/invalid-gpu-conf.xml | 22 ++ .../conf/invalid-shadow-buffer1-conf.xml | 23 ++ .../conf/invalid-shadow-buffer2-conf.xml | 23 ++ .../resources/conf/shadow-buffer-conf.xml | 23 ++ 9 files changed, 716 insertions(+), 41 deletions(-) create mode 100644 src/test/java/org/apache/sysds/test/component/misc/DMLScriptTest.java create mode 100644 src/test/resources/conf/invalid-codegen-conf.xml create mode 100644 src/test/resources/conf/invalid-gpu-conf.xml create mode 100644 src/test/resources/conf/invalid-shadow-buffer1-conf.xml create mode 100644 src/test/resources/conf/invalid-shadow-buffer2-conf.xml create mode 100644 src/test/resources/conf/shadow-buffer-conf.xml diff --git a/src/main/java/org/apache/sysds/api/DMLOptions.java b/src/main/java/org/apache/sysds/api/DMLOptions.java index a289b29bcde..763ac7b9388 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 static DMLOptions parseCLArguments(String[] args) 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 @@ else if (lineageType.equalsIgnoreCase("debugger")) } 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 @@ else if (lineageType.equalsIgnoreCase("debugger")) 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 @@ else if (lineageType.equalsIgnoreCase("debugger")) 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 @@ else if (lineageType.equalsIgnoreCase("debugger")) 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 @@ private static Options createCLIOptions() { .withDescription("monitors and reports summary execution statistics; heavy hitter is 10 unless overridden; default off") .hasOptionalArg().create("stats"); Option ngramsOpt = OptionBuilder//.withArgName("ngrams") - .withDescription("monitors and reports the most occurring n-grams; -ngrams ") - .hasOptionalArgs(2).create("ngrams"); + .withDescription("monitors and reports the most occurring n-grams; -ngrams ") + .hasOptionalArgs(3).create("ngrams"); Option fedStatsOpt = OptionBuilder.withArgName("count") .withDescription("monitors and reports summary execution statistics of federated workers; heavy hitter 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 c0e1a2a320c..34329ca64dc 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 static void loadNativeCodeGenerator(GeneratorAPI generator) { 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 3e6239b5e49..ec8843440a3 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 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.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 void testLineageReuseP() throws Exception { 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 void testNVArgs4() throws Exception { Map 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 00000000000..5b5483823ad --- /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 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 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 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 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 00000000000..df1be48365b --- /dev/null +++ b/src/test/resources/conf/invalid-codegen-conf.xml @@ -0,0 +1,23 @@ + + + + true + CUDA + 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 00000000000..28a7f595c75 --- /dev/null +++ b/src/test/resources/conf/invalid-gpu-conf.xml @@ -0,0 +1,22 @@ + + + + -1 + 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 00000000000..6574d3c1ac1 --- /dev/null +++ b/src/test/resources/conf/invalid-shadow-buffer1-conf.xml @@ -0,0 +1,23 @@ + + + + single + 2 + 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 00000000000..33203bb2553 --- /dev/null +++ b/src/test/resources/conf/invalid-shadow-buffer2-conf.xml @@ -0,0 +1,23 @@ + + + + single + -1 + 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 00000000000..ddc32be3349 --- /dev/null +++ b/src/test/resources/conf/shadow-buffer-conf.xml @@ -0,0 +1,23 @@ + + + + single + 0.01 +