Nordlet

Tinklaraštis

Apskaitos API testavimo planas prieš paleidimą į gamybą

Patikimumo užtikrinimo vadovas inžinierių komandoms: dubliuojantys įrašai, idempotentiškumo pakartotinis naudojimas, „webhook“ parašai, ne iš eilės gaunami įvykiai, dešimtainės trupmenos piniginėms vertėms, prieigos sritys, periodų uždarymas ir atkūrimas.

Nordlet Team · · 15 min. skaitymo

Apskaitos API grąžintas 201 Created statusas nepasako beveik nieko. Tai tik patvirtina, kad serveris atsakė. Tai nepatvirtina, kad buvo sukurta lygiai viena sąskaita faktūra, kad debetas lygus kreditui, kad dokumento numeris priskirtas vieną kartą, ar kad pakartotinis bandymas po nutrūkusio ryšio nesukurs antros kopijos. Dauguma dublikatų gamybinėje aplinkoje (production) atsiranda būtent dėl šios spragos: kai serveris įvykdo (commit) operaciją, bet klientas, nesulaukęs atsakymo ir nežinodamas baigties, tyliai ją pakartoja su nauju raktu.

Šis planas skirtas komandoms, vertinančioms apskaitos API prieš integruojant jį su realiais apskaitos duomenimis. Čia daugiausia dėmesio skiriama sistemos elgsenai klaidų atvejais, o ne standartiniams sėkmingiems scenarijams (happy paths). Kiekvienoje toliau aprašytoje srityje nurodyta, ką reikia testuoti, kokius tvirtinimus (assertions) naudoti ir kas laikoma sėkmingu testu. Šiame kontekste naudojamas Nordlet pavyzdys, kurio API naudoja apribotos prieigos (scoped) „bearer“ raktus, dešimtainėmis trupmenomis išreikštas pinigų sumas (decimal-string), idempotentiškumo raktus ir pasirašytas webhook užklausas. Tikslią galinių punktų (endpoints) sintaksę ir atsakymų struktūrą rasite puslapiuose API conventions ir Getting started, todėl geriau remtis jais, o ne prielaidomis.

Ką iš tiesų reiškia „sėkmingas testas“

Testas įrodo, kad apskaitos integracija yra saugi tik tada, kai tikrinama semantika, o ne HTTP statuso kodai. Kiekviename scenarijuje testavimo rinkinys turi patvirtinti:

  • Verslo pasekmė (side effect): sukuriamas lygiai vienas klientas, sąskaita faktūra, dvejybinis įrašas (journal entry), numerio priskyrimas arba mokėjimo būsenos pasikeitimas.
  • Apskaitos vientisumas: debetas lygus kreditui, o piniginių sumų tikslumas išlieka po serializacijos.
  • Pakartojimo elgsena: pakartojus užklausą grąžinamas pirminis rezultatas, o ne sukuriamas naujas įrašas.
  • Patikimumas (durability): įvykdžius operaciją (commit), sukuriami audito įrašai ir webhook įvykiai.
  • Klaidos be pasekmių: atmestos užklausos nepanaudoja dokumentų numerių ir neįrašo dalinių didžiosios knygos (ledger) eilučių.
  • Atkūrimas: laikiną klaidą galima pakartoti be duomenų dubliavimo ar praradimo.

„Google“ API gairės nubrėžia aiškią ribą: saugu kartoti tik tas operacijas, kurias pakartojus išlieka ta pati galutinė būsena, todėl API turi nurodyti, kurios operacijos yra idempotentiškos, užuot aklai kartojus kiekvieną klaidą.

Vienkartinės, stebimos aplinkos paruošimas

Naudokite smėliadėžės (sandbox) įmonę, o ne gamybinę apskaitą. Nordlet smėliadėžės įmonė naudoja tuos pačius modulius ir API elgseną kaip ir reali įmonė, bei yra pažymėta kaip testinė, todėl joje saugu atlikti didelės apimties dublikatų ir klaidų testus. Ši žyma po sukūrimo yra nekeičiama, todėl vėliau realios apskaitos duomenų nebus galima perklasifikuoti į testinius. Atkreipkite dėmesį, kad smėliadėžės naudojimas yra apskaitomas ir apmokestinamas lygiai taip pat, kaip ir naudojimas realioje įmonėje, todėl planuodami apimties testus atsižvelkite į turimą kainodarą.

