pygame: CLEAN — runtime uses dict/set throughout (O(1) membership) libgdx-0002: ModelBuilder.rebuildReferences Array.contains O(P*M) — patch libgdx-0005: Stage.touchDragged touchFocuses.contains O(F^2) — patch libgdx-0006: AfterAction.delegate currentActions.indexOf O(W*A) per frame — patch unit: extend LibGDXTest to 7 tests, all PASS (50x-1971x speedup measured)
76 lines
3.1 KiB
Java
76 lines
3.1 KiB
Java
import java.util.*;
|
||
|
||
/**
|
||
* CWE-407 unit tests for Nomad new defects.
|
||
*
|
||
* nomad-0005: scheduler/reconciler/reconcile_cluster.go ~line 1337
|
||
* handleReconnectingAllocs() builds a []string replacements slice by following
|
||
* the NextAllocation linked list, then iterates all allocs with:
|
||
* slices.Contains(replacements, replacementAlloc.ID)
|
||
* This is O(|all| × |replacements|) = O(A × R).
|
||
* In a deployment with many reconnecting allocations and a large alloc set,
|
||
* this becomes effectively O(A²).
|
||
* Fix: map[string]struct{} built from the linked-list walk → O(1) membership.
|
||
*
|
||
* Note: nomad-0001 through nomad-0004 (bitmap port alloc, stream namespace
|
||
* filter, vault secrets dedup, checkstore difference) were found in a prior
|
||
* scan and carry UNDF-2026-000000476 through UNDF-2026-000000479.
|
||
* nomad-0005 is the reconnect reconciler defect first identified here.
|
||
*/
|
||
public class NomadTest {
|
||
|
||
// --- nomad-0005 simulation ---
|
||
|
||
static boolean containsReplacements_slice(List<String> replacements, String allocID) {
|
||
return replacements.contains(allocID); // O(R) — defect
|
||
}
|
||
|
||
static boolean containsReplacements_map(Set<String> replacementsSet, String allocID) {
|
||
return replacementsSet.contains(allocID); // O(1) — fix
|
||
}
|
||
|
||
static void testNomad0005() throws Exception {
|
||
int A = 2000; // total allocations in a large deployment
|
||
int R = 500; // length of replacement chain per reconnecting alloc
|
||
|
||
List<String> replacementsSlice = new ArrayList<>(R);
|
||
Set<String> replacementsSet = new HashSet<>(R);
|
||
for (int i = 0; i < R; i++) {
|
||
String id = "alloc-replace-" + i;
|
||
replacementsSlice.add(id);
|
||
replacementsSet.add(id);
|
||
}
|
||
|
||
// alloc IDs that the outer loop iterates over all allocations
|
||
List<String> allAllocIDs = new ArrayList<>(A);
|
||
for (int i = 0; i < A; i++) allAllocIDs.add("alloc-" + i);
|
||
|
||
// worst-case candidate: last entry in replacements (tail of chain)
|
||
String targetID = "alloc-replace-" + (R - 1);
|
||
|
||
long t0 = System.nanoTime();
|
||
int hitSlice = 0;
|
||
for (String id : allAllocIDs) {
|
||
if (containsReplacements_slice(replacementsSlice, targetID)) hitSlice++;
|
||
}
|
||
long sliceNs = System.nanoTime() - t0;
|
||
|
||
long t1 = System.nanoTime();
|
||
int hitMap = 0;
|
||
for (String id : allAllocIDs) {
|
||
if (containsReplacements_map(replacementsSet, targetID)) hitMap++;
|
||
}
|
||
long mapNs = System.nanoTime() - t1;
|
||
|
||
if (hitSlice != hitMap) throw new AssertionError("result mismatch: " + hitSlice + " vs " + hitMap);
|
||
double ratio = (double) sliceNs / Math.max(mapNs, 1);
|
||
System.out.printf("nomad-0005 PASS A=%d R=%d slice=%dns map=%dns ratio=%.1fx%n",
|
||
A, R, sliceNs, mapNs, ratio);
|
||
if (ratio < 5.0) throw new AssertionError("expected speedup >= 5x, got " + ratio);
|
||
}
|
||
|
||
public static void main(String[] args) throws Exception {
|
||
testNomad0005();
|
||
System.out.println("ALL PASS");
|
||
}
|
||
}
|