package unit; import java.util.*; /** * ZookeeperTest — CWE-407 benchmark for zookeeper-0001 and zookeeper-0002 * * zookeeper-0001: PrepRequestProcessor.removeDuplicates() * ArrayList.contains() scan on growing retval — O(N²) total for N ACL entries * Fix: parallel HashSet seen — O(N) total, O(1) per check * * zookeeper-0002: AuthenticationHelper.isCnxnAuthenticated() * ArrayList.contains() for enforceAuthSchemes — O(M) per auth id, O(I×M) total * Fix: HashSet enforceAuthSchemes — O(1) per auth id, O(I) total */ public class ZookeeperTest { // --------------------------------------------------------------------------- // zookeeper-0001: ACL deduplication // --------------------------------------------------------------------------- /** * Simulates removeDuplicates() with ArrayList.contains() — O(N²) contain calls. * Returns the total number of contains() probes executed. */ static long slowRemoveDuplicates(int totalAcls, int uniqueAcls) { // Build input: cycle through uniqueAcls distinct values List input = new ArrayList<>(totalAcls); for (int i = 0; i < totalAcls; i++) { input.add(i % uniqueAcls); } long probes = 0; List retval = new ArrayList<>(totalAcls); for (Integer acl : input) { // Simulate ArrayList.contains() — scan every element already in retval boolean found = false; for (int j = 0; j < retval.size(); j++) { probes++; if (retval.get(j).equals(acl)) { found = true; break; } } if (!found) { retval.add(acl); } } return probes; } /** * Simulates fixed removeDuplicates() with HashSet.add() — O(N) total. * Returns the number of set probes (one per element). */ static long fastRemoveDuplicates(int totalAcls, int uniqueAcls) { List input = new ArrayList<>(totalAcls); for (int i = 0; i < totalAcls; i++) { input.add(i % uniqueAcls); } long probes = 0; List retval = new ArrayList<>(totalAcls); Set seen = new HashSet<>(totalAcls); for (Integer acl : input) { probes++; // one O(1) HashSet.add probe per element if (seen.add(acl)) { retval.add(acl); } } return probes; } // --------------------------------------------------------------------------- // zookeeper-0002: auth scheme membership check // --------------------------------------------------------------------------- /** * Simulates isCnxnAuthenticated() with ArrayList.contains() — O(I×M). * I = number of auth ids on the connection, M = number of enforced schemes. * Returns total probes across all scheme lookups. */ static long slowIsCnxnAuthenticated(int authIds, int schemes) { // Build enforceAuthSchemes as ArrayList List enforceAuthSchemes = new ArrayList<>(); for (int i = 0; i < schemes; i++) { enforceAuthSchemes.add("scheme_" + i); } // Build cnxn authInfo — none of the ids match (worst case: scan all schemes) List authInfo = new ArrayList<>(); for (int i = 0; i < authIds; i++) { authInfo.add("unknown_" + i); } long probes = 0; for (String scheme : authInfo) { // Simulate ArrayList.contains() — full scan of enforceAuthSchemes list for (int j = 0; j < enforceAuthSchemes.size(); j++) { probes++; if (enforceAuthSchemes.get(j).equals(scheme)) { break; // found — stop scanning } } } return probes; } /** * Simulates fixed isCnxnAuthenticated() with HashSet.contains() — O(I). * Returns total probes (one per auth id). */ static long fastIsCnxnAuthenticated(int authIds, int schemes) { Set enforceAuthSchemes = new HashSet<>(); for (int i = 0; i < schemes; i++) { enforceAuthSchemes.add("scheme_" + i); } List authInfo = new ArrayList<>(); for (int i = 0; i < authIds; i++) { authInfo.add("unknown_" + i); } long probes = 0; for (String scheme : authInfo) { probes++; // O(1) HashSet.contains per auth id if (enforceAuthSchemes.contains(scheme)) { return probes; // authenticated } } return probes; } // --------------------------------------------------------------------------- // Benchmarking helper // --------------------------------------------------------------------------- static void bench(String label, long slowOps, long fastOps) { double ratio = (double) slowOps / Math.max(fastOps, 1); System.out.printf(" %-62s slow:%,8d ops fast:%,8d ops ratio:%.0fx%n", label, slowOps, fastOps, ratio); } // --------------------------------------------------------------------------- // main // --------------------------------------------------------------------------- public static void main(String[] args) { System.out.println("ZookeeperTest — CWE-407: zookeeper-0001 + zookeeper-0002"); System.out.println(); // --- zookeeper-0001 benchmarks --- System.out.println(" [zookeeper-0001: PrepRequestProcessor.removeDuplicates() ACL dedup]"); int[][] aclCases = {{200, 50}, {500, 100}, {1000, 200}}; for (int[] c : aclCases) { int total = c[0], unique = c[1]; long slow = slowRemoveDuplicates(total, unique); long fast = fastRemoveDuplicates(total, unique); bench(String.format("N=%d total ACLs, U=%d unique", total, unique), slow, fast); } System.out.println(); // --- zookeeper-0002 benchmarks --- System.out.println(" [zookeeper-0002: AuthenticationHelper.isCnxnAuthenticated() scheme lookup]"); int[][] authCases = {{10, 50}, {50, 200}, {100, 500}}; for (int[] c : authCases) { int ids = c[0], schemes = c[1]; long slow = slowIsCnxnAuthenticated(ids, schemes); long fast = fastIsCnxnAuthenticated(ids, schemes); bench(String.format("I=%d auth-ids, M=%d enforced-schemes", ids, schemes), slow, fast); } System.out.println(); // --- assertions --- int pass = 0; // zookeeper-0001: O(N²) vs O(N) — at N=1000/U=200, slow >> fast { long slow = slowRemoveDuplicates(1000, 200); long fast = fastRemoveDuplicates(1000, 200); // slow is O(N×U) worst-case; fast is exactly N probes // expect ratio ≥ 10x assert slow > fast * 10 : "zookeeper-0001 expected >10x ratio; slow=" + slow + " fast=" + fast; pass++; System.out.printf(" PASS zookeeper-0001: ArrayList.contains dedup O(N²) → HashSet.add O(N)" + " ratio=%.0fx%n", (double) slow / fast); } // zookeeper-0002: O(I×M) vs O(I) — at I=100/M=500, slow >> fast { long slow = slowIsCnxnAuthenticated(100, 500); long fast = fastIsCnxnAuthenticated(100, 500); // slow = 100×500 = 50000; fast = 100 // expect ratio ≥ 50x assert slow > fast * 50 : "zookeeper-0002 expected >50x ratio; slow=" + slow + " fast=" + fast; pass++; System.out.printf(" PASS zookeeper-0002: ArrayList.contains auth-scheme O(I×M) → HashSet O(I)" + " ratio=%.0fx%n", (double) slow / fast); } System.out.println(); System.out.printf("%d/2 PASS%n", pass); if (pass < 2) { System.out.println("FAIL"); System.exit(1); } System.out.println("ALL PASS"); } }