Prieš rašydami bet kokį testą, paruoškite:

  • Atskirą smėliadėžės įmonę su isSandbox: true.
  • Testinį API raktą, kurio prieigos sritis apima tik testuojamus modulius.
  • webhook gavėją (endpoint) arba vietinį tunelį, kuris išsaugo neapdorotą (raw) užklausos kūną.
  • Iš anksto sukurtus (seeded) pirkėjus, tiekėjus ir žinomą sąskaitų planą.
  • Bent du apskaitos periodus: vieną atvirą, kitą – uždarytą.
  • Testinį laikrodį ar datų fiksavimą, jei sistema tai palaiko.
  • Vietinę saugyklą, kurioje registruojamas kiekvienas užklausos bandymas, idempotentiškumo raktas, atsakymo maiša (hash), webhook pristatymas ir sutikrinimo (reconciliation) rezultatas.

Nevykdykite dublikatų testų naudojant bendrus testinės (staging) aplinkos duomenis. Dėl ankstesnių paleidimų likęs atsitiktinis pirkėjas ar sąskaita faktūra padarys vėlesnius tvirtinimus dviprasmiškus.

Kiekvienoje duomenų keitimo (mutation) testavimo aplinkoje (fixture) turi būti užfiksuotas metodas, galinis punktas, visas užklausos kūnas, idempotentiškumo raktas, rakto aprėptis, kliento koreliacijos ID, pradžios ir pabaigos laiko žymos (timestamps), atsakymo statusas, antraštės (headers), atsakymo kūnas, užklausos ID ir tai, ar ryšys nenutrūko prieš gaunant atsakymą. Pinigų sumoms naudokite fiksuotas dešimtaines eilutes, pvz., "75.0000". Nordlet pinigines vertes atvaizduoja kaip dešimtaines eilutes, turinčias iki keturių skaitmenų po kablelio, ir tai matoma pateiktame sąskaitos faktūros pavyzdyje.

Kita aplinkos paruošimo dalis – dirbtinis klaidų sukėlimas (failure injection). Jūsų testavimo įrankis turi gebėti uždelsti atsakymą, nutraukti TCP ryšį po to, kai serveris gauna užklausą, grąžinti sintetinius 429/500/502/503/504 atsakymus, grąžinti ne 2xx statusą iš webhook imtuvo, pristatyti tą patį webhook du kartus, sukeisti įvykių seką, sugadinti vieną webhook kūno baitą, pakeisti užklausos naudingąją apkrovą išlaikant tą patį idempotentiškumo raktą, vienu metu vykdyti dvi identiškas užklausas ir uždaryti apskaitos periodą tarp paruošimo ir įrašo patvirtinimo (posting). Šie scenarijai yra vertesni nei šimtas sėkmingų pavyzdžių.

Užfiksuokite API kontraktą prieš programuojant kartojimo logiką

Sugeneruokite arba atsisiųskite OpenAPI schemą ir palyginkite ją su savo klientu. Nordlet skelbia savo OpenAPI specifikaciją API reference puslapyje ir pagal tą pačią specifikaciją generuoja tipizuotus SDK, todėl schemomis paremti testai yra kur kas pranašesni nei ranka rašytos spėlionės.

Patikrinkite privalomus laukus ir jų tipus, dešimtainių eilučių laukus, datų ir laiko žymų formatus, leidžiamus veiksmus ir aprėptis, klaidų struktūrą, webhook įvykių schemas, kurie metodai priima idempotentiškumo raktą ir kokie atsakymo laukai identifikuoja sukurtą objektą.

Sėkmingo testo kriterijai (Pass criteria). Klientas lokaliai atmeta netinkamus duomenis pagal tai, ką leidžia schema. Serverio atsakymai atitinka dokumentuotą schemą. Neteisingos dešimtainės trupmenos, blogos datos ir trūkstami privalomi laukai sugeneruoja struktūrizuotas validacijos klaidas. Esant deterministinei validacijos klaidai, pakartotinis bandymas nevykdomas.

