java-topology/defects/quarkus/unit/QuarkusTest.java

270 lines
10 KiB
Java

import java.util.*;
/**
* CWE-407 unit tests for Quarkus.
*
* quarkus-0001: BeanInfo.getBoundInterceptors()
* independent-projects/arc/processor/.../BeanInfo.java
* Builds deduplicated interceptor list using ArrayList.contains() inside
* nested loops over lifecycle+method interceptions.
* Complexity: O(M * I^2) where M = intercepted methods, I = interceptors.
* Fix: LinkedHashSet for O(1) dedup → O(M * I).
*
* quarkus-0002: BeanInfo.getBoundDecorators()
* Same file. ArrayList.contains(dm.decorator) inside loop over decorated methods.
* Complexity: O(M * D^2) where M = decorated methods, D = decorators.
* Fix: LinkedHashSet for O(1) dedup → O(M * D).
*
* quarkus-0003: RuntimeUpdatesProcessor.checkForClassFilesChangesInModule()
* core/deployment/.../dev/RuntimeUpdatesProcessor.java
* moduleChangedSourceFiles is ArrayList<Path>; contains(sourceFilePath) called
* for every class file in the module during dev mode hot reload.
* Complexity: O(C * S) where C = class files, S = changed source files.
* Fix: change declaration to Set<Path> (LinkedHashSet) → O(C).
*
* quarkus-0004: CORSFilter.handle()
* extensions/vertx-http/.../cors/CORSFilter.java
* corsConfig.origins().get().contains(origin) on List<String> executed per
* HTTP request. O(O) per request where O = configured origins count.
* Fix: pre-build HashSet<String> of exact origins at construction → O(1) per request.
*/
public class QuarkusTest {
// -----------------------------------------------------------------------
// quarkus-0001 / quarkus-0002: getBoundInterceptors / getBoundDecorators
// -----------------------------------------------------------------------
/** Defect: deduplicate using ArrayList.contains — O(N^2). */
static List<Integer> deduplicateList(List<Integer> inputs) {
List<Integer> bound = new ArrayList<>();
for (int item : inputs) {
if (!bound.contains(item)) { // O(N) per call — defect
bound.add(item);
}
}
return bound;
}
/** Fix: deduplicate using LinkedHashSet — O(N) total, preserves order. */
static List<Integer> deduplicateSet(List<Integer> inputs) {
Set<Integer> seen = new LinkedHashSet<>();
for (int item : inputs) {
seen.add(item); // O(1) per call — fix
}
return new ArrayList<>(seen);
}
static void testQuarkus0001_getBoundInterceptors() throws Exception {
// Simulate M=200 intercepted methods, each with I=100 interceptors (some repeated)
int M = 200;
int I = 100;
int totalInterceptors = 50; // universe of unique interceptors
List<Integer> allInterceptors = new ArrayList<>();
Random rng = new Random(42);
for (int m = 0; m < M; m++) {
for (int i = 0; i < I; i++) {
allInterceptors.add(rng.nextInt(totalInterceptors));
}
}
long t0 = System.nanoTime();
for (int trial = 0; trial < 1000; trial++) {
deduplicateList(allInterceptors);
}
long defectNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
for (int trial = 0; trial < 1000; trial++) {
deduplicateSet(allInterceptors);
}
long fixNs = System.nanoTime() - t1;
double ratio = (double) defectNs / fixNs;
System.out.printf("quarkus-0001 getBoundInterceptors: defect=%.1fms fix=%.1fms ratio=%.1fx%n",
defectNs / 1e6, fixNs / 1e6, ratio);
if (ratio < 2.0) {
throw new AssertionError("Expected ratio >= 2.0, got " + ratio);
}
System.out.println("quarkus-0001 PASS");
}
static void testQuarkus0002_getBoundDecorators() throws Exception {
// Simulate M=150 decorated methods, each with D=80 decorators (some repeated)
int M = 150;
int D = 80;
int totalDecorators = 30;
List<Integer> allDecorators = new ArrayList<>();
Random rng = new Random(123);
for (int m = 0; m < M; m++) {
for (int d = 0; d < D; d++) {
allDecorators.add(rng.nextInt(totalDecorators));
}
}
long t0 = System.nanoTime();
for (int trial = 0; trial < 1000; trial++) {
deduplicateList(allDecorators);
}
long defectNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
for (int trial = 0; trial < 1000; trial++) {
deduplicateSet(allDecorators);
}
long fixNs = System.nanoTime() - t1;
double ratio = (double) defectNs / fixNs;
System.out.printf("quarkus-0002 getBoundDecorators: defect=%.1fms fix=%.1fms ratio=%.1fx%n",
defectNs / 1e6, fixNs / 1e6, ratio);
if (ratio < 2.0) {
throw new AssertionError("Expected ratio >= 2.0, got " + ratio);
}
System.out.println("quarkus-0002 PASS");
}
// -----------------------------------------------------------------------
// quarkus-0003: checkForClassFilesChangesInModule — dev mode hot reload
// -----------------------------------------------------------------------
/** Defect: List<String>.contains per class file — O(C * S). */
static int scanModuleDefect(List<String> classFiles, List<String> changedSourceFiles) {
int deletions = 0;
for (String classFile : classFiles) {
String sourceFile = classFile.replace(".class", ".java");
if (changedSourceFiles.contains(sourceFile)) { // O(S) per call — defect
deletions++;
}
}
return deletions;
}
/** Fix: Set<String>.contains per class file — O(C). */
static int scanModuleFix(List<String> classFiles, Set<String> changedSourceFiles) {
int deletions = 0;
for (String classFile : classFiles) {
String sourceFile = classFile.replace(".class", ".java");
if (changedSourceFiles.contains(sourceFile)) { // O(1) per call — fix
deletions++;
}
}
return deletions;
}
static void testQuarkus0003_devModeChangedSourceFiles() throws Exception {
// Simulate: C=2000 class files, S=200 changed source files
int C = 2000;
int S = 200;
List<String> classFiles = new ArrayList<>(C);
List<String> changedSourceList = new ArrayList<>(S);
Set<String> changedSourceSet = new LinkedHashSet<>(S * 2);
for (int i = 0; i < C; i++) {
classFiles.add("com/example/Foo" + i + ".class");
}
for (int i = 0; i < S; i++) {
String src = "com/example/Foo" + (i * 5) + ".java";
changedSourceList.add(src);
changedSourceSet.add(src);
}
long t0 = System.nanoTime();
for (int trial = 0; trial < 200; trial++) {
scanModuleDefect(classFiles, changedSourceList);
}
long defectNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
for (int trial = 0; trial < 200; trial++) {
scanModuleFix(classFiles, changedSourceSet);
}
long fixNs = System.nanoTime() - t1;
double ratio = (double) defectNs / fixNs;
System.out.printf("quarkus-0003 devModeChangedSourceFiles: defect=%.1fms fix=%.1fms ratio=%.1fx%n",
defectNs / 1e6, fixNs / 1e6, ratio);
if (ratio < 5.0) {
throw new AssertionError("Expected ratio >= 5.0, got " + ratio);
}
System.out.println("quarkus-0003 PASS");
}
// -----------------------------------------------------------------------
// quarkus-0004: CORSFilter.handle — origins list lookup per request
// -----------------------------------------------------------------------
/** Defect: List<String>.contains per HTTP request — O(O). */
static int handleRequestsDefect(List<String> origins, String[] incomingOrigins) {
int allowed = 0;
for (String origin : incomingOrigins) {
if (origins.contains(origin)) { // O(O) per request — defect
allowed++;
}
}
return allowed;
}
/** Fix: pre-built HashSet<String>.contains per request — O(1). */
static int handleRequestsFix(Set<String> originsSet, String[] incomingOrigins) {
int allowed = 0;
for (String origin : incomingOrigins) {
if (originsSet.contains(origin)) { // O(1) per request — fix
allowed++;
}
}
return allowed;
}
static void testQuarkus0004_corsOriginsLookup() throws Exception {
// Simulate: O=100 configured origins, R=100000 requests
int O = 100;
int R = 100000;
List<String> originsList = new ArrayList<>(O);
Set<String> originsSet = new HashSet<>(O * 2);
for (int i = 0; i < O; i++) {
originsList.add("https://example" + i + ".com");
originsSet.add("https://example" + i + ".com");
}
// Requests target last origin (worst case for list scan)
String[] requests = new String[R];
for (int i = 0; i < R; i++) {
requests[i] = "https://example" + ((i % O)) + ".com";
}
long t0 = System.nanoTime();
handleRequestsDefect(originsList, requests);
long defectNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
handleRequestsFix(originsSet, requests);
long fixNs = System.nanoTime() - t1;
double ratio = (double) defectNs / fixNs;
System.out.printf("quarkus-0004 corsOriginsLookup: defect=%.1fms fix=%.1fms ratio=%.1fx%n",
defectNs / 1e6, fixNs / 1e6, ratio);
if (ratio < 2.0) {
throw new AssertionError("Expected ratio >= 2.0, got " + ratio);
}
System.out.println("quarkus-0004 PASS");
}
// -----------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------
public static void main(String[] args) throws Exception {
testQuarkus0001_getBoundInterceptors();
testQuarkus0002_getBoundDecorators();
testQuarkus0003_devModeChangedSourceFiles();
testQuarkus0004_corsOriginsLookup();
System.out.println("ALL PASS");
}
}