package httpapi import ( "bytes" "context" "encoding/json" "io" "log/slog" "net/http" "net/http/httptest" "testing" "time" "git.totmin.ru/en2zmax/addrkit/internal/domain/address" "git.totmin.ru/en2zmax/addrkit/internal/domain/match" "git.totmin.ru/en2zmax/addrkit/internal/domain/outages" ) func testResolver(t *testing.T) *match.Resolver { t.Helper() var entries []address.Entry for _, a := range []string{"Станционная улица 1/1", "Искитимская улица 5"} { p := address.Parse(a) entries = append(entries, address.Entry{ ID: a, Address: a, District: "Тестовый", Ordinal: p.Ordinal, NameKey: p.NameKey, StreetType: p.StreetType, StreetKey: p.StreetKey, House: p.House, HouseFrac: p.HouseFrac, HouseLetter: p.HouseLetter, }) } return match.NewResolver(match.NewIndex("test-version", entries, match.DefaultOptions()), nil) } type fakeSource struct { list []outages.Outage err error } func (f fakeSource) Query(context.Context, string) ([]outages.Outage, error) { return f.list, f.err } func newServer(t *testing.T, src fakeSource) *httptest.Server { t.Helper() srv := New(testResolver(t), src, slog.New(slog.NewTextHandler(io.Discard, nil)), time.UTC) ts := httptest.NewServer(srv.Handler()) t.Cleanup(ts.Close) return ts } func postJSON(t *testing.T, url, body string) *http.Response { t.Helper() resp, err := http.Post(url, "application/json", bytes.NewBufferString(body)) if err != nil { t.Fatalf("post: %v", err) } return resp } func TestResolveEndpoint(t *testing.T) { ts := newServer(t, fakeSource{}) resp := postJSON(t, ts.URL+"/v1/resolve", `{"address":"2-я Станционная 1/1"}`) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("status = %d", resp.StatusCode) } var res match.Result if err := json.NewDecoder(resp.Body).Decode(&res); err != nil { t.Fatalf("decode: %v", err) } if res.Status != address.StatusFound || res.Address != "Станционная улица 1/1" { t.Fatalf("unexpected result: %+v", res) } } func TestOutagesEndpointFiltersHouse(t *testing.T) { src := fakeSource{list: []outages.Outage{ {Address: "Станционная улица 1/1", System: "Теплоснабжение"}, {Address: "Станционная улица 1/2", System: "Теплоснабжение"}, }} ts := newServer(t, src) resp := postJSON(t, ts.URL+"/v1/outages", `{"address":"станционная 1/1"}`) defer resp.Body.Close() var out outagesResponse if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { t.Fatalf("decode: %v", err) } if out.Status != address.StatusFound { t.Fatalf("status = %q, want found", out.Status) } if len(out.Outages) != 1 || out.Outages[0].Address != "Станционная улица 1/1" { t.Fatalf("house filter failed: %+v", out.Outages) } } func TestResolveValidation(t *testing.T) { ts := newServer(t, fakeSource{}) resp := postJSON(t, ts.URL+"/v1/resolve", `{}`) defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { t.Fatalf("status = %d, want 400", resp.StatusCode) } } func TestReadyzAndVersion(t *testing.T) { ts := newServer(t, fakeSource{}) resp, err := http.Get(ts.URL + "/v1/readyz") if err != nil { t.Fatalf("readyz: %v", err) } resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("readyz status = %d", resp.StatusCode) } resp, err = http.Get(ts.URL + "/v1/version") if err != nil { t.Fatalf("version: %v", err) } defer resp.Body.Close() var v map[string]string _ = json.NewDecoder(resp.Body).Decode(&v) if v["data_version"] != "test-version" { t.Fatalf("version = %q", v["data_version"]) } }