Klaida, kurią reikia pagauti. Klientas nuskaito "121.0000" kaip dvejetainį skaičių su slankiuoju kableliu (binary float) ir vėliau serializuoja šiek tiek kitokią sumą. Sveikieji skaičiai praeina, o PVM eilutės ir trupmeniniai kiekiai sukelia klaidą. Testuokite pinigines sumas tik kaip eilutes visoje grandinėje.

Autentifikacija ir nuomininkų izoliavimas (tenant isolation)

Skaitymui ir rašymui naudokite atskirus raktus. Tada ištestuokite visas galimas kombinacijas: trūkstamas raktas, neteisingas raktas, teisingas raktas su nepakankama modulio prieigos sritimi, teisingas raktas su tinkama prieigos sritimi, kitai įmonei priklausantis raktas ir bandymas nuskaityti kitos įmonės objektą.

Tvirtinimai (Assertions):

  • Trūkstami arba neteisingi prisijungimo duomenys grąžina 401.
  • Tinkamas raktas, neturintis reikiamų teisių, grąžina 403.
  • Nė vienos iš šių klaidų atveju nesukuriama jokia apskaitos operacija.
  • Sėkminga užklausa negali nuskaityti ar pakeisti kitos įmonės įrašų.
  • Saugumo klaidų atveju užklausos niekada nekartojamos automatiškai.

Sėkmingo testo kriterijus. Po testų atlikti nuskaitymai patvirtina, kad autentifikacija veikia korektiškai ir įmonių duomenys yra izoliuoti, – to neįmanoma padaryti remiantis vien HTTP statuso kodais.

Sėkmingos vienos transakcijos įrodymas

Paleiskite nedidelį, deterministinį procesą: sukurkite arba raskite testinį pirkėją, sukurkite sąskaitą faktūrą su pinigų sumomis, išreikštomis dešimtainėmis eilutėmis, išrašykite ją, nuskaitykite sąskaitą ir jos poveikį apskaitai, nuskaitykite audito įrašą bei gaukite webhook užklausą. Nordlet „Getting Started“ pavyzdyje rodoma, kaip sąskaitos faktūros išrašymas priskiria sekos nepertraukiantį numerį, patikrina, ar periodas atviras, ir toje pačioje transakcijoje užregistruoja subalansuotą dvejybinį įrašą.

Įsitikinkite, kad sąskaita faktūra pasiekia lauktą būseną, dokumento numeris priskiriamas tik vieną kartą, debetas lygus kreditui, PVM ir eilučių sumos atitinka tikėtiną apvalinimo (half-up) rezultatą, audito įraše nurodytas asmuo ir atliktas pakeitimas, webhook galiausiai yra pristatomas, o API atsakymas bei vėlesnis nuskaitymas rodo tą patį sąskaitos faktūros ID ir būseną.

Viena svarbi taisyklė, kurią verta atsiminti: gautas webhook nėra įrodymas, kad operacija buvo patvirtinta (committed). API atsakymas kartu su pakartotiniu duomenų nuskaitymu (read-back) yra pagrindiniai jūsų transakcijos sėkmės rodikliai. Webhook įrodo tik tai, kad pranešimas buvo išsiųstas sistemos išorėn, ir tai testuojama atskirai.

Idempotentiškumas: tas pats raktas, tas pats kūnas

Sugeneruokite vieną raktą kiekvienai loginei verslo operacijai, o ne kiekvienam tinklo užklausos bandymui. Išsiųskite pakeitimo užklausą su raktu K ir kūnu B, išsaugokite sukurto objekto ID ir tada vėl išsiųskite lygiai tokią pačią užklausą.

Įsitikinkite, kad antrasis atsakymas atspindi tą pačią operaciją, objekto ID yra identiškas ir kad egzistuoja tik vienas verslo objektas, vienas didžiosios knygos įrašas, vienas dokumento numeris, vienas finansinis poveikis. Pakartotinis atsakymas turi turėti dokumentuotą pakartojimo antraštę – Nordlet atveju tai yra x-idempotent-replay: true – o audito sekoje neturi matytis jokio antro pakeitimo.

