package api import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "crypto-miner-server/internal/db" "crypto-miner-server/internal/recon" ) func TestReconScanEndpoint(t *testing.T) { recon.SetPortDialHook(func(host string, port int, _ time.Duration) bool { return port == 80 }) t.Cleanup(func() { recon.SetPortDialHook(nil) }) recon.SetFetchPageHook(func(rawURL string) (int, string, error) { return 200, `
`, nil }) t.Cleanup(func() { recon.SetFetchPageHook(nil) }) database, err := db.New(t.TempDir()) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = database.Close() }) h := NewReconHandler(database, nil) body, _ := json.Marshal(map[string]interface{}{ "host": "recon.lab", "port": 80, "scheme": "http", }) req := httptest.NewRequest(http.MethodPost, "/api/v1/recon/scan", bytes.NewReader(body)) w := httptest.NewRecorder() h.Scan(w, req) if w.Code != http.StatusOK { t.Fatalf("status=%d body=%s", w.Code, w.Body.String()) } var report recon.ScanReport if err := json.Unmarshal(w.Body.Bytes(), &report); err != nil { t.Fatal(err) } if report.Host != "recon.lab" || report.Crawl == nil || len(report.Recommendations) == 0 { t.Fatalf("report=%+v", report) } rows, err := database.ListOathLedger(5) if err != nil { t.Fatal(err) } if len(rows) == 0 || rows[0].ActionType != db.OathReconScan { t.Fatalf("oath rows=%+v", rows) } } func TestReconScanRequiresHost(t *testing.T) { h := NewReconHandler(nil, nil) req := httptest.NewRequest(http.MethodPost, "/api/v1/recon/scan", bytes.NewReader([]byte(`{}`))) w := httptest.NewRecorder() h.Scan(w, req) if w.Code != http.StatusBadRequest { t.Fatalf("status=%d", w.Code) } }