Kontrak yang Didorong oleh Konsumen atau otomatisasi tes QA bermata Gitlab CI

Tujuan publikasi ini adalah :


  • Pengantar Singkat untuk Kontrak yang Didorong Konsumen (CDC)
  • Konfigurasikan pipa CI berbasis CDI

Kontrak Berbasis Konsumen


Pada bagian ini, kita akan membahas poin-poin utama CDC. Artikel ini tidak lengkap tentang masalah pengujian kontrak. Ada cukup banyak materi tentang hal ini di Habré yang sama.


Untuk melanjutkan, kita perlu berkenalan dengan ketentuan utama CDC:


  • Pengujian kontak adalah pada tingkat Layanan / Tes Integrasi di atas Unit Tes menurut piramida Mike Cohn .
  • Pengujian kontrak dapat diterapkan ketika ada 2 (atau lebih) layanan yang berinteraksi satu sama lain.
  • Pendekatan berbasis konsumen berarti bahwa langkah pertama dalam implementasi adalah menulis tes di sisi konsumen. Hasil pengujian adalah perjanjian (kontrak) yang diformat json yang menggambarkan interaksi antara konsumen (mis. Antarmuka web / antarmuka seluler: layanan yang ingin menerima beberapa data) dan penyedia (mis. Server API: layanan yang menyediakan data)
  • Langkah selanjutnya adalah memeriksa kontrak dengan penyedia. Ini sepenuhnya dilaksanakan oleh kerangka Pakta .

Jadi, mari kita mulai dengan tes sisi konsumen . Saya menggunakan Pactman . Seperti inilah tes ini:


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) 

Menggunakan Pact DSL, kami menggambarkan interaksi permintaan / respons. Setelah memulai tes, kami mendapatkan file baru ({konsumen} - {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" } } } 

Selanjutnya, kita harus memberikan pakta kepada penyedia untuk verifikasi. Ini dilakukan dengan menggunakan Pact Broker.


Pact Broker adalah repositori kontrak dengan beberapa fitur tambahan yang memungkinkan kami melacak kompatibilitas versi layanan, serta menghasilkan diagram jaringan (interaksi layanan).


Broker pakta
gambar


Perjanjian
gambar


Matriks versi
gambar


Verifikasi Penyedia


Bagian dari tes ini sepenuhnya dilakukan oleh kerangka kerja. Setelah verifikasi, hasilnya dikirim kembali ke 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 

Menjalankan kedua bagian tes di dalam pipa


Sekarang setelah kedua bagian pengujian kontrak telah dibongkar, alangkah baiknya menjalankannya di setiap komit. Di sinilah Gitlab CI datang untuk menyelamatkan. Pekerjaan pipeline dijelaskan dalam .gitlab-ci.yml . Sebelum kita beralih ke saluran pipa, kita perlu mengatakan beberapa kata tentang GitLab Runner, yang merupakan proyek open-source, dan digunakan untuk menjalankan pekerjaan dan mengirim hasilnya kembali ke GitLab. Pekerjaan dapat dijalankan secara lokal atau menggunakan wadah buruh pelabuhan. Dalam proyek kami, kami menggunakan Docker. Infrastruktur pengujian diimplementasikan dalam wadah dan dijelaskan dalam docker-compose.yml , yang terletak di akar proyek.


 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: 

Jadi, kami memiliki layanan yang berjalan dalam wadah sesuai kebutuhan.


Penyedia Layanan:


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

Pact Broker dan databasenya. Volume memungkinkan kami memiliki repositori permanen untuk pakta dan hasil verifikasi penyedia:


 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 

Negara Penyedia Layanan. Dalam praktiknya, ia harus membawa penyedia ke kondisi tertentu (misalnya, dapatkan pengguna dalam basis data). Namun, dalam contoh kami, itu hanya melakukan fungsi dummy.


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

Layanan yang menjalankan Tes Konsumen. Perhatikan perintah yang berjalan di dalam wadah, 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 

Verifikasi Penyedia Layanan:


 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 

Pipa Pelanggan
.gitlab-ci.yml di akar proyek konsumen menjelaskan proses yang berjalan di sisi konsumen:


 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 

Berikut ini yang terjadi:


Di before_script kita masuk ke registri gitlab menggunakan variabel $ GIT_USER dan $ GIT_PASS yang kita atur di Pengaturan> CI / CD
gambar


  • Selanjutnya, kami mengkloning proyek uji
  • Pada langkah berikutnya, kami meningkatkan Pact Broker
  • Kemudian Uji Konsumen dimulai.
  • Setelah itu, gunakan Gitlab API untuk memulai verifikasi penyedia.
  • Dan akhirnya, kita membersihkan diri kita sendiri

Pipipeline penyedia
Konfigurasi pipa penyedia disimpan di .gitlab-ci.yml di root proyek penyedia.


 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 

Seperti di Consumer Pipeline, kami memiliki beberapa pekerjaan:


  • Mengkloning proyek uji
  • Verifikasi penyedia
  • Kami membersihkan diri

Ringkas :


  • Menulis tes kontrak dengan Python
  • Siapkan lingkungan pengujian dalam wadah Docker
  • CI yang dikonfigurasikan berdasarkan uji kontrak, mis. berkomitmen untuk proyek konsumen akan meluncurkan pipa CI ( di sisi konsumen : mengkloning lingkungan pengujian -> memulai Pact Broker -> menguji konsumen -> memulai verifikasi penyedia -> membersihkan; di sisi penyedia : mengkloning lingkungan pengujian -> verifikasi penyedia -> membersihkan )
    Berkomitmen pada proyek penyedia memulai verifikasi penyedia untuk memastikan bahwa penyedia mematuhi pakta

Terima kasih atas perhatian anda

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


All Articles