package scan import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" ) func TestFetchGreenhouse_ParsesFixture(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := map[string]any{ "jobs": []any{ map[string]any{ "id": 1, "title": "Security Engineer", "absolute_url": "https://dragos.greenhouse.io/jobs/1", "location": map[string]any{ "name": "San Francisco, CA", }, }, map[string]any{ "id": 2, "title": "Red Team Operator", "absolute_url": "https://dragos.greenhouse.io/jobs/2", "location": map[string]any{ "name": "Remote", }, }, }, } _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchGreenhouse(context.Background(), srv.Client(), srv.URL, "Dragos") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 2 { t.Fatalf("jobs = %d, want 2", len(jobs)) } if jobs[0].Title != "Security Engineer" { t.Errorf("job[0].Title = %q, want Security Engineer", jobs[0].Title) } if jobs[0].URL != "https://dragos.greenhouse.io/jobs/1" { t.Errorf("job[0].URL = %q", jobs[0].URL) } if jobs[0].Company != "Dragos" { t.Errorf("job[0].Company = %q, want Dragos", jobs[0].Company) } if jobs[0].Location != "San Francisco, CA" { t.Errorf("job[0].Location = %q", jobs[0].Location) } if jobs[0].Source != "greenhouse" { t.Errorf("job[0].Source = %q, want greenhouse", jobs[0].Source) } if jobs[1].Title != "Red Team Operator" { t.Errorf("job[1].Title = %q", jobs[1].Title) } if jobs[1].Location != "Remote" { t.Errorf("job[1].Location = %q", jobs[1].Location) } } func TestFetchGreenhouse_EmptyJobs(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := map[string]any{"jobs": []any{}} _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchGreenhouse(context.Background(), srv.Client(), srv.URL, "Acme") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 0 { t.Fatalf("jobs = %d, want 0", len(jobs)) } } func TestFetchAshby_ParsesFixture(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := map[string]any{ "jobs": []any{ map[string]any{ "id": "job1", "title": "Pentester", "jobUrl": "https://ashby.example.com/jobs/job1", "location": "New York, NY", }, map[string]any{ "id": "job2", "title": "AI Security Researcher", "jobUrl": "https://ashby.example.com/jobs/job2", "location": "Remote", }, }, } _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchAshby(context.Background(), srv.Client(), srv.URL, "Acme") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 2 { t.Fatalf("jobs = %d, want 2", len(jobs)) } if jobs[0].Title != "Pentester" { t.Errorf("job[0].Title = %q, want Pentester", jobs[0].Title) } if jobs[0].URL != "https://ashby.example.com/jobs/job1" { t.Errorf("job[0].URL = %q", jobs[0].URL) } if jobs[0].Company != "Acme" { t.Errorf("job[0].Company = %q, want Acme", jobs[0].Company) } if jobs[0].Location != "New York, NY" { t.Errorf("job[0].Location = %q", jobs[0].Location) } if jobs[0].Source != "ashby" { t.Errorf("job[0].Source = %q, want ashby", jobs[0].Source) } if jobs[1].Title != "AI Security Researcher" { t.Errorf("job[1].Title = %q", jobs[1].Title) } if jobs[1].Location != "Remote" { t.Errorf("job[1].Location = %q", jobs[1].Location) } } func TestFetchAshby_EmptyJobs(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := map[string]any{"jobs": []any{}} _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchAshby(context.Background(), srv.Client(), srv.URL, "Acme") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 0 { t.Fatalf("jobs = %d, want 0", len(jobs)) } } func TestFetchLever_ParsesFixture(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := []any{ map[string]any{ "id": "posting1", "text": "Red Team Lead", "hostedUrl": "https://lever.example.com/postings/posting1", "categories": map[string]any{ "location": "San Francisco, CA", }, }, map[string]any{ "id": "posting2", "text": "Offensive Security Engineer", "hostedUrl": "https://lever.example.com/postings/posting2", "categories": map[string]any{ "location": "Los Angeles, CA", }, }, } _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchLever(context.Background(), srv.Client(), srv.URL, "Bishop Fox") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 2 { t.Fatalf("jobs = %d, want 2", len(jobs)) } if jobs[0].Title != "Red Team Lead" { t.Errorf("job[0].Title = %q, want Red Team Lead", jobs[0].Title) } if jobs[0].URL != "https://lever.example.com/postings/posting1" { t.Errorf("job[0].URL = %q", jobs[0].URL) } if jobs[0].Company != "Bishop Fox" { t.Errorf("job[0].Company = %q, want Bishop Fox", jobs[0].Company) } if jobs[0].Location != "San Francisco, CA" { t.Errorf("job[0].Location = %q", jobs[0].Location) } if jobs[0].Source != "lever" { t.Errorf("job[0].Source = %q, want lever", jobs[0].Source) } if jobs[1].Title != "Offensive Security Engineer" { t.Errorf("job[1].Title = %q", jobs[1].Title) } if jobs[1].Location != "Los Angeles, CA" { t.Errorf("job[1].Location = %q", jobs[1].Location) } } func TestFetchLever_EmptyPostings(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { payload := []any{} _ = json.NewEncoder(w).Encode(payload) })) defer srv.Close() jobs, err := fetchLever(context.Background(), srv.Client(), srv.URL, "Beta Corp") if err != nil { t.Fatalf("fetch: %v", err) } if len(jobs) != 0 { t.Fatalf("jobs = %d, want 0", len(jobs)) } } // Sanity check: company API adapters dispatch correctly through the Fetch function func TestFetch_DispatachesCompanyAdapters(t *testing.T) { cases := []AdapterType{AdapterGreenhouse, AdapterAshby, AdapterLever} for _, typ := range cases { _, err := Fetch(context.Background(), &http.Client{}, Company{Name: "test"}, AdapterInfo{Type: typ, URL: "http://127.0.0.1:1"}) // Expect a real network error (connection refused), NOT "unsupported adapter type". if err == nil { t.Errorf("%s: expected connection error", typ) } if err.Error() == "unsupported adapter type: "+string(typ) { t.Errorf("%s: dispatch not wired", typ) } } }