mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 00:24:19 +00:00
7605902324
* test(audit): add gremlins/rapid/coverage tooling + AUDIT.md scaffold * test(audit): hygiene sweep (race-clean except logger global; Finding #2) + smell inventory * test(audit): cover untested error/edge branches (TLS proxy+pin, migration tag cleanup=Finding #1) * test(audit): strengthen internal/sub link tests (dedup key, TLS/Reality mapping, clash well-formedness) * test(audit): property (rapid) + fuzz tests for joinHostPort/userinfo/pin/ParseLink * test(audit): tighten frontend subSortIndex rejection assertions + wire coverage * ci(audit): add shuffle gate + non-blocking race job (Finding #2) + fuzz-smoke; document mutation policy * chore(audit): gitignore frontend coverage output * test(audit): exhaustive whole-repo pass — strengthen 5 weak/fake tests (netproxy, CSP, modal per-protocol loops, schema coercions) * docs(contributing): add Testing section (conventions, race/shuffle, fuzz, mutation policy); drop AUDIT.md ledger * fix(logger,migration): guard logBuffer with mutex; execute legacy tag cleanup (tx.Exec); make CI race gate blocking * ci(mutation): add nightly scoped gremlins workflow (informational artifacts) * test(audit): strengthen runtime tests — baseURL scheme/port bounds, isNonEmptySlice, trafficReset * test(audit): strengthen clash tests — reality field mapping + tcp-header validation * test(audit): runtime — egress-proxy + content-type tests; drop redundant bp=='' branch * test(audit): strengthen link parser/helper tests (defaultPort, splitComma, base64, canonicalQuery, tls/reality/transport mapping) * test(audit): strengthen sub/xray/common/netsafe/mtproto/config/middleware tests (kill surviving mutants) * test(audit): raise timeout on protocol-iteration modal tests (heavy re-renders, slow on CI) * fix(logger): GetLogs returns at most c entries (off-by-one fix; addresses PR review) * perf(logger): snapshot logBuffer under lock so GetLogs doesn't block logging; clarify fuzz-seed docs (addresses PR review)
100 lines
3.7 KiB
Go
100 lines
3.7 KiB
Go
package mtproto
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestParseMetricLineBraceBoundary pins the contract of the brace-position
|
|
// guard in parseMetricLine (manager.go:425 -> `if end < brace`).
|
|
//
|
|
// Once a '{' is found at index `brace`, the matching '}' must appear AFTER it.
|
|
// A '}' that precedes the '{', or a '{' with no closing '}' at all
|
|
// (strings.IndexByte returns -1, which is < brace), is a malformed line and
|
|
// must yield an error rather than slicing past the brace.
|
|
func TestParseMetricLineBraceBoundary(t *testing.T) {
|
|
t.Run("closing brace before opening brace is malformed", func(t *testing.T) {
|
|
// '}' at index 8 comes before '{' at index 16: end < brace must hold,
|
|
// so this is rejected. Mutating `<` to `>`/`>=` would accept it.
|
|
_, _, _, err := parseMetricLine(`mtg_x_a}_b{direction="x"} 5`)
|
|
if err == nil {
|
|
t.Fatal("expected error for '}' appearing before '{'")
|
|
}
|
|
})
|
|
|
|
t.Run("opening brace with no closing brace is malformed", func(t *testing.T) {
|
|
// No '}' at all -> end == -1, which is < brace. Must error.
|
|
// If the guard were dropped/inverted the code would slice line[brace+1:-1]
|
|
// and panic; asserting a clean error keeps that contract.
|
|
_, _, _, err := parseMetricLine(`mtg_traffic{direction="x" 5`)
|
|
if err == nil {
|
|
t.Fatal("expected error for '{' without a closing '}'")
|
|
}
|
|
})
|
|
|
|
t.Run("well-formed braces are accepted", func(t *testing.T) {
|
|
// '{' at index 11, '}' at index 25: end > brace, so the guard must NOT
|
|
// fire and parsing must succeed. Guards against a mutant that always errors.
|
|
name, labels, val, err := parseMetricLine(`mtg_traffic{direction="up"} 42`)
|
|
if err != nil {
|
|
t.Fatalf("well-formed line should parse: %v", err)
|
|
}
|
|
if name != "mtg_traffic" {
|
|
t.Fatalf("name=%q", name)
|
|
}
|
|
if labels["direction"] != "up" {
|
|
t.Fatalf("labels=%v", labels)
|
|
}
|
|
if val != 42 {
|
|
t.Fatalf("val=%v", val)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestParseMetricLineLabelEqualsBoundary pins the contract of the '=' guard in
|
|
// the per-label loop (manager.go:430 -> `if eq < 0`).
|
|
//
|
|
// - eq < 0 (no '=' in the segment): the segment is skipped, no label added.
|
|
// - eq == 0 (segment begins with '='): the key is empty but the pair is STILL
|
|
// parsed, producing labels[""] = value. The boundary is `< 0`, not `<= 0`.
|
|
func TestParseMetricLineLabelEqualsBoundary(t *testing.T) {
|
|
t.Run("label segment without '=' is skipped, not fatal", func(t *testing.T) {
|
|
// "novalue" has no '=' (eq == -1) and must be skipped. A real key=val
|
|
// segment in the same line must still be parsed. Mutating `< 0` to `> 0`
|
|
// would take kv[:eq] with eq=-1 and panic; mutating away the skip would
|
|
// also corrupt parsing.
|
|
name, labels, val, err := parseMetricLine(`mtg_traffic{novalue,direction="down"} 9`)
|
|
if err != nil {
|
|
t.Fatalf("line with a value-less label should still parse: %v", err)
|
|
}
|
|
if name != "mtg_traffic" {
|
|
t.Fatalf("name=%q", name)
|
|
}
|
|
if _, present := labels["novalue"]; present {
|
|
t.Fatalf("value-less segment must not create a label: %v", labels)
|
|
}
|
|
if labels["direction"] != "down" {
|
|
t.Fatalf("real label must still be parsed: %v", labels)
|
|
}
|
|
if val != 9 {
|
|
t.Fatalf("val=%v", val)
|
|
}
|
|
})
|
|
|
|
t.Run("label segment beginning with '=' is parsed as empty key", func(t *testing.T) {
|
|
// "=onlyvalue": eq == 0. Since the guard is `< 0`, this is NOT skipped:
|
|
// it yields labels[""] = "onlyvalue". A mutant changing `< 0` to `<= 0`
|
|
// would skip it, losing the empty-key entry.
|
|
_, labels, _, err := parseMetricLine(`mtg_traffic{=onlyvalue} 1`)
|
|
if err != nil {
|
|
t.Fatalf("segment with empty key should still parse: %v", err)
|
|
}
|
|
v, present := labels[""]
|
|
if !present {
|
|
t.Fatalf("eq==0 segment must produce an empty-key label: %v", labels)
|
|
}
|
|
if v != "onlyvalue" {
|
|
t.Fatalf("empty-key label value=%q", v)
|
|
}
|
|
})
|
|
}
|