109 lines
3.8 KiB
Java
109 lines
3.8 KiB
Java
package unit;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.HashSet;
|
||
import java.util.List;
|
||
import java.util.Set;
|
||
|
||
/**
|
||
* consul CWE-407 unit tests:
|
||
*
|
||
* consul-0001: ExcludeBasedOnChecks — slices.Contains(IgnoreCheckIDs) per check
|
||
*
|
||
* No JUnit, no external deps.
|
||
* Compile: javac -d . ConsulAlgorithmTest.java
|
||
* Run: java -ea unit.ConsulAlgorithmTest
|
||
*/
|
||
public class ConsulAlgorithmTest {
|
||
|
||
static int passed = 0;
|
||
static int total = 0;
|
||
|
||
// -----------------------------------------------------------------------
|
||
// consul-0001: ExcludeBasedOnChecks
|
||
//
|
||
// Called in health query hot path for every service node returned.
|
||
// Outer loop = all checks on the node (C checks).
|
||
// Inner scan = slices.Contains(opts.IgnoreCheckIDs, check.CheckID) → O(I).
|
||
// Total for one node: O(C × I).
|
||
// Total for a health query returning N nodes: O(N × C × I).
|
||
// -----------------------------------------------------------------------
|
||
|
||
/**
|
||
* Slow: mirrors Go ExcludeBasedOnChecks — linear scan over ignoreIDs per check.
|
||
*/
|
||
static long slowExcludeBasedOnChecks(String[] checks, String[] ignoreIDs) {
|
||
long ops = 0;
|
||
for (String check : checks) {
|
||
ops++;
|
||
// slices.Contains linear scan
|
||
boolean ignored = false;
|
||
for (String id : ignoreIDs) {
|
||
ops++;
|
||
if (id.equals(check)) { ignored = true; break; }
|
||
}
|
||
if (!ignored) {
|
||
// would call ExcludeBasedOnStatus — simulate with a no-op
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/**
|
||
* Fast: pre-build HashSet from ignoreIDs → O(I + C) per node.
|
||
*/
|
||
static long fastExcludeBasedOnChecks(String[] checks, String[] ignoreIDs) {
|
||
long ops = 0;
|
||
Set<String> ignoreSet = new HashSet<>();
|
||
for (String id : ignoreIDs) { ignoreSet.add(id); ops++; }
|
||
for (String check : checks) {
|
||
ops++;
|
||
if (!ignoreSet.contains(check)) {
|
||
// would call ExcludeBasedOnStatus
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
static void testExcludeBasedOnChecks() {
|
||
System.out.println("--- consul-0001: ExcludeBasedOnChecks ---");
|
||
|
||
// Simulate: many nodes, each with C checks, I ignore IDs
|
||
int[] ignoreCounts = {20, 50, 100};
|
||
int checksPerNode = 30;
|
||
int nodeCount = 500;
|
||
|
||
for (int i : ignoreCounts) {
|
||
String[] ignoreIDs = new String[i];
|
||
for (int j = 0; j < i; j++) ignoreIDs[j] = "ignore-" + j;
|
||
|
||
// Build checks array for nodeCount nodes × checksPerNode
|
||
String[] allChecks = new String[nodeCount * checksPerNode];
|
||
for (int n = 0; n < nodeCount * checksPerNode; n++) {
|
||
allChecks[n] = "check-" + (n % (checksPerNode * 2)); // some overlap with ignore
|
||
}
|
||
|
||
long slowOps = slowExcludeBasedOnChecks(allChecks, ignoreIDs);
|
||
long fastOps = fastExcludeBasedOnChecks(allChecks, ignoreIDs);
|
||
|
||
double ratio = (double) slowOps / fastOps;
|
||
boolean pass = ratio > (double) i / 3.0;
|
||
total++;
|
||
if (pass) passed++;
|
||
System.out.printf(" nodes=%-3d checks/node=%d ignoreIDs=%-3d slow=%,10d fast=%,8d ratio=%6.1fx %s%n",
|
||
nodeCount, checksPerNode, i, slowOps, fastOps, ratio, pass ? "PASS" : "FAIL");
|
||
assert pass : "consul-0001 FAIL: ratio=" + ratio;
|
||
}
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("=== Consul CWE-407 unit tests ===");
|
||
testExcludeBasedOnChecks();
|
||
System.out.printf("%n%d/%d PASS%n", passed, total);
|
||
if (passed != total) {
|
||
System.exit(1);
|
||
}
|
||
}
|
||
}
|