Fix flakey test AbstractTypeTest#meaninglessEmptyness why is equality so hard

patch by David Capwell; reviewed by Caleb Rackliffe for CASSANDRA-20733
This commit is contained in:
David Capwell 2025-06-26 15:00:38 -07:00
parent 1c2307bd62
commit 78d6892dfb
4 changed files with 32 additions and 10 deletions

View File

@ -300,11 +300,9 @@ public class AbstractTypeTest
continue;
if (type.isEmptyValueMeaningless())
{
AbstractType<?> finalType = type;
// some types (such as TimeUUID) have the same equqlas, so equality checks don't work here, need reference checks
Assertions.assertThat(AbstractTypeGenerators.MEANINGLESS_EMPTYNESS)
Assertions.assertThat(AbstractTypeGenerators.supportsMeaninglessEmptyness(type))
.describedAs("New type %s detected that says its emptyness is meaningless, but it isn't allowed to be! This is a legacy concept only!", type.getClass())
.anyMatch(t -> t == finalType);
.isTrue();
Assertions.assertThat(type.isNull(ByteBufferUtil.EMPTY_BYTE_BUFFER)).isTrue();
}
@ -314,7 +312,7 @@ public class AbstractTypeTest
@Test
public void onlyMeaninglessEmptyness()
{
qt().forAll(Generators.filter(AbstractTypeGenerators.builder().withDefaultSizeGen(1).build(), t -> !AbstractTypeGenerators.MEANINGLESS_EMPTYNESS.contains(t))).checkAssert(type -> {
qt().forAll(Generators.filter(AbstractTypeGenerators.builder().withDefaultSizeGen(1).build(), t -> !AbstractTypeGenerators.supportsMeaninglessEmptyness(t))).checkAssert(type -> {
Assertions.assertThat(type.isEmptyValueMeaningless()).isFalse();
});
}

View File

@ -313,7 +313,7 @@ public class TxnConditionTest
@Test
public void harryPotterAndTheMeaninglessEmptyness()
{
for (var type : AbstractTypeGenerators.MEANINGLESS_EMPTYNESS)
for (var type : AbstractTypeGenerators.meaninglessEmptyness())
{
if (type == CounterColumnType.instance) continue;
TableMetadata metadata = TableMetadata.builder("ks", "tbl")

View File

@ -41,6 +41,7 @@ import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
@ -186,7 +187,7 @@ public final class AbstractTypeGenerators
.build();
// NEVER EVER EVER UPDATE THIS LIST!
// meaningless emptyness is a legacy thrift concept, so only types from back then apply and all new types will never apply
public static final ImmutableUniqueList<AbstractType<?>> MEANINGLESS_EMPTYNESS = ImmutableUniqueList.of(
private static final ImmutableList<AbstractType<?>> MEANINGLESS_EMPTYNESS = ImmutableList.of(
CounterColumnType.instance,
BooleanType.instance,
@ -209,6 +210,22 @@ public final class AbstractTypeGenerators
LongType.instance
);
public static Iterable<AbstractType<?>> meaninglessEmptyness()
{
return MEANINGLESS_EMPTYNESS;
}
public static boolean supportsMeaninglessEmptyness(AbstractType<?> type)
{
// Why list iteration rather than contains? Because equality is hard... and some types like to do things like
// public boolean equals(Object obj) { return obj instanceof AbstractTimeUUIDType<?>; }
for (var t : meaninglessEmptyness())
{
if (t == type) return true;
}
return false;
}
private AbstractTypeGenerators()
{

View File

@ -66,7 +66,8 @@ public class ImmutableUniqueList<T> extends AbstractList<T> implements RandomAcc
{
Builder<T> builder = builder(values.length);
for (T v : values)
builder.add(v);
if (!builder.maybeAdd(v))
throw new IllegalArgumentException("Unable to add " + v + " as its a duplicate");
return builder.build();
}
@ -123,12 +124,18 @@ public class ImmutableUniqueList<T> extends AbstractList<T> implements RandomAcc
this.values = new ArrayList<>(expectedSize);
}
public Builder<T> add(T t)
public boolean maybeAdd(T t)
{
if (indexLookup.containsKey(t)) return this;
if (indexLookup.containsKey(t)) return false;
int idx = this.idx++;
indexLookup.put(t, idx);
values.add(t);
return true;
}
public Builder<T> add(T t)
{
maybeAdd(t);
return this;
}