Jūsų kartojimo ciklas (retry loop) priklauso nuo dviejų saugojimo taisyklių, todėl patikrinkite jas tiesiogiai: išsaugota 4xx klaida atkartojama kaip bet kuris kitas atsakymas, tuo tarpu 5xx klaida apskritai neišsaugoma, todėl bandant pakartoti operaciją po serverio klaidos, ji vykdoma iš naujo, užuot grąžinus išsaugotą rezultatą. Raktai taip pat turi galiojimo laiką (Nordlet atveju – 24 valandas), kuris riboja, kiek laiko galimas atsako atkartojimas.

Nordlet dokumentacija užtikrina, kad pridėjus Idempotency-Key antraštę išvengiama dublikato kūrimo pakartojant užklausą, o API konvencijos apibrėžia tikslią pakartojimo antraštę ir reikalavimą gauti atsakymą baitu tikslumu (byte-for-byte). Šis principas atitinka skelbiamą Stripe modelį: raktas identifikuoja loginę operaciją, pakartojimai grąžina išsaugotą rezultatą, o tas pats raktas su skirtingais parametrais yra atmetamas, užuot jį tyliai pakeitus.

Sėkmingo testo kriterijus. Egzistuoja lygiai vienas finansinės būsenos pasikeitimas nepriklausomai nuo to, kiek kartų klientas siunčia tą pačią užklausą rakto galiojimo lange.

Idempotentiškumas: tas pats raktas, pakeistas kūnas

Išsiųskite pradinę užklausą su raktu K ir kūnu B1, po to antrą užklausą su raktu K ir kūnu B2, kuriame skiriasi bent viena suma, pirkėjas, data ar eilutė.

Laukiamas rezultatas: užklausa atmetama su dokumentuota rakto pakartotinio naudojimo klaida – Nordlet grąžina 422 idempotency_key_reuse – pradinis įrašas lieka nepaliestas, neatsiranda joks antras įrašas, numeris ar audito įvykis, ir klientas to „neištaiso“ generuodamas naują raktą. Jei sistema tyliai priimtų B2, kartojimo raktai taptų nesaugūs.

Vienalaikės dubliuojančios užklausos

Vienu metu išsiųskite dvi identiškas užklausas su tuo pačiu raktu. Priklausomai nuo dokumentuotos elgsenos, viena užklausa įvykdoma, o kita gauna vykdomo konflikto pranešimą (in-progress conflict) – Nordlet atveju grąžinama 409 idempotency_in_progress – arba ilgainiui abi užklausos gauna tą patį rezultatą.

Įsitikinkite, kad abi užklausos negali sukurti nepriklausomų finansinių įrašų, priskiriamas ne daugiau kaip vienas dokumento numeris, laikinas konfliktas bandomas pakartoti su tuo pačiu raktu (o ne sukuriant naują), galutinis resursas yra užbaigtas ir nuskaitomas, o idempotentiškumo įrašas neužstringa visam laikui.

Klaidos atvejis. Užklausų kartojimo biblioteka, kuri kiekvienam bandymui sukuria po naują UUID, vieną loginę operaciją paverčia keliais nepriklausomais įrašais ir visiškai panaikina idempotentiškumo prasmę.

Neaiški baigtis nutrūkus ryšiui

Tai pati svarbiausia simuliacija siekiant atkartoti gamybinės aplinkos problemas. Išsiųskite užklausą su raktu K, leiskite serveriui ją patvirtinti, nutraukite ryšį prieš gaudami atsakymą, užfiksuokite baigtį kaip nežinomą, tada pakartokite užklausą su tuo pačiu raktu K ir patikrinkite rezultatą nuskaitant resursą ir audito duomenis.

Įsitikinkite, kad pakartotinis bandymas grąžina pirminį arba dokumentuotą atkartotą atsakymą, egzistuoja lygiai vienas finansinis veiksmas, klientas pažymi operaciją kaip baigtą tik po sėkmingo atkartojimo arba sutikrinimo (reconciliation) nuskaitymo, ir nesukuriamas joks naujas raktas. Laikotarpio pabaigos (timeout) klaida nereiškia, kad „nieko neįvyko“. Stripe apibūdina idempotentiškumą būtent kaip apsaugą nuo ryšio klaidų, kai serveris gali įvykdyti užklausą, tačiau klientas negauna atsakymo.

