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

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 4c9d30a132 test(config): add unit test coverage for the remaining 
config objects (#6094)
4c9d30a132 is described below

commit 4c9d30a132672b9a0e8ecfe1d480a473dae16e4d
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sat Jul 4 01:27:46 2026 -0700

    test(config): add unit test coverage for the remaining config objects 
(#6094)
    
    ### What changes were proposed in this PR?
    
    Add unit test coverage for the remaining `common/config` objects,
    selected from the Codecov report (all 0%). No production-code changes.
    
    | File | Codecov before | What the tests pin |
    | --- | --- | --- |
    | `UdfConfig.scala` | 0% | python/R path + log handler defaults from
    udf.conf |
    | `DefaultsConfig.scala` | 0% | the `reinit` flag and the flattened
    `allDefaults` short-key/value map from default.conf |
    | `ComputingUnitConfig.scala` | 0% | local/sharing enabled flags |
    | `LLMConfig.scala` | 0% | LiteLLM base URL + master key |
    | `PekkoConfig.scala` | 0% | actor/serialization, remote/artery, and
    cluster/failure-detector settings from cluster.conf (no ActorSystem
    started) |
    | `PythonUtils.scala` | 0% | `getPythonExecutable` blank→`python3`
    fallback and trimmed-path branch |
    
    Reading each value forces resolution from the backing `.conf`;
    env/system-property-overridable values are guarded on the override being
    unset (mirroring `StorageConfigSpec`).
    
    ### Any related issues, documentation, discussions?
    
    Follow-up to the review feedback on #6043: prioritize tests that fill
    uncovered code paths.
    
    ### How was this PR tested?
    
    - `sbt "Config/testOnly *UdfConfigSpec *DefaultsConfigSpec
    *ComputingUnitConfigSpec *LLMConfigSpec *PekkoConfigSpec
    *PythonUtilsSpec"` — 13 tests, all green
    - `sbt "Config/Test/scalafmtCheck"` and `sbt "Config/scalafixAll
    --check"` — clean
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../common/config/ComputingUnitConfigSpec.scala    | 43 ++++++++++++
 .../texera/common/config/DefaultsConfigSpec.scala  | 52 ++++++++++++++
 .../texera/common/config/LLMConfigSpec.scala       | 39 +++++++++++
 .../texera/common/config/PekkoConfigSpec.scala     | 79 ++++++++++++++++++++++
 .../texera/common/config/PythonUtilsSpec.scala     | 52 ++++++++++++++
 .../texera/common/config/UdfConfigSpec.scala       | 53 +++++++++++++++
 6 files changed, 318 insertions(+)

diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/ComputingUnitConfigSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/ComputingUnitConfigSpec.scala
new file mode 100644
index 0000000000..40608acf1c
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/ComputingUnitConfigSpec.scala
@@ -0,0 +1,43 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[ComputingUnitConfig]]. Reading each value forces resolution 
from computing-unit.conf,
+  * so a renamed or mistyped key surfaces here as a ConfigException. Both 
flags carry a `${?ENV}`
+  * override, so exact-value assertions are guarded.
+  */
+class ComputingUnitConfigSpec extends AnyFlatSpec with Matchers {
+
+  private def ifUnset(name: String)(assertion: => Any): Unit =
+    if (!sys.env.contains(name) && !sys.props.contains(name)) assertion
+
+  "ComputingUnitConfig" should "resolve the local/sharing flags from 
computing-unit.conf" in {
+    ifUnset("COMPUTING_UNIT_LOCAL_ENABLED")(
+      ComputingUnitConfig.localComputingUnitEnabled shouldBe true
+    )
+    ifUnset("COMPUTING_UNIT_SHARING_ENABLED")(
+      ComputingUnitConfig.sharingComputingUnitEnabled shouldBe false
+    )
+  }
+}
diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/DefaultsConfigSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/DefaultsConfigSpec.scala
new file mode 100644
index 0000000000..3da26e1ff8
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/DefaultsConfigSpec.scala
@@ -0,0 +1,52 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[DefaultsConfig]]. Reading each value forces resolution from 
default.conf, so a
+  * renamed or mistyped key surfaces here as a ConfigException. The `reinit` 
flag carries a
+  * `${?ENV}` override, so its exact-value assertion is guarded.
+  */
+class DefaultsConfigSpec extends AnyFlatSpec with Matchers {
+
+  private def ifUnset(name: String)(assertion: => Any): Unit =
+    if (!sys.env.contains(name) && !sys.props.contains(name)) assertion
+
+  "DefaultsConfig.reinit" should "default the reset-to-defaults flag to false" 
in {
+    ifUnset("CONFIG_SERVICE_ALWAYS_RESET_CONFIGURATIONS_TO_DEFAULT_VALUES")(
+      DefaultsConfig.reinit shouldBe false
+    )
+  }
+
+  "DefaultsConfig.allDefaults" should "flatten default.conf into 
short-key/value entries" in {
+    val defaults = DefaultsConfig.allDefaults
+    defaults should not be empty
+    // scalar leaves are flattened to their last path segment
+    ifUnset("DATASET_SINGLE_FILE_UPLOAD_MAX_SIZE_MIB")(
+      defaults.get("single_file_upload_max_size_mib") shouldBe Some("20")
+    )
+    ifUnset("GUI_TABS_HUB_ENABLED")(defaults.get("hub_enabled") shouldBe 
Some("true"))
+    // every value is rendered as a String
+    defaults.values.foreach(_ shouldBe a[String])
+  }
+}
diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/LLMConfigSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/LLMConfigSpec.scala
new file mode 100644
index 0000000000..ee64a32300
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/LLMConfigSpec.scala
@@ -0,0 +1,39 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[LLMConfig]]. Reading each value forces resolution from 
llm.conf, so a renamed or
+  * mistyped key surfaces here as a ConfigException. Both values carry a 
`${?ENV}` override, so
+  * exact-value assertions are guarded.
+  */
+class LLMConfigSpec extends AnyFlatSpec with Matchers {
+
+  private def ifUnset(name: String)(assertion: => Any): Unit =
+    if (!sys.env.contains(name) && !sys.props.contains(name)) assertion
+
+  "LLMConfig" should "resolve the LiteLLM base URL and master key from 
llm.conf" in {
+    ifUnset("LITELLM_BASE_URL")(LLMConfig.baseUrl shouldBe 
"http://0.0.0.0:4000";)
+    ifUnset("LITELLM_MASTER_KEY")(LLMConfig.masterKey shouldBe "")
+  }
+}
diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/PekkoConfigSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/PekkoConfigSpec.scala
new file mode 100644
index 0000000000..13282f286d
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/PekkoConfigSpec.scala
@@ -0,0 +1,79 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[PekkoConfig]]. Reading keys off the returned config forces 
resolution of cluster.conf
+  * (merged with the Typesafe default application config), so a renamed or 
mistyped key surfaces here
+  * as a ConfigException. The log level carries a `${?ENV}` override, so its 
assertion is guarded.
+  */
+class PekkoConfigSpec extends AnyFlatSpec with Matchers {
+
+  "PekkoConfig.pekkoConfig" should "load the actor/serialization settings from 
cluster.conf" in {
+    val config = PekkoConfig.pekkoConfig
+    config.getString("pekko.actor.provider") shouldBe "cluster"
+    config.getBoolean("pekko.actor.allow-java-serialization") shouldBe false
+    config.getBoolean("pekko.actor.enable-additional-serialization-bindings") 
shouldBe true
+    config.getString(
+      "pekko.actor.serializers.kryo"
+    ) shouldBe "io.altoo.serialization.kryo.pekko.PekkoKryoSerializer"
+    config.getStringList("pekko.loggers").get(0) shouldBe 
"org.apache.pekko.event.slf4j.Slf4jLogger"
+    config.getString(
+      "pekko.logging-filter"
+    ) shouldBe "org.apache.pekko.event.slf4j.Slf4jLoggingFilter"
+  }
+
+  it should "expose the remote/artery transport settings" in {
+    val config = PekkoConfig.pekkoConfig
+    config.getString("pekko.remote.artery.transport") shouldBe "tcp"
+    config.getString("pekko.remote.artery.canonical.hostname") shouldBe 
"0.0.0.0"
+    config.getInt("pekko.remote.artery.canonical.port") shouldBe 0
+    config.getBytes("pekko.remote.artery.advanced.maximum-frame-size") 
shouldBe 31457280L
+    config.getBytes("pekko.remote.artery.advanced.maximum-large-frame-size") 
shouldBe 125829120L
+  }
+
+  it should "expose the cluster and failure-detector settings" in {
+    val config = PekkoConfig.pekkoConfig
+    config.getStringList("pekko.cluster.seed-nodes").size shouldBe 0
+    config.getString(
+      "pekko.cluster.downing-provider-class"
+    ) shouldBe "org.apache.pekko.cluster.sbr.SplitBrainResolverProvider"
+    config.getString("pekko.cluster.gossip-interval") shouldBe "10s"
+    
config.getString("pekko.cluster.failure-detector.acceptable-heartbeat-pause") 
shouldBe "50s"
+    config.getString(
+      "pekko-kryo-serialization.kryo-initializer"
+    ) shouldBe "org.apache.texera.amber.engine.common.AmberKryoInitializer"
+  }
+
+  it should "resolve the log levels" in {
+    val config = PekkoConfig.pekkoConfig
+    // ${?TEXERA_SERVICE_LOG_LEVEL} can be satisfied by an OS env var or a JVM 
system property
+    if (
+      !sys.env
+        .contains("TEXERA_SERVICE_LOG_LEVEL") && 
!sys.props.contains("TEXERA_SERVICE_LOG_LEVEL")
+    ) {
+      config.getString("pekko.loglevel") shouldBe "INFO"
+    }
+    config.getString("pekko.stdout-loglevel") shouldBe "INFO"
+  }
+}
diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/PythonUtilsSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/PythonUtilsSpec.scala
new file mode 100644
index 0000000000..2878041b34
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/PythonUtilsSpec.scala
@@ -0,0 +1,52 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[PythonUtils]]. `getPythonExecutable` falls back to "python3" 
when the configured
+  * python path is blank, else returns the trimmed path. The blank-path 
default depends on
+  * UDF_PYTHON_PATH, so the exact-value assertion is guarded on that override 
being unset.
+  */
+class PythonUtilsSpec extends AnyFlatSpec with Matchers {
+
+  "PythonUtils.getPythonExecutable" should "fall back to python3 when no 
python path is configured" in {
+    // ${?UDF_PYTHON_PATH} can be satisfied by an OS env var or a JVM system 
property
+    val overrideValue =
+      sys.env.get("UDF_PYTHON_PATH").orElse(sys.props.get("UDF_PYTHON_PATH"))
+    if (overrideValue.forall(_.trim.isEmpty)) {
+      PythonUtils.getPythonExecutable shouldBe "python3"
+    }
+  }
+
+  it should "never return a blank or untrimmed executable" in {
+    val executable = PythonUtils.getPythonExecutable
+    executable should not be empty
+    executable shouldBe executable.trim
+  }
+
+  it should "match its own fallback logic against the backing UdfConfig value" 
in {
+    val expected =
+      if (UdfConfig.pythonPath.trim.isEmpty) "python3" else 
UdfConfig.pythonPath.trim
+    PythonUtils.getPythonExecutable shouldBe expected
+  }
+}
diff --git 
a/common/config/src/test/scala/org/apache/texera/common/config/UdfConfigSpec.scala
 
