diff --git a/test/unit/org/apache/cassandra/utils/AbstractTypeGenerators.java b/test/unit/org/apache/cassandra/utils/AbstractTypeGenerators.java index 7ff9683d45..bde6482e91 100644 --- a/test/unit/org/apache/cassandra/utils/AbstractTypeGenerators.java +++ b/test/unit/org/apache/cassandra/utils/AbstractTypeGenerators.java @@ -828,16 +828,19 @@ public final class AbstractTypeGenerators return userTypeGen(elementGen, sizeGen, ksGen, nameGen, BOOLEAN_GEN); } - private static ThreadLocal OVERRIDE_KEYSPACE = new ThreadLocal<>(); + private static final ThreadLocal OVERRIDE_KEYSPACE = new ThreadLocal<>(); + private static final ThreadLocal> SEEN_UDT_NAMES = new ThreadLocal<>(); public static void overrideUDTKeyspace(String ks) { OVERRIDE_KEYSPACE.set(ks); + SEEN_UDT_NAMES.set(new HashSet<>()); } public static void clearUDTKeyspace() { OVERRIDE_KEYSPACE.remove(); + SEEN_UDT_NAMES.remove(); } public interface UserTypeFieldsGen @@ -876,7 +879,11 @@ public final class AbstractTypeGenerators String ks = OVERRIDE_KEYSPACE.get(); if (ks == null) ks = ksGen.generate(rnd); - String name = nameGen.generate(rnd); + Set seenNames = SEEN_UDT_NAMES.get(); + Gen localNameGen = nameGen; + if (seenNames != null) + localNameGen = Generators.filter(nameGen, seenNames::add); + String name = localNameGen.generate(rnd); ByteBuffer nameBB = AsciiType.instance.decompose(name); for (int i = 0; i < numElements; i++) diff --git a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java index 651b85022a..e3d4017744 100644 --- a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java +++ b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java @@ -1750,6 +1750,7 @@ public final class CassandraGenerators Set udts = CassandraGenerators.extractUDTs(metadata); if (!udts.isEmpty()) { + List ordered = new ArrayList<>(); Deque pending = new ArrayDeque<>(udts); Set visited = new HashSet<>(); while (!pending.isEmpty()) @@ -1759,8 +1760,22 @@ public final class CassandraGenerators subTypes.remove(next); // it includes self if (subTypes.isEmpty() || subTypes.stream().allMatch(t -> visited.contains(t.name))) { - fn.accept(next); + try + { + fn.accept(next); + } + catch (Throwable t) + { + StringBuilder sb = new StringBuilder(); + sb.append("Unable to add type ").append(next.toCqlString(false, false, false)); + sb.append("\nHistory:"); + for (var udt : ordered) + sb.append("\n\t").append(udt.toCqlString(false, false, false)); + AssertionError e = new AssertionError(sb.toString(), t); + throw e; + } visited.add(next.name); + ordered.add(next); } else {