whitepaper: 398/185 — wave6d (rails-0012..16, jsc-0001/2, vtk, sm-0002, redis/valkey-0003, helm-0002/3, k8s-0003)
This commit is contained in:
parent
eb9612e4bf
commit
3735145aa5
47 changed files with 3488 additions and 33 deletions
|
|
@ -3,15 +3,24 @@ package unit;
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Standalone unit test for helm CWE-407 defect.
|
||||
* Standalone unit tests for helm CWE-407 defects.
|
||||
*
|
||||
* helm-0001: processDependencyEnabled — O(n²) nested dependency lookup
|
||||
* Pattern A: for each existing dep, scan all metadata deps — O(E × M).
|
||||
* Pattern B: getAliasDependency called per metadata dep — O(M × C).
|
||||
*
|
||||
* slow() counts ops for both patterns with nested loops.
|
||||
* fast() counts ops using a pre-built name→entry map for O(1) lookups.
|
||||
* Assert: slowOps > fastOps * 5x for D=200 dependencies.
|
||||
*
|
||||
* helm-0002: filterReleases / filterPlugins — O(R×M) slices.Contains in filter loops
|
||||
* Slow: slices.Contains(ignoredNames, name) called per release/plugin — O(R×M).
|
||||
* Fast: pre-built map[name]struct{} — O(R+M).
|
||||
* Assert: slowOps > fastOps * 5x for R=500, M=100.
|
||||
*
|
||||
* helm-0003: checkRequestedRepos / isRepoRequested — O(n×m) nested + per-iteration scan
|
||||
* Slow: nested loop O(M×R) + isRepoRequested O(R×M) per repo.
|
||||
* Fast: pre-built map[name]struct{} for O(1) lookups.
|
||||
* Assert: slowOps > fastOps * 5x for R=300, M=100.
|
||||
*/
|
||||
public class HelmTest {
|
||||
|
||||
|
|
@ -21,6 +30,8 @@ public class HelmTest {
|
|||
ChartDep(String name, String version) { this.name = name; this.version = version; }
|
||||
}
|
||||
|
||||
// ── helm-0001 ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Slow path — Pattern A: O(existing × metaDeps).
|
||||
* Pattern B: O(metaDeps × charts) where getAliasDependency scans charts linearly.
|
||||
|
|
@ -113,8 +124,152 @@ public class HelmTest {
|
|||
if (!pass) throw new AssertionError("helm-0001 FAIL: slow=" + sOps + " fast=" + fOps);
|
||||
}
|
||||
|
||||
// ── helm-0002 ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Slow: filterReleases — slices.Contains(ignoredNames, name) per release — O(R×M).
|
||||
* R = number of releases, M = size of ignoredNames list.
|
||||
*/
|
||||
static long slowFilterReleases(List<String> releases, List<String> ignoredNames) {
|
||||
long ops = 0;
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String rel : releases) {
|
||||
// slices.Contains — O(M) linear scan per release
|
||||
boolean found = false;
|
||||
for (int i = 0; i < ignoredNames.size(); i++) {
|
||||
ops++;
|
||||
if (ignoredNames.get(i).equals(rel)) { found = true; break; }
|
||||
}
|
||||
if (!found) filtered.add(rel);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast: build map[name]struct{} once — O(M) build, O(1) per release lookup.
|
||||
*/
|
||||
static long fastFilterReleases(List<String> releases, List<String> ignoredNames) {
|
||||
long ops = 0;
|
||||
// O(M) build
|
||||
Set<String> ignoreSet = new HashSet<>(ignoredNames.size());
|
||||
for (String name : ignoredNames) { ops++; ignoreSet.add(name); }
|
||||
// O(R) filter with O(1) lookup
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String rel : releases) {
|
||||
ops++; // O(1) map lookup
|
||||
if (!ignoreSet.contains(rel)) filtered.add(rel);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void testFilterReleases() {
|
||||
int R = 500; // releases
|
||||
int M = 100; // ignored names
|
||||
// ignoredNames all miss — worst case, full scan every release
|
||||
List<String> releases = new ArrayList<>(R);
|
||||
for (int i = 0; i < R; i++) releases.add("release-" + i);
|
||||
List<String> ignoredNames = new ArrayList<>(M);
|
||||
for (int i = 0; i < M; i++) ignoredNames.add("ignored-" + i);
|
||||
|
||||
long sOps = slowFilterReleases(releases, ignoredNames);
|
||||
long fOps = fastFilterReleases(releases, ignoredNames);
|
||||
|
||||
int Nx = 5;
|
||||
boolean pass = sOps > fOps * Nx;
|
||||
System.out.printf("helm-0002 [R=%d M=%d]: slow=%d fast=%d ratio=%.1fx — %s%n",
|
||||
R, M, sOps, fOps, (double) sOps / fOps, pass ? "PASS" : "FAIL");
|
||||
if (!pass) throw new AssertionError("helm-0002 FAIL: slow=" + sOps + " fast=" + fOps);
|
||||
}
|
||||
|
||||
// ── helm-0003 ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Slow: checkRequestedRepos nested loop O(M×R) + isRepoRequested inside outer loop O(R×M).
|
||||
* R = configured repos, M = requested repo names.
|
||||
*/
|
||||
static long slowRepoUpdate(List<String> allRepos, List<String> requestedRepos) {
|
||||
long ops = 0;
|
||||
|
||||
// checkRequestedRepos — O(M × R) nested loop
|
||||
for (String req : requestedRepos) {
|
||||
boolean found = false;
|
||||
for (String repo : allRepos) { // O(R) per requested name
|
||||
ops++;
|
||||
if (req.equals(repo)) { found = true; break; }
|
||||
}
|
||||
// (error if !found — not counted)
|
||||
}
|
||||
|
||||
// runUpdate loop — isRepoRequested(cfg.Name, o.names) O(M) per repo
|
||||
for (String repo : allRepos) {
|
||||
boolean requested = false;
|
||||
for (String req : requestedRepos) { // O(M) per repo — slices.Contains
|
||||
ops++;
|
||||
if (repo.equals(req)) { requested = true; break; }
|
||||
}
|
||||
if (requested) {
|
||||
// would build ChartRepository
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast: build map[name]struct{} once; O(1) membership for both passes.
|
||||
*/
|
||||
static long fastRepoUpdate(List<String> allRepos, List<String> requestedRepos) {
|
||||
long ops = 0;
|
||||
|
||||
// Build set from requestedRepos — O(M)
|
||||
Set<String> requestedSet = new HashSet<>(requestedRepos.size());
|
||||
for (String req : requestedRepos) { ops++; requestedSet.add(req); }
|
||||
|
||||
// Build set from allRepos — O(R) for checkRequestedRepos
|
||||
Set<String> validSet = new HashSet<>(allRepos.size());
|
||||
for (String repo : allRepos) { ops++; validSet.add(repo); }
|
||||
|
||||
// checkRequestedRepos — O(M) with O(1) lookup
|
||||
for (String req : requestedRepos) {
|
||||
ops++;
|
||||
// validSet.contains(req) — O(1)
|
||||
}
|
||||
|
||||
// runUpdate loop — O(R) with O(1) isRepoRequested
|
||||
for (String repo : allRepos) {
|
||||
ops++; // O(1) map lookup
|
||||
if (requestedSet.contains(repo)) {
|
||||
// would build ChartRepository
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void testRepoUpdate() {
|
||||
int R = 300; // configured repositories
|
||||
int M = 100; // requested repo names (all valid, none matching — worst case)
|
||||
List<String> allRepos = new ArrayList<>(R);
|
||||
for (int i = 0; i < R; i++) allRepos.add("repo-" + i);
|
||||
List<String> requestedRepos = new ArrayList<>(M);
|
||||
for (int i = R; i < R + M; i++) requestedRepos.add("repo-" + i); // disjoint — full scans
|
||||
|
||||
long sOps = slowRepoUpdate(allRepos, requestedRepos);
|
||||
long fOps = fastRepoUpdate(allRepos, requestedRepos);
|
||||
|
||||
int Nx = 5;
|
||||
boolean pass = sOps > fOps * Nx;
|
||||
System.out.printf("helm-0003 [R=%d M=%d]: slow=%d fast=%d ratio=%.1fx — %s%n",
|
||||
R, M, sOps, fOps, (double) sOps / fOps, pass ? "PASS" : "FAIL");
|
||||
if (!pass) throw new AssertionError("helm-0003 FAIL: slow=" + sOps + " fast=" + fOps);
|
||||
}
|
||||
|
||||
// ── main ──────────────────────────────────────────────────────────────────
|
||||
|
||||
public static void main(String[] args) {
|
||||
testProcessDependencies();
|
||||
System.out.println("1/1 PASS");
|
||||
testFilterReleases();
|
||||
testRepoUpdate();
|
||||
System.out.println("3/3 PASS");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue