mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Without ARTEX_PG_DSN and without a config file, go test ./server/ failed
44 tests with "no database config found" instead of skipping them. The
tests go through NewManager and t.Fatal on its error: 35 through the
shared fixture trafficEvidenceServer (directly, or through
verificationFixture and newNotifyFixture), 2 through ingestServer, and 7
call NewManager themselves. The 7 already carry a skip on m.pg == nil,
but it sits after the t.Fatal and is never reached.
Add skipWithoutDSN, which calls db.DSN() and skips with the message the
db package and assembly_test.go already use ("no database config (%v) —
skipping"), and call it before NewManager at those 9 sites.
Nothing changes when a database is configured: db.DSN() succeeds, the
helper returns, and a NewManager error (for example an unreachable
Postgres) still fails the test.
109 lines
3.9 KiB
Go
109 lines
3.9 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/Autumn-27/artex/traffic"
|
|
)
|
|
|
|
// ingestServer wires a Server with a live traffic store, like
|
|
// trafficEvidenceServer but without the finding plumbing.
|
|
func ingestServer(t *testing.T) (*Server, func(method, path, body string) *httptest.ResponseRecorder) {
|
|
t.Helper()
|
|
skipWithoutDSN(t)
|
|
m, err := NewManager(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { m.Close() })
|
|
m.traffic, err = traffic.Open(filepath.Join(m.dir, "traffic"), ":0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
s := New(ctx, m, t.TempDir(), t.TempDir(), t.TempDir())
|
|
s.archiveWG.Wait()
|
|
<-s.side.done
|
|
token, err := signJWT(s.jwtKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return s, func(method, path, body string) *httptest.ResponseRecorder {
|
|
r := httptest.NewRequest(method, path, strings.NewReader(body))
|
|
r.Header.Set("Authorization", "Bearer "+token)
|
|
r.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
s.Handler().ServeHTTP(w, r)
|
|
return w
|
|
}
|
|
}
|
|
|
|
func TestTrafficIngestFlow(t *testing.T) {
|
|
s, request := ingestServer(t)
|
|
|
|
body := fmt.Sprintf(`{"exchanges":[
|
|
{"method":"POST","url":"https://api.example.com/v1/login","status":200,
|
|
"requestHeaders":{"content-type":"application/json"},"requestBody":"{\"u\":\"u1\"}",
|
|
"responseHeaders":{"content-type":"application/json"},"responseBody":"{\"token\":\"t\"}"},
|
|
{"method":"GET","url":"https://api.example.com/v1/profile","status":200,
|
|
"requestHeaders":{},"requestBody":"",
|
|
"responseHeaders":{},"responseBody":"{\"name\":\"n\"}"}
|
|
]}`)
|
|
w := request("POST", "/api/traffic/ingest", body)
|
|
if w.Code != 200 {
|
|
t.Fatalf("ingest status = %d, body = %s", w.Code, w.Body)
|
|
}
|
|
if !strings.Contains(w.Body.String(), `"ingested":2`) || !strings.Contains(w.Body.String(), `"failed":0`) {
|
|
t.Fatalf("unexpected counts: %s", w.Body)
|
|
}
|
|
|
|
// Both entries are visible on the normal traffic API, like proxy traffic.
|
|
w = request("GET", "/api/traffic", "")
|
|
if w.Code != 200 || !strings.Contains(w.Body.String(), "api.example.com") {
|
|
t.Fatalf("traffic page after ingest: %d %s", w.Code, w.Body)
|
|
}
|
|
|
|
// One bad URL among good ones: the batch reports per-entry failure.
|
|
mixed := `{"exchanges":[
|
|
{"method":"GET","url":"https://good.example.com/ok","status":200,"responseBody":"ok"},
|
|
{"method":"GET","url":"::::","status":200,"responseBody":"bad"}
|
|
]}`
|
|
w = request("POST", "/api/traffic/ingest", mixed)
|
|
if w.Code != 200 || !strings.Contains(w.Body.String(), `"ingested":1`) || !strings.Contains(w.Body.String(), `"failed":1`) {
|
|
t.Fatalf("mixed batch: %d %s", w.Code, w.Body)
|
|
}
|
|
|
|
// Guards: empty batch, oversized batch, oversized body truncation.
|
|
if w = request("POST", "/api/traffic/ingest", `{"exchanges":[]}`); w.Code != 400 {
|
|
t.Fatalf("empty batch status = %d", w.Code)
|
|
}
|
|
big := `{"exchanges":[` + strings.Repeat(`{"method":"GET","url":"https://x.example.com/"},`, maxIngestBatch) + `{}]}`
|
|
if w = request("POST", "/api/traffic/ingest", big); w.Code != 400 {
|
|
t.Fatalf("oversized batch status = %d", w.Code)
|
|
}
|
|
trunc := `{"exchanges":[{"method":"GET","url":"https://big.example.com/","status":200,"responseBody":"` + strings.Repeat("x", maxIngestBodySize+1024) + `"}]}`
|
|
w = request("POST", "/api/traffic/ingest", trunc)
|
|
if w.Code != 200 || !strings.Contains(w.Body.String(), `"ingested":1`) {
|
|
t.Fatalf("truncating batch: %d %s", w.Code, w.Body)
|
|
}
|
|
if n, _ := s.m.Traffic().Count(); n != 4 { // 2 + 1 + 1
|
|
t.Fatalf("final count = %d, want 4", n)
|
|
}
|
|
}
|
|
|
|
func TestTrafficIngestRequiresAuth(t *testing.T) {
|
|
s, _ := ingestServer(t)
|
|
r := httptest.NewRequest("POST", "/api/traffic/ingest", strings.NewReader(`{"exchanges":[]}`))
|
|
w := httptest.NewRecorder()
|
|
s.Handler().ServeHTTP(w, r)
|
|
if w.Code != 401 {
|
|
t.Fatalf("unauthenticated ingest status = %d, want 401", w.Code)
|
|
}
|
|
}
|