package marketintel import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" ) const sampleResult = `{ "results": [ {"generated_internal_id":"CONT_AWD_X","Award ID":"FA8773-23-C-0001","Recipient Name":"ACME CYBER LLC", "Recipient UEI":"ABC123DEF456","Award Amount":"12500000.50","Awarding Agency":"Department of Defense", "Awarding Sub Agency":"Department of the Air Force","Period of Performance Start Date":"2023-05-01", "Period of Performance Current End Date":"2026-04-30","NAICS":{"code":"541512","description":"COMPUTER SYSTEMS DESIGN SERVICES"}, "Description":"Cyber support","recipient_id":"rid-1"} ], "page_metadata": {"page":1,"hasNext":true} }` func TestFetchAwardsMapsFields(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Errorf("expected POST, got %s", r.Method) } _, _ = w.Write([]byte(sampleResult)) })) defer srv.Close() p := NewUSASpending(srv.URL) awards, hasNext, err := p.FetchAwards(context.Background(), AwardQuery{ NAICS: []string{"541512"}, AwardTypeCodes: []string{"A", "B", "C", "D"}, Limit: 100, Page: 1, }) if err != nil { t.Fatalf("fetch: %v", err) } if !hasNext { t.Fatal("hasNext should be true") } if len(awards) != 1 { t.Fatalf("want 1 award, got %d", len(awards)) } a := awards[0] if a.GeneratedInternalID != "CONT_AWD_X" || a.RecipientName != "ACME CYBER LLC" || a.RecipientUEI != "ABC123DEF456" { t.Fatalf("identity mapped wrong: %+v", a) } if a.AwardAmount == nil || a.AwardAmount.String() != "12500000.5" { t.Fatalf("amount mapped wrong: %v", a.AwardAmount) } if a.NAICSCode != "541512" || a.AwardingSubAgency != "Department of the Air Force" { t.Fatalf("naics/subagency wrong: %+v", a) } if a.POPStart == nil || a.POPEnd == nil || a.POPEnd.Format("2006-01-02") != "2026-04-30" { t.Fatalf("pop dates wrong: %v %v", a.POPStart, a.POPEnd) } if a.IsGalapagos { t.Fatal("market pull must not be flagged galapagos") } } func TestFetchAwards429(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTooManyRequests) })) defer srv.Close() p := NewUSASpending(srv.URL) if _, _, err := p.FetchAwards(context.Background(), AwardQuery{Limit: 10, Page: 1}); err != ErrThrottled { t.Fatalf("429 must map to ErrThrottled, got %v", err) } } func TestFetchAwardsOwnPastPerformanceFlag(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(sampleResult)) })) defer srv.Close() p := NewUSASpending(srv.URL) awards, _, err := p.FetchAwards(context.Background(), AwardQuery{RecipientSearch: []string{"N3GDEB78RNF8"}, Limit: 100, Page: 1}) if err != nil { t.Fatalf("fetch: %v", err) } if len(awards) != 1 || !awards[0].IsGalapagos { t.Fatalf("recipient search pull must flag IsGalapagos, got %+v", awards) } var raw map[string]any if err := json.Unmarshal(awards[0].Raw, &raw); err != nil { t.Fatalf("raw must be valid json: %v", err) } }