package unit; import java.util.*; /** * CWE-407 unit test: podman GetRunningPods * File: libpod/runtime_pod.go:147 — GetRunningPods * * Slow: for each container, scan pods []string via slices.Contains → O(n²) * Fast: use map[string]bool for seen set → O(n) * * Run: javac -d . RunningPodsAlgorithm.java && java -ea unit.RunningPodsAlgorithm */ public class RunningPodsAlgorithm { // ── Slow implementation (mirrors defective Go code) ─────────────────────── static class SlowGetRunningPods { final long ops; final List podIDs; SlowGetRunningPods(List containerPodIDs) { long count = 0; List pods = new ArrayList<>(); for (String podID : containerPodIDs) { // slices.Contains(pods, podID) — O(n) scan boolean found = false; for (String existing : pods) { count++; if (existing.equals(podID)) { found = true; break; } } if (!found) { pods.add(podID); } } this.ops = count; this.podIDs = pods; } } // ── Fast implementation (proposed fix) ──────────────────────────────────── static class FastGetRunningPods { final long ops; final List podIDs; FastGetRunningPods(List containerPodIDs) { long count = 0; Map seen = new HashMap<>(containerPodIDs.size() * 2); List pods = new ArrayList<>(); for (String podID : containerPodIDs) { count++; // O(1) map lookup if (!seen.getOrDefault(podID, false)) { seen.put(podID, true); pods.add(podID); } } this.ops = count; this.podIDs = pods; } } // ── Node / Result types ─────────────────────────────────────────────────── static class Node { final String containerID; final String podID; Node(String containerID, String podID) { this.containerID = containerID; this.podID = podID; } } static class Result { final long slowOps; final long fastOps; final List slowPods; final List fastPods; Result(long slowOps, long fastOps, List slowPods, List fastPods) { this.slowOps = slowOps; this.fastOps = fastOps; this.slowPods = slowPods; this.fastPods = fastPods; } } // ── test infrastructure ─────────────────────────────────────────────────── static int passed = 0, total = 0; static void test(String name, boolean condition) { total++; if (condition) { passed++; System.out.println("PASS: " + name); } else { System.out.println("FAIL: " + name); } } /** * Build a workload: nContainers containers spread across nPods pods. * containersPerPod = nContainers / nPods (worst case for dedup). */ static Result run(int nContainers, int nPods) { List containerPodIDs = new ArrayList<>(nContainers); for (int i = 0; i < nContainers; i++) { containerPodIDs.add("pod-" + (i % nPods)); } SlowGetRunningPods slow = new SlowGetRunningPods(containerPodIDs); FastGetRunningPods fast = new FastGetRunningPods(containerPodIDs); return new Result(slow.ops, fast.ops, slow.podIDs, fast.podIDs); } public static void main(String[] args) { // T1: 1000 containers, 100 pods (10 containers per pod) { Result r = run(1000, 100); // Slow: each of 1000 containers scans growing pods list — sum ~0+1+2+... per batch // Fast: 1000 O(1) lookups test("T1-slow-is-quadratic [N=1000,pods=100]", r.slowOps > 1000); // definitely more than linear test("T1-fast-is-linear [N=1000,pods=100]", r.fastOps <= 1000 + 5); double speedup = (double) r.slowOps / r.fastOps; test("T1-speedup>=10x", speedup >= 10.0); System.out.printf(" slow=%d ops, fast=%d ops, speedup=%.1fx%n", r.slowOps, r.fastOps, speedup); List ss = new ArrayList<>(r.slowPods); Collections.sort(ss); List fs = new ArrayList<>(r.fastPods); Collections.sort(fs); test("T1-results-match", ss.equals(fs)); } // T2: 5000 containers, 500 pods (10 per pod) { Result r = run(5000, 500); double speedup = (double) r.slowOps / r.fastOps; test("T2-slow-quadratic [N=5000,pods=500]", r.slowOps > 5000); test("T2-fast-linear [N=5000]", r.fastOps <= 5000 + 5); test("T2-speedup>=10x", speedup >= 10.0); System.out.printf(" slow=%d ops, fast=%d ops, speedup=%.1fx%n", r.slowOps, r.fastOps, speedup); List ss = new ArrayList<>(r.slowPods); Collections.sort(ss); List fs = new ArrayList<>(r.fastPods); Collections.sort(fs); test("T2-results-match", ss.equals(fs)); } // T3: 100 containers, all different pods (max dedup overhead) { Result r = run(100, 100); // Each container requires full scan of growing pods list // Total: 0+1+2+...+99 = 4950 ops for slow test("T3-slow-sum-series [N=100,pods=100]", r.slowOps >= 100L * 99 / 2); test("T3-fast-linear [N=100]", r.fastOps <= 100 + 5); double speedup = (double) r.slowOps / r.fastOps; test("T3-speedup>=40x [N=100]", speedup >= 40.0); System.out.printf(" slow=%d ops, fast=%d ops, speedup=%.1fx%n", r.slowOps, r.fastOps, speedup); } // T4: Correctness — single pod, many containers { Result r = run(50, 1); test("T4-single-pod-result", r.fastPods.size() == 1); test("T4-single-pod-results-match", r.slowPods.equals(r.fastPods)); } System.out.println(); System.out.printf("%d/%d PASS%n", passed, total); if (passed != total) System.exit(1); } }