Files
2026-10-05 20:35:47 +02:00

129 lines
4.0 KiB
Go

package web
import (
"archive/zip"
"bytes"
"mime/multipart"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"pcap-web-tools/internal/pcap"
)
func testPcap(t *testing.T, packets int) []byte {
t.Helper()
var buf bytes.Buffer
w, err := pcap.NewWriter(&buf, pcap.LinkTypeEthernet)
if err != nil {
t.Fatal(err)
}
for i := range packets {
if err := w.WritePacket(time.Unix(int64(i), 0), make([]byte, 100)); err != nil {
t.Fatal(err)
}
}
return buf.Bytes()
}
func postUpload(t *testing.T, srv *Server, target, filename string, file []byte, fields map[string]string) *httptest.ResponseRecorder {
t.Helper()
var body bytes.Buffer
mw := multipart.NewWriter(&body)
for k, v := range fields {
mw.WriteField(k, v)
}
if file != nil {
fw, err := mw.CreateFormFile("file", filename)
if err != nil {
t.Fatal(err)
}
fw.Write(file)
}
mw.Close()
req := httptest.NewRequest("POST", target, &body)
req.Header.Set("Content-Type", mw.FormDataContentType())
rec := httptest.NewRecorder()
srv.ServeHTTP(rec, req)
return rec
}
func TestSplitHandler(t *testing.T) {
srv, err := New(Config{MaxUploadBytes: 1 << 20})
if err != nil {
t.Fatal(err)
}
in := testPcap(t, 25)
tests := []struct {
name string
fields map[string]string
want []int // packets per part
}{
{"by packets", map[string]string{"mode": "packets", "packets": "10"}, []int{10, 10, 5}},
// Each record is 116 bytes: 24 + 8*116 = 952 <= 1000, a ninth does not fit.
{"by size", map[string]string{"mode": "size", "size": "1", "unit": "KB"}, []int{8, 8, 8, 1}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rec := postUpload(t, srv, "/split", `C:\caps\my capture.pcap`, in, tt.fields)
if rec.Code != http.StatusOK || rec.Header().Get("Content-Type") != "application/zip" {
t.Fatalf("status %d %s: %s", rec.Code, rec.Header().Get("Content-Type"), rec.Body)
}
if cd := rec.Header().Get("Content-Disposition"); cd != `attachment; filename="my_capture_split.zip"` {
t.Errorf("Content-Disposition %q", cd)
}
zr, err := zip.NewReader(bytes.NewReader(rec.Body.Bytes()), int64(rec.Body.Len()))
if err != nil {
t.Fatal(err)
}
if len(zr.File) != len(tt.want) {
t.Fatalf("got %d files, want %d", len(zr.File), len(tt.want))
}
for i, f := range zr.File {
if want := "my_capture_00" + string(rune('1'+i)) + ".pcap"; f.Name != want {
t.Errorf("file %d named %q, want %q", i, f.Name, want)
}
if want := int64(24 + tt.want[i]*116); int64(f.UncompressedSize64) != want {
t.Errorf("%s: %d bytes, want %d", f.Name, f.UncompressedSize64, want)
}
}
})
}
}
func TestSplitHandlerErrors(t *testing.T) {
srv, err := New(Config{MaxUploadBytes: 4000})
if err != nil {
t.Fatal(err)
}
defer func(n int) { maxSplitParts = n }(maxSplitParts)
maxSplitParts = 5
ok := map[string]string{"mode": "packets", "packets": "1"}
tests := []struct {
name string
file []byte
fields map[string]string
status int
want string
}{
{"no file", nil, ok, http.StatusBadRequest, "choose a pcap file"},
{"not pcap", []byte(strings.Repeat("x", 100)), ok, http.StatusBadRequest, "not a pcap file"},
{"too large", testPcap(t, 700), ok, http.StatusRequestEntityTooLarge, "file too large"},
{"too many parts", testPcap(t, 6), ok, http.StatusBadRequest, "more than 5 files"},
{"bad packets", testPcap(t, 1), map[string]string{"mode": "packets", "packets": "0"}, http.StatusBadRequest, "at least 1"},
{"bad size", testPcap(t, 1), map[string]string{"mode": "size", "size": "abc", "unit": "MB"}, http.StatusBadRequest, "positive number"},
{"bad unit", testPcap(t, 1), map[string]string{"mode": "size", "size": "1", "unit": "XB"}, http.StatusBadRequest, "unknown size unit"},
{"no mode", testPcap(t, 1), map[string]string{}, http.StatusBadRequest, "choose whether"},
}
for _, tt := range tests {
rec := postUpload(t, srv, "/split", "x.pcap", tt.file, tt.fields)
if rec.Code != tt.status || !strings.Contains(rec.Body.String(), tt.want) {
t.Errorf("%s: status %d, body %.300s", tt.name, rec.Code, rec.Body)
}
}
}