diff --git a/pramen/core/src/main/scala/za/co/absa/pramen/core/utils/ConfigUtils.scala b/pramen/core/src/main/scala/za/co/absa/pramen/core/utils/ConfigUtils.scala index c8c040f0b..5ccdd5c57 100644 --- a/pramen/core/src/main/scala/za/co/absa/pramen/core/utils/ConfigUtils.scala +++ b/pramen/core/src/main/scala/za/co/absa/pramen/core/utils/ConfigUtils.scala @@ -20,6 +20,7 @@ import com.typesafe.config._ import org.slf4j.LoggerFactory import za.co.absa.pramen.core.utils.StringUtils.{escapeString, trimLeft} +import java.io.{File, PrintWriter} import java.nio.file.{Files, Paths} import java.time.format.DateTimeFormatter import java.time.{DayOfWeek, LocalDate} @@ -585,4 +586,16 @@ object ConfigUtils { processStruct("", "", root, isRoot = true) } + + /** + * Writes the contents of a configuration to a file in HOCON format. + * + * @param conf A configuration. + * @param fileName The output file name. + */ + def writeConfigToFile(conf: Config, fileName: String): Unit = { + val pw = new PrintWriter(new File(fileName)) + pw.write(conf.root().render()) + pw.close() + } } diff --git a/pramen/core/src/test/scala/za/co/absa/pramen/core/PipelineRunnerSuite.scala b/pramen/core/src/test/scala/za/co/absa/pramen/core/PipelineRunnerSuite.scala index ca0341efe..eec77ca3d 100644 --- a/pramen/core/src/test/scala/za/co/absa/pramen/core/PipelineRunnerSuite.scala +++ b/pramen/core/src/test/scala/za/co/absa/pramen/core/PipelineRunnerSuite.scala @@ -16,13 +16,17 @@ package za.co.absa.pramen.core +import com.typesafe.config.ConfigFactory import org.scalatest.BeforeAndAfterAll import org.scalatest.wordspec.AnyWordSpec -import za.co.absa.pramen.base.{ExitException, NoExitSecurityManager} import za.co.absa.pramen.core.base.SparkTestBase import za.co.absa.pramen.core.fixtures.TempDirFixture +import za.co.absa.pramen.core.mocks.{ExitException, NoExitSecurityManager} +import za.co.absa.pramen.core.utils.ConfigUtils import za.co.absa.pramen.runner.PipelineRunner +import java.nio.file.Paths + class PipelineRunnerSuite extends AnyWordSpec with BeforeAndAfterAll with TempDirFixture with SparkTestBase { override def beforeAll(): Unit = System.setSecurityManager(new NoExitSecurityManager()) @@ -50,5 +54,28 @@ class PipelineRunnerSuite extends AnyWordSpec with BeforeAndAfterAll with TempDi assert(e.status != 0) } } + + "exit with zero exit code on a pipeline with minimal configuration" in { + val conf = ConfigFactory.parseString( + """pramen { + | pipeline.name = "Test pipeline" + | bookkeeping.enabled = false + | stop.spark.session = false + |} + |""".stripMargin) + withTempDirectory("pramen_main") { tempDir => + val workflowPath = Paths.get(tempDir, "workflow.conf").toString + + ConfigUtils.writeConfigToFile(conf, workflowPath) + + try { + PipelineRunner.main(Array("--workflow", workflowPath)) + } catch { + case e: ExitException => + assert(e.status == 0) + } + } + } } } + diff --git a/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/ExitException.scala b/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/ExitException.scala index a5503180b..a39f40395 100644 --- a/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/ExitException.scala +++ b/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/ExitException.scala @@ -14,6 +14,6 @@ * limitations under the License. */ -package za.co.absa.pramen.base +package za.co.absa.pramen.core.mocks case class ExitException(status: Int) extends SecurityException("System.exit() is not allowed") diff --git a/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/NoExitSecurityManager.scala b/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/NoExitSecurityManager.scala index 6be3bb414..aae14724a 100644 --- a/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/NoExitSecurityManager.scala +++ b/pramen/core/src/test/scala/za/co/absa/pramen/core/mocks/NoExitSecurityManager.scala @@ -14,7 +14,7 @@ * limitations under the License. */ -package za.co.absa.pramen.base +package za.co.absa.pramen.core.mocks import java.security.Permission