apache / apache/texera

IntervalOpExecSpec uses an unseeded global Random, making failures unreproducible

Open Beginner friendly
#8,150 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Scala
Stars
314
Forks
187
Avg merge
1d 21h
Merged PRs (30d)
214

Description

### What happened?

`IntervalOpExecSpec` drives its inputs from the **global, unseeded** `scala.util.Random`, so its execution path — and therefore its branch coverage — differs from run to run.

```scala
import scala.util.Random.{nextInt, nextLong}
...
val leftOrder = LazyList.continually(nextInt(10)).take(leftInput.length).toList
val rightOrder = LazyList.continually(nextInt(10)).take(rightInput.length).toList
...
val pointList: Array[Long] = LazyList.continually(nextLong()).take(1000).toArray
val rangeList: Array[Long] = LazyList.continually(nextLong()).take(1000).toArray
```

`scala.util.Random` used this way is the shared singleton with no seed, so nothing is reproducible.

**Two consequences.**

The one that is merely annoying: `WorkflowOperator`'s module-wide branch totals are not stable. Two `WorkflowOperator/jacoco` runs on the *same* tree, differing only in an unrelated spec, reported `IntervalJoinOpExec.scala` at 21 and then 22 missed branch arms. That was isolated by diffing every `` between the two reports. Anyone quoting module-wide arm counts from a single run can be off by a few, through no fault of their change.

The one that matters more: **a genuine failure here may not reproduce.** If an ordering or a `nextLong()` value trips a real bug in the interval-join logic, the run that catches it cannot be replayed, and a re-run will very likely go green.

The fix is small — seed a local generator, e.g. `val rng = new scala.util.Random(42)` and use `rng.nextInt` / `rng.nextLong` — which keeps the input variety while making every run reproducible.

Note the spec filename is `IntervalOpExecSpec.scala`, not `IntervalJoinOpExecSpec.scala`, so a search keyed on the class name misses it.

### How to reproduce?

1. `common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/intervalJoin/IntervalOpExecSpec.scala:31` — the `import scala.util.Random.{nextInt, nextLong}`, then uses at lines 243, 244, 486, 487 and 495.
2. Run `WorkflowOperator/jacoco` twice on an unchanged tree, one fresh sbt JVM each, removing `common/workflow-operator/target/scala-2.13/jacoco` between runs. Compare the `` figures for `IntervalJoinOpExec.scala` in the two `jacoco.xml` reports; they differ between runs.

Exclude `FileScanSourceOpExecSpec` when doing this — it aborts at suite level on Windows in its own cleanup, and because sbt-jacoco runs unforked and skips `saveRuntimeData` when the test task fails, an unfiltered run emits an all-zero report rather than a partial one.

### Version/Branch

1.3.0-incubating-SNAPSHOT (main)

### Was this issue authored using generative AI tooling?

Generated-by: Claude Code (Opus 5)

Contributor guide

Open the contributing guide

Research direction

Start with common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/intervalJoin/IntervalOpExecSpec.scala, especially the Random import and uses at lines 243, 244, 486, 487, and 495. Run WorkflowOperator/jacoco twice as described, excluding FileScanSourceOpExec, and compare the IntervalJoinOpExec.scala branch counters. Done means the spec retains varied inputs while repeated runs produce reproducible results.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
testing-qa
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
86/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.