Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

V projektoch súvisiacich s rozvojom architektúry mikroslužieb sa CI/CD posúva z kategórie príjemnej príležitosti do kategórie naliehavej potreby. Automatizované testovanie je neoddeliteľnou súčasťou nepretržitej integrácie, kompetentný prístup môže tímu poskytnúť veľa príjemných večerov s rodinou a priateľmi. V opačnom prípade hrozí, že projekt nebude nikdy dokončený.

Je možné pokryť celý kód mikroslužby jednotkovými testami s falošnými objektmi, ale to len čiastočne rieši problém a zanecháva veľa otázok a ťažkostí, najmä pri testovaní práce s dátami. Ako vždy, medzi tie najpálčivejšie patrí testovanie konzistencie dát v relačnej databáze, testovanie práce s cloudovými službami a vytváranie nesprávnych predpokladov pri písaní falošných objektov.

Toto všetko a ešte niečo navyše sa dá vyriešiť testovaním celej mikroslužby v kontajneri Docker. Nepochybnou výhodou na zabezpečenie platnosti testov je, že sa testujú rovnaké obrázky Docker, ktoré idú do výroby.

Automatizácia tohto prístupu predstavuje množstvo problémov, ktorých riešenie bude popísané nižšie:

  • konflikty paralelných úloh v rovnakom hostiteľovi dokovacieho zariadenia;
  • konflikty identifikátorov v databáze počas testovacích iterácií;
  • čakanie, kým budú pripravené mikroslužby;
  • zlučovanie a odosielanie protokolov do externých systémov;
  • testovanie odchádzajúcich požiadaviek HTTP;
  • testovanie webových zásuviek (pomocou SignalR);
  • testovanie autentifikácie a autorizácie OAuth.

Tento článok je založený na moja reč na SECR 2019. Takže pre tých, ktorí sú príliš leniví na čítanie, tu je záznam prejavu.

Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

V tomto článku vám poviem, ako pomocou skriptu spustiť testovanú službu, databázu a služby Amazon AWS v Docker, potom testy na Postman a po ich dokončení zastaviť a odstrániť vytvorené kontajnery. Testy sa vykonávajú pri každej zmene kódu. Týmto spôsobom zabezpečíme, aby každá verzia správne fungovala s databázou a službami AWS.

Rovnaký skript spúšťajú samotní vývojári na svojich Windows desktopoch aj server Gitlab CI pod Linuxom.

Aby bolo opodstatnené, zavedenie nových testov by nemalo vyžadovať inštaláciu dodatočných nástrojov ani na počítači vývojára, ani na serveri, kde sa testy spúšťajú v rámci commit.Docker tento problém rieši.

Test sa musí spustiť na lokálnom serveri z nasledujúcich dôvodov:

  • Sieť nie je nikdy úplne spoľahlivá. Z tisíc žiadostí môže jedna zlyhať;
    V tomto prípade automatický test nebude fungovať, práca sa zastaví a budete musieť hľadať dôvod v protokoloch;
  • Niektoré služby tretích strán nepovoľujú príliš časté požiadavky.

Okrem toho je nežiaduce používať stojan, pretože:

  • Stojan môže byť rozbitý nielen zlým kódom, ktorý na ňom beží, ale aj údajmi, ktoré správny kód nedokáže spracovať;
  • Bez ohľadu na to, ako veľmi sa snažíme vrátiť späť všetky zmeny vykonané testom počas samotného testu, niečo sa môže pokaziť (prečo inak testovať?).

O projekte a organizácii procesov

Naša spoločnosť vyvinula mikroservisnú webovú aplikáciu spustenú v Dockeri v cloude Amazon AWS. Unit testy boli už na projekte použité, no často sa vyskytli chyby, ktoré unit testy neodhalili. Bolo potrebné otestovať celú mikroslužbu spolu s databázou a službami Amazonu.

