summaryrefslogtreecommitdiffstats
path: root/internal/lookup/lookup_test.go
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 21:12:05 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 21:12:05 -0300
commit97b49ae7081b989274b313532ff17c71694097a9 (patch)
tree6595e0d5a39d04971a71e886bc3f8cc589741f5d /internal/lookup/lookup_test.go
parent83ce95cf10fd9e9d581362453c558239d37ae06e (diff)
downloadtelegram-main.tar.gz
Read the faixa from the client instead of fetching it againHEADv0.2.1main
cep.is/go v0.2.0 exposes the municipality as Error.Faixa, which is what internal/lookup existed to work around: v0.1.0 discarded the 404 body, so the bot re-issued the request just to read the block back. The extra GET on the 404 path is gone, and with it the second timeout, the body size cap and the "is it still a 404?" check that guarded it. The replies are byte for byte what they were -- the formatting tests did not change a single assertion, only the type they build.
Diffstat (limited to 'internal/lookup/lookup_test.go')
-rw-r--r--internal/lookup/lookup_test.go279
1 files changed, 0 insertions, 279 deletions
diff --git a/internal/lookup/lookup_test.go b/internal/lookup/lookup_test.go
deleted file mode 100644
index 6eb7b4e..0000000
--- a/internal/lookup/lookup_test.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package lookup
-
-import (
- "context"
- "errors"
- "net/http"
- "net/http/httptest"
- "sync/atomic"
- "testing"
- "time"
-
- cepis "cep.is/go"
-)
-
-const areal404 = `{"erro":"cep_nao_encontrado","mensagem":"CEP não existe na base do DNE",
- "faixa":{"localidade":"Areal","uf":"RJ","estado":"Rio de Janeiro","regiao":"Sudeste",
- "ibge":"3300225","cep_ini":"25845001","cep_fim":"25849899","ceps":118}}`
-
-const plain404 = `{"erro":"cep_nao_encontrado","mensagem":"CEP não existe na base do DNE"}`
-
-const address200 = `{"cep":"01001000","logradouro":"Praça da Sé","bairro":"Sé",
- "localidade":"São Paulo","uf":"SP","estado":"São Paulo","regiao":"Sudeste","ddd":"11"}`
-
-// fakeAPI answers every request with the same status and body, and counts how
-// many arrived: the count is what proves the extra request happens only on the
-// 404 path.
-type fakeAPI struct {
- server *httptest.Server
- requests atomic.Int64
-
- // delay is applied from the delayFrom-th request on, which is how the
- // second request — the one that reads the faixa — is made slow without
- // slowing the lookup that precedes it.
- delay time.Duration
- delayFrom int64
-}
-
-func newFakeAPI(t *testing.T, status int, body string) *fakeAPI {
- t.Helper()
- f := &fakeAPI{delayFrom: 1}
- f.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- n := f.requests.Add(1)
- if f.delay > 0 && n >= f.delayFrom {
- select {
- case <-time.After(f.delay):
- case <-r.Context().Done():
- return
- }
- }
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- w.WriteHeader(status)
- w.Write([]byte(body))
- }))
- t.Cleanup(f.server.Close)
- return f
-}
-
-func newClient(t *testing.T, f *fakeAPI, opts ...Option) *Client {
- t.Helper()
- api, err := cepis.New(
- cepis.WithBaseURL(f.server.URL),
- cepis.WithMaxAttempts(1),
- cepis.WithTimeout(2*time.Second),
- )
- if err != nil {
- t.Fatalf("cepis.New: %v", err)
- }
- return New(api, opts...)
-}
-
-func TestNotFoundCarriesTheMunicipality(t *testing.T) {
- f := newFakeAPI(t, http.StatusNotFound, areal404)
- _, err := newClient(t, f).Lookup(context.Background(), "25845-000")
-
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatalf("err = %v, want a not-found error", err)
- }
- faixa := FaixaOf(err)
- if faixa == nil {
- t.Fatal("the faixa on the 404 was dropped")
- }
- if faixa.Place() != "Areal/RJ" {
- t.Fatalf("place = %q, want Areal/RJ", faixa.Place())
- }
- if faixa.CEPs != 118 {
- t.Fatalf("ceps = %d, want 118", faixa.CEPs)
- }
- if faixa.CEPIni != "25845001" || faixa.CEPFim != "25849899" {
- t.Fatalf("range = %s..%s, want 25845001..25849899", faixa.CEPIni, faixa.CEPFim)
- }
- if faixa.IBGE != "3300225" || faixa.Estado != "Rio de Janeiro" || faixa.Regiao != "Sudeste" {
- t.Fatalf("faixa lost fields: %+v", faixa)
- }
-}
-
-func TestNotFoundWithoutFaixaIsUntouched(t *testing.T) {
- f := newFakeAPI(t, http.StatusNotFound, plain404)
- _, err := newClient(t, f).Lookup(context.Background(), "99999999")
-
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatalf("err = %v, want a not-found error", err)
- }
- if faixa := FaixaOf(err); faixa != nil {
- t.Fatalf("invented a municipality: %+v", faixa)
- }
- var notFound *NotFoundError
- if errors.As(err, &notFound) {
- t.Fatal("a 404 without a faixa should come back as the library's own error")
- }
-}
-
-// A faixa the bot cannot trust must cost nothing: the reply falls back to the
-// plain one, and never to a panic or an unanswered message.
-func TestMalformedFaixaFallsBack(t *testing.T) {
- bodies := map[string]string{
- "empty body": ``,
- "not JSON": `<html>captive portal</html>`,
- "truncated": `{"erro":"cep_nao_encontrado","faixa":{"localidade":"Areal"`,
- "faixa is null": `{"erro":"cep_nao_encontrado","faixa":null}`,
- "faixa is a string": `{"erro":"cep_nao_encontrado","faixa":"Areal/RJ"}`,
- "faixa is an array": `{"erro":"cep_nao_encontrado","faixa":[{"localidade":"Areal"}]}`,
- "no localidade": `{"faixa":{"uf":"RJ","cep_ini":"25845001","cep_fim":"25849899"}}`,
- "blank localidade": `{"faixa":{"localidade":" ","uf":"RJ"}}`,
- "ceps is a string": `{"faixa":{"localidade":"Areal","uf":"RJ","ceps":"118"}}`,
- "whole body is null": `null`,
- "whole body is array": `[]`,
- }
-
- for name, body := range bodies {
- t.Run(name, func(t *testing.T) {
- f := newFakeAPI(t, http.StatusNotFound, body)
- _, err := newClient(t, f).Lookup(context.Background(), "25845000")
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatalf("err = %v, want a not-found error", err)
- }
- if faixa := FaixaOf(err); faixa != nil {
- t.Fatalf("trusted a broken faixa: %+v", faixa)
- }
- })
- }
-}
-
-// A negative count is nonsense the formatter would print verbatim, so it is
-// flattened to "unknown" while the municipality itself is kept.
-func TestNegativeCountIsDropped(t *testing.T) {
- f := newFakeAPI(t, http.StatusNotFound, `{"faixa":{"localidade":"Areal","uf":"RJ","ceps":-3}}`)
- _, err := newClient(t, f).Lookup(context.Background(), "25845000")
-
- faixa := FaixaOf(err)
- if faixa == nil {
- t.Fatal("the municipality should have survived a bad count")
- }
- if faixa.CEPs != 0 {
- t.Fatalf("ceps = %d, want 0", faixa.CEPs)
- }
-}
-
-func TestSuccessCostsOneRequest(t *testing.T) {
- f := newFakeAPI(t, http.StatusOK, address200)
- address, err := newClient(t, f).Lookup(context.Background(), "01001000")
-
- if err != nil {
- t.Fatalf("Lookup: %v", err)
- }
- if address.Localidade != "São Paulo" {
- t.Fatalf("localidade = %q", address.Localidade)
- }
- if got := f.requests.Load(); got != 1 {
- t.Fatalf("the API saw %d requests for a hit, want 1", got)
- }
-}
-
-func TestOtherFailuresAskOnlyOnce(t *testing.T) {
- f := newFakeAPI(t, http.StatusInternalServerError, `{"erro":"interno"}`)
- _, err := newClient(t, f).Lookup(context.Background(), "50000000")
-
- if !errors.Is(err, cepis.ErrServer) {
- t.Fatalf("err = %v, want a server error", err)
- }
- if got := f.requests.Load(); got != 1 {
- t.Fatalf("the API saw %d requests for a 500, want 1", got)
- }
-}
-
-// The faixa is worth one short wait and no more. A slow API still gets an
-// answer out to the user, without the municipality.
-func TestSlowFaixaIsAbandoned(t *testing.T) {
- f := newFakeAPI(t, http.StatusNotFound, areal404)
- client := newClient(t, f, WithTimeout(20*time.Millisecond))
- f.delay, f.delayFrom = 500*time.Millisecond, 2
-
- started := time.Now()
- _, err := client.Lookup(context.Background(), "25845000")
- elapsed := time.Since(started)
-
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatalf("err = %v, want a not-found error", err)
- }
- if faixa := FaixaOf(err); faixa != nil {
- t.Fatalf("used a faixa that arrived too late: %+v", faixa)
- }
- if elapsed > 400*time.Millisecond {
- t.Fatalf("waited %v for the faixa, want it abandoned quickly", elapsed)
- }
-}
-
-// A CEP that stopped being a 404 between the two requests is not a
-// municipality: the second answer is ignored rather than mixed into the first.
-func TestFaixaIgnoresANonNotFoundSecondAnswer(t *testing.T) {
- var count atomic.Int64
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- if count.Add(1) == 1 {
- w.WriteHeader(http.StatusNotFound)
- w.Write([]byte(plain404))
- return
- }
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(address200))
- }))
- t.Cleanup(server.Close)
-
- api, err := cepis.New(cepis.WithBaseURL(server.URL), cepis.WithMaxAttempts(1))
- if err != nil {
- t.Fatalf("cepis.New: %v", err)
- }
-
- _, err = New(api).Lookup(context.Background(), "25845000")
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatalf("err = %v, want a not-found error", err)
- }
- if faixa := FaixaOf(err); faixa != nil {
- t.Fatalf("read a municipality out of a 200: %+v", faixa)
- }
-}
-
-func TestFaixaOfAcceptsAnything(t *testing.T) {
- for name, err := range map[string]error{
- "nil": nil,
- "unrelated": errors.New("boom"),
- "not found": cepis.ErrCEPNotFound,
- "no faixa": &NotFoundError{Err: cepis.ErrCEPNotFound},
- "wrapped": &NotFoundError{Faixa: &Faixa{Localidade: "Areal", UF: "RJ"}, Err: cepis.ErrCEPNotFound},
- "empty type": &NotFoundError{},
- } {
- if name == "wrapped" {
- if got := FaixaOf(err); got == nil || got.Place() != "Areal/RJ" {
- t.Fatalf("%s: FaixaOf = %+v", name, got)
- }
- continue
- }
- if got := FaixaOf(err); got != nil {
- t.Fatalf("%s: FaixaOf = %+v, want nil", name, got)
- }
- }
-}
-
-// The zero value still matches the sentinel, so no construction of this type
-// can ever produce an error the bot fails to recognise as a not-found.
-func TestEmptyNotFoundErrorStillMatches(t *testing.T) {
- var err error = &NotFoundError{}
- if !errors.Is(err, cepis.ErrCEPNotFound) {
- t.Fatal("an empty NotFoundError should still be a not-found")
- }
- if err.Error() == "" {
- t.Fatal("an empty NotFoundError should still say something")
- }
-}
-
-func TestPlaceWithoutUF(t *testing.T) {
- faixa := &Faixa{Localidade: "Areal"}
- if faixa.Place() != "Areal" {
- t.Fatalf("place = %q, want Areal", faixa.Place())
- }
- var missing *Faixa
- if missing.Place() != "" {
- t.Fatalf("place = %q, want empty", missing.Place())
- }
-}