summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md52
-rw-r--r--copy/cepis-status.cpy31
-rw-r--r--copy/cepis.cpy8
-rw-r--r--src/cepis-config.cob2
-rw-r--r--src/cepis-lookup-many.cob2
-rw-r--r--src/cepis-lookup.cob135
-rw-r--r--src/cepis-normalize-cep.cob2
-rw-r--r--src/cepis-request.cob2
-rw-r--r--tests/cepis-tests.cob109
-rw-r--r--tests/server.py42
10 files changed, 376 insertions, 9 deletions
diff --git a/README.md b/README.md
index 021448c..158112b 100644
--- a/README.md
+++ b/README.md
@@ -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"}