diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 20:39:38 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 20:39:38 -0300 |
| commit | 4014037e505876ed8c4df229ace3a65092e64ca8 (patch) | |
| tree | 367a84c87c75df41fb7218604a3a7d0260cd6cb5 | |
| parent | f979d07d23098b96e758b3feb555cd06d85d9b2d (diff) | |
| download | cobol-703f2337efa636217b03c9d9860f5fe148c3b1b5.tar.gz | |
A CEP that fails is rarely a random number: it is someone who knows the
city and guessed the digits, and the classic guess is the -000 that 957
municipalities never received. The API now attaches that municipality to
the 404, and a caller left with nothing but "does not exist" cannot tell
a typo in a real city from a CEP that was never plausible.
It goes in CEPIS-STATUS, not CEPIS-ADDRESS. The call has still failed
and the address is still empty; putting a localidade where the address
lives would let a caller that forgets to test the status read Areal as
the answer to a CEP that does not exist.
Parsing is best effort throughout. faixa is omitted rather than sent as
null for a band no municipality owns, so its absence is the normal case
and there is a flag instead of a marker value; a block that is missing,
is not an object, or is short of localidade, uf, cep_ini, cep_fim and
ceps is dropped and the not-found comes back clean. Failing a 404 the
caller already understands over a decoration on it would be a poor
trade.
cep_ini and cep_fim are the CEPs that exist, not the bounds the Correios
publish, and the span between them is mostly empty -- hence ceps beside
them, so the pair is not read as a list.
| -rw-r--r-- | README.md | 52 | ||||
| -rw-r--r-- | copy/cepis-status.cpy | 31 | ||||
| -rw-r--r-- | copy/cepis.cpy | 8 | ||||
| -rw-r--r-- | src/cepis-config.cob | 2 | ||||
| -rw-r--r-- | src/cepis-lookup-many.cob | 2 | ||||
| -rw-r--r-- | src/cepis-lookup.cob | 135 | ||||
| -rw-r--r-- | src/cepis-normalize-cep.cob | 2 | ||||
| -rw-r--r-- | src/cepis-request.cob | 2 | ||||
| -rw-r--r-- | tests/cepis-tests.cob | 109 | ||||
| -rw-r--r-- | tests/server.py | 42 |
10 files changed, 376 insertions, 9 deletions
@@ -168,7 +168,7 @@ CALL "CEPIS-NORMALIZE-CEP" USING CEPIS-CEP-INPUT CEPIS-CEP CEPIS-STATUS | `CFG-BACKOFF-BASE-MS` | `500` | base of the exponential wait | | `CFG-BACKOFF-MAX-MS` | `8000` | cap on each wait, `Retry-After` included | | `CFG-TOTAL-TIMEOUT-MS` | `0` | cap on the whole call, attempts and waits included; `0` means none | -| `CFG-USER-AGENT` | `cepis-cobol/0.1.0 (+https://cep.is)` | identifies the library and version | +| `CFG-USER-AGENT` | `cepis-cobol/0.2.0 (+https://cep.is)` | identifies the library and version | Retries cover 429, 5xx and transport failures, with exponential backoff and full jitter; 400 and 404 are never retried. @@ -189,7 +189,7 @@ already retried on its own before giving up. | condition | when | does retrying help? | | --- | --- | --- | | `CEPIS-INVALID-CEP` | not 8 digits | no | -| `CEPIS-NOT-FOUND` | well-formed, not in the database | no | +| `CEPIS-NOT-FOUND` | well-formed, not in the database; see `CEPIS-FAIXA` | no | | `CEPIS-RATE-LIMITED` | 429; see `CEPIS-STATUS-RETRY-AFTER-MS` | yes, later | | `CEPIS-SERVER-ERROR` | 5xx; see `CEPIS-STATUS-HTTP` | yes, later | | `CEPIS-NETWORK-ERROR` | DNS, connection, timeout, TLS | yes, later | @@ -211,6 +211,54 @@ status seen and `CEPIS-STATUS-ATTEMPTS` how many attempts were made. API is answering instead of it — a captive Wi-Fi portal, a corporate proxy, an HTML error page. Useful as a diagnosis: the problem is not in your code. +### Where a missing CEP would have been + +A `CEPIS-NOT-FOUND` from `CEPIS-LOOKUP` may also carry `CEPIS-FAIXA`: the +municipality the CEP would have belonged to. A CEP that fails is rarely a +random number — it is someone who knows the city and guessed the digits, +and the classic guess is the `-000` that 957 municipalities never received. + +```cobol +IF CEPIS-NOT-FOUND AND CEPIS-FAIXA-KNOWN + DISPLAY "no such CEP -- " FUNCTION TRIM (CEPIS-FAIXA-LOCALIDADE) + "/" CEPIS-FAIXA-UF " has " CEPIS-FAIXA-CEPS + " CEPs, from " CEPIS-FAIXA-CEP-INI + " to " CEPIS-FAIXA-CEP-FIM +END-IF +``` + +**It is still a 404.** The lookup failed, `CEPIS-ADDRESS` is empty, and +nothing in `CEPIS-FAIXA` is an address for the CEP that was asked for. It +says where the guess landed, not what it resolves to. + +`CEPIS-FAIXA-CEP-INI` and `CEPIS-FAIXA-CEP-FIM` are the smallest and the +largest CEP the municipality **actually has**, not the bounds the Correios +publish. The DNE's own start for Areal/RJ is `25845000` — exactly the CEP +that just failed, which is why the range comes back starting one past it, +at `25845001`. + +**The span is sparse, and it is not a list.** Areal's 118 CEPs are +scattered over the ~4900 numbers between `25845001` and `25849899`; almost +none of that interval exists either. That is what `CEPIS-FAIXA-CEPS` is +for — show it next to the pair, and never iterate the two as a range. + +The API omits `faixa` — it never sends it as null — when the CEP falls in a +band no municipality owns, so **test `CEPIS-FAIXA-KNOWN` before reading +anything below it.** A `faixa` that is missing, malformed, or short of its +members leaves the flag off and the not-found otherwise untouched; a +decoration on an error is never worth failing that error over. + +Only `CEPIS-LOOKUP` fills it. `CEPIS-LOOKUP-MANY` and `CEPIS-HEALTH` clear +it, so `CEPIS-FAIXA-ABSENT` holds after a batch or a health call and a +faixa never survives from one lookup into the next. + +| field | bytes | | field | bytes | +| --- | --- | --- | --- | --- | +| `faixa-localidade` | 100 | | `faixa-ibge` | 10 | +| `faixa-uf` | 2 | | `faixa-cep-ini` | 8 | +| `faixa-estado` | 60 | | `faixa-cep-fim` | 8 | +| `faixa-regiao` | 30 | | `faixa-ceps` | `9(9)` | + ## Field widths COBOL records are fixed width. A value longer than its field is truncated diff --git a/copy/cepis-status.cpy b/copy/cepis-status.cpy index 75632c8..b98a753 100644 --- a/copy/cepis-status.cpy +++ b/copy/cepis-status.cpy @@ -1,7 +1,7 @@ *> --------------------------------------------------------------------- *> Status layout without its 01 level, so the library can keep a private *> scratch status alongside the caller's without duplicating the -*> definition. Replace the field-name tag and the level number. +*> definition. Replace the field-name tag and the two level numbers. *> *> The six failure categories are split by the decision the caller has to *> make, not by the HTTP status that produced them. @@ -21,3 +21,32 @@ :L1: :P:-STATUS-RETRY-AFTER-MS PIC S9(9) SIGN IS LEADING SEPARATE. :L1: :P:-STATUS-ATTEMPTS PIC 9(4). + +*> The municipality a CEP that does not exist would have belonged to. +*> Context for the error, never an address: the lookup is still +*> :P:-NOT-FOUND and CEPIS-ADDRESS is still empty. Only GET /{cep} fills +*> it, so it stays absent after a batch or a health call. +*> +*> :P:-FAIXA-CEP-INI and :P:-FAIXA-CEP-FIM are the smallest and the +*> largest CEP the municipality actually has, not the bounds the Correios +*> publish -- the DNE's own start for Areal/RJ is 25845000, exactly the +*> CEP that just failed. The range is sparse: Areal's 118 CEPs are +*> scattered over the ~4900 numbers between 25845001 and 25849899, so the +*> pair is a span to show a human, never a list of valid CEPs. That is +*> what :P:-FAIXA-CEPS counts. +*> +*> The API omits "faixa" -- it never sends null -- when the CEP falls in +*> a band no municipality owns, so test the flag before reading anything +*> below it. +:L1: :P:-FAIXA. + :L2: :P:-FAIXA-PRESENT PIC X. + 88 :P:-FAIXA-KNOWN VALUE "Y". + 88 :P:-FAIXA-ABSENT VALUE "N". + :L2: :P:-FAIXA-LOCALIDADE PIC X(100). + :L2: :P:-FAIXA-UF PIC X(2). + :L2: :P:-FAIXA-ESTADO PIC X(60). + :L2: :P:-FAIXA-REGIAO PIC X(30). + :L2: :P:-FAIXA-IBGE PIC X(10). + :L2: :P:-FAIXA-CEP-INI PIC X(8). + :L2: :P:-FAIXA-CEP-FIM PIC X(8). + :L2: :P:-FAIXA-CEPS PIC 9(9). diff --git a/copy/cepis.cpy b/copy/cepis.cpy index 59d643c..84a9976 100644 --- a/copy/cepis.cpy +++ b/copy/cepis.cpy @@ -1,5 +1,5 @@ *> --------------------------------------------------------------------- -*> cepis 0.1.0 -- public data layouts for the cep.is client. +*> cepis 0.2.0 -- public data layouts for the cep.is client. *> *> Copy this into WORKING-STORAGE (callers) or LINKAGE (subprograms). *> It defines, in order: @@ -34,9 +34,13 @@ *> categories are split by the decision the caller has to make, not by *> the HTTP status that produced them. CEPIS-RETRIABLE covers the three *> the client already retried on its own before giving up. +*> +*> A CEPIS-NOT-FOUND may also carry CEPIS-FAIXA, the municipality the +*> missing CEP would have belonged to. CEPIS-FAIXA-PRESENT says whether +*> it does; the call has still failed either way. 01 CEPIS-STATUS. COPY "cepis-status.cpy" REPLACING - ==:P:== BY ==CEPIS== ==:L1:== BY ==05==. + ==:P:== BY ==CEPIS== ==:L1:== BY ==05== ==:L2:== BY ==10==. *> A CEP as the caller has it: "01001-000", "01001000" or "01001.000". 01 CEPIS-CEP-INPUT PIC X(20). diff --git a/src/cepis-config.cob b/src/cepis-config.cob index 0f17fd1..87e0312 100644 --- a/src/cepis-config.cob +++ b/src/cepis-config.cob @@ -15,7 +15,7 @@ PROGRAM-ID. CEPIS-DEFAULT-CONFIG. DATA DIVISION. WORKING-STORAGE SECTION. -01 CEPIS-VERSION PIC X(5) VALUE "0.1.0". +01 CEPIS-VERSION PIC X(5) VALUE "0.2.0". LINKAGE SECTION. COPY "cepis.cpy". diff --git a/src/cepis-lookup-many.cob b/src/cepis-lookup-many.cob index d76fa72..65b6496 100644 --- a/src/cepis-lookup-many.cob +++ b/src/cepis-lookup-many.cob @@ -33,7 +33,7 @@ COPY "cepis-csv.cpy". 01 WS-NORM. COPY "cepis-status.cpy" REPLACING - ==:P:== BY ==WSN== ==:L1:== BY ==05==. + ==:P:== BY ==WSN== ==:L1:== BY ==05== ==:L2:== BY ==10==. 01 WS-CHUNK-MAX PIC 9(4) VALUE 500. 01 WS-BATCH-MAX PIC 9(4) VALUE 1000. diff --git a/src/cepis-lookup.cob b/src/cepis-lookup.cob index cc6e412..90f1502 100644 --- a/src/cepis-lookup.cob +++ b/src/cepis-lookup.cob @@ -22,6 +22,13 @@ PROGRAM-ID. CEPIS-LOOKUP. *> means the CEP is a whole municipality and the point is its centroid, *> with a radius of 7 to 40 km. Computing shipping from the second is *> wrong by tens of kilometres. +*> +*> A CEPIS-NOT-FOUND may come back with CEPIS-FAIXA filled: the +*> municipality the CEP would have belonged to. A CEP that fails is +*> rarely a random number -- it is usually someone who knows the city and +*> guessed the digits, and the classic guess is the -000 that 957 +*> municipalities never received. The lookup has still failed and the +*> address is still empty; CEPIS-FAIXA only names where the guess landed. *> --------------------------------------------------------------------- DATA DIVISION. @@ -38,6 +45,17 @@ COPY "cepis-json.cpy". 01 WS-LON PIC S9(3)V9(6). 01 WS-RAIO PIC 9(9). 01 WS-PRECISAO PIC X(16). +01 WS-FAIXA-FROM PIC 9(9). +01 WS-FAIXA-TO PIC 9(9). +01 WS-FAIXA-OK PIC X. +01 WS-F-LOCALIDADE PIC X(100). +01 WS-F-UF PIC X(2). +01 WS-F-ESTADO PIC X(60). +01 WS-F-REGIAO PIC X(30). +01 WS-F-IBGE PIC X(10). +01 WS-F-CEP-INI PIC X(8). +01 WS-F-CEP-FIM PIC X(8). +01 WS-F-CEPS PIC 9(9). 01 WS-I PIC 9(4). 01 WS-C PIC X. 01 WS-DOTS PIC 9(4). @@ -82,6 +100,7 @@ MAIN-START. STRING "CEP " WS-CEP " does not exist in the DNE database" DELIMITED BY SIZE INTO CEPIS-STATUS-MESSAGE END-STRING + PERFORM PARSE-FAIXA WHEN 400 SET CEPIS-INVALID-CEP TO TRUE PERFORM API-MESSAGE @@ -133,6 +152,13 @@ GET-GEO-MEMBER. END-CALL. *> ------------------------------------------------------------------- +GET-FAIXA-MEMBER. + MOVE WS-FAIXA-FROM TO JS-FROM + MOVE WS-FAIXA-TO TO JS-TO + CALL "CEPIS-JSON-GET" USING HTTP-BODY CEPIS-JSON-SCAN + END-CALL. + +*> ------------------------------------------------------------------- PARSE-ADDRESS. MOVE "cep" TO JS-KEY PERFORM GET-MEMBER @@ -290,6 +316,115 @@ PARSE-GEO. END-IF. *> ------------------------------------------------------------------- +*> The 404 body may name the municipality the CEP would have belonged +*> to. It is context for the error and nothing else: the status stays +*> CEPIS-NOT-FOUND and CEPIS-ADDRESS stays empty, because a CEP that the +*> DNE does not have is not an address no matter which city it is near. +*> +*> "faixa" is omitted -- never sent as null -- when the CEP falls in a +*> band no municipality owns, so its absence is the normal case, not an +*> error. Everything here is therefore best effort: a faixa that is +*> missing, is not an object, or is short of the members below is +*> dropped, and the caller still gets a clean not-found. Turning a 404 +*> the caller already understands into CEPIS-INVALID-RESPONSE over a +*> decoration would be a poor trade. +*> +*> cep_ini and cep_fim must both be eight digits and ceps must be a +*> number, or the whole block is dropped. The span is sparse -- Areal's +*> 118 CEPs are spread over the ~4900 numbers between 25845001 and +*> 25849899 -- so handing a caller the pair without the count invites +*> reading it as a list of valid CEPs, which it is not. +PARSE-FAIXA. + INITIALIZE CEPIS-FAIXA + SET CEPIS-FAIXA-ABSENT TO TRUE + MOVE "faixa" TO JS-KEY + PERFORM GET-MEMBER + IF JS-TYPE NOT = "O" + EXIT PARAGRAPH + END-IF + MOVE JS-VSTART TO WS-FAIXA-FROM + MOVE JS-VEND TO WS-FAIXA-TO + MOVE "Y" TO WS-FAIXA-OK + + MOVE "localidade" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" AND JS-VALUE-LEN > 0 + MOVE JS-VALUE TO WS-F-LOCALIDADE + ELSE + MOVE "N" TO WS-FAIXA-OK + END-IF + + MOVE "uf" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" AND JS-VALUE-LEN = 2 + MOVE JS-VALUE TO WS-F-UF + ELSE + MOVE "N" TO WS-FAIXA-OK + END-IF + + MOVE "cep_ini" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" AND JS-VALUE-LEN = 8 + MOVE JS-VALUE TO WS-F-CEP-INI + ELSE + MOVE "N" TO WS-FAIXA-OK + END-IF + + MOVE "cep_fim" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" AND JS-VALUE-LEN = 8 + MOVE JS-VALUE TO WS-F-CEP-FIM + ELSE + MOVE "N" TO WS-FAIXA-OK + END-IF + + MOVE "ceps" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + PERFORM CHECK-NUMERIC + IF WS-NUM-OK = "Y" + COMPUTE WS-F-CEPS ROUNDED = FUNCTION NUMVAL (JS-VALUE) + ELSE + MOVE "N" TO WS-FAIXA-OK + END-IF + + IF WS-FAIXA-OK NOT = "Y" + EXIT PARAGRAPH + END-IF + + *> The three below are decoration: a faixa the API sends without + *> them still names the municipality, so they never fail the block. + MOVE SPACES TO WS-F-ESTADO + MOVE "estado" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" + MOVE JS-VALUE TO WS-F-ESTADO + END-IF + + MOVE SPACES TO WS-F-REGIAO + MOVE "regiao" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" + MOVE JS-VALUE TO WS-F-REGIAO + END-IF + + MOVE SPACES TO WS-F-IBGE + MOVE "ibge" TO JS-KEY + PERFORM GET-FAIXA-MEMBER + IF JS-TYPE = "S" + MOVE JS-VALUE TO WS-F-IBGE + END-IF + + SET CEPIS-FAIXA-KNOWN TO TRUE + MOVE WS-F-LOCALIDADE TO CEPIS-FAIXA-LOCALIDADE + MOVE WS-F-UF TO CEPIS-FAIXA-UF + MOVE WS-F-ESTADO TO CEPIS-FAIXA-ESTADO + MOVE WS-F-REGIAO TO CEPIS-FAIXA-REGIAO + MOVE WS-F-IBGE TO CEPIS-FAIXA-IBGE + MOVE WS-F-CEP-INI TO CEPIS-FAIXA-CEP-INI + MOVE WS-F-CEP-FIM TO CEPIS-FAIXA-CEP-FIM + MOVE WS-F-CEPS TO CEPIS-FAIXA-CEPS. + +*> ------------------------------------------------------------------- *> FUNCTION NUMVAL answers 0 for text it cannot read, which would turn *> "lat": "not a number" into a coordinate off the coast of Africa. The *> text is therefore checked before it is converted. diff --git a/src/cepis-normalize-cep.cob b/src/cepis-normalize-cep.cob index 41615ad..cdbc954 100644 --- a/src/cepis-normalize-cep.cob +++ b/src/cepis-normalize-cep.cob @@ -36,6 +36,8 @@ MAIN-START. MOVE 0 TO CEPIS-STATUS-ATTEMPTS MOVE -1 TO CEPIS-STATUS-RETRY-AFTER-MS MOVE SPACES TO CEPIS-STATUS-MESSAGE + INITIALIZE CEPIS-FAIXA + SET CEPIS-FAIXA-ABSENT TO TRUE PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 20 MOVE CEPIS-CEP-INPUT(WS-I:1) TO WS-C diff --git a/src/cepis-request.cob b/src/cepis-request.cob index b45f5da..30c9477 100644 --- a/src/cepis-request.cob +++ b/src/cepis-request.cob @@ -143,6 +143,8 @@ RESET-STATE. MOVE 0 TO CEPIS-STATUS-HTTP MOVE -1 TO CEPIS-STATUS-RETRY-AFTER-MS MOVE 0 TO CEPIS-STATUS-ATTEMPTS + INITIALIZE CEPIS-FAIXA + SET CEPIS-FAIXA-ABSENT TO TRUE MOVE 0 TO HTTP-STATUS MOVE 0 TO HTTP-BODY-LEN MOVE "N" TO WS-DONE diff --git a/tests/cepis-tests.cob b/tests/cepis-tests.cob index 4bc1a11..6978a2d 100644 --- a/tests/cepis-tests.cob +++ b/tests/cepis-tests.cob @@ -67,7 +67,7 @@ MAIN-START. MOVE 2 TO RETURN-CODE STOP RUN END-IF - DISPLAY "cepis 0.1.0 test suite against " FUNCTION TRIM (WS-BASE) + DISPLAY "cepis 0.2.0 test suite against " FUNCTION TRIM (WS-BASE) DISPLAY " " PERFORM T-NORMALIZE-ACCEPTS @@ -79,6 +79,11 @@ MAIN-START. PERFORM T-UNKNOWN-FIELDS PERFORM T-LONG-VALUE-FLAGGED PERFORM T-NOT-FOUND + PERFORM T-NOT-FOUND-FAIXA + PERFORM T-NOT-FOUND-FAIXA-OMITTED + PERFORM T-NOT-FOUND-FAIXA-MALFORMED + PERFORM T-NOT-FOUND-FAIXA-NOT-OBJECT + PERFORM T-FAIXA-CLEARED-ON-SUCCESS PERFORM T-NOT-FOUND-NOT-RETRIED PERFORM T-INVALID-NEVER-LEAVES PERFORM T-API-400 @@ -308,6 +313,106 @@ T-NOT-FOUND. MOVE CEPIS-STATUS-MESSAGE TO WS-DETAIL PERFORM CHECK. +*> 25845000 is the DNE's own published start for Areal/RJ and does not +*> exist -- the classic guess. The faixa says which municipality the +*> guess landed in; cep_ini is 25845001, one past what was asked for. +T-NOT-FOUND-FAIXA. + PERFORM FRESH-CONFIG + MOVE "25845-000" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + MOVE "N" TO WS-OK + IF CEPIS-NOT-FOUND AND CEPIS-FAIXA-KNOWN + AND CEPIS-FAIXA-LOCALIDADE = "Areal" + AND CEPIS-FAIXA-UF = "RJ" + AND CEPIS-FAIXA-ESTADO = "Rio de Janeiro" + AND CEPIS-FAIXA-REGIAO = "Sudeste" + AND CEPIS-FAIXA-IBGE = "3300225" + AND CEPIS-FAIXA-CEP-INI = "25845001" + AND CEPIS-FAIXA-CEP-FIM = "25849899" + AND CEPIS-FAIXA-CEPS = 118 + AND ADDR-LOCALIDADE = SPACES AND ADDR-CEP = SPACES + MOVE "Y" TO WS-OK + END-IF + MOVE "a 404 names the municipality, and stays a 404" TO WS-LABEL + MOVE CEPIS-FAIXA-LOCALIDADE TO WS-DETAIL + PERFORM CHECK. + +*> 25849900 is one past Areal's last CEP, in a band no municipality +*> owns, so the API sends no faixa -- it never sends null. Runs after +*> the test above on purpose: the faixa that one left behind must not +*> survive into this lookup. +T-NOT-FOUND-FAIXA-OMITTED. + PERFORM FRESH-CONFIG + MOVE "25849900" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + MOVE "N" TO WS-OK + IF CEPIS-NOT-FOUND AND CEPIS-FAIXA-ABSENT + AND CEPIS-FAIXA-LOCALIDADE = SPACES + AND CEPIS-FAIXA-CEPS = 0 + MOVE "Y" TO WS-OK + END-IF + MOVE "a band no municipality owns has no faixa at all" TO WS-LABEL + MOVE CEPIS-FAIXA-LOCALIDADE TO WS-DETAIL + PERFORM CHECK. + +T-NOT-FOUND-FAIXA-MALFORMED. + PERFORM FRESH-CONFIG + MOVE "25845002" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + MOVE 0 TO WS-TALLY + INSPECT CEPIS-STATUS-MESSAGE + TALLYING WS-TALLY FOR ALL "does not exist in the DNE database" + MOVE "N" TO WS-OK + IF CEPIS-NOT-FOUND AND CEPIS-FAIXA-ABSENT AND WS-TALLY = 1 + AND CEPIS-FAIXA-LOCALIDADE = SPACES + MOVE "Y" TO WS-OK + END-IF + MOVE "a malformed faixa is dropped, the 404 is clean" TO WS-LABEL + MOVE CEPIS-STATUS-MESSAGE TO WS-DETAIL + PERFORM CHECK. + +T-NOT-FOUND-FAIXA-NOT-OBJECT. + PERFORM FRESH-CONFIG + MOVE "25845003" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + MOVE "N" TO WS-OK + IF CEPIS-NOT-FOUND AND CEPIS-FAIXA-ABSENT + MOVE "Y" TO WS-OK + END-IF + MOVE "a faixa that is not an object is dropped" TO WS-LABEL + MOVE CEPIS-STATUS-MESSAGE TO WS-DETAIL + PERFORM CHECK. + +T-FAIXA-CLEARED-ON-SUCCESS. + PERFORM FRESH-CONFIG + MOVE "25845000" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + MOVE "N" TO WS-OK + IF CEPIS-FAIXA-KNOWN + MOVE "01001-000" TO CEPIS-CEP-INPUT + CALL "CEPIS-LOOKUP" USING CEPIS-CONFIG CEPIS-CEP-INPUT + CEPIS-ADDRESS CEPIS-STATUS + END-CALL + IF CEPIS-OK AND CEPIS-FAIXA-ABSENT + AND ADDR-LOCALIDADE = "São Paulo" + MOVE "Y" TO WS-OK + END-IF + END-IF + MOVE "a later success clears the faixa of an earlier 404" + TO WS-LABEL + MOVE CEPIS-FAIXA-LOCALIDADE TO WS-DETAIL + PERFORM CHECK. + T-NOT-FOUND-NOT-RETRIED. MOVE "/99999999" TO WS-COUNT-PATH PERFORM COUNT-FOR @@ -746,7 +851,7 @@ T-TRAILING-SLASH. T-DEFAULT-USER-AGENT. CALL "CEPIS-DEFAULT-CONFIG" USING CEPIS-CONFIG MOVE 0 TO WS-TALLY - INSPECT CFG-USER-AGENT TALLYING WS-TALLY FOR ALL "cepis-cobol/0.1.0" + INSPECT CFG-USER-AGENT TALLYING WS-TALLY FOR ALL "cepis-cobol/0.2.0" MOVE "N" TO WS-OK IF WS-TALLY = 1 AND CFG-BASE-URL = "https://cep.is" AND CFG-MAX-ATTEMPTS = 3 AND CFG-BACKOFF-BASE-MS = 500 diff --git a/tests/server.py b/tests/server.py index 46185a0..57fa120 100644 --- a/tests/server.py +++ b/tests/server.py @@ -76,6 +76,22 @@ SYNTHETIC = [ DROPPED_CEP = "00000099" +# The municipality a missing CEP would have belonged to, attached to the +# 404 for /25845000 below. The numbers are Areal/RJ's real ones: cep_ini is +# 25845001, one past the 25845000 the DNE publishes as the start of the +# range and that the route refuses, and the 118 CEPs are scattered over the +# ~4900 numbers up to cep_fim rather than filling them. +AREAL = { + "localidade": "Areal", + "uf": "RJ", + "estado": "Rio de Janeiro", + "regiao": "Sudeste", + "ibge": "3300225", + "cep_ini": "25845001", + "cep_fim": "25849899", + "ceps": 118, +} + LONG_STREET = "Avenida " + ("Muito Comprida " * 20) COUNTS = {} @@ -166,6 +182,32 @@ def route(path, query, hits): return 404, json_body( {"erro": "cep_nao_encontrado", "mensagem": "gone"} ), {} + if path == "/25845000": + return 404, json_body( + { + "erro": "cep_nao_encontrado", + "mensagem": "CEP não existe na base do DNE", + "faixa": AREAL, + } + ), {} + if path == "/25849900": + return 404, json_body( + { + "erro": "cep_nao_encontrado", + "mensagem": "CEP não existe na base do DNE", + } + ), {} + if path == "/25845002": + broken = dict(AREAL) + broken["cep_fim"] = "nope" + broken["ceps"] = "many" + return 404, json_body( + {"erro": "cep_nao_encontrado", "faixa": broken} + ), {} + if path == "/25845003": + return 404, json_body( + {"erro": "cep_nao_encontrado", "faixa": "Areal"} + ), {} if path == "/00000000": return 400, json_body( {"erro": "cep_invalido", "mensagem": "rejected by the API"} |