Projekt využíva štandardný nepretržitý integračný proces, ktorý zahŕňa testovanie mikroslužby pri každom potvrdení. Po priradení úlohy vývojár vykoná zmeny v mikroslužbe, manuálne ju otestuje a spustí všetky dostupné automatizované testy. V prípade potreby vývojár zmení testy. Ak sa nenájdu žiadne problémy, vykoná sa potvrdenie vo vetve tohto problému. Po každom potvrdení sa na serveri automaticky spustia testy. Zlúčenie do spoločnej vetvy a spustenie automatických testov na nej nastáva po úspešnej kontrole. Ak testy na zdieľanej pobočke prejdú, služba sa automaticky aktualizuje v testovacom prostredí na Amazon Elastic Container Service (bench). Stojan je nevyhnutný pre všetkých vývojárov a testerov a nie je vhodné ho rozbíjať. Testeri v tomto prostredí kontrolujú opravu alebo novú funkciu vykonaním manuálnych testov.

Architektúra projektu

Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

Aplikácia pozostáva z viac ako desiatich služieb. Niektoré z nich sú napísané v .NET Core a niektoré v NodeJs. Každá služba beží v kontajneri Docker v službe Amazon Elastic Container Service. Každý má svoju vlastnú databázu Postgres a niektoré majú aj Redis. Neexistujú žiadne spoločné databázy. Ak viaceré služby potrebujú rovnaké údaje, potom sa tieto údaje, keď sa zmenia, prenesú do každej z týchto služieb prostredníctvom SNS (Simple Notification Service) a SQS (Amazon Simple Queue Service) a služby si ich uložia do svojich vlastných oddelených databáz.

SQS a SNS

SQS vám umožňuje zaradiť správy do frontu a čítať správy z frontu pomocou protokolu HTTPS.

Ak niekoľko služieb číta jeden front, potom každá správa dorazí iba do jednej z nich. Je to užitočné pri spustení niekoľkých inštancií tej istej služby, aby sa medzi ne rozložilo zaťaženie.

Ak chcete, aby bola každá správa doručená viacerým službám, každý príjemca musí mať svoj vlastný front a SNS je potrebné na duplikovanie správ do viacerých frontov.

V SNS vytvoríte tému a odoberáte ju, napríklad poradie SQS. Môžete posielať správy k téme. V tomto prípade sa správa odošle do každého frontu prihláseného na odber tejto témy. SNS nemá spôsob čítania správ. Ak počas ladenia alebo testovania potrebujete zistiť, čo sa odosiela SNS, môžete vytvoriť front SQS, prihlásiť sa na odber požadovanej témy a prečítať si front.

Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

Brána API

Väčšina služieb nie je priamo dostupná z internetu. Prístup je cez API Gateway, ktorá kontroluje prístupové práva. Aj toto je naša služba a existujú na to aj testy.

Upozornenia v reálnom čase

Aplikácia používa SignalRaby sa používateľovi zobrazovali upozornenia v reálnom čase. Toto je implementované v oznamovacej službe. Je prístupný priamo z internetu a sám funguje s OAuth, pretože sa ukázalo ako nepraktické zabudovať podporu pre webové sokety do brány v porovnaní s integráciou OAuth a notifikačnej služby.

Dobre známy testovací prístup

Unit testy nahrádzajú veci ako databáza falošnými objektmi. Ak sa napríklad mikroslužba pokúsi vytvoriť záznam v tabuľke s cudzím kľúčom a záznam, na ktorý tento kľúč odkazuje, neexistuje, požiadavku nemožno dokončiť. Jednotkové testy to nedokážu zistiť.

В článok od Microsoftu Navrhuje sa použiť databázu v pamäti a implementovať falošné objekty.

Databáza v pamäti je jedným z DBMS podporovaných Entity Framework. Bol vytvorený špeciálne na testovanie. Údaje v takejto databáze sa uchovávajú len dovtedy, kým sa neskončí proces, ktorý ju používa. Nevyžaduje vytváranie tabuliek a nekontroluje integritu údajov.

Mock objekty modelujú triedu, ktorú nahrádzajú, len do tej miery, do akej vývojár testu rozumie, ako to funguje.

Ako dosiahnuť, aby sa Postgres automaticky spustil a vykonal migráciu pri spustení testu, nie je uvedené v článku spoločnosti Microsoft. Moje riešenie to robí a navyše do samotnej mikroslužby nepridáva žiadny kód špeciálne pre testy.

Prejdime k riešeniu

Počas procesu vývoja sa ukázalo, že testy jednotiek nestačia na včasné nájdenie všetkých problémov, a preto sa rozhodlo pristupovať k tejto problematike z iného uhla.

