java-topology/defects/activemq/unit/ActiveMQTest2.java

147 lines
5.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.

import java.util.*;
/**
* CWE-407 unit tests for Apache ActiveMQ defects 0002 and 0003.
*
* activemq-0002: DemandForwardingBridgeSupport.java duplicateSuppressionIsRequired()
* candidateConsumers is an ArrayList; matchFound() calls candidateConsumers.contains()
* — O(C) per alias per subscription — O(S×N×C) total per network connect.
* Fix: convert candidateConsumers to HashSet before the outer sub-scan loop for O(1) lookup.
*
* activemq-0003: TransactionContext.java isInXATransaction()
* ENDED_XA_TRANSACTION_CONTEXTS values are ArrayList<TransactionContext>;
* transactions.contains(this) — O(C) linear scan per XA txn bucket.
* Fix: change values to Set<TransactionContext> for O(1) contains.
*/
public class ActiveMQTest2 {
// Simulate defect: matchFound with ArrayList candidateConsumers
static boolean matchFound_list(List<Integer> candidateConsumers, List<Integer> networkConsumers) {
for (Integer alias : networkConsumers) {
if (candidateConsumers.contains(alias)) return true; // O(C) — defect
}
return false;
}
// Simulate fix: matchFound with HashSet candidateConsumers
static boolean matchFound_set(Set<Integer> candidateSet, List<Integer> networkConsumers) {
for (Integer alias : networkConsumers) {
if (candidateSet.contains(alias)) return true; // O(1)
}
return false;
}
static void testActiveMQ0002() throws Exception {
int C = 500; // candidateConsumers per remote subscription
int S = 2000; // current subscriptions in the region
int N = 3; // networkConsumerIds per existing sub (small, 13)
List<Integer> candidateList = new ArrayList<>(C);
for (int i = 0; i < C; i++) candidateList.add(i);
Set<Integer> candidateSet = new HashSet<>(candidateList);
// Build S existing subs, each with N networkConsumerIds (not overlapping — full scan)
List<List<Integer>> subs = new ArrayList<>(S);
for (int s = 0; s < S; s++) {
List<Integer> nc = new ArrayList<>(N);
for (int n = 0; n < N; n++) nc.add(C + s * N + n); // no overlap → full C scan each time
subs.add(nc);
}
// correctness: last sub has a matching id → find it
subs.get(S - 1).set(0, candidateList.get(0));
boolean r1 = false, r2 = false;
for (List<Integer> nc : subs) {
if (matchFound_list(candidateList, nc)) { r1 = true; break; }
}
for (List<Integer> nc : subs) {
if (matchFound_set(candidateSet, nc)) { r2 = true; break; }
}
assert r1 == r2 : "list and set must agree: " + r1 + " vs " + r2;
// Reset: no match case (worst case — full scan)
subs.get(S - 1).set(0, C + S * N + 99);
int REPS = 20;
long t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) {
for (List<Integer> nc : subs) matchFound_list(candidateList, nc);
}
long tList = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) {
for (List<Integer> nc : subs) matchFound_set(candidateSet, nc);
}
long tSet = System.nanoTime() - t0;
double ratio = (double) tList / tSet;
System.out.printf("activemq-0002: list=%.3fs set=%.3fs ratio=%.1f×%n",
tList / 1e9, tSet / 1e9, ratio);
assert ratio > 4 : "Expected >4× speedup, got " + ratio;
System.out.println("PASS activemq-0002");
}
// Simulate defect: isInXATransaction with List values
static boolean isInXATransaction_list(Map<Integer, List<Integer>> endedContexts, int self) {
for (List<Integer> transactions : endedContexts.values()) {
if (transactions.contains(self)) return true; // O(C) — defect
}
return false;
}
// Simulate fix: isInXATransaction with Set values
static boolean isInXATransaction_set(Map<Integer, Set<Integer>> endedContexts, int self) {
for (Set<Integer> transactions : endedContexts.values()) {
if (transactions.contains(self)) return true; // O(1)
}
return false;
}
static void testActiveMQ0003() throws Exception {
int T = 50; // ended XA transaction buckets
int C = 200; // contexts per bucket
Map<Integer, List<Integer>> listMap = new LinkedHashMap<>();
Map<Integer, Set<Integer>> setMap = new LinkedHashMap<>();
for (int t = 0; t < T; t++) {
List<Integer> lst = new ArrayList<>(C);
Set<Integer> set = new LinkedHashSet<>(C);
for (int c = 0; c < C; c++) {
int ctx = t * C + c;
lst.add(ctx);
set.add(ctx);
}
listMap.put(t, lst);
setMap.put(t, set);
}
// self not in any bucket → worst case (full scan)
int self = T * C + 999;
// correctness: not present
assert !isInXATransaction_list(listMap, self);
assert !isInXATransaction_set(setMap, self);
int REPS = 10_000;
long t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) isInXATransaction_list(listMap, self);
long tList = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) isInXATransaction_set(setMap, self);
long tSet = System.nanoTime() - t0;
double ratio = (double) tList / tSet;
System.out.printf("activemq-0003: list=%.3fs set=%.3fs ratio=%.1f×%n",
tList / 1e9, tSet / 1e9, ratio);
assert ratio > 5 : "Expected >5× speedup, got " + ratio;
System.out.println("PASS activemq-0003");
}
public static void main(String[] args) throws Exception {
testActiveMQ0002();
testActiveMQ0003();
System.out.println("ALL PASS");
}
}