eugenegujing opened a new pull request, #7609:
URL: https://github.com/apache/texera/pull/7609

   ### What changes were proposed in this PR?
   
   This PR adds `StartChannelHandlerSpec`, the first unit coverage for 
`amber/src/main/scala/org/apache/texera/amber/engine/architecture/worker/promisehandlers/StartChannelHandler.scala`.
 The handler was last changed by #6913, which adjusted the boundary-state 
emission but added only integration coverage (`LoopIntegrationSpec`) and 
Python-side unit tests, so the Scala handler's state-emission and exception 
paths were unasserted at the unit level.
   
   No production code is changed; this is a test-only PR.
   
   The spec drives a real `DataProcessor` and asserts on the worker's outgoing 
messages, so the marker and the emitted state are checked as the wire payloads 
a downstream worker would actually receive rather than as mocked calls. The 15 
tests pin the handler's three steps and the order between them:
   
   - the input port is resolved from the channel the ECM arrived on, and that 
port is what `produceStateOnStart` receives;
   - the unaligned START_CHANNEL marker reaches every data channel and no 
control channel, after the pending output is flushed;
   - the operator's boundary state is emitted to every data channel with the 
"no loop" envelope, an empty-but-present state is still emitted, and no state 
is emitted when the operator produces none;
   - every marker precedes every state, and the marker still goes out first 
when the operator throws;
   - a sink worker with no data channels emits nothing at all yet still replies 
successfully, and a second invocation repeats the whole sequence because the 
handler has no once-only guard;
   - an operator exception, an operator `Error`, and a failure raised inside 
`emitState` are all swallowed, reported through `handleExecutorException`, and 
answered with a successful reply, while a `ControlThrowable` escapes and an 
unassigned port fails the RPC outright.
   
   Four of these record current behavior that a reader may find surprising, and 
each says so in a comment rather than implying endorsement. `ErrorUtils.safely` 
swallows `java.lang.Error` because its `OutOfMemoryError` guard is a 
commented-out line, the port resolution sits before the `try` so an unassigned 
port escapes as an RPC failure instead of being reported like every other 
failure one line later, and the RPC replies successfully even after the 
operator fails because the failure is surfaced out of band. If any of these is 
later changed deliberately, the corresponding test turns red and forces that 
decision to be explicit, which is the point of pinning them.
   
   ### Any related issues, documentation, discussions?
   
   Closes #7606
   
   ### How was this PR tested?
   
   The 15 new tests were run locally, together with the three pre-existing 
specs in the same package and the wider worker package:
   
   ```
   sbt "WorkflowExecutionService/testOnly 
org.apache.texera.amber.engine.architecture.worker.promisehandlers.StartChannelHandlerSpec"
     -> Tests: succeeded 15, failed 0
   
   sbt "WorkflowExecutionService/testOnly 
org.apache.texera.amber.engine.architecture.worker.promisehandlers.*"
     -> Suites: completed 4, Tests: succeeded 31, failed 0
   
   sbt "WorkflowExecutionService/testOnly 
org.apache.texera.amber.engine.architecture.worker.*"
     -> Suites: completed 14, Tests: succeeded 112, failed 0
   
   sbt "WorkflowExecutionService/Test/scalafmtCheck"
     -> success
   ```
   
   Both positive and negative directions are covered, along with the empty and 
boundary cases: a produced state and no produced state, an empty-but-present 
state, zero downstream data channels, a never-registered input channel, and a 
repeated invocation.
   
   The assertions were mutation-checked rather than assumed to be meaningful. 
Fifteen mutations were applied to the production code one at a time and every 
one of them turned the spec red, including flipping `NO_ALIGNMENT` to 
`PORT_ALIGNMENT`, swapping `METHOD_START_CHANNEL` for `METHOD_END_CHANNEL`, 
inverting `isDefined`, deleting the `emitState` call, passing a constant port 
to `produceStateOnStart`, sending the marker after the `try` block instead of 
before it, dropping the `handleExecutorException` call, restricting the marker 
to the first data channel only, deleting the `outputManager.flush()` that 
precedes the marker, hoisting `emitState` out of the `try`, adding an 
idempotence guard, and pausing with a different `PauseType`. The production 
files were restored and verified byte-identical to `HEAD` afterwards.
   
   ### Was this PR authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Claude Opus 5)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to