Contrats axés sur le consommateur ou automatisation des tests d'assurance qualité Gitlab CI-eyed

Les objectifs de cette publication sont :


  • Une brève introduction aux contrats axĂ©s sur le consommateur (CDC)
  • Configurer le pipeline CI basĂ© sur CDI

Contrats axés sur le consommateur


Dans cette partie, nous passerons en revue les principaux points du CDC. Cet article n'est pas exhaustif au sujet des tests de contrat. Il y a une quantité suffisante de documents à ce sujet sur le même Habré .


Pour continuer, nous devons nous familiariser avec les principales dispositions du CDC:


  • Les tests de contact sont au niveau des tests de service / intĂ©gration au-dessus des tests unitaires selon la pyramide Mike Cohn .
  • Les tests de contrat peuvent ĂŞtre appliquĂ©s lorsqu'il y a 2 (ou plus) services qui interagissent les uns avec les autres.
  • L'approche axĂ©e sur le consommateur signifie que la première Ă©tape de la mise en Ĺ“uvre consiste Ă  rĂ©diger un test du cĂ´tĂ© du consommateur. Le rĂ©sultat du test est un pacte (contrat) au format json qui dĂ©crit l'interaction entre le consommateur (par exemple, interface Web / interface mobile: un service qui souhaite recevoir des donnĂ©es) et le fournisseur (par exemple, l'API serveur: un service qui fournit des donnĂ©es)
  • L'Ă©tape suivante consiste Ă  vĂ©rifier le contrat avec le fournisseur. Ceci est pleinement mis en Ĺ“uvre par le cadre du Pacte .

Commençons donc par le test côté consommateur . J'ai utilisé Pactman . Voici à quoi ressemble le test:


import pytest from pactman import Like from model.client import Client @pytest.fixture() def consumer(pact): return Client(pact.uri) def test_app(pact, consumer): expected = '123456789' (pact .given('provider in some state') .upon_receiving("request to get user's phone number") .with_request( method='GET', path=f'/phone/john', ) .will_respond_with(200, body=Like(expected)) .given('provider in some state') .upon_receiving("request to get non-existent user's phone number") .with_request( method='GET', path=f'/phone/micky' ) .will_respond_with(404) ) with pact: consumer.get_users_phone(user='john', host=pact.uri) consumer.get_users_phone(user='micky', host=pact.uri) 

À l'aide de Pact DSL, nous décrivons les interactions demande / réponse. Après avoir commencé le test, nous obtenons un nouveau fichier ({consumer} - {provider} -pact.json):


 { "consumer": { "name": 'basic_client' }, "provider": { "name": 'basic_flask_app' }, "interactions": [ { "providerStates": [ { "name": "provider in some state", "params": {} } ], "description": "request to get user's phone number", "request": { "method": "GET", "path": "/phone/john" }, "response": { "status": 200, "body": "123456789", "matchingRules": { "body": { "$": { "matchers": [ { "match": "type" } ] } } } } }, { "providerStates": [ { "name": "provider in some state", "params": {} } ], "description": "request to get non-existent user's phone number", "request": { "method": "GET", "path": "/phone/micky" }, "response": { "status": 404 } } ], "metadata": { "pactSpecification": { "version": "3.0.0" } } } 

Ensuite, nous devons transmettre le pacte au fournisseur pour vérification. Cela se fait à l'aide de Pact Broker.


Pact Broker est un référentiel de contrats avec quelques fonctionnalités supplémentaires qui nous permettent de suivre la compatibilité des versions de service, ainsi que de générer des diagrammes de réseau (interaction de service).


Courtier Pacte
image


Le pacte
image


Matrice des versions
image


Vérification du fournisseur


Cette partie du test est entièrement réalisée par le framework. Après vérification, les résultats sont renvoyés à Pact Broker.


 provider-verifier_1 | Verifying a pact between basic_client and basic_flask_app provider-verifier_1 | Given provider in some state provider-verifier_1 | request to get user's phone number provider-verifier_1 | with GET /phone/john provider-verifier_1 | returns a response which provider-verifier_1 | WARN: Skipping set up for provider state 'provider in some state' for consumer 'basic_client' as there is no --provider-states-setup-url specified. provider-verifier_1 | has status code 200 provider-verifier_1 | has a matching body provider-verifier_1 | Given provider in some state provider-verifier_1 | request to get non-existent user's phone number provider-verifier_1 | with GET /phone/micky provider-verifier_1 | returns a response which provider-verifier_1 | WARN: Skipping set up for provider state 'provider in some state' for consumer 'basic_client' as there is no --provider-states-setup-url specified. provider-verifier_1 | has status code 404 provider-verifier_1 | provider-verifier_1 | 2 interactions, 0 failures 

Exécution des deux parties du test dans le pipeline


Maintenant que les deux parties du test de contrat ont été démontées, il serait bon de les exécuter à chaque validation. C'est là que Gitlab CI vient à la rescousse. Les travaux de pipeline sont décrits dans .gitlab-ci.yml . Avant de passer au pipeline, nous devons dire quelques mots sur GitLab Runner, qui est un projet open source, utilisé pour exécuter des travaux et renvoyer les résultats à GitLab. Les travaux peuvent être exécutés localement ou à l'aide de conteneurs Docker. Dans notre projet, nous utilisons Docker. L'infrastructure de test est implémentée dans des conteneurs et est décrite dans docker-compose.yml , situé à la racine du projet.


 version: '2' services: basic-flask-app: image: registry.gitlab.com/tknino69/basic_flask_app:latest ports: - 5005:5005 postgres: image: postgres ports: - 5432:5432 env_file: - test-setup.env volumes: - db-data:/var/lib/postgresql/data/pgdata pactbroker: image: dius/pact-broker links: - postgres ports: - 80:80 env_file: - test-setup.env provider-states: image: registry.gitlab.com/tknino69/cdc/provider-states:latest build: provider-states ports: - 5000:5000 consumer-test: image: registry.gitlab.com/tknino69/cdc/consumer-test:latest command: ["sh", "-c", "find -name '*.pyc' -delete && pytest $${TEST}"] links: - pactbroker environment: - CONSUMER_VERSION=$CI_COMMIT_SHA provider-verifier: image: registry.gitlab.com/tknino69/cdc/provider-verifier:latest build: provider-verifier ports: - 5001:5000 links: - pactbroker depends_on: - consumer-test - provider-states command: ['sh', '-c', 'find -name "*.pyc" -delete && CONSUMER_VERSION=`curl --header "PRIVATE-TOKEN:$${API_TOKEN}" https://gitlab.com/api/v4/projects/$${BASIC_CLIENT}/repository/commits | jq ".[0] .id" | sed -e "s/\x22//g"` && echo $${CONSUMER_VERSION} && pact-provider-verifier $${PACT_BROKER}/pacts/provider/$${PROVIDER}/consumer/$${CONSUMER}/version/$${CONSUMER_VERSION} --provider-base-url=$${BASE_URL} --pact-broker-base-url=$${PACT_BROKER} --provider=$${PROVIDER} --consumer-version-tag=$${CONSUMER_VERSION} --provider-app-version=$${PROVIDER_VERSION} -v --publish-verification-results=PUBLISH_VERIFICATION_RESULTS'] environment: - PROVIDER_VERSION=$CI_COMMIT_SHA - API_TOKEN=$API_TOKEN env_file: - test-setup.env volumes: db-data: 

Nous avons donc des services qui s'exécutent dans des conteneurs selon les besoins.


Prestataire de services:


 basic-flask-app: image: registry.gitlab.com/tknino69/basic_flask_app:latest ports: - 5005:5005 

Pact Broker et sa base de données. Les volumes nous permettent d'avoir un référentiel permanent pour les pactes et les résultats de la vérification des fournisseurs:


 postgres: image: postgres ports: - 5432:5432 env_file: - test-setup.env volumes: - db-data:/var/lib/postgresql/data/pgdata pactbroker: image: dius/pact-broker links: - postgres ports: - 80:80 env_file: - test-setup.env 

États fournisseurs de services. En pratique, cela devrait amener le fournisseur dans un certain état (par exemple, obtenir l'utilisateur dans la base de données). Cependant, dans notre exemple, il exécute simplement une fonction fictive.


 provider-states: image: registry.gitlab.com/tknino69/cdc/provider-states:latest build: provider-states ports: - 5000:5000 

Un service qui exécute le Consumer Test. Notez la commande qui s'exécute dans le conteneur find -name '* .pyc' -delete && pytest $$ {TEST}


 consumer-test: image: registry.gitlab.com/tknino69/cdc/consumer-test:latest command: ["sh", "-c", "find -name '*.pyc' -delete && pytest $${TEST}"] links: - pactbroker environment: - CONSUMER_VERSION=$CI_COMMIT_SHA 

Vérificateur de fournisseur de services:


 provider-verifier: image: registry.gitlab.com/tknino69/cdc/provider-verifier:latest build: provider-verifier ports: - 5001:5000 links: - pactbroker depends_on: - consumer-test - provider-states command: ['sh', '-c', 'find -name "*.pyc" -delete && CONSUMER_VERSION=`curl --header "PRIVATE-TOKEN:$${API_TOKEN}" https://gitlab.com/api/v4/projects/$${BASIC_CLIENT}/repository/commits | jq ".[0] .id" | sed -e "s/\x22//g"` && echo $${CONSUMER_VERSION} && pact-provider-verifier $${PACT_BROKER}/pacts/provider/$${PROVIDER}/consumer/$${CONSUMER}/version/$${CONSUMER_VERSION} --provider-base-url=$${BASE_URL} --pact-broker-base-url=$${PACT_BROKER} --provider=$${PROVIDER} --consumer-version-tag=$${CONSUMER_VERSION} --provider-app-version=$${PROVIDER_VERSION} -v --publish-verification-results=PUBLISH_VERIFICATION_RESULTS'] environment: - PROVIDER_VERSION=$CI_COMMIT_SHA - API_TOKEN=$API_TOKEN env_file: - test-setup.env 

Pipeline de consommation
.gitlab-ci.yml à la racine du projet consommateur décrit les processus qui s'exécutent côté consommateur:


 image: gitlab/dind:latest variables: TEST: 'tests/docker-compose.app.yml' CONSUMER_VERSION: $CI_COMMIT_SHA BASIC_APP: '11993024' services: - gitlab/gitlab-runner:latest before_script: - docker login -u $GIT_USER -p $GIT_PASS registry.gitlab.com stages: - clone_test - get_broker_up - test - verify_provider - clean_up clone test: tags: - cdc stage: clone_test script: - git clone https://$GIT_USER:$GIT_PASS@gitlab.com/tknino69/cdc.git && ls -ali artifacts: paths: - cdc/ broker: tags: - cdc stage: get_broker_up script: - cd cdc && docker-compose -f docker-compose.yml up -d pactbroker dependencies: - clone test test: tags: - cdc stage: test script: - cd cdc && CONSUMER_VERSION=$CONSUMER_VERSION docker-compose -f docker-compose.yml -f $TEST up consumer-test dependencies: - clone test provider verification: tags: - cdc stage: verify_provider script: - curl -X POST -F token=$CI_JOB_TOKEN -F ref=master https://gitlab.com/api/v4/projects/$BASIC_APP/trigger/pipeline when: on_success clean up: tags: - cdc stage: clean_up script: - cd cdc && docker-compose stop consumer-test dependencies: - clone test 

Voici ce qui se passe:


Dans before_script nous nous before_script à notre registre gitlab en utilisant les variables $ GIT_USER et $ GIT_PASS que nous avons définies dans Paramètres> CI / CD
image


  • Ensuite, nous clonons un projet de test
  • Ă€ l'Ă©tape suivante, nous augmentons Pact Broker
  • Ensuite, le test du consommateur dĂ©marre.
  • Après cela, utilisez l'API Gitlab pour dĂ©marrer la vĂ©rification du fournisseur.
  • Et enfin, on se nettoie

Pipipeline du fournisseur
La configuration du pipeline de fournisseur est stockée dans .gitlab-ci.yml à la racine du projet de fournisseur.


 image: gitlab/dind:latest variables: TEST: 'tests/docker-compose.app.yml' PROVIDER_VERSION: $CI_COMMIT_SHA services: - gitlab/gitlab-runner:latest stages: - clone_test - provider_verification - clean_up clone test: tags: - cdc stage: clone_test script: - git clone https://$GIT_USER:$GIT_PASS@gitlab.com/tknino69/cdc.git artifacts: paths: - cdc/ verify provider: tags: - cdc stage: provider_verification before_script: - cd cdc - docker login -u $GIT_USER -p $GIT_PASS registry.gitlab.com && docker-compose -f docker-compose.yml up -d basic-flask-app script: - PROVIDER_VERSION=$PROVIDER_VERSION docker-compose -f docker-compose.yml -f $TEST up provider-verifier dependencies: - clone test .clean up: tags: - cdc stage: clean_up script: - cd cdc && docker-compose down --rmi local 

Comme dans le Consumer Pipeline, nous avons plusieurs emplois:


  • Cloner un projet de test
  • VĂ©rifier le fournisseur
  • Nous nous nettoyons

Résumer :


  • A Ă©crit un test de contrat en Python
  • Configurer un environnement de test dans des conteneurs Docker
  • CI configurĂ© sur la base de tests de contrat, c.-Ă -d. commit to the consumer project lancera le pipeline CI ( cĂ´tĂ© consommateur : clonage de l'environnement de test -> dĂ©marrage de Pact Broker -> test du consommateur -> dĂ©marrage de la vĂ©rification du fournisseur -> nettoyage; cĂ´tĂ© fournisseur : clonage de l'environnement de test -> vĂ©rification du fournisseur -> nettoyage )
    S'engager dans le projet du fournisseur lance la vérification du fournisseur pour s'assurer que le fournisseur se conforme au pacte

Merci de votre attention.

Source: https://habr.com/ru/post/fr451132/


All Articles