diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index b3eb5829..e8c9f00a 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -27,6 +27,7 @@ on: - pactflow-example-provider-python-updated - pactflow-example-consumer-js-sns-updated - pactflow-example-provider-js-sns-updated + - pactflow-example-consumer-python-sns-updated - pact-workshop-js-updated - pactflow-example-bi-directional-consumer-nock-updated - pactflow-example-bi-directional-consumer-wiremock-updated @@ -64,6 +65,7 @@ on: - pactflow-example-provider-python-updated - pactflow-example-consumer-js-sns-updated - pactflow-example-provider-js-sns-updated + - pactflow-example-consumer-python-sns-updated - pact-workshop-js-updated - pactflow-example-bi-directional-consumer-nock-updated - pactflow-example-bi-directional-consumer-wiremock-updated @@ -163,6 +165,10 @@ jobs: - name: Sync example_provider_js_sns docs run: bundle exec scripts/sync/example_provider_js_sns.rb && echo 'COMMIT_MESSAGE=synced example_provider_js_sns docs' >> $GITHUB_ENV if: steps.identify_event.outputs.update_event == 'pactflow-example-provider-js-sns-updated' + + - name: Sync example_consumer_python_sns docs + run: bundle exec scripts/sync/example_consumer_python_sns.rb && echo 'COMMIT_MESSAGE=synced example_consumer_python_sns docs' >> $GITHUB_ENV + if: steps.identify_event.outputs.update_event == 'pactflow-example-consumer-python-sns-updated' - name: Sync example_consumer_golang docs run: bundle exec scripts/sync/example_consumer_golang.rb && echo 'COMMIT_MESSAGE=synced example_consumer_golang docs' >> $GITHUB_ENV diff --git a/scripts/sync/example_consumer_python_sns.rb b/scripts/sync/example_consumer_python_sns.rb new file mode 100755 index 00000000..9b38387a --- /dev/null +++ b/scripts/sync/example_consumer_python_sns.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +require 'octokit' +require 'base64' +require 'fileutils' +require 'pathname' +require_relative 'support' + +SOURCE_REPO = 'pactflow/example-consumer-python-sns' +DESTINATION_DIR = relative_path_to('website/docs/docs/examples/aws/sns/consumer/python') +TRANSFORM_PATH = -> (path) { File.join(DESTINATION_DIR, path.downcase) } +INCLUDE = [ + ->(path) { %w{README.md}.include?(path) } +] +IGNORE = [] + +CUSTOM_ACTIONS = [ + [:all, ->(md_file_contents) { + md_file_contents.enable_headers + md_file_contents.extract_title + md_file_contents.fields[:sidebar_label] = md_file_contents.fields[:title] + md_file_contents.add_lines_at_start("## Source Code\n\nhttps://github.com/#{SOURCE_REPO}\n") + } + ] +] + + +FileUtils.mkdir_p DESTINATION_DIR + +sync(SOURCE_REPO, INCLUDE, IGNORE, TRANSFORM_PATH, CUSTOM_ACTIONS, 'main') diff --git a/website/docs/docs/examples/aws/sns/consumer/python/readme.md b/website/docs/docs/examples/aws/sns/consumer/python/readme.md new file mode 100644 index 00000000..c454409c --- /dev/null +++ b/website/docs/docs/examples/aws/sns/consumer/python/readme.md @@ -0,0 +1,57 @@ +--- +custom_edit_url: https://github.com/pactflow/example-consumer-python-sns/edit/main/README.md +title: Example Python AWS SNS Consumer +sidebar_label: Example Python AWS SNS Consumer +--- + + + +## Source Code + +https://github.com/pactflow/example-consumer-python-sns + + +[![Build Status](https://github.com/pactflow/example-consumer-python-sns/actions/workflows/build.yml/badge.svg)](https://github.com/pactflow/example-consumer-python-sns/actions) + +[![Can I deploy Status](https://test.pactflow.io/pacticipants/pactflow-example-consumer-python-sns/branches/main/latest-version/can-i-deploy/to-environment/production/badge.svg)](https://test.pactflow.io/pacticipants/pactflow-example-consumer-python-sns/branches/main/latest-version/can-i-deploy/to-environment/production/badge) + +[![Pact Status](https://test.pactflow.io/pacts/provider/pactflow-example-provider-python-sns/consumer/pactflow-example-consumer-python-sns/latest/badge.svg?label=consumer)](https://test.pactflow.io/pacts/provider/pactflow-example-provider-python-sns/consumer/pactflow-example-consumer-python-sns/latest) (latest pact) + +[![Pact Status](https://test.pactflow.io/matrix/provider/pactflow-example-provider-python-sns/latest/main/consumer/pactflow-example-consumer-python-sns/latest/main/badge.svg?label=consumer)](https://test.pactflow.io/pacts/provider/pactflow-example-provider-python-sns/consumer/pactflow-example-consumer-python-sns/latest/prod) (prod/prod pact) + +This is an example of a Python AWS SNS consumer that uses Pact, [Pactflow](https://pactflow.io) and GitHub Actions to ensure that it is compatible with the expectations its consumers have of it. + +All examples in the series `example-consumer--sns` provide the same functionality to be easily comparable across languages. +As such, please refer to [https://docs.pactflow.io/docs/examples/aws/sns/consumer/](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/AWS) to avoid unnecessary duplication of details here. + +Language specific sections which differ from the canonical example only can be found below. + +### How to write tests? + +We recommend that you split the code that is responsible for handling the protocol specific things - in this case the lambda and SNS input - and the piece of code that actually handles the payload. + +You're probably familiar with layered architectures such as Ports and Adaptors (also referred to as a Hexagonal architecture). Following a modular architecture will allow you to do this much more easily: + +![Code Modularity](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/docs/ports-and-adapters.png) + +This code base is setup with this modularity in mind: + +- [Lambda Handler](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/src/_lambda/product.py) +- [Event Service](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/src/product/product_service.py) +- Business Logic + - [Product](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/src/product/product.py) + - [Repository](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/src/product/product_repository.py) + +The target of our [consumer pact test](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/tests/unit/product_service_pact_test.py) is the [Event Service](https://raw.githubusercontent.com/pactflow/example-consumer-python-sns/main/src/product/product_service.py), which is responsible for consuming a Product update event, and persisting it to a database (the Repository). + +See also: + +- https://dius.com.au/2017/09/22/contract-testing-serverless-and-asynchronous-applications/ +- https://dius.com.au/2018/10/01/contract-testing-serverless-and-asynchronous-applications---part-2/ + +## Usage + +### Testing + +- Run the unit tests: `make test` +- Run a (local) lambda integration test: `make integration` diff --git a/website/sidebars.js b/website/sidebars.js index cd9811c9..ec406ed3 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -297,6 +297,7 @@ module.exports = { { AWS: [ 'docs/examples/aws/sns/consumer/readme', + 'docs/examples/aws/sns/consumer/python/readme', 'docs/examples/aws/sns/provider/readme' ], Cypress: ['docs/examples/cypress/readme'],