java-topology/defects/zookeeper/unit/ZookeeperTest.java

213 lines
8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<ACL> seen — O(N) total, O(1) per check
*
* zookeeper-0002: AuthenticationHelper.isCnxnAuthenticated()
* ArrayList<String>.contains() for enforceAuthSchemes — O(M) per auth id, O(I×M) total
* Fix: HashSet<String> 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<Integer> input = new ArrayList<>(totalAcls);
for (int i = 0; i < totalAcls; i++) {
input.add(i % uniqueAcls);
}
long probes = 0;
List<Integer> 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<Integer> input = new ArrayList<>(totalAcls);
for (int i = 0; i < totalAcls; i++) {
input.add(i % uniqueAcls);
}
long probes = 0;
List<Integer> retval = new ArrayList<>(totalAcls);
Set<Integer> 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<String> 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<String> 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<String> enforceAuthSchemes = new HashSet<>();
for (int i = 0; i < schemes; i++) {
enforceAuthSchemes.add("scheme_" + i);
}
List<String> 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");
}
}