feat: add comprehensive HTTP e2e tests covering connector, TLS, probeResist, idleTimeout, and UDP relay
Adds 12 new HTTP handler test scenarios: HTTP connector (no-auth, auth, TLS upstream), CONNECT tunnel (no-sniffing, bypass-403), probeResist (host, web, file, knock), idleTimeout, and UDP relay over HTTP. Introduces RunGostContainerWithFiles helper for mounting extra files into test containers.
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
# Plan: Expand E2E Test Suite
|
||||
|
||||
## Context
|
||||
|
||||
The e2e test framework (`tests/e2e/`) currently covers only **2 protocols** (Shadowsocks, parallel selector) out of **~30+ registered protocols** in gost. This plan systematically adds test coverage for all major protocols, following the existing Docker-based testcontainers pattern exactly.
|
||||
|
||||
**Key insight**: gost auto-generates self-signed TLS certs when none are provided (`x/config/parsing/tls.go` — `BuildDefaultTLSConfig`), and clients with default config skip cert verification. This means TLS-based protocols (ws→wss, h2c→h2, quic, etc.) can be tested **without mounting cert files**.
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Refactor `utils.go` — Add Reusable Test Helpers
|
||||
|
||||
**File**: `tests/e2e/utils.go`
|
||||
|
||||
Extract the repeated patterns from `shadowsocks_test.go` into reusable helpers:
|
||||
|
||||
1. **`RunTCPCase(t, ctx, networkName, echoIP, name, serverConfig, clientConfig string)`** — Full lifecycle: start server → render client config → start client → curl assertion → cleanup. Extracts the logic from `ShadowsocksSuite.runTCPCase`.
|
||||
|
||||
2. **`RunUDPCase(t, ctx, networkName, name, serverConfig, clientConfig string)`** — Same for UDP: start server → render client → start client → dial UDP → retry loop → assertion → cleanup. Extracts from `runUDPCase`.
|
||||
|
||||
These eliminate ~40 lines of boilerplate per suite. Each suite's test methods become one-liners:
|
||||
```go
|
||||
func (s *SOCKS5Suite) TestSOCKS5TCP() {
|
||||
RunTCPCase(s.T(), s.ctx, SharedNetworkName, s.echoIP, "socks5-tcp",
|
||||
"testdata/socks5/tcp_server.yaml", "testdata/socks5/tcp_client.yaml")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Tier 1 — Core Protocols (Plain TCP, No Special Infrastructure)
|
||||
|
||||
Each suite follows the exact pattern: suite struct → `SetupSuite` (echo containers) → `TearDownSuite` → test methods calling `RunTCPCase`/`RunUDPCase` → `suite.Run()` entry point.
|
||||
|
||||
### 1A. HTTP Proxy Suite
|
||||
- **Files**: `http_test.go`, `testdata/http/` (2 configs)
|
||||
- **Configs**: `server.yaml` (handler `http`, listener `tcp`), `server_auth.yaml` (+ basic auth)
|
||||
- **Tests**: `TestHTTPProxy`, `TestHTTPProxyAuth` (curl with `--proxy-user`)
|
||||
- **Note**: Simplest test — single gost container acts as HTTP proxy
|
||||
|
||||
### 1B. SOCKS5 Suite
|
||||
- **Files**: `socks5_test.go`, `testdata/socks5/` (4 configs)
|
||||
- **Configs**: `tcp_server.yaml` (handler `socks5`), `tcp_client.yaml` (connector `socks5`, dialer `tcp`), + auth variants
|
||||
- **Tests**: `TestSOCKS5TCP`, `TestSOCKS5TCPAuth`
|
||||
|
||||
### 1C. SOCKS4 Suite
|
||||
- **Files**: `socks4_test.go`, `testdata/socks4/` (4 configs)
|
||||
- **Configs**: `tcp_server.yaml` (handler `socks4`), `tcp_client.yaml` (connector `socks4`), + socks4a variants
|
||||
- **Tests**: `TestSOCKS4TCP`, `TestSOCKS4aTCP`
|
||||
|
||||
### 1D. HTTP2 Cleartext Suite
|
||||
- **Files**: `http2_test.go`, `testdata/http2/` (2 configs)
|
||||
- **Configs**: `tcp_server.yaml` (handler `http2`, listener `http2`), `tcp_client.yaml` (connector `http2`, dialer `http2`)
|
||||
- **Tests**: `TestHTTP2TCP`
|
||||
|
||||
### 1E. Relay Suite
|
||||
- **Files**: `relay_test.go`, `testdata/relay/` (4 configs)
|
||||
- **Configs**: `tcp_server.yaml` (handler `relay`, listener `tcp`), `tcp_client.yaml` (connector `relay`, dialer `tcp`), + auth variants
|
||||
- **Tests**: `TestRelayTCP`, `TestRelayTCPAuth`
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Tier 2 — TLS/Transport Protocols
|
||||
|
||||
Same pattern but using TLS listeners/dialers. No explicit cert files needed — gost auto-generates them.
|
||||
|
||||
### 2A. TLS Suite
|
||||
- **Files**: `tls_test.go`, `testdata/tls/` (4 configs)
|
||||
- **Tests**: `TestTLSHTTPProxy` (handler `http` + listener `tls`), `TestTLSSOCKS5` (handler `socks5` + listener `tls`)
|
||||
|
||||
### 2B. WebSocket Suite
|
||||
- **Files**: `ws_test.go`, `testdata/ws/` (4 configs)
|
||||
- **Tests**: `TestWSSOCKS5` (dialer `ws`), `TestWSSSOCKS5` (dialer `wss`)
|
||||
|
||||
### 2C. gRPC Suite
|
||||
- **Files**: `grpc_test.go`, `testdata/grpc/` (2 configs)
|
||||
- **Tests**: `TestGRPCSOCKS5` (listener `grpc`, metadata `insecure: true`)
|
||||
|
||||
### 2D. HTTP/2 TLS (h2) Suite
|
||||
- **Files**: `h2_test.go`, `testdata/h2/` (2 configs)
|
||||
- **Tests**: `TestH2HTTP2Proxy` (listener `h2`, dialer `h2`)
|
||||
|
||||
### 2E. QUIC Suite
|
||||
- **Files**: `quic_test.go`, `testdata/quic/` (2 configs)
|
||||
- **Tests**: `TestQUICHTTP` (listener `quic`, handler `http` — uses UDP ports)
|
||||
|
||||
### 2F. KCP Suite
|
||||
- **Files**: `kcp_test.go`, `testdata/kcp/` (2 configs)
|
||||
- **Tests**: `TestKCPSOCKS5` (listener `kcp`, handler `socks5` — uses UDP)
|
||||
|
||||
### 2G. Multiplex Variants (mws/mwss/mtls/mtcp)
|
||||
- **Files**: `mux_test.go`, `testdata/mux/` (6 configs)
|
||||
- **Tests**: `TestMWSSOCKS5`, `TestMWSSSOCKS5`, `TestMtlSSOCKS5`, `TestMtcpSOCKS5`
|
||||
|
||||
### 2H. Obfuscation (ohttp/otls)
|
||||
- **Files**: `obfs_test.go`, `testdata/obfs/` (4 configs)
|
||||
- **Tests**: `TestOHTTP`, `TestOTLS`
|
||||
|
||||
### 2I. PHT (HTTP Pipe)
|
||||
- **Files**: `pht_test.go`, `testdata/pht/` (4 configs)
|
||||
- **Tests**: `TestPHT`, `TestPHTS`
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Tier 3 — Special Infrastructure (Deferred)
|
||||
|
||||
These require Docker capabilities (`NET_ADMIN`, `NET_RAW`), SSH key generation, or iptables setup. Implemented after Tiers 1-2 are stable.
|
||||
|
||||
| Protocol | Challenge | Approach |
|
||||
|----------|-----------|----------|
|
||||
| SSH/sshd | Host key generation | Generate SSH key at test time, mount into container |
|
||||
| HTTP/3/WebTransport | QUIC+UDP, TLS | Uses UDP like QUIC suite; auto certs work |
|
||||
| TUN/TAP | `CAP_NET_ADMIN`, `/dev/net/tun` | Privileged container + routing setup |
|
||||
| Tungo/MASQUE | Same as TUN | Same approach |
|
||||
| ICMP | `CAP_NET_RAW`, raw sockets | Privileged container |
|
||||
| Redirect (red/redu) | iptables rules | Privileged + iptables setup in container |
|
||||
| DTLS | UDP + TLS | Auto certs; UDP port mapping |
|
||||
|
||||
---
|
||||
|
||||
## Files to Create/Modify
|
||||
|
||||
### New files (per suite):
|
||||
- `tests/e2e/<protocol>_test.go` — Suite struct + test methods
|
||||
- `tests/e2e/testdata/<protocol>/` — Server + client YAML configs
|
||||
|
||||
### Modified files:
|
||||
- `tests/e2e/utils.go` — Add `RunTCPCase`, `RunUDPCase` helpers
|
||||
- `tests/e2e/shadowsocks_test.go` — Refactor to use new helpers (optional, reduces duplication)
|
||||
- `tests/e2e/README.md` — Document new suites
|
||||
|
||||
### Reference files (read-only):
|
||||
- `tests/e2e/shadowsocks_test.go` — Pattern template for all suites
|
||||
- `tests/e2e/testdata/shadowsocks/tcp_server_aes256gcm.yaml` — Server config template
|
||||
- `tests/e2e/testdata/shadowsocks/tcp_client_aes256gcm.yaml` — Client config template
|
||||
|
||||
---
|
||||
|
||||
## Config Pattern Reference
|
||||
|
||||
**Server** (all protocols):
|
||||
```yaml
|
||||
services:
|
||||
- name: <proto>-server
|
||||
addr: :<port>
|
||||
handler:
|
||||
type: <handler-type>
|
||||
listener:
|
||||
type: <listener-type>
|
||||
```
|
||||
|
||||
**Client** (all protocols):
|
||||
```yaml
|
||||
services:
|
||||
- name: http-proxy
|
||||
addr: :8080
|
||||
handler:
|
||||
type: http
|
||||
chain: <proto>-chain
|
||||
listener:
|
||||
type: tcp
|
||||
chains:
|
||||
- name: <proto>-chain
|
||||
hops:
|
||||
- name: <proto>-hop
|
||||
nodes:
|
||||
- name: <proto>-node
|
||||
addr: {{.ServerAddr}}
|
||||
connector:
|
||||
type: <connector-type>
|
||||
dialer:
|
||||
type: <dialer-type>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
After each suite is implemented:
|
||||
1. `cd gost && go build ./...` — Ensure compilation
|
||||
2. `go vet ./tests/e2e/` — Static analysis
|
||||
3. `go test ./tests/e2e/ -v -run TestXxxSuite -timeout 5m` — Run individual suite
|
||||
4. `go test ./tests/e2e/ -v -timeout 10m` — Run all suites together
|
||||
Reference in New Issue
Block a user