Nastavenie testovacieho prostredia

Prvou úlohou je nasadenie testovacieho prostredia. Kroky potrebné na spustenie mikroslužby:

  • Nakonfigurujte testovanú službu pre lokálne prostredie, špecifikujte podrobnosti pre pripojenie k databáze a AWS v premenných prostredia;
  • Spustite Postgres a vykonajte migráciu spustením Liquibase.
    V relačných DBMS musíte pred zápisom údajov do databázy vytvoriť dátovú schému, inými slovami, tabuľky. Pri aktualizácii aplikácie musia byť tabuľky prenesené do podoby, akú používa nová verzia, a pokiaľ možno bez straty údajov. Toto sa nazýva migrácia. Vytváranie tabuliek v pôvodne prázdnej databáze je špeciálnym prípadom migrácie. Migráciu je možné zabudovať do samotnej aplikácie. .NET aj NodeJS majú migračné rámce. V našom prípade sú z bezpečnostných dôvodov mikroslužby zbavené práva na zmenu dátovej schémy a migrácia sa vykonáva pomocou Liquibase.
  • Spustite Amazon LocalStack. Toto je implementácia služieb AWS na spustenie doma. Na Docker Hub je hotový obrázok pre LocalStack.
  • Spustite skript na vytvorenie potrebných entít v LocalStack. Shell skripty používajú AWS CLI.

Používa sa na testovanie na projekte poštár. Existovala aj predtým, no bola spustená manuálne a testovala sa aplikácia už nasadená v stánku. Tento nástroj vám umožňuje vytvárať ľubovoľné požiadavky HTTP(S) a kontrolovať, či odpovede zodpovedajú očakávaniam. Dotazy sa skombinujú do kolekcie a celú kolekciu možno spustiť.

Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

Ako funguje automatický test?

Počas testu v Dockeri všetko funguje: testovaná služba, Postgres, migračný nástroj aj Postman, respektíve jeho konzolová verzia – Newman.

Docker rieši množstvo problémov:

  • Nezávislosť od konfigurácie hostiteľa;
  • Inštalácia závislostí: Docker stiahne obrázky z Docker Hub;
  • Vrátenie systému do pôvodného stavu: jednoduché odstránenie nádob.

docker-compose spája kontajnery do virtuálnej siete izolovanej od internetu, v ktorej sa kontajnery navzájom nachádzajú podľa názvov domén.

Test je riadený skriptom shellu. Na spustenie testu v systéme Windows používame git-bash. Jeden skript teda stačí pre Windows aj Linux. Git a Docker sú nainštalované všetkými vývojármi projektu. Pri inštalácii Git na Windows je nainštalovaný git-bash, takže ho má každý.

Skript vykonáva nasledujúce kroky:

  • Vytváranie obrázkov doku
    docker-compose build
  • Spustenie databázy a LocalStack
    docker-compose up -d <контейнер>
  • Migrácia databázy a príprava LocalStacku
    docker-compose run <контейнер>
  • Spustenie testovanej služby
    docker-compose up -d <сервис>
  • Spustenie testu (Newman)
  • Zastavenie všetkých kontajnerov
    docker-compose down
  • Uverejňovanie výsledkov v Slack
    Máme chat, kde chodia správy so zeleným začiarknutím alebo červeným krížikom a odkazom na denník.

Nasledujúce obrázky Docker sú zahrnuté v týchto krokoch:

  • Testovaná služba má rovnaký imidž ako pri výrobe. Konfigurácia pre test je cez premenné prostredia.
  • Pre Postgres, Redis a LocalStack sa používajú hotové obrázky z Docker Hub. Existujú aj hotové obrázky pre Liquibase a Newman. My staviame naše na ich kostre, pridávame tam naše súbory.
  • Na prípravu LocalStack použijete hotový obrázok AWS CLI a vytvoríte obrázok obsahujúci skript založený na ňom.

použitím objemy, nemusíte vytvárať obrázok Docker len na pridávanie súborov do kontajnera. Objemy však nie sú vhodné pre naše prostredie, pretože samotné úlohy Gitlab CI bežia v kontajneroch. Docker môžete ovládať z takéhoto kontajnera, ale zväzky pripájajú iba priečinky z hostiteľského systému a nie z iného kontajnera.