Konservatyvi pakartotinių užklausų politika

Sprendimai dėl pakartotinių užklausų turi priklausyti tiek nuo klaidos tipo, tiek nuo operacijos idempotentiškumo, o ne vien nuo HTTP metodo.

Dažniausiai kartojamos, išlaikant tą patį raktą: nutrūkęs ryšys (connection reset) arba užklausos laiko pabaiga (timeout) po idempotentiškos užklausos, 408, 429 (išlaukus pagal retry-after instrukciją) ir 502/503/504. Dokumentuotą in-progress idempotentiškumo klaidą galima pakartoti po nedidelio laiko tarpo.

Nekartojamos be papildomo sutikrinimo: 400/422 validacijos klaidos, 401/403 autentifikacijos klaidos, 404 dėl nerasto resurso, 409 verslo logikos konfliktai, nesusiję su tebevykdomu idempotentiškumo raktu, pakeista užklausos struktūra su tuo pačiu raktu ir klaida dėl uždaryto apskaitos periodo.

Įsitikinkite, kad naudojamas ribotas eksponentinis vėlavimas su pridėtu atsitiktinumu (bounded exponential backoff with jitter), aiškiai apibrėžtas maksimalus bandymų skaičius ir praėjęs laikas, paisoma retry-after dėl greičio ribojimų (rate limits), tas pats raktas išlaikomas visiems vienos operacijos pakartojimams, o naujai operacijai generuojamas naujas raktas; be to, žurnalai (logs) atskiria pirminį bandymą nuo pakartojimų.

Atskirai ištestuokite greičio ribojimą. Viršykite dokumentuotą limitą – pagal nutylėjimą Nordlet leidžia 300 užklausų per minutę vienam API raktui, o kai kuriems neautentifikuotiems galiniams punktams taikomi dar griežtesni limitai – tada įsitikinkite, kad serveris grąžina greičio ribojimo (rate-limit) atsakymą, klientas interpretuoja retry-after kaip pauzę, o ne kaip klaidą, jis pristabdo užklausas, užuot be perstojo jas siuntęs, ir kad pakartotinai siunčiama ribojama užklausa naudoja originalų raktą. x-ratelimit-* antraštės nurodo likusį biudžetą, kuris gali pasitarnauti kaip geras indikatorius prieš atliekant tvirtinimą (pre-assertion). Atskirkite greičio ribojimo testus nuo finansinių įrašų tvirtinimų, nebent jūsų testavimo įrankis gali atskirti atidėtą (throttled) bandymą nuo sėkmingo (committed).

Webhook parašo tikrinimas

Sukurkite imtuvą, kuris išsaugo neapdorotus (raw) baitus. Kiekvienam įvykiui: išsaugokite neapdorotą užklausos kūną, nuskaitykite x-nordlet-signature antraštę, apskaičiuokite laukiamą HMAC-SHA256 naudodami prenumeratos paslaptį (secret), palyginkite rezultatus naudodami laiko atžvilgiu pastovią funkciją (constant-time function), apdorokite (parse) JSON tik po to, kai parašas bus patvirtintas, užregistruokite gavimą ir grąžinkite greitą 2xx atsakymą tik patikimai jį priėmę (durable acceptance). Nordlet pasirašo HMAC pagal neapdorotą kūną, siunčia jį kaip sha256=<hex> ir kartoja išsiuntimą naudodama eksponentinį vėlavimą. Stripe webhook instrukcijos taip pat pabrėžia nepakeisto neapdoroto kūno tikrinimą naudojant laiko atžvilgiu pastovų palyginimą.

Atlikite negatyvius testus: teisingas kūnas ir paslaptis, teisingas kūnas, bet neteisinga paslaptis, vieno baito pakeitimas kūne, per naujo serializuotas JSON su pakeistais tarpais, trūkstama antraštė, neteisingai suformuotas paražas, pakartotas senas pristatymas (jei schemoje naudojama laiko žyma) ir galiojantis paražas, išsiųstas klaidingai prenumeratai.

