Netdata: well-engineered with Judy arrays, dictionaries, hash tables throughout. No CWE-407 defects found. Telegraf: dedup processor Apply() calls m.GetField(f.Key) O(F) inside field comparison loop → O(F²). Fix: build field map for O(1) lookup. 125x overhead at F=500.
113 lines
3.7 KiB
Java
113 lines
3.7 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test for Telegraf dedup processor defect.
|
|
*
|
|
* telegraf-0001: Dedup Apply() calls GetField(key) O(F) inside field loop → O(F²)
|
|
*
|
|
* Simulates the defect (linear field scan per field) vs the fix (hash map lookup).
|
|
*/
|
|
public class TelegrafTest {
|
|
|
|
// --- telegraf-0001: Dedup GetField quadratic ---
|
|
|
|
/** Simulate metric fields as a list (Go slice of *Field). */
|
|
static List<String[]> makeFields(int n) {
|
|
List<String[]> fields = new ArrayList<>(n);
|
|
for (int i = 0; i < n; i++) {
|
|
fields.add(new String[]{"field_" + i, "value_" + i});
|
|
}
|
|
return fields;
|
|
}
|
|
|
|
/** DEFECTIVE: linear scan for each field lookup, O(F) per call. */
|
|
static Object getFieldLinear(List<String[]> fields, String key) {
|
|
for (String[] f : fields) {
|
|
if (f[0].equals(key)) {
|
|
return f[1];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** DEFECTIVE: dedup comparison using linear GetField — O(F²). */
|
|
static long dedupCompareDefective(List<String[]> incoming, List<String[]> cached) {
|
|
long ops = 0;
|
|
for (String[] f : incoming) {
|
|
// Linear scan of cached fields
|
|
for (String[] cf : cached) {
|
|
ops++;
|
|
if (cf[0].equals(f[0])) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/** FIXED: build hash map first, then O(1) lookup — O(F). */
|
|
static long dedupCompareFixed(List<String[]> incoming, List<String[]> cached) {
|
|
long ops = 0;
|
|
Map<String, String> cachedMap = new HashMap<>(cached.size());
|
|
for (String[] cf : cached) {
|
|
cachedMap.put(cf[0], cf[1]);
|
|
ops++;
|
|
}
|
|
for (String[] f : incoming) {
|
|
cachedMap.get(f[0]); // O(1) amortized
|
|
ops++;
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
static boolean testDedupGetField() {
|
|
System.out.println("=== telegraf-0001: Dedup GetField O(F²) → O(F) ===");
|
|
boolean pass = true;
|
|
|
|
int[] sizes = {10, 50, 100, 500};
|
|
for (int n : sizes) {
|
|
List<String[]> incoming = makeFields(n);
|
|
List<String[]> cached = makeFields(n);
|
|
|
|
long defectOps = dedupCompareDefective(incoming, cached);
|
|
long fixedOps = dedupCompareFixed(incoming, cached);
|
|
double ratio = (double) defectOps / fixedOps;
|
|
|
|
System.out.printf(" F=%d: defect=%d ops, fixed=%d ops, ratio=%.1fx%n",
|
|
n, defectOps, fixedOps, ratio);
|
|
|
|
// At F=100: defect ~5050 ops (sum 1..100), fixed ~200 ops, ratio ~25x
|
|
// At F=500: defect ~125250 ops, fixed ~1000 ops, ratio ~125x
|
|
if (n >= 50 && ratio < 2.0) {
|
|
System.out.printf(" FAIL: expected ratio >= 2.0 at F=%d, got %.1f%n", n, ratio);
|
|
pass = false;
|
|
}
|
|
}
|
|
|
|
// Verify correctness: both should find the same matches
|
|
List<String[]> a = makeFields(20);
|
|
List<String[]> b = makeFields(20);
|
|
for (String[] f : a) {
|
|
Object linearResult = getFieldLinear(b, f[0]);
|
|
if (linearResult == null || !linearResult.equals(f[1])) {
|
|
System.out.println(" FAIL: linear lookup returned wrong result for " + f[0]);
|
|
pass = false;
|
|
}
|
|
}
|
|
|
|
System.out.println(" " + (pass ? "PASS" : "FAIL"));
|
|
return pass;
|
|
}
|
|
|
|
// --- Main ---
|
|
|
|
public static void main(String[] args) {
|
|
boolean allPass = true;
|
|
|
|
allPass &= testDedupGetField();
|
|
|
|
System.out.println();
|
|
System.out.println(allPass ? "ALL TESTS PASSED" : "SOME TESTS FAILED");
|
|
System.exit(allPass ? 0 : 1);
|
|
}
|
|
}
|