Problémy, s ktorými sa môžete stretnúť

Čakanie na pripravenosť

Keď je spustený kontajner so službou, neznamená to, že je pripravený prijímať pripojenia. Musíte počkať, kým bude pripojenie pokračovať.

Tento problém sa niekedy rieši pomocou skriptu wait-for-it.sh, ktorý čaká na príležitosť nadviazať TCP spojenie. LocalStack však môže vyvolať chybu 502 Bad Gateway. Okrem toho pozostáva z mnohých služieb a ak je jedna z nich pripravená, o ostatných to nič nehovorí.

rozhodnutie: skripty na poskytovanie LocalStack, ktoré čakajú na odpoveď 200 od SQS aj SNS.

Konflikty paralelných úloh

Na tom istom hostiteľovi Docker môže súčasne prebiehať viacero testov, takže názvy kontajnerov a sietí musia byť jedinečné. Navyše, testy z rôznych vetiev tej istej služby môžu bežať aj súčasne, takže nestačí napísať ich mená do každého komponovaného súboru.

rozhodnutie: Skript nastaví premennú COMPOSE_PROJECT_NAME na jedinečnú hodnotu.

Funkcie systému Windows

Pri používaní Dockeru v systéme Windows chcem poukázať na niekoľko vecí, pretože tieto skúsenosti sú dôležité na pochopenie toho, prečo sa vyskytujú chyby.

  1. Skripty shellu v kontajneri musia mať konce riadkov systému Linux.
    Symbol shell CR je syntaktická chyba. Z chybového hlásenia je ťažké povedať, že je to tak. Pri úprave takýchto skriptov v systéme Windows potrebujete správny textový editor. Okrem toho musí byť správne nakonfigurovaný systém správy verzií.

Takto je git nakonfigurovaný:

git config core.autocrlf input

  1. Git-bash emuluje štandardné priečinky Linuxu a pri volaní súboru exe (vrátane docker.exe) nahrádza absolútne cesty systému Linux cestami systému Windows. To však nedáva zmysel pre cesty, ktoré nie sú na lokálnom počítači (alebo cesty v kontajneri). Toto správanie nemožno zakázať.

rozhodnutie: pridajte ďalšiu lomku na začiatok cesty: //bin namiesto /bin. Linux takýmto cestám rozumie, preňho je niekoľko lomiek rovnakých ako jedna. Ale git-bash takéto cesty nepozná a nepokúša sa ich konvertovať.

Výstup denníka

Pri spustení testov by som chcel vidieť protokoly z Newmana aj testovanej služby. Keďže udalosti týchto protokolov sú vzájomne prepojené, ich spojenie v jednej konzole je oveľa pohodlnejšie ako dva samostatné súbory. Newman sa spustí cez docker-compose runa tak jeho výstup skončí v konzole. Ostáva už len zabezpečiť, aby tam išiel aj výstup služby.

Pôvodné riešenie bolo urobiť ukotviť žiadna vlajka -d, ale pomocou možností shellu pošlite tento proces na pozadie:

docker-compose up <service> &

Toto fungovalo, kým nebolo potrebné posielať protokoly z Dockera do služby tretej strany. ukotviť prestal odosielať protokoly do konzoly. Tým však fungoval pripojiť dokovacia stanica.

rozhodnutie:

docker attach --no-stdin ${COMPOSE_PROJECT_NAME}_<сервис>_1 &

Konflikt identifikátorov počas testovania

Testy prebiehajú v niekoľkých iteráciách. Databáza nie je vyčistená. Záznamy v databáze majú jedinečné ID. Ak zapíšeme konkrétne ID do požiadaviek, pri druhej iterácii dostaneme konflikt.

Aby sa tomu zabránilo, musia byť identifikátory buď jedinečné, alebo musia byť vymazané všetky objekty vytvorené testom. Niektoré objekty nie je možné z dôvodu požiadaviek vymazať.

rozhodnutie: generovanie identifikátorov GUID pomocou skriptov Postman.

var uuid = require('uuid');
var myid = uuid.v4();
pm.environment.set('myUUID', myid);

Potom použite symbol v dotaze {{myUUID}}, ktorá bude nahradená hodnotou premennej.

