diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e4d85f5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +services: + broker-pact: + image: pactfoundation/pact-broker + ports: + - "9292:9292" + environment: + PACT_BROKER_DATABASE_USERNAME: pactbrokeruser + PACT_BROKER_DATABASE_PASSWORD: pactbrokerpass + PACT_BROKER_DATABASE_NAME: pactbroker + PACT_BROKER_DATABASE_HOST: db + PACT_BROKER_DATABASE_PORT: 5432 + depends_on: + - db + + db: + image: postgres:12 + environment: + POSTGRES_USER: pactbrokeruser + POSTGRES_PASSWORD: pactbrokerpass + POSTGRES_DB: pactbroker + ports: + - "5432:5432" diff --git a/publish_pact.py b/publish_pact.py new file mode 100644 index 0000000..762d082 --- /dev/null +++ b/publish_pact.py @@ -0,0 +1,4 @@ +from pact import Broker + +broker = Broker(broker_base_url='http://localhost:9292') +broker.publish('SearchReportConsumer', version='1.0.0', pact_dir='./pacts') \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0f83889..1a0b9fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,91 +1,36 @@ -aiohttp==3.9.3 -aiosignal==1.3.1 -annotated-types==0.7.0 anyio==4.4.0 -attrs==23.2.0 -boto3==1.24.54 -botocore==1.27.96 -cachetools==5.3.2 -certifi==2024.2.2 -cffi==1.16.0 +boto3==1.35.8 +botocore==1.35.8 +certifi==2024.7.4 +cffi==1.17.0 charset-normalizer==3.3.2 click==8.1.7 -Deprecated==1.2.14 -dnspython==2.6.1 -email_validator==2.2.0 -et-xmlfile==1.1.0 -execnet==2.0.2 -fastapi==0.111.0 -fastapi-cli==0.0.4 -frozenlist==1.4.1 -google-auth==2.28.0 -google-auth-oauthlib==1.2.0 -gspread==5.4.0 +common-fate-schema==0.7.0 +exceptiongroup==1.2.2 +fastapi==0.112.2 +flux==1.3.5 h11==0.14.0 -httpcore==1.0.5 -httptools==0.6.1 -httpx==0.27.0 -idna==3.6 -iniconfig==2.0.0 -Jinja2==3.1.4 +idna==3.8 jmespath==1.0.1 -jsonpickle==2.0.0 -mail-parser==3.15.0 -markdown-it-py==3.0.0 -MarkupSafe==2.1.5 -mdurl==0.1.2 +Logbook==1.7.0.post0 multidict==6.0.5 -numpy==1.26.4 -oauthlib==3.2.2 -opencv-python==4.7.0.68 -openpyxl==3.0.9 -orjson==3.10.6 -packaging==23.2 -pact-python==2.2.0 -percy-selenium==1.0.4 -pluggy==1.4.0 -psutil==5.9.8 -pyasn1==0.5.1 -pyasn1-modules==0.3.0 -pycparser==2.21 -pydantic==2.8.2 -pydantic_core==2.20.1 -PyGithub==1.55 -Pygments==2.18.0 -PyJWT==2.8.0 -PyMySQL==0.9.3 -PyNaCl==1.5.0 -PyPika==0.48.8 -pytest==7.2.1 -pytest-instafail==0.4.2 -pytest-rerunfailures==10.2 -pytest-xdist==3.2.0 -python-dateutil==2.8.2 -python-dotenv==1.0.1 -python-multipart==0.0.9 -pytz==2021.3 -PyYAML==6.0.1 -requests==2.31.0 -requests-oauthlib==1.3.1 -rich==13.7.1 -rsa==4.9 -s3transfer==0.6.2 -selenium==3.141.0 -setuptools==69.1.0 -shellingham==1.5.4 -simplejson==3.19.2 +pact==1.12.0 +pact-python==2.2.1 +provider==0.11.0 +psutil==6.0.0 +pycparser==2.22 +pydantic==1.10.18 +python-dateutil==2.9.0.post0 +requests==2.32.3 +s3transfer==0.10.2 six==1.16.0 -slackclient==2.9.3 sniffio==1.3.1 -starlette==0.37.2 -typer==0.12.3 +starlette==0.38.2 +toml==0.10.2 typing_extensions==4.12.2 -ujson==5.10.0 -urllib3==1.26.7 -uvicorn==0.30.1 -uvloop==0.19.0 -watchfiles==0.22.0 -webdriver-manager==4.0.1 -websockets==12.0 -wrapt==1.16.0 +urllib3==1.26.19 +uvicorn==0.30.6 +waiting==1.5.0 yarl==1.9.4 + +PyYAML~=6.0.2 \ No newline at end of file diff --git a/tests/config.yml b/tests/config.yml new file mode 100644 index 0000000..fa680c8 --- /dev/null +++ b/tests/config.yml @@ -0,0 +1,31 @@ +# config.yml + +# Provider configuration +provider: + name: "SearchReportProvider" # Provider'ın adı + base_url: "http://localhost:8080" # Provider'ın yerel ortamda çalıştığı URL + +# Pact Broker configuration (optional, if using a broker) +pact_broker: + url: "http://localhost:9292/" # Pact Broker URL'i + username: "your-username" # Pact Broker'a erişim için kullanıcı adı + password: "your-password" # Pact Broker'a erişim için parola + consumer_version_tag: "dev" # Tüketiciye ait sürüm etiketleri (örn. dev, prod) + provider_version_tag: "master" # Sağlayıcıya ait sürüm etiketleri (örn. master, staging) + enable_ssl_verification: true # SSL doğrulamasını etkinleştir (gerektiğinde false yapılabilir) + +# Pact files path (for local testing without broker) +pact_files: + path: "./pacts" # Pact dosyalarının yerel olarak bulunduğu klasör + +# Verification configuration +verification: + publish_results: true # Pact Broker'a test sonuçlarını otomatik olarak yayınla + provider_version: "1.0.0" # Provider'ın versiyonu (test sonuçlarını yayınlamak için kullanılır) + retry_attempts: 3 # Pact doğrulaması başarısız olursa kaç kez yeniden denensin + timeout: 5000 # Sağlayıcı API'ye yapılan istekler için zaman aşımı (ms cinsinden) + +# Test environment variables (optional) +environment: + ENV: "local" # Testin çalıştığı ortam (örn. local, dev, prod) + API_KEY: "your-api-key" # Sağlayıcı API için kullanılacak olan API anahtarı (gerekliyse) diff --git a/tests/consumer_internal_query.py b/tests/consumer_internal_query.py new file mode 100644 index 0000000..f55c920 --- /dev/null +++ b/tests/consumer_internal_query.py @@ -0,0 +1,186 @@ +import atexit +import unittest +from pact import Consumer, Provider +import requests + +# Pact configurations +pact = Consumer('InternalQueryConsumer').has_pact_with(Provider('InternalQueryProvider'), pact_dir='./pacts') +pact.start_service() # Pact services starting +atexit.register(pact.stop_service) + + +class InternalQueryContract(unittest.TestCase): + def test_internal_query(self): + expected_response = { + "data": [ + { + "image_url": "https://img.lowestfare.com.hk/Content/img/logo.png", + "name": "邁爾斯堡薩尼貝爾蓋特威溫德姆拉昆塔套房酒店 迈尔斯堡萨尼贝尔盖特威温德姆拉昆塔套房酒店 La Quinta Inn & Suites by Wyndham Ft. Myers-Sanibel Gateway", + "item_id": "1024295", + "product_last_modified_by": "CatalogAPI", + "url": "https://aws-www-test-3.hutchgo.com.hk/zh-hk/", + "in_stock": 1, + "price": { + "HKD": 0 + }, + "product_modified_at": "2024-08-08 02:53:59", + "locale": "zh_HK:hotel", + "id": "1024295:zh_HK:hotel", + "category": [], + "discount": { + "HKD": 0 + }, + "original_price": { + "HKD": 0 + } + }, + { + "image_url": "https://img.lowestfare.com.hk/Content/img/logo.png", + "name": "龐當PLT套房酒店 庞当PLT套房酒店 Pendang Suite Hotel PLT", + "item_id": "1559382", + "product_last_modified_by": "CatalogAPI", + "url": "https://aws-www-test-3.hutchgo.com.hk/zh-hk/", + "in_stock": 1, + "price": { + "HKD": 0 + }, + "product_modified_at": "2024-08-08 02:53:59", + "locale": "zh_HK:hotel", + "id": "1559382:zh_HK:hotel", + "category": [], + "discount": { + "HKD": 0 + }, + "original_price": { + "HKD": 0 + } + }, + { + "image_url": "https://img.lowestfare.com.hk/Content/img/logo.png", + "name": "龍目島蘭科馬塔蘭菲芙酒店 (favehotel Langko Mataram - Lombok) 龙目岛兰科马塔兰菲芙酒店 (favehotel Langko Mataram - Lombok) favehotel Langko Mataram - Lombok", + "item_id": "1340653", + "product_last_modified_by": "CatalogAPI", + "url": "https://aws-www-test-3.hutchgo.com.hk/zh-hk/", + "in_stock": 1, + "price": { + "HKD": 0 + }, + "product_modified_at": "2024-08-08 02:53:59", + "locale": "zh_HK:hotel", + "id": "1340653:zh_HK:hotel", + "category": [], + "discount": { + "HKD": 0 + }, + "original_price": { + "HKD": 0 + } + }, + { + "image_url": "https://img.lowestfare.com.hk/Content/img/logo.png", + "name": "黑風洞酒店 黑风洞酒店 Batu Caves Hotel", + "item_id": "1533940", + "product_last_modified_by": "CatalogAPI", + "url": "https://aws-www-test-3.hutchgo.com.hk/zh-hk/", + "in_stock": 1, + "price": { + "HKD": 0 + }, + "product_modified_at": "2024-08-08 02:53:59", + "locale": "zh_HK:hotel", + "id": "1533940:zh_HK:hotel", + "category": [], + "discount": { + "HKD": 0 + }, + "original_price": { + "HKD": 0 + } + }, + { + "image_url": "https://img.lowestfare.com.hk/Content/img/logo.png", + "name": "龍仁中心CO'OP酒店 (Yongin Central CO'OP Hotel) 龙仁中心CO'OP酒店 (Yongin Central CO'OP Hotel) Yongin Central CO'OP Hotel", + "item_id": "1289139", + "product_last_modified_by": "CatalogAPI", + "url": "https://aws-www-test-3.hutchgo.com.hk/zh-hk/", + "in_stock": 1, + "price": { + "HKD": 0 + }, + "product_modified_at": "2024-08-08 02:53:59", + "locale": "zh_HK:hotel", + "id": "1289139:zh_HK:hotel", + "category": [], + "discount": { + "HKD": 0 + }, + "original_price": { + "HKD": 0 + } + } + ], + "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAd34d_sWejAzaTNwTlhUYVdzMjBHLThhTmNjZw==", + "size": 5, + "success": True, + "total": 10 + } + + request_body = { + "size": 5, + "_source": { + "exclude": ["modified_by", "modified_at", "recommendations", "suggest"] + }, + "query": { + "bool": { + "must": [ + { + "match": { + "locale": "zh_HK:hotel" + } + } + ], + "must_not": [ + { + "bool": { + "must": [ + { + "exists": { + "field": "is_status_passive" + } + }, + { + "term": { + "is_status_passive": 1 + } + } + ] + } + } + ] + } + } + } + + # Define the Pact interaction + (pact + .given('Internal query endpoint with given partner data') + .upon_receiving('a request to insert an event') + .with_request('POST', '/v2/internal-query', body=request_body, headers={'Content-Type': 'application/json'}) + .will_respond_with(200, body=expected_response, headers={'Content-Type': 'application/json'})) + + # With the Pact service running, send the request and check the response + with pact: + result = requests.post(pact.uri + '/v2/internal-query', + params= + { + 'partner': 'hutchgouat' + }, json=request_body, + headers={'Content-Type': 'application/json'}) + self.assertEqual(result.status_code, 200) + actual_response = result.json() + + self.assertEqual(actual_response, expected_response) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/consumer_search_report.py b/tests/consumer_search_report.py new file mode 100644 index 0000000..f0474ad --- /dev/null +++ b/tests/consumer_search_report.py @@ -0,0 +1,134 @@ +import atexit +import unittest +from pact import Consumer, Provider +import requests + +# Pact configurations +pact = Consumer('SearchReportConsumer').has_pact_with(Provider('SearchReportProvider'), pact_dir='./pacts') +pact.start_service() # Pact services starting +atexit.register(pact.stop_service) + + +class SearchReportContract(unittest.TestCase): + def test_search_report(self): + expected_response = { + "data": { + "noSearch": 1, + "search": 5, + "searchResults": { + "searchResultFound": { + "noSearch": 0, + "search": 5, + "searchResultType": "searchResultFound", + "terms": [ + { + "noSearch": 0, + "search": 1, + "searchTerm": "çanta", + "totalSearch": 1 + }, + { + "noSearch": 0, + "search": 2, + "searchTerm": "Terlik", + "totalSearch": 2 + }, + { + "noSearch": 0, + "search": 1, + "searchTerm": "vs", + "totalSearch": 1 + }, + { + "noSearch": 0, + "search": 1, + "searchTerm": "Survivor", + "totalSearch": 1 + } + ], + "totalSearch": 5 + }, + "searchResultNotFound": { + "noSearch": 1, + "search": 0, + "searchResultType": "searchResultNotFound", + "terms": [ + { + "noSearch": 1, + "search": 0, + "searchTerm": "Statrum", + "totalSearch": 1 + } + ], + "totalSearch": 1 + } + }, + "totalSearch": 6 + }, + "metaData": { + "isCached": False, + "cacheTime": 0, + "expireTime": 0, + "ttl": 0, + "expireIn": 0, + "checksum": "e3ba8dcb1334f7a5a458f01f7cf1bb2cfbf456de56d34cff6682edab02f6c3b4" + }, + "status": 200 + } + + request_body = { + "partners": [ + "kappatr" + ], + "time": { + "start": 1690502400, + "end": 1690543915 + }, + "timezone": "Europe/Istanbul", + "_compare": { + "start": 1660425659, + "end": 1683765360 + }, + "select": [ + "search", + "noSearch", + "totalSearch" + ], + "aggregations": [ + { + "outputName": "searchResults", + "field": "searchResultType", + "outputType": "object", + "subAggregations": [ + { + "outputName": "terms", + "field": "searchTerm", + "outputType": "array", + "subAggregations": [] + } + ] + } + ], + "preFilters": [], + "postFilters": [] + } + + # Define the Pact interaction + (pact + .given('Search report with given partner data') + .upon_receiving('a request to insert an event') + .with_request('POST', '/v3/search-report', body=request_body, headers={'Content-Type': 'application/json'}) + .will_respond_with(200, body=expected_response, headers={'Content-Type': 'application/json'})) + + # With the Pact service running, send the request and check the response + with pact: + result = requests.post(pact.uri + '/v3/search-report', json=request_body, + headers={'Content-Type': 'application/json'}) + self.assertEqual(result.status_code, 200) + actual_response = result.json() + + self.assertEqual(actual_response, expected_response) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/consumer_tests/base/base_consumer.py b/tests/consumer_tests/base/base_consumer.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/provider_tests/base/base_provider.py b/tests/provider_tests/base/base_provider.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/verify_provider_internal_query.py b/tests/verify_provider_internal_query.py new file mode 100644 index 0000000..fc6b05b --- /dev/null +++ b/tests/verify_provider_internal_query.py @@ -0,0 +1,43 @@ +import unittest +from pact import Verifier +import yaml +import os + +# Config dosyasını yükleyelim +current_dir = os.path.dirname(os.path.abspath(__file__)) +config_path = os.path.join(current_dir, "config.yml") # Config dosyasının yolunu doğru ayarlayın +print("Checking config file path:", os.path.abspath(config_path)) + +if not os.path.exists(config_path): + raise FileNotFoundError(f"Config file not found: {config_path}") + +with open(config_path, "r") as ymlfile: + config = yaml.safe_load(ymlfile) + +# Config dosyasından gelen ayarlar +# provider_name = config['provider']['name'] +# provider_base_url = config['provider']['base_url'] +# pact_files_path = config['pact_files']['path'] +# broker_url = config.get('pact_broker', {}).get('url', None) +# broker_username = config.get('pact_broker', {}).get('username', None) +# broker_password = config.get('pact_broker', {}).get('password', None) +# consumer_version_tag = config.get('pact_broker', {}).get('consumer_version_tag', None) +# provider_version_tag = config.get('pact_broker', {}).get('provider_version_tag', None) +# enable_ssl_verification = config.get('pact_broker', {}).get('enable_ssl_verification', True) + + +class ProviderVerification(unittest.TestCase): + def test_verify_provider(self): + # Verifier sınıfı ile provider'ı doğrulayın + verifier = Verifier(provider='InternalQueryProvider', provider_base_url="https://kube-prod-dataforce.useinsider.com/pcd-api") + verifier.verify_pacts('./pacts/internalqueryconsumer-internalqueryprovider.json') + + # Pact dosyasını doğrulama işlemi + #success, logs = verifier.verify_pacts('./pacts/internalqueryconsumer-internalqueryprovider.json') + + # Doğrulamanın başarılı olduğunu kontrol edin + #assert success == 0, f"Verification failed: {logs}" + + +if __name__ == '__main__': + unittest.main()