Sėkmingo testo kriterijai. Priimamas tik teisingas neapdorotas kūnas ir paslaptis. Neteisingi parašai gauna atsakymą, kurio statusas nėra 2xx. Netinkami pranešimai niekada nepatenka į apskaitos eilę. Paslaptys nepatenka į įprastus įrašų žurnalus (logs). Handler'is (apdorotojas) patvirtina užklausos gavimą (acknowledges) tik tada, kai įvykis yra patikimai išsaugotas.

Dubliuojantys ir ne iš eilės gaunami webhook

Pristatymo patikimumas yra atskira problema nuo API idempotentiškumo, todėl imtuvas taip pat turi būti idempotentiškas. Pristatykite tą patį įvykį du kartus, pristatykite sale_invoice.paid įvykį anksčiau nei sale_invoice.issued įvykį, grąžinkite 500 klaidą po įvykio išsaugojimo, bet prieš grąžinant atsakymą API, ir pakartotinai pristatykite įvykį, kurį vartotojas jau apdorojo.

Įsitikinkite, kad dubliuoti pristatymai nesudubliuoja mokėjimų, būsenos pakeitimų ar operacijų didžiojoje knygoje; kad deduplikacijos raktas naudoja paslaugos teikėjo pristatymo arba įvykio ID, jei toks yra (arba dokumentuotą sudėtinį raktą, o ne tiesiog laiko žymą); kad ne iš eilės atėję įvykiai niekada neperrašo naujesnės būsenos senesne; kad vartotojas gali nuskaityti esamą būseną iš API, kai eiliškumas yra nepakankamas, ir kad nesėkmingi bandymai siunčiami per eilę (queue) arba "dead-letter" keliu. Stripe atvirai įspėja, kad pristatymo eiliškumas nėra garantuojamas, ir rekomenduoja išsaugoti apdorotų įvykių ID.

Palikite API galinį punktą kuo paprastesnį: patikrinkite struktūrą (shape), patikrinkite parašą, išsaugokite arba įdėkite į eilę, patvirtinkite (acknowledge) ir grąžinkite 2xx. Sutikrinimas ir pranešimai turi būti palikti asinchroniniam apdorojimui. Ištestuokite tai uždelsdami (sleep) tolimesnius procesus taip, kad jie viršytų pristatymo laukimo laiką (timeout); teisingas imtuvas vis tiek patvirtina užklausos gavimą (acknowledge) po sėkmingo perdavimo į eilę.

Atviri ir uždaryti apskaitos periodai

Nordlet reikalauja, kad įrašymo (posting) metu būtų patikrinta, ar periodas neuždarytas – tai taikoma rankiniams didžiosios knygos įrašams, dokumentų srautams ir duomenų importui, todėl ištestuokite šią kontrolę keliose vietose. Sukurkite atitikmenis turinčius dokumentus, kurių data patenka į atvirą periodą, į uždarytą periodą, į ribą prieš pat periodo uždarymą, į pirmąją kito atviro periodo dieną, taip pat dokumentą su teisinga dokumento data, bet neteisinga įrašymo (posting) data, jei API jas atskiria.

Uždaryto periodo atveju įsitikinkite, kad užklausa yra atmetama grąžinant dokumentuotą periodo uždarymo klaidą – Nordlet tai yra 409 conflict – ir kad nesukuriamos jokios didžiosios knygos eilutės, nepanaudojamas joks dokumento numeris, dokumentas netampa užregistruotu (posted) ir neišsiunčiamas sėkmingą operaciją liudijantis webhook. Tuo tarpu atviro periodo versija turi būti sėkminga ir turėti tokias pačias finansines vertes.

Lenktynių sąlygų testas (Race test). Pradėkite įrašo kūrimą (posting) atvirame periode, o užklausos vykdymo metu (mid-request) uždarykite periodą; tada įsitikinkite, kad vykdymas negali apeiti šio uždarymo. Svarbiausia taisyklė norint, kad testas būtų sėkmingas: užregistruotas įrašas niekada neturi atsidurti periode, kuris buvo uždarytas dar prieš transakcijos įvykdymą (commit).

Audituojamumas ir sutikrinimas (reconciliation)

