package virustotal import ( "context" "crypto/sha256" "encoding/hex" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestScannerLookupMalicious(t *testing.T) { sha := sha256.Sum256([]byte("evil")) shaHex := hex.EncodeToString(sha[:]) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet && strings.Contains(r.URL.Path, "/files/"+shaHex) { _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{ "attributes": map[string]any{ "last_analysis_stats": map[string]any{ "malicious": 2, "suspicious": 0, }, }, }, }) return } http.NotFound(w, r) })) defer srv.Close() sc := NewScanner("test-key", nil) sc.client.baseURL = srv.URL + "/api/v3" _, err := sc.ScanBytes(context.Background(), "evil.bin", []byte("evil"), shaHex) if err == nil { t.Fatal("expected ErrMalicious") } if err != ErrMalicious { t.Fatalf("err = %v, want ErrMalicious", err) } } func TestScannerUploadAndPollClean(t *testing.T) { pollCount := 0 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { case r.Method == http.MethodGet && strings.HasSuffix(r.URL.Path, "/files/"+SHA256Hex([]byte("clean"))): http.NotFound(w, r) case r.Method == http.MethodPost && strings.HasSuffix(r.URL.Path, "/files"): _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{"id": "analysis-1"}, }) case r.Method == http.MethodGet && strings.Contains(r.URL.Path, "/analyses/analysis-1"): pollCount++ status := "queued" if pollCount >= 2 { status = "completed" } _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{ "attributes": map[string]any{ "status": status, "stats": map[string]any{ "malicious": 0, "suspicious": 0, }, }, }, }) default: http.NotFound(w, r) } })) defer srv.Close() sc := NewScanner("test-key", nil) sc.client.baseURL = srv.URL + "/api/v3" result, err := sc.ScanBytes(context.Background(), "clean.txt", []byte("clean"), "") if err != nil { t.Fatalf("ScanBytes: %v", err) } if result.Status != "clean" { t.Fatalf("status = %q, want clean", result.Status) } } func TestScannerFailOpenOnUnavailable(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "down", http.StatusServiceUnavailable) })) defer srv.Close() sc := NewScanner("test-key", nil) sc.client.baseURL = srv.URL + "/api/v3" result, err := sc.ScanBytes(context.Background(), "file.bin", []byte("payload"), "") if err != nil { t.Fatalf("expected fail-open, got err %v", err) } if result.Status != "skipped" { t.Fatalf("status = %q, want skipped", result.Status) } }