Files
scratchbox/internal/http/handlers_unit_test.go
T
2026-05-31 20:17:49 -05:00

144 lines
3.6 KiB
Go

package httpapi
import (
"errors"
"io"
"log"
"net/http"
"net/http/httptest"
"net/netip"
"path/filepath"
"strings"
"testing"
"scratchbox/internal/config"
"scratchbox/internal/storage"
)
func TestMultipartFileCount(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodPost, "/api/scratch", nil)
if got := multipartFileCount(req); got != 0 {
t.Fatalf("multipartFileCount() = %d, want 0", got)
}
}
func TestWriteCreateErrorBranches(t *testing.T) {
t.Parallel()
s := &Server{}
rec1 := httptest.NewRecorder()
s.writeCreateError(rec1, &http.MaxBytesError{Limit: 5})
if rec1.Code != http.StatusRequestEntityTooLarge {
t.Fatalf("max bytes error status = %d, want %d", rec1.Code, http.StatusRequestEntityTooLarge)
}
rec2 := httptest.NewRecorder()
s.writeCreateError(rec2, errors.New("request body too large"))
if rec2.Code != http.StatusRequestEntityTooLarge {
t.Fatalf("body too large string status = %d, want %d", rec2.Code, http.StatusRequestEntityTooLarge)
}
rec3 := httptest.NewRecorder()
s.writeCreateError(rec3, errors.New("other parse failure"))
if rec3.Code != http.StatusBadRequest {
t.Fatalf("generic error status = %d, want %d", rec3.Code, http.StatusBadRequest)
}
}
func TestNewServerInitializes(t *testing.T) {
tmp := t.TempDir()
store, err := storage.NewFilesystemStore(filepath.Join(tmp, "data"))
if err != nil {
t.Fatalf("NewFilesystemStore() error = %v", err)
}
cfg := config.Config{
Limits: config.LimitsConfig{MaxUploadSizeBytes: 1024},
Security: config.SecurityConfig{
RateLimit: config.RateLimitConfig{Enabled: false},
},
}
srv, err := NewServer(cfg, store, log.New(io.Discard, "", 0))
if err != nil {
t.Fatalf("NewServer() error = %v", err)
}
if srv == nil {
t.Fatalf("expected initialized server")
}
}
func TestGetUIConfig(t *testing.T) {
t.Parallel()
s := &Server{
cfg: config.Config{
Limits: config.LimitsConfig{
MaxUploadSizeBytes: 2048,
},
},
}
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
s.getUIConfig(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
if got := rec.Body.String(); got == "" || !containsAll(got, "max_upload_size_bytes", "2048", `"upload_allowed":true`) {
t.Fatalf("unexpected body: %q", got)
}
}
func TestGetUIConfigUploadDenied(t *testing.T) {
t.Parallel()
s := &Server{
cfg: config.Config{
Limits: config.LimitsConfig{
MaxUploadSizeBytes: 2048,
},
Security: config.SecurityConfig{
AllowedPrefixes: []netip.Prefix{
netip.MustParsePrefix("10.0.0.0/8"),
},
},
},
}
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
s.getUIConfig(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
if got := rec.Body.String(); got == "" || !containsAll(got, `"upload_allowed":false`) {
t.Fatalf("unexpected body: %q", got)
}
}
func TestWriteCreateErrorBranchesWithConfig(t *testing.T) {
tmp := t.TempDir()
store, err := storage.NewFilesystemStore(filepath.Join(tmp, "data"))
if err != nil {
t.Fatalf("NewFilesystemStore() error = %v", err)
}
cfg := config.Config{
Limits: config.LimitsConfig{MaxUploadSizeBytes: 1024},
Security: config.SecurityConfig{
RateLimit: config.RateLimitConfig{Enabled: false},
},
}
if _, err := NewServer(cfg, store, log.New(io.Discard, "", 0)); err != nil {
t.Fatalf("NewServer() error = %v", err)
}
}
func containsAll(haystack string, needles ...string) bool {
for _, needle := range needles {
if !strings.Contains(haystack, needle) {
return false
}
}
return true
}