fix: use transform equality for partition compatibility#1314
Conversation
zeroshade
left a comment
There was a problem hiding this comment.
LGTM. Switching CompatibleWith from interface identity to Transform.Equals is correct, aligns with PartitionField.Equals, and removes the panic risk on non-comparable transforms. One optional coverage nit inline.
| assert.Equal(t, 1002, spec3.LastAssignedFieldID()) | ||
| } | ||
|
|
||
| func TestPartitionSpecCompatibleWithUsesTransformEquals(t *testing.T) { |
There was a problem hiding this comment.
nit: this nicely pins the non-comparable custom-transform path. It'd be worth also asserting the built-in parameterized cases directly at the CompatibleWith level - e.g. bucket[16] vs bucket[32] and truncate[4] vs truncate[8] should be incompatible, while identical transforms stay compatible. They work today via the built-in Equals impls, but a couple of table-driven cases here would guard against regressions.
laskoviymishka
left a comment
There was a problem hiding this comment.
Nice catch — == on a Transform interface was a latent panic for any concrete type with a non-comparable field, and it bypassed transform-specific equality too. Swapping to .Equals() is the right call and matches what PartitionField.Equals and PartitionSpec.Equals already do; this really was the one spot that survived the old pattern.
The thing I'd settle before this merges is the regression test — as written it doesn't clearly prove the bug it guards against. The two require.NotPanics closures share one compatible bool, and NotPanics records a panic without FailNow, so on a panic the stale value still flows into the assertion below and you get a confusing double failure. Folding both calls into a single NotPanics closure makes the panic-safety check unambiguously the thing under test. A line on why nonComparableTransform is the fixture that matters — the []int field is what makes it non-comparable and what would have panicked under == — keeps it a durable regression test rather than something a future reader can't tell is load-bearing.
Tighten the test and I'm happy to take another pass and approve.
| var compatible bool | ||
| require.NotPanics(t, func() { | ||
| compatible = spec.CompatibleWith(&sameTransformSpec) | ||
| }) | ||
| assert.True(t, compatible) | ||
|
|
||
| require.NotPanics(t, func() { | ||
| compatible = spec.CompatibleWith(&differentTransformSpec) | ||
| }) | ||
| assert.False(t, compatible) |
There was a problem hiding this comment.
require.NotPanics records the panic but doesn't FailNow, so on a panic the stale compatible still flows into the assert.True/assert.False below and you get a confusing double failure. The two closures also share one var compatible bool, which reads like cross-closure capture and would race under t.Parallel().
I'd fold both into a single closure so the panic-safety check is unambiguously the thing under test:
require.NotPanics(t, func() {
assert.True(t, spec.CompatibleWith(&sameTransformSpec))
assert.False(t, spec.CompatibleWith(&differentTransformSpec))
})While you're in here, a one-line comment on nonComparableTransform saying the []int field is what makes it non-comparable — and what would have panicked under the old == — would make it clear this fixture is load-bearing.
Summary
Why
PartitionField.Equals already delegates transform comparison to Transform.Equals, but PartitionSpec.CompatibleWith compared transform interfaces directly. That can panic for non-comparable transform implementations and also bypass transform-specific equality semantics.
Testing