Skip to content

Extend AggregationOperation and IntervalJoinOpExec unit test coverage #6901

Description

@mengw15

Task Summary

Two pure workflow-operator classes have small, sharply-defined coverage gaps: AggregationOperation (common/workflow-operator/.../aggregate/AggregationOperation.scala, ~81%, 16 lines unhit) and IntervalJoinOpExec (common/workflow-operator/.../intervalJoin/IntervalJoinOpExec.scala, ~86%, 15 lines unhit). Both are dependency-free in-memory logic — no DB, no storage, no clock. Most of what is left is partial branch coverage rather than whole untested methods, so the lines below are named from codecov's line-level data; testing anything else in these files will re-cover already-green code. Extend the existing AggregationOperationSpec and IntervalOpExecSpec rather than adding new files.

Behavior to add

AggregationOperation — the 16 unhit lines are:

  • The four-clause type guard in sumAgg (138-141), minAgg (196-199) and maxAgg (221-224) — 12 of the 16 lines, and the main prize. Each is attributeType != INTEGER && != DOUBLE && != LONG && != TIMESTAMP, and the clauses are only partially exercised. For each of the three aggregations, call it with each supported type so the chain falls all the way through, and with unsupported types (STRING, BOOLEAN, BINARY) so it short-circuits at different clauses and throws UnsupportedOperationException. Assert the message names the aggregation and the offending type.
  • getNumericalValue's TIMESTAMP branch (249-250) — AVERAGE over a TIMESTAMP column is the only route in. Two timestamps an hour apart should average to their epoch-millis midpoint.
  • AveragePartialObj (29) — the case class is never constructed today, which means no test currently drives an AVERAGE partial end to end. An AVERAGE round-trip (inititerate twice → mergefinalAgg) covers this and 249-250 together.
  • newAggFunc's case a: AggregationFunction => a (127) — the non-COUNT arm of the COUNT→SUM remap. Existing tests only drive the COUNT arm; assert that SUM/MIN/MAX/AVERAGE pass through unchanged.

IntervalJoinOpExec — the 15 unhit lines are:

  • The TimeIntervalType ladder in the right-bound computation (201-212) plus the per-type dispatch at 176, 186 and 196 — 11 of the 15 lines, and the main prize. Cover YEAR / MONTH / DAY / HOUR / MINUTE / SECOND, and the case None fallback at 213-214 (plusDays). Reaching None needs care: every existing test goes through the 6-argument IntervalJoinOpDesc constructor, which forces Some(...), and the field is declared var timeIntervalType: Option[TimeIntervalType] = _, i.e. initialised to null rather than None. Build a TIMESTAMP desc with timeIntervalType left unset, serialize it, and assert day semantics — whether Jackson materialises None or null here is exactly the unobvious part worth pinning.
  • processNumValue's bound-combination arms (144, 148) — the includeLeftBound && !includeRightBound and !includeLeftBound && includeRightBound dispatch conditions.
  • removeTooSmallTupleInRightCache (97) — the right-cache eviction comparison. Note the left-cache equivalent is already covered; only the right side is red.
  • intervalCompare (165).

Keep TIMESTAMP fixtures away from Feb 29 and DST boundaries; the interval arithmetic goes through plusYears/plusMonths calendar math.

A correctness defect in the same file (not a coverage item)

While writing the maxAgg tests, note that maxAgg seeds its accumulator with AttributeTypeUtils.minValue(attributeType) but its finaliser collapses to null when the partial equals AttributeTypeUtils.maxValue(attributeType). minAgg is consistent — it seeds maxValue and finalises against maxValue. So maxAgg has it both ways round: MAX over an empty input returns the type's minimum instead of null, and a legitimate MAX result that happens to equal the type's maximum is wrongly collapsed to null.

Those finaliser lines are already covered, so fixing this will not move the coverage number — it is a correctness fix that happens to sit next to the work. Fix it in the same PR (#6878 is the precedent for fix-plus-tests) or file it separately, but do not encode the current result as if it were intended.

Task Type

  • Refactor / Cleanup
  • DevOps / Deployment / CI
  • Testing / QA
  • Documentation
  • Performance
  • Other

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions