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 4af3a85bcd test(amber): trim subsumed loop-body e2e cases to speed up 
amber-integration (#6884)
4af3a85bcd is described below

commit 4af3a85bcd4ecd3c1f8b5588ed4a1e25361f7ef7
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sat Jul 25 19:54:37 2026 -0700

    test(amber): trim subsumed loop-body e2e cases to speed up 
amber-integration (#6884)
    
    ### What changes were proposed in this PR?
    
    `LoopIntegrationSpec` costs **~4m16s of the ~6-minute
    `amber-integration` test step (~70%)** on every PR. The cost tracks
    worker spawns almost perfectly (~2s per Python worker boot + Flight
    handshake; 132 spawns across the suite), because every loop iteration
    respawns each worker in the re-executed regions:
    
    | Test | Time | Worker spawns (py + jvm) |
    |---|---:|---:|
    | single loop (Python-only) | 17s | 6 + 1 |
    | nested 3×3 (Python-only) | 63s | 24 + 1 |
    | single + Limit | 19s | 6 + 4 |
    | nested + Limit | 64s | 24 + 10 |
    | nested + chain (Limit→Sleep) | 72s | 24 + 19 |
    | single + chain | 21s | 6 + 7 |
    
    Two cases are **strict subsets** of the nested-chain case, which already
    covers nested routing, counter magnitude across JVM hops, the JVM→JVM
    state handoff, and both operator kinds in one workflow:
    
    - `nested + Limit` (~64s) — nested × Limit ⊂ nested × (Limit → Sleep)
    - `single + chain` (~21s) — chain ⊂ nested chain
    
    This PR removes those two, saving **~85s (~33% of the loop suite)** with
    no unique coverage lost. Retained matrix: Python-only single (base),
    Python-only nested (pins the no-JVM path), single + Limit (verbatim
    repro of the #6660 bug), nested + chain (superset JVM case). The
    subsumption reasoning is recorded in the retained test's comment so the
    cases don't get re-added.
    
    The deeper fix (reusing workers across loop iterations instead of
    respawn-per-jump) is an engine design change and out of scope here.
    
    ### Any related issues, documentation, discussions?
    
    Follow-up to #6661 (which introduced the JVM loop-body cases). Related
    engine context: #6660.
    
    ### How was this PR tested?
    
    Test-only change (removes two e2e cases; no source touched).
    `WorkflowExecutionService/Test/compile` + `scalafmtCheckAll` +
    `scalafixAll --check` pass locally (Java 17); the remaining suite runs
    in the `amber-integration` CI job on this PR.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Fable 5)
---
 .../amber/engine/e2e/LoopIntegrationSpec.scala     | 78 +++-------------------
 1 file changed, 11 insertions(+), 67 deletions(-)

diff --git 
a/amber/src/test/integration/org/apache/texera/amber/engine/e2e/LoopIntegrationSpec.scala
 
b/amber/src/test/integration/org/apache/texera/amber/engine/e2e/LoopIntegrationSpec.scala
index 2c81f78045..3dec510b90 100644
--- 
a/amber/src/test/integration/org/apache/texera/amber/engine/e2e/LoopIntegrationSpec.scala
+++ 
b/amber/src/test/integration/org/apache/texera/amber/engine/e2e/LoopIntegrationSpec.scala
@@ -282,54 +282,22 @@ class LoopIntegrationSpec
     )
   }
 