Spolupráca cez LocalStack

Ak testovaná služba číta alebo zapisuje do frontu SQS, potom na overenie musí samotný test pracovať aj s týmto frontom.

rozhodnutie: požiadavky od Postmana na LocalStack.

Rozhranie API služieb AWS je zdokumentované, čo umožňuje zadávať dopyty bez súpravy SDK.

Ak služba zapíše do fronty, potom ju prečítame a skontrolujeme obsah správy.

Ak služba posiela správy SNS, v prípravnej fáze LocalStack tiež vytvorí front a prihlási sa na odber tejto témy SNS. Potom všetko príde na to, čo bolo opísané vyššie.

Ak služba potrebuje prečítať správu z frontu, tak v predchádzajúcom testovacom kroku zapíšeme túto správu do frontu.

Testovanie požiadaviek HTTP pochádzajúcich z testovanej mikroslužby

Niektoré služby fungujú cez HTTP s niečím iným ako AWS a niektoré funkcie AWS nie sú implementované v LocalStack.

rozhodnutie: v týchto prípadoch môže pomôcť MockServer, ktorá má hotový obrázok v Docker hub. Očakávané požiadavky a odpovede na ne sú konfigurované požiadavkou HTTP. Rozhranie API je zdokumentované, takže požadujeme od Postmana.

Testovanie overenia a autorizácie OAuth

Používame OAuth a Webové tokeny JSON (JWT). Test vyžaduje poskytovateľa OAuth, ktorého môžeme spustiť lokálne.

Celá interakcia medzi službou a poskytovateľom OAuth spočíva v dvoch požiadavkách: po prvé, je požadovaná konfigurácia /.známa/openid-konfiguráciaa potom sa na adrese z konfigurácie vyžiada verejný kľúč (JWKS). Toto všetko je statický obsah.

rozhodnutie: Náš testovací poskytovateľ OAuth je server so statickým obsahom a dva súbory na ňom. Token je vygenerovaný raz a odovzdaný Gitu.

Vlastnosti testovania SignalR

Poštár nefunguje s websocketmi. Na testovanie SignalR bol vytvorený špeciálny nástroj.

Klient SignalR môže byť viac než len prehliadač. Pod .NET Core je preň k dispozícii klientska knižnica. Klient napísaný v .NET Core nadviaže spojenie, overí sa a čaká na špecifickú sekvenciu správ. Ak je prijatá neočakávaná správa alebo sa stratí spojenie, klient ukončí prácu s kódom 1. Ak bude prijatá posledná očakávaná správa, klient opustí program s kódom 0.

Newman pracuje súčasne s klientom. Spustí sa niekoľko klientov, aby skontrolovali, či sú správy doručené každému, kto ich potrebuje.

Automatizované testovanie mikroslužieb v Dockeri pre nepretržitú integráciu

Na spustenie viacerých klientov použite možnosť --stupnica na príkazovom riadku docker-compose.

Pred spustením skript Postman čaká, kým všetci klienti nadviažu spojenie.
S problémom čakania na spoj sme sa už stretli. Ale boli tam servery a tu je klient. Je potrebný iný prístup.

rozhodnutie: klient v kontajneri používa mechanizmus Kontrola zdraviainformovať skript na hostiteľovi o jeho stave. Klient vytvorí súbor na špecifickej ceste, povedzme /healthcheck, hneď ako sa vytvorí spojenie. Skript HealthCheck v súbore docker vyzerá takto:

HEALTHCHECK --interval=3s CMD if [ ! -e /healthcheck ]; then false; fi

Tím docker skontrolovať Zobrazuje normálny stav, zdravotný stav a výstupný kód pre kontajner.

Po dokončení Newman skript skontroluje, že všetky kontajnery s klientom boli ukončené s kódom 0.

Happinnes existuje

Po prekonaní vyššie popísaných ťažkostí sme mali súbor stabilných bežiacich testov. V testoch každá služba funguje ako jeden celok, ktorý interaguje s databázou a Amazon LocalStack.

Tieto testy chránia tím 30+ vývojárov pred chybami v aplikácii s komplexnou interakciou 10+ mikroslužieb s častým nasadením.

Zdroj: hab.com

Pridať komentár