143 lines
5.9 KiB
Java
143 lines
5.9 KiB
Java
package unit;
|
||
|
||
import java.util.HashMap;
|
||
|
||
/**
|
||
* wolfssl-0001 unit test
|
||
*
|
||
* Models the O(C×S) ALPN selection in ALPN_find_match() / TLSX_ALPN_Find()
|
||
* and the O(C+S) fixed version using a hash set of server names.
|
||
*
|
||
* Compile: javac -d . WolfSslAlpnFindTest.java
|
||
* Run: java unit.WolfSslAlpnFindTest
|
||
*/
|
||
public class WolfSslAlpnFindTest {
|
||
|
||
// ------------------------------------------------------------------ //
|
||
// Model TLSX_ALPN_Find: O(S) linear scan of server linked list //
|
||
// ------------------------------------------------------------------ //
|
||
static String tlsxAlpnFind(String[] serverList, String name) {
|
||
for (String s : serverList) {
|
||
if (s.length() == name.length() && s.equals(name))
|
||
return s;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// ------------------------------------------------------------------ //
|
||
// DEFECTIVE: O(C × S) — ALPN_find_match calls TLSX_ALPN_Find(O(S)) //
|
||
// for each of C client-offered names //
|
||
// ------------------------------------------------------------------ //
|
||
static String defectiveMatch(String[] serverList, String[] clientNames) {
|
||
// Outer: iterate client list (wolfSSL uses client-preference order)
|
||
for (String clientName : clientNames) {
|
||
// Inner: TLSX_ALPN_Find — O(S) scan
|
||
String found = tlsxAlpnFind(serverList, clientName);
|
||
if (found != null) return found;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// ------------------------------------------------------------------ //
|
||
// FIXED: O(C + S) — hash set of server names, O(1) lookup //
|
||
// ------------------------------------------------------------------ //
|
||
static String fixedMatch(String[] serverList, String[] clientNames) {
|
||
// Build hash set of server names — O(S)
|
||
HashMap<String, String> serverSet = new HashMap<>();
|
||
for (String s : serverList) serverSet.put(s, s);
|
||
|
||
// Iterate client list — O(C), each lookup O(1) expected
|
||
for (String clientName : clientNames) {
|
||
String found = serverSet.get(clientName);
|
||
if (found != null) return found;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// ------------------------------------------------------------------ //
|
||
// Counting versions //
|
||
// ------------------------------------------------------------------ //
|
||
static long[] ops = new long[2];
|
||
|
||
static String defectiveCounting(String[] serverList, String[] clientNames) {
|
||
for (String cn : clientNames) {
|
||
for (String sn : serverList) {
|
||
ops[0]++;
|
||
if (sn.equals(cn)) return sn;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
static String fixedCounting(String[] serverList, String[] clientNames) {
|
||
HashMap<String, String> ss = new HashMap<>();
|
||
for (String s : serverList) { ops[1]++; ss.put(s, s); }
|
||
for (String cn : clientNames) {
|
||
ops[1]++;
|
||
String found = ss.get(cn);
|
||
if (found != null) return found;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
static int pass = 0, fail = 0;
|
||
|
||
static void check(String label, boolean cond) {
|
||
if (cond) { System.out.println(" PASS " + label); pass++; }
|
||
else { System.out.println(" FAIL " + label); fail++; }
|
||
}
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("=== wolfssl-0001: ALPN_find_match O(C×S) defect ===\n");
|
||
|
||
// wolfSSL uses client-preference order (matches first client name found in server)
|
||
String[] server = {"h2", "http/1.1", "grpc"};
|
||
|
||
// Test 1: first client name matches server
|
||
String[] client1 = {"h2", "ftp"};
|
||
check("defective: match h2", "h2".equals(defectiveMatch(server, client1)));
|
||
check("fixed: match h2", "h2".equals(fixedMatch(server, client1)));
|
||
|
||
// Test 2: second client name matches
|
||
String[] client2 = {"ftp", "grpc"};
|
||
check("defective: match grpc", "grpc".equals(defectiveMatch(server, client2)));
|
||
check("fixed: match grpc", "grpc".equals(fixedMatch(server, client2)));
|
||
|
||
// Test 3: client-preference wins (wolfSSL: first matching client entry)
|
||
String[] client3 = {"grpc", "h2"};
|
||
check("defective: client-pref → grpc", "grpc".equals(defectiveMatch(server, client3)));
|
||
check("fixed: client-pref → grpc", "grpc".equals(fixedMatch(server, client3)));
|
||
|
||
// Test 4: no match
|
||
String[] client4 = {"smtp", "pop3"};
|
||
check("defective: no match → null", defectiveMatch(server, client4) == null);
|
||
check("fixed: no match → null", fixedMatch(server, client4) == null);
|
||
|
||
// Test 5: complexity — adversarial client list
|
||
int S = 5;
|
||
int C = 400;
|
||
String[] bigServer = new String[S];
|
||
for (int i = 0; i < S; i++) bigServer[i] = "proto-server-" + i;
|
||
|
||
String[] bigClient = new String[C];
|
||
for (int i = 0; i < C - 1; i++) bigClient[i] = "proto-client-" + i;
|
||
bigClient[C - 1] = bigServer[S - 1]; // match at end — worst case
|
||
|
||
ops[0] = 0; ops[1] = 0;
|
||
String rd = defectiveCounting(bigServer, bigClient);
|
||
String rf = fixedCounting(bigServer, bigClient);
|
||
|
||
System.out.println("\n Complexity comparison (S=" + S + ", C=" + C + "):");
|
||
System.out.println(" Defective ops: " + ops[0] + " (expected ~" + ((long)(C-1)*S + 1) + ")");
|
||
System.out.println(" Fixed ops: " + ops[1] + " (expected ~" + (S + C) + ")");
|
||
System.out.printf(" Speedup: %.1fx%n", (double) ops[0] / ops[1]);
|
||
|
||
check("defective and fixed agree on result",
|
||
java.util.Objects.equals(rd, rf));
|
||
check("defective ops > 4x fixed ops (quadratic vs linear)",
|
||
ops[0] > 4 * ops[1]);
|
||
|
||
System.out.println("\n--- " + (pass + fail) + " tests: " + pass + " passed, " + fail + " failed ---");
|
||
if (fail > 0) System.exit(1);
|
||
}
|
||
}
|