Po kiekvienos sėkmingos operacijos patvirtinkite, kad verslo objektas egzistuoja, apskaitos įrašas egzistuoja ir debetas lygus kreditui, audito įrašas egzistuoja, webhook įvykis egzistuoja arba gali būti nuskaitytas, o jūsų operacijos įraše nurodytas paslaugos teikėjo objekto ID, kurio pakartotiniai bandymai nurodo į tą pačią loginę operaciją.

Po kiekvienos atmestos operacijos įsitikinkite, kad nėra jokio dalinio dokumento įrašo, numeris nebuvo panaudotas, nebent kontraktas leidžia rezervuoti, nėra jokio didžiosios knygos įrašo, nėra jokio sėkmingos operacijos webhook, o klaida turi užklausos ID, skirtą diagnostikai. Nordlet konvencijos apibrėžia duomenų keitimo operacijų audituojamumą ir subalansuotus dvejybinius įrašus kaip platformos garantijas, o balansą užtikrina atidėtas duomenų bazės trigeris (deferred database trigger) įrašo patvirtinimo (commit) metu, o ne tik aplikacijos kodas. Paverskite šias garantijas po testavimo atliekamomis sutikrinimo (reconciliation) užklausomis, užuot pasitikėję tik HTTP atsakymu.

Pagrindinė testų matrica

Sritis Testuojamas veiksmas Laukiamas tvirtinimas Sėkmingo testo kriterijus
Autentifikacija Nėra rakto, neteisingas raktas, nepakankama prieigos sritis Struktūrizuota 401/403 klaida; jokių operacijos pasekmių (no side effect) Visi atmesti bandymai nesukuria jokio apskaitos įrašo
Schema ir piniginės sumos Neteisinga dešimtainė trupmena, data, trūkstamas privalomas laukas Laukų lygio validacijos klaida Nevykdomas joks pakartotinis bandymas arba dalinis įrašymas
Įprastas įrašymas (posting) Sąskaitos faktūros sukūrimas ir išrašymas atvirame periode Vienas dokumentas, vienas subalansuotas dvejybinis įrašas, vienas audito įrašas Nuskaityta būsena ir didžioji knyga atitinka
Pakartojimas su tuo pačiu raktu Pakartota identiška operacija, tas pats raktas ir kūnas Grąžinamas pirminis rezultatas; jokių dublikatų Objekto ID, numeris, poveikis didžiajai knygai ir audito įrašas nesidubliuoja
Pakeistas kūnas, tas pats raktas Rakto pakartotinis panaudojimas su kita pinigų suma Dokumentuotas atmetimas dėl rakto panaudojimo pakartotinai Pirminis įrašas lieka nepakeistas; nieko naujo neįrašoma
Nutrūkęs ryšys Įvykdoma (commit), nutraukiama, kartojama su tuo pačiu raktu Pakartotas (replayed) rezultatas Tiksliai viena finansinė pasekmė
Uždarytas periodas Dokumento su data, patenkančia į uždarytą periodą, įrašymas Atmetimas dėl uždaryto periodo Jokių įrašų didžiojoje knygoje, jokio numerio priskyrimo, jokio webhook pranešimo apie sėkmę
webhook parašas Klaidinga paslaptis, pakeistas kūnas Ne 2xx atsakymas iš imtuvo Priimamas tik teisingas neapdorotas kūnas (raw body) ir paslaptis

Ką daryčiau pirmiausia

Jei laiko nedaug, vykdykite testus tokia tvarka, kuri padės pagauti daugiausiai kainuojančias klaidas. Pradėkite nuo nutrūkusio ryšio ir pakartojimo testo, nes šis vienintelis scenarijus sukelia daugiausia realių dublikatų. Po to testuokite idempotentiškumą su tuo pačiu raktu ir pakeistu kūnu. Tuomet – uždarytus periodus, nes įrašymas uždarytame mėnesyje yra audito problema, kuri iškyla gana vėlai. Toliau seka parašų tikrinimas ir ne iš eilės gaunami webhook, o pilnas schemos ir autentifikacijos matricų testavimas gali vykti nepertraukiamai (CI) po to, kai klientas tampa stabilus.