b/common/config/src/test/scala/org/apache/texera/common/config/UdfConfigSpec.scala
new file mode 100644
index 0000000000..5490268747
--- /dev/null
+++ 
b/common/config/src/test/scala/org/apache/texera/common/config/UdfConfigSpec.scala
@@ -0,0 +1,53 @@
+/*
+ * 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.texera.common.config
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+/**
+  * Spec for [[UdfConfig]]. Reading each value forces resolution from 
udf.conf, so a renamed or
+  * mistyped key surfaces here as a ConfigException. Every value carries a 
`${?ENV}` override, so
+  * exact-value assertions are guarded on the override being absent from env 
and system properties.
+  */
+class UdfConfigSpec extends AnyFlatSpec with Matchers {
+
+  private def ifUnset(name: String)(assertion: => Any): Unit =
+    if (!sys.env.contains(name) && !sys.props.contains(name)) assertion
+
+  "UdfConfig" should "resolve the python and R defaults from udf.conf" in {
+    ifUnset("UDF_PYTHON_PATH")(UdfConfig.pythonPath shouldBe "")
+    ifUnset("UDF_R_PATH")(UdfConfig.rPath shouldBe "")
+    ifUnset("UDF_PYTHON_LOG_STREAMHANDLER_LEVEL")(
+      UdfConfig.pythonLogStreamHandlerLevel shouldBe "INFO"
+    )
+    
ifUnset("UDF_PYTHON_LOG_FILEHANDLER_DIR")(UdfConfig.pythonLogFileHandlerDir 
shouldBe "/tmp/")
+    
ifUnset("UDF_PYTHON_LOG_FILEHANDLER_LEVEL")(UdfConfig.pythonLogFileHandlerLevel 
shouldBe "INFO")
+  }
+
+  it should "resolve the non-empty log format strings" in {
+    ifUnset("UDF_PYTHON_LOG_STREAMHANDLER_FORMAT")(
+      UdfConfig.pythonLogStreamHandlerFormat should not be empty
+    )
+    ifUnset("UDF_PYTHON_LOG_FILEHANDLER_FORMAT")(
+      UdfConfig.pythonLogFileHandlerFormat should not be empty
+    )
+  }
+}

Reply via email to