import java.util.*; /** * CWE-407 unit tests for CockroachDB — three defects: * * cockroach-0001: IndexesUsed.add() calls slices.Contains on a growing slice * for each of N add() calls → O(N²) index deduplication during * SQL query plan building. * * cockroach-0002: BuildFingerprintQueryForIndex / BuildExperimentalFingerprintQueryForIndex * call slices.Contains(ignoredColumns, col) for every column in * every index column loop → O(C × I) where C = columns, I = ignored list. * * cockroach-0003: EnsureUserOnlyBelongsToRoles iterates currentRoles (size R) and * calls slices.Contains(roles, role) (size D) for each → O(R × D) * during LDAP-driven role synchronisation. */ public class CockroachTest { // ── cockroach-0001 ──────────────────────────────────────────────────────── /** Defective: ArrayList.contains inside an accumulation loop → O(N²). */ static List indexesUsedAdd_defective(int n) { List indexes = new ArrayList<>(); for (long i = 0; i < n; i++) { long tableID = i % 50; long indexID = i % 20; long[] entry = new long[]{tableID, indexID}; boolean found = false; for (long[] e : indexes) { if (e[0] == entry[0] && e[1] == entry[1]) { found = true; break; } } if (!found) indexes.add(entry); } return indexes; } /** Fixed: HashMap set for O(1) membership → O(N) total. */ static List indexesUsedAdd_fixed(int n) { List indexes = new ArrayList<>(); Set seen = new HashSet<>(); for (long i = 0; i < n; i++) { long tableID = i % 50; long indexID = i % 20; long key = tableID * 1_000_000L + indexID; if (seen.add(key)) { indexes.add(new long[]{tableID, indexID}); } } return indexes; } // ── cockroach-0002 ──────────────────────────────────────────────────────── /** Defective: linear scan of ignoredColumns for every column → O(C × I). */ static List fingerprintColumns_defective(List columns, List ignored) { List result = new ArrayList<>(); for (String col : columns) { if (ignored.contains(col)) continue; // O(I) per column result.add(col); } return result; } /** Fixed: build a HashSet once, then O(1) per column → O(C + I). */ static List fingerprintColumns_fixed(List columns, List ignored) { Set ignoredSet = new HashSet<>(ignored); List result = new ArrayList<>(); for (String col : columns) { if (!ignoredSet.contains(col)) result.add(col); } return result; } // ── cockroach-0003 ──────────────────────────────────────────────────────── /** Defective: for each currentRole call roles.contains → O(R × D). */ static List rolesToRevoke_defective(Set currentRoles, List desiredRoles) { List toRevoke = new ArrayList<>(); for (String role : currentRoles) { if (!desiredRoles.contains(role)) toRevoke.add(role); // O(D) per role } return toRevoke; } /** Fixed: build desiredSet once → O(R + D). */ static List rolesToRevoke_fixed(Set currentRoles, List desiredRoles) { Set desiredSet = new HashSet<>(desiredRoles); List toRevoke = new ArrayList<>(); for (String role : currentRoles) { if (!desiredSet.contains(role)) toRevoke.add(role); } return toRevoke; } // ── helpers ─────────────────────────────────────────────────────────────── static long bench(Runnable r) { long t0 = System.nanoTime(); r.run(); return System.nanoTime() - t0; } // ── main ───────────────────────────────────────────────────────────────── public static void main(String[] args) { int pass = 0, fail = 0; // --- cockroach-0001 correctness --- { List def = indexesUsedAdd_defective(500); List fix = indexesUsedAdd_fixed(500); if (def.size() == fix.size()) { System.out.println("PASS cockroach-0001 correctness (size=" + def.size() + ")"); pass++; } else { System.out.println("FAIL cockroach-0001 correctness def=" + def.size() + " fix=" + fix.size()); fail++; } } // --- cockroach-0001 performance --- { int N = 2000; long tDef = bench(() -> indexesUsedAdd_defective(N)); long tFix = bench(() -> indexesUsedAdd_fixed(N)); double ratio = (double) tDef / Math.max(tFix, 1); System.out.printf("PASS cockroach-0001 perf defective=%dms fixed=%dms ratio=%.1fx%n", tDef / 1_000_000, tFix / 1_000_000, ratio); if (ratio >= 2.0) pass++; else { System.out.println("FAIL cockroach-0001 perf ratio too low"); fail++; } } // --- cockroach-0002 correctness --- { List columns = new ArrayList<>(); for (int i = 0; i < 200; i++) columns.add("col_" + i); List ignored = new ArrayList<>(); for (int i = 0; i < 50; i++) ignored.add("col_" + (i * 4)); List def = fingerprintColumns_defective(columns, ignored); List fix = fingerprintColumns_fixed(columns, ignored); if (def.equals(fix)) { System.out.println("PASS cockroach-0002 correctness (kept=" + def.size() + ")"); pass++; } else { System.out.println("FAIL cockroach-0002 correctness"); fail++; } } // --- cockroach-0002 performance --- { List columns = new ArrayList<>(); for (int i = 0; i < 1000; i++) columns.add("col_" + i); List ignored = new ArrayList<>(); for (int i = 0; i < 500; i++) ignored.add("col_" + (i * 2)); long tDef = bench(() -> fingerprintColumns_defective(columns, ignored)); long tFix = bench(() -> fingerprintColumns_fixed(columns, ignored)); double ratio = (double) tDef / Math.max(tFix, 1); System.out.printf("PASS cockroach-0002 perf defective=%dms fixed=%dms ratio=%.1fx%n", tDef / 1_000_000, tFix / 1_000_000, ratio); if (ratio >= 1.5) pass++; else { System.out.println("FAIL cockroach-0002 perf ratio too low"); fail++; } } // --- cockroach-0003 correctness --- { Set current = new HashSet<>(); for (int i = 0; i < 100; i++) current.add("role_" + i); List desired = new ArrayList<>(); for (int i = 0; i < 60; i++) desired.add("role_" + i); List def = rolesToRevoke_defective(current, desired); List fix = rolesToRevoke_fixed(current, desired); Collections.sort(def); Collections.sort(fix); if (def.equals(fix)) { System.out.println("PASS cockroach-0003 correctness (toRevoke=" + def.size() + ")"); pass++; } else { System.out.println("FAIL cockroach-0003 correctness def=" + def + " fix=" + fix); fail++; } } // --- cockroach-0003 performance --- { Set current = new HashSet<>(); for (int i = 0; i < 2000; i++) current.add("role_" + i); List desired = new ArrayList<>(); for (int i = 0; i < 1000; i++) desired.add("role_" + i); long tDef = bench(() -> rolesToRevoke_defective(current, desired)); long tFix = bench(() -> rolesToRevoke_fixed(current, desired)); double ratio = (double) tDef / Math.max(tFix, 1); System.out.printf("PASS cockroach-0003 perf defective=%dms fixed=%dms ratio=%.1fx%n", tDef / 1_000_000, tFix / 1_000_000, ratio); if (ratio >= 2.0) pass++; else { System.out.println("FAIL cockroach-0003 perf ratio too low"); fail++; } } System.out.println(); System.out.println("Results: " + pass + " PASS, " + fail + " FAIL"); if (fail > 0) System.exit(1); } }