This project forwards every outgoing request of its user's workstation. It must be fast, reliable, and not break silently. These rules exist because a broken or slow proxy cripples developer productivity — there is no "it's just a tool, we can tolerate regressions."
- Every code change runs
mvn clean verifyand all tests must be green. - Do not "optimize" or "simplify" code without a matching test. If the behaviour was untested and is now load-bearing, write the test before you touch the code.
- Integration test
SimpleProxyChainIntegrationTestis the safety net for the request path. If you changeSimpleProxyChain,FiltersSource407,Config,ProxyUI, or their wiring, you must extend this test. - Flaky tests are bugs. Fix the root cause, don't reduce assertions.
- The proxy sits on the hot path of every HTTP request. Keep per-request overhead minimal:
- No new allocations in the
ChainedProxyManager.lookupChainedProxies/ChainedProxyAdapter.filterRequestpath beyond what Netty forces. - Pre-compile regexes, pre-resolve addresses, cache headers.
- No blocking I/O in a Netty event loop.
- Logging in hot paths must be guarded with
log.isDebugEnabled().
- No new allocations in the
- Before claiming a change is neutral or positive for performance, run
packaging/perf/bench-compare.ps1— it benchmarks this project against a baseline (typically the currently deployed 8888 instance) and prints a NEW-vs-OLD delta. Keep p50/p95 within noise or improve them.
- Aim for every branch in the request/config/password hot path to have at least one test.
- Tests that currently guard hot paths:
Area Test URI → host extraction SimpleProxyChainHostTest407 burst → once-only callback FiltersSource407TestConfig parsing / equality ConfigTestConfig file change → debounced callback FileWatcherTestPassword XOR roundtrip CryptoTestEnd-to-end routing + auth + concurrency SimpleProxyChainIntegrationTest - Use JUnit Jupiter (JUnit 5). Don't re-introduce JUnit 4.
- A PR that reduces coverage is a rejected PR.
Before a change is "done":
mvn clean verify→ green. No exceptions.pwsh .\packaging\perf\bench-compare.ps1→ NEW ≥ OLD on throughput, p50, p95 (or within ±5% noise).pwsh .\packaging\build-native.ps1→target/native/output/Proxy/Proxy.exebuilds and is self-contained.- README / DEVELOPMENT.md mention any new user-visible switch.
- Auto-update subsystem (removed deliberately; deployment happens via Chocolatey).
- Console/SWT UI (AWT with headless degradation covers every case).
- JVM / env-variable auto-configuration (brittle, was the source of most bugs).
- JUnit 4 or Mockito with reflection magic that bypasses the real wire behaviour of LittleProxy.
- No field-initializer that can throw (e.g. AWT
PopupMenuthrowsHeadlessException). Use lazy construction. - Default to
volatileover synchronized for single-field publication (seecachedAuthHeaderValue). Thread.yield()is not a scheduling primitive; preferThread.sleep,wait/notify, or aBlockingQueue.- Don't swallow
InterruptedExceptionwithout re-setting the interrupt flag.
SimpleProxyChain— request routing + auth injection (hot path).FiltersSource407— one-shot auth-failure callback.Config+FileWatcher— live-reload; keep effective-config-basedequals()so cosmetic edits don't restart the proxy.Proxy— orchestration, tray UI wiring, restart-in-place.packaging/perf/— benchmark harness (do not delete; this is how we detect regressions).