This is an automated email from the ASF dual-hosted git repository.
aglinxinyuan 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 aa8966250a test(amber): add unit test coverage for AddressInfo (#4916)
aa8966250a is described below
commit aa8966250a06c5d67e7d388f1c2f0a9646ca25b1
Author: Xinyuan Lin <[email protected]>
AuthorDate: Mon May 4 03:14:35 2026 -0700
test(amber): add unit test coverage for AddressInfo (#4916)
### What changes were proposed in this PR?
Adds `AddressInfoSpec` covering `AddressInfo`
(amber/src/main/scala/org/apache/texera/amber/engine/architecture/deploysemantics/AddressInfo.scala),
the case class the cluster scheduler uses to describe worker /
controller node addresses. It has no test coverage today.
The new spec pins:
- Both fields (`allAddresses`, `controllerAddress`) round-trip from the
case-class constructor.
- The order of `allAddresses` is preserved (the cluster scheduler picks
workers based on this order, so any reorder is observable).
- An empty `allAddresses` array is accepted (controller-only
configurations).
- The controller address may also appear in `allAddresses` (collocated
mode).
- `copy()` allows one field to change while preserving the other.
- Case-class equality with an `Array` field is reference-based, not
element-wise. This is locked down explicitly so a future change to (say)
`Seq` doesn't silently flip the equality semantics for callers.
No production code changed; this is test-only.
### Any related issues, documentation, discussions?
Closes #4915
### How was this PR tested?
Added 6 new unit tests in `AddressInfoSpec`. Verified locally:
```
sbt 'WorkflowExecutionService/Test/testOnly
org.apache.texera.amber.engine.architecture.deploysemantics.AddressInfoSpec'
# → Tests: succeeded 6, failed 0
sbt 'WorkflowExecutionService/Test/scalafmtCheck'
# → clean
```
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.../deploysemantics/AddressInfoSpec.scala | 84 ++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git
a/amber/src/test/scala/org/apache/texera/amber/engine/architecture/deploysemantics/AddressInfoSpec.scala
b/amber/src/test/scala/org/apache/texera/amber/engine/architecture/deploysemantics/AddressInfoSpec.scala
new file mode 100644
index 0000000000..0ea16a47df
--- /dev/null
+++
b/amber/src/test/scala/org/apache/texera/amber/engine/architecture/deploysemantics/AddressInfoSpec.scala
@@ -0,0 +1,84 @@
+/*
+ * 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.amber.engine.architecture.deploysemantics
+
+import org.apache.pekko.actor.Address
+import org.scalatest.flatspec.AnyFlatSpec
+
+class AddressInfoSpec extends AnyFlatSpec {
+
+ private def addr(host: String, port: Int): Address =
+ Address("pekko", "Amber", host, port)
+
+ "AddressInfo" should "expose the addresses it was constructed with" in {
+ val nodes = Array(addr("h1", 2552), addr("h2", 2552), addr("h3", 2552))
+ val controller = addr("ctrl", 2552)
+ val info = AddressInfo(nodes, controller)
+ assert(info.allAddresses.toList == nodes.toList)
+ assert(info.controllerAddress == controller)
+ }
+
+ it should "preserve the order of allAddresses" in {
+ // The cluster scheduler picks workers based on this list's order, so
+ // any reorder is observable.
+ val nodes = Array(addr("c", 1), addr("a", 2), addr("b", 3))
+ val info = AddressInfo(nodes, addr("ctrl", 0))
+ assert(info.allAddresses.map(_.host.get).toList == List("c", "a", "b"))
+ }
+
+ it should "accept an empty allAddresses array" in {
+ // Edge case: no worker nodes (e.g., controller-only configuration).
+ val info = AddressInfo(Array.empty[Address], addr("ctrl", 0))
+ assert(info.allAddresses.isEmpty)
+ assert(info.controllerAddress.host.contains("ctrl"))
+ }
+
+ it should "allow the controller to also appear in allAddresses (collocated)"
in {
+ val controller = addr("ctrl", 2552)
+ val info = AddressInfo(Array(controller, addr("worker", 2552)), controller)
+ assert(info.allAddresses.contains(controller))
+ assert(info.controllerAddress == controller)
+ }
+
+ it should "support copy(), allowing one field to change while the other is
preserved" in {
+ val a = AddressInfo(Array(addr("h1", 1)), addr("ctrl-a", 0))
+ val b = a.copy(controllerAddress = addr("ctrl-b", 0))
+ assert(b.controllerAddress.host.contains("ctrl-b"))
+ assert(b.allAddresses.toList == a.allAddresses.toList)
+ // original is unchanged
+ assert(a.controllerAddress.host.contains("ctrl-a"))
+ }
+
+ it should "use Array reference equality (not element-wise) for the
allAddresses field" in {
+ // Case-class equality on `Array` fields uses array reference equality,
+ // not element-wise equality. Two AddressInfo values that hold the SAME
+ // array instance compare equal; two AddressInfo values that hold
+ // distinct arrays with the SAME elements do NOT. Lock this down so a
+ // future change to (say) Seq doesn't silently flip equality semantics
+ // for callers.
+ val nodes = Array(addr("h", 1))
+ val ctrl = addr("ctrl", 0)
+ val sameRef = AddressInfo(nodes, ctrl)
+ val sameRefAgain = AddressInfo(nodes, ctrl) // shares the same array
reference
+ val differentRef = AddressInfo(Array(addr("h", 1)), ctrl) // different
array reference
+ assert(sameRef == sameRefAgain, "shared Array reference → equal")
+ assert(sameRef != differentRef, "distinct Array references → not equal (no
element-wise check)")
+ }
+}