عقود يحركها المستهلك أو أتمتة اختبار Gitlab CI-eyed QA

أهداف هذا المنشور هي :


  • مقدمة موجزة عن العقود التي يحركها المستهلك (CDC)
  • تكوين خط أنابيب CI المستندة إلى CDI

عقود يحركها المستهلك


في هذا الجزء ، سنتجاوز النقاط الرئيسية في مركز السيطرة على الأمراض. هذه المقالة ليست شاملة بشأن موضوع اختبار العقد. هناك كمية كافية من المواد حول هذا الموضوع على نفس Habré .


للمتابعة ، نحتاج إلى التعرف على الأحكام الرئيسية لمركز السيطرة على الأمراض:


  • يقع اختبار الاتصال في مستوى اختبارات الخدمة / التكامل أعلى من اختبارات الوحدة وفقًا لهرم مايك كوهن .
  • يمكن تطبيق اختبار العقود عندما يكون هناك 2 (أو أكثر) من الخدمات التي تتفاعل مع بعضها البعض.
  • النهج الذي يقوده المستهلك يعني أن الخطوة الأولى في التنفيذ هي كتابة اختبار على جانب المستهلك. نتيجة الاختبار عبارة عن اتفاق (عقد) بتنسيق json يصف التفاعل بين المستهلك (على سبيل المثال ، واجهة الويب / واجهة الجوال: خدمة تريد تلقي بعض البيانات) والموفر (على سبيل المثال ، واجهة برمجة تطبيقات الخادم: خدمة توفر البيانات)
  • والخطوة التالية هي التحقق من العقد مع المزود. يتم تنفيذ هذا بالكامل من قبل إطار الميثاق .

لذلك ، لنبدأ باختبار جانب المستهلك . اعتدت Pactman . هذا هو ما يشبه الاختبار:


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) 

باستخدام Pact DSL ، نصف تفاعلات الطلب / الاستجابة. بعد بدء الاختبار ، نحصل على ملف جديد ({customer} - {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" } } } 

بعد ذلك ، نحتاج إلى تمرير الاتفاق إلى الموفر للتحقق منه. يتم ذلك باستخدام Pact Broker.


Pact Broker هو مستودع للعقود يحتوي على بعض الميزات الإضافية التي تسمح لنا بتتبع توافق إصدارات الخدمة ، وكذلك إنشاء مخططات الشبكة (تفاعل الخدمة).


وسيط الاتفاق
صورة


الاتفاق
صورة


مصفوفة الإصدار
صورة


التحقق من مزود


يتم تنفيذ هذا الجزء من الاختبار بالكامل بواسطة الإطار. بعد التحقق ، يتم إرسال النتائج مرة أخرى إلى 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 

تشغيل كلا الجزأين من الاختبار في خط الأنابيب


الآن وقد تم تفكيك كلا الجزأين من اختبار العقد ، سيكون من الجيد تشغيلهما على كل التزام. هنا يأتي دور Gitlab CI. يتم وصف وظائف خطوط الأنابيب في .gitlab-ci.yml . قبل أن ننتقل إلى خط الأنابيب ، نحتاج أن نقول بضع كلمات حول GitLab Runner ، وهو مشروع مفتوح المصدر ، ويستخدم لتشغيل الوظائف وإرسال النتائج مرة أخرى إلى GitLab. يمكن تشغيل الوظائف محليًا أو باستخدام حاويات الرصيف. في مشروعنا نستخدم Docker. يتم تنفيذ البنية التحتية للاختبار في حاويات ويتم وصفها في docker-compose.yml ، الموجود في جذر المشروع.


 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: 

لذلك ، لدينا خدمات تعمل في حاويات حسب الحاجة.


مقدم الخدمة:


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

Pact Broker وقاعدة بياناتها. تسمح وحدات التخزين بأن يكون لدينا مستودع دائم للاتفاقيات ونتائج التحقق من المزود:


 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 

خدمة تدير اختبار المستهلك. انتبه إلى الأمر الذي يتم تشغيله في الحاوية - 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 

التحقق من مزود الخدمة:


 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 

خط أنابيب المستهلك
.gitlab-ci.yml من جذر مشروع المستهلك العمليات التي تعمل على جانب المستهلك:


 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 

هنا يحدث ما يلي:


في before_script نقوم بتسجيل الدخول إلى سجل gitlab الخاص بنا باستخدام متغيرات GIT_USER $ و GIT_PASS التي قمنا بتعيينها في الإعدادات> CI / CD
صورة


  • بعد ذلك ، استنساخ مشروع اختبار
  • في الخطوة التالية ، نرفع Pact Broker
  • ثم يبدأ اختبار المستهلك.
  • بعد ذلك ، استخدم واجهة برمجة تطبيقات Gitlab لبدء التحقق من الموفر.
  • وأخيرا ، نقوم بتنظيف أنفسنا

خط أنابيب مزود
يتم تخزين تكوين خط أنابيب الموفر في .gitlab-ci.yml في جذر مشروع الموفر.


 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 

كما هو الحال في خط أنابيب المستهلك ، لدينا العديد من الوظائف:


  • استنساخ مشروع اختبار
  • تحقق من الموفر
  • نقوم بتنظيف أنفسنا

تلخيص :


  • كتب اختبار العقد في بيثون
  • قم بإعداد بيئة اختبار في حاويات Docker
  • CI المكونة بناءً على اختبارات العقد ، أي سيؤدي الالتزام بمشروع المستهلك إلى إطلاق خط أنابيب CI ( على جانب المستهلك : استنساخ بيئة الاختبار -> بدء Pact Broker -> اختبار المستهلك -> بدء التحقق من مزود -> التنظيف ؛ على جانب الموفر : استنساخ بيئة الاختبار -> التحقق من الموفر -> التنظيف ).
    الالتزام بمشروع الموفر يبدأ التحقق من الموفر لضمان امتثال الموفر للميثاق

شكرا لاهتمامكم

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


All Articles