-  it should "run a nested loop whose inner body contains a JVM (Scala) 
operator" in {
-    // TextInput -> OuterStart -> InnerStart -> Limit -> InnerEnd -> OuterEnd.
-    //
-    // The nested variant of the JVM-hop test: the OUTER loop's state crosses
-    // the Scala operator stamped (loop_counter = 1, loop_start_id = outer), so
-    // this pins that the JVM hop preserves the counter MAGNITUDE too, not just
-    // the id. A zeroed counter would make the inner LoopEnd mis-consume the
-    // outer state (KeyError on the missing 'table' key / clobbered jump id)
-    // instead of passing it through with -1.
-    val src = textInput("1\n2\n3")
-    val outerStart = loopStart("i = 0", "table")
-    val innerStart = loopStart("j = 0", "table.iloc[j]")
-    val mid = limit(10)
-    val innerEnd = loopEnd("j += 1", "j < len(table)")
-    val outerEnd = loopEnd("i += 1", "i < len(table)")
-    val materialized = runAndGetMaterializedRowCounts(
-      List(src, outerStart, innerStart, mid, innerEnd, outerEnd),
-      List(
-        link(src, outerStart),
-        link(outerStart, innerStart),
-        link(innerStart, mid),
-        link(mid, innerEnd),
-        link(innerEnd, outerEnd)
-      )
-    )
-    val outerRows = materialized.getOrElse(outerEnd.operatorIdentifier, -1L)
-    val innerRows = materialized.getOrElse(innerEnd.operatorIdentifier, -1L)
-    assert(
-      outerRows == 9,
-      s"outer LoopEnd must accumulate all 9 inner-iteration rows with a Scala 
" +
-        s"operator in the inner body: expected 9, got $outerRows (all: 
$materialized)"
-    )
-    assert(
-      innerRows == 3,
-      s"inner LoopEnd must reset per outer iteration (3 rows, not 9): " +
-        s"expected 3, got $innerRows (all: $materialized)"
-    )
-  }
-
   it should "run a nested loop whose inner body chains multiple JVM operators" 
in {
     // TextInput -> OuterStart -> InnerStart -> Limit -> Sleep(0) -> InnerEnd 
-> OuterEnd.
     //
     // The strongest combination: nested (the OUTER loop's state crosses the
     // JVM hops stamped with loop_counter = 1, so the counter MAGNITUDE must
-    // survive both hops) x multi-hop (the JVM-to-JVM state handoff between
-    // the two Scala workers) x both operator kinds. A zeroed counter or a
-    // blanked id at either hop would mis-route the outer state at the inner
-    // LoopEnd.
+    // survive both hops -- a zeroed counter would make the inner LoopEnd
+    // mis-consume the outer state instead of passing it through with -1) x
+    // multi-hop (the JVM-to-JVM state handoff: the first Scala worker WRITES
+    // the envelope columns to its output state table and the second Scala
+    // worker READS them back) x both operator kinds.
+    //
+    // This case strictly subsumes a nested loop with a single JVM operator
+    // and a single loop with a JVM chain; those were removed as separate
+    // tests because each loop iteration respawns every worker in the
+    // re-executed regions (~2s per Python worker), making every extra e2e
+    // workflow expensive (~1 minute per nested case in CI).
     val src = textInput("1\n2\n3")
     val outerStart = loopStart("i = 0", "table")
     val innerStart = loopStart("j = 0", "table.iloc[j]")
@@ -363,28 +331,4 @@ class LoopIntegrationSpec
     )
   }
 
-  it should "run a loop whose body chains multiple JVM operators" in {
-    // TextInput -> LoopStart -> Limit -> Sleep(0) -> LoopEnd.
-    //
-    // Two consecutive JVM hops pin the JVM-to-JVM state handoff: the first
-    // Scala worker WRITES the envelope columns to its output state table and
-    // the second Scala worker READS them back. The single-JVM-op tests never
-    // exercise that pairing (there, each hop faces a Python worker on at
-    // least one side). Sleep(0) is a pure identity pass-through.
-    val src = textInput("1\n2\n3")
-    val start = loopStart("i = 0", "table.iloc[i]")
-    val first = limit(10)
-    val second = sleep(0)
-    val end = loopEnd("i += 1", "i < len(table)")
-    val materialized = runAndGetMaterializedRowCounts(
-      List(src, start, first, second, end),
-      List(link(src, start), link(start, first), link(first, second), 
link(second, end))
-    )
-    val endRows = materialized.getOrElse(end.operatorIdentifier, -1L)
-    assert(
-      endRows == 3,
-      s"LoopEnd must accumulate all 3 iterations with two chained JVM " +
-        s"operators in the loop body: expected 3, got $endRows (all: 
$materialized)"
-    )
-  }
 }

Reply via email to