package testweb import ( "encoding/base64" "os" "path/filepath" "strings" "testing" ) const sampleLog = `=== META === Time: 2026-05-28T08:00:00+08:00 ClientIP: 127.0.0.1 Method: POST Path: /mng/file/auth/upload Kind: file DurationMs: 100 Status: 200 === 1. 入站请求(transit → forward)=== URL: POST 127.0.0.1:16001/mng/file/auth/upload Headers: Content-Type: multipart/form-data; boundary=abc X-Authorization: tok-in X-Forward-Token: secret Body: body_len=3 body_base64=Zm9v === 2. 出站转发(forward → 政务云)=== TargetURL: https://59.202.52.129:28211/mng/file/auth/upload Method: POST Headers: Content-Type: multipart/form-data; boundary=abc X-Authorization: tok-out Body: body_len=3 body_base64=Zm9v === 3. 回复(政务云 → forward → transit)=== UpstreamStatus: 200 UpstreamHeaders: Content-Type: application/json Body: {"success":true,"record":{"fileId":"id1"}} BodyJSON: { "success": true, "record": { "fileId": "id1" } } ` func TestParseAPILogBytes_outboundBody(t *testing.T) { p, err := ParseAPILogBytes("2026-05-28 08/20260528080000_file_abcd.log", []byte(sampleLog)) if err != nil { t.Fatal(err) } if p.Outbound.URL != "https://59.202.52.129:28211/mng/file/auth/upload" { t.Fatalf("outbound url=%q", p.Outbound.URL) } if p.Outbound.Headers["X-Authorization"] != "tok-out" { t.Fatalf("auth=%q", p.Outbound.Headers["X-Authorization"]) } if string(p.Outbound.BodyBytes) != "foo" { t.Fatalf("body=%q", p.Outbound.BodyBytes) } if p.Response.Status != 200 || !strings.Contains(p.Response.Body, "fileId") { t.Fatalf("response=%+v", p.Response) } } func TestListFileLogs_and_resolve(t *testing.T) { tmp := t.TempDir() hour := filepath.Join(tmp, "2026-05-28 08") if err := os.MkdirAll(hour, 0o755); err != nil { t.Fatal(err) } name := "20260528080000_file_abcd.log" if err := os.WriteFile(filepath.Join(hour, name), []byte(sampleLog), 0o644); err != nil { t.Fatal(err) } list, err := ListFileLogs(tmp) if err != nil || len(list) != 1 { t.Fatalf("list=%v err=%v", list, err) } rel := list[0].Rel p, err := ParseAPILogFile(tmp, rel) if err != nil { t.Fatal(err) } if p.Meta["Kind"] != "file" { t.Fatalf("kind=%v", p.Meta) } if _, err := resolveLogRelPath(tmp, "../etc/passwd"); err == nil { t.Fatal("expected reject ..") } if _, err := resolveLogRelPath(tmp, "bad/name.log"); err == nil { t.Fatal("expected reject pattern") } } func TestToPostmanCollection_multipart(t *testing.T) { p, err := ParseAPILogBytes("x.log", []byte(sampleLog)) if err != nil { t.Fatal(err) } data, err := ToPostmanCollection(p, false) if err != nil { t.Fatal(err) } s := string(data) if !strings.Contains(s, "postman.com/json/collection/v2.1.0") { t.Fatal("missing schema") } if !strings.Contains(s, "formdata") { t.Fatal("expected formdata") } } func Test_applyBody_plain(t *testing.T) { var rs RequestSection rs.Headers = map[string]string{"Content-Type": "application/json"} applyBodyToSection(&rs, []string{`{"a":1}`}) if !rs.BodyPlain || string(rs.BodyBytes) != `{"a":1}` { t.Fatalf("%+v", rs) } b64 := base64.StdEncoding.EncodeToString([]byte("bin")) applyBodyToSection(&rs, []string{"body_len=3", "body_base64=" + b64}) if string(rs.BodyBytes) != "bin" { t.Fatalf("got %q", rs.BodyBytes) } }