129 lines
4.0 KiB
Go
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 postSplit(t *testing.T, srv *Server, 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", "/split", &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 := postSplit(t, srv, `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 := postSplit(t, srv, "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)
|
|
}
|
|
}
|
|
}
|