Visa kita šiame plane papildo šiuos penkis punktus. Pasiekite, kad jie praeitų smėliadėžės įmonėje (būtų „žali“), o nuskaitymo sutikrinimai (reconciliation reads) patvirtintų rezultatų teisingumą – ir galėsite būti tikri, kad integracija yra saugi, dar prieš jai paliečiant tikrą apskaitos didžiąją knygą. Smėliadėžės įmonę ir ribotą testinį raktą galite sukurti per kelias minutes skiltyje Get started, o kokių modulių jums reikės, galite pasitikrinti features sąraše.

D.U.K.

Ar 2xx atsakymo pakanka patvirtinti, kad apskaitos operacija buvo sėkminga?

Ne. Statuso kodas patvirtina tik tai, kad serveris atsakė, bet ne tai, kad egzistuoja lygiai vienas dokumentas, vienas priskirtas numeris ir vienas subalansuotas dvejybinis įrašas. Po kiekvieno pakeitimo testo, gavus atsakymą, turėtų sekti sukurto objekto, jo apskaitos įtakos ir audito įrašo nuskaitymas. Pavojingiausias atvejis yra priešingas scenarijus: kai operacija įvykdyta (committed), tačiau klientas atsakymo taip ir negavo.

Ar turėčiau sugeneruoti naują idempotentiškumo raktą, kai pasibaigia užklausos laukimo laikas (timeout)?

Ne, ir tai yra ta klaida, dėl kurios gamybinėje aplinkoje atsiranda daugiausiai dublikatų. Raktas identifikuoja loginę verslo operaciją, o ne bandymą prisijungti. Pakartokite užklausą su tuo pačiu raktu ir sutikrinkite nuskaitydami resursą. Užklausų kartojimo biblioteka, generuojanti naują UUID kiekvienam bandymui, vieną planuotą sąskaitą faktūrą paverčia keliais nepriklausomais įrašais.

Kas nutiks, jei pakartotinai panaudosiu idempotentiškumo raktą su kitais duomenimis?

Teisingas API tokią užklausą atmeta, o ne tyliai pritaiko naują kūną. Nordlet grąžina 422 idempotency_key_reuse ir palieka pirminį įrašą nepaliestą. Jūsų klientas turėtų tai vertinti kaip programavimo klaidą, kurią reikia ištaisyti, o ne kaip problemą, kurią galima apeti sugeneruojant naują raktą.

Ar webhook gali atstoti sukurto objekto nuskaitymą?

Ne. Webhook pristatymas tik įrodo, kad pranešimas buvo išsiųstas išorėn, o ne tai, kad transakcija buvo įvykdyta (committed) taip, kaip tikėjotės. Be to, pristatymo eiliškumas nėra garantuojamas. Patikrinkite parašą pagal neapdorotą (raw) kūną, atmeskite dublikatus (deduplicate) pagal pristatymo arba įvykio ID, ir nuskaitykite esamą būseną iš API kaskart, kai vien įvykių eiliškumo nepakanka norint nustatyti, kas pasikeitė.

Kaip testuoti įrašo registravimą (posting) į uždarytą apskaitos periodą?

Sukurkite lygiaverčius dokumentus atvirame ir uždarytame perioduose, bei įsitikinkite, kad uždaryto periodo atveju užklausa atmetama be jokių sugeneruotų didžiosios knygos eilučių, be panaudoto dokumento numerio, be jokių būsenos pasikeitimų ir be sėkmingo webhook pranešimo. Tada atlikite lenktynių sąlygų (race) versijos testą: pradėkite įrašą atvirame periode ir užklausos vykdymo metu uždarykite jį. Užregistruotas įrašas niekada neturi atsidurti periode, kuris buvo uždarytas dar prieš įvykdant (commit) transakciją.

Ar galiu atlikti didelės apimties dublikatų testus smėliadėžės (sandbox) įmonėje?

Taip. Smėliadėžės įmonė veikia kaip ir reali įmonė, tik yra pažymėta kaip testinė (test data) ir po to nedelsiant ištrinama (o ne laikoma per visą duomenų saugojimo langą), todėl tai yra tinkama vieta atlikti destruktyvius ir dubliavimo testus. Naudojimasis smėliadėže vis tiek apskaitomas ir apmokestinamas kaip realus naudojimas, todėl planuokite apimtis, o ne vykdykite testus nesibaigiančiu ciklu.