{"id":1387,"date":"2022-03-08T08:05:57","date_gmt":"2022-03-08T15:05:57","guid":{"rendered":"https:\/\/bullyrooks.com\/?p=1387"},"modified":"2022-03-13T13:43:15","modified_gmt":"2022-03-13T20:43:15","slug":"kube-cloud-pt6-provider-contract-test-for-rest-endpoints","status":"publish","type":"post","link":"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-provider-contract-test-for-rest-endpoints\/","title":{"rendered":"Kube Cloud Pt6 | Provider Contract Test for REST Endpoints"},"content":{"rendered":"\n<p>Now lets move over to message-generator repo and create a new branch<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git checkout -b provider-test<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Pom Updates for Dependencies<\/h2>\n\n\n\n<p>Update the pom.xml to pull in both the provider test library and the plugin<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\n        &lt;pact.version>4.3.5&lt;\/pact.version>\n        &lt;maven-failsafe-plugin.version>3.0.0-M5&lt;\/maven-failsafe-plugin.version>\n        &lt;maven-surefire-plugin.version>3.0.0-M5&lt;\/maven-surefire-plugin.version>\n        &lt;pact.maven.plugin.version>4.3.5&lt;\/pact.maven.plugin.version>\n    &lt;\/properties>\n...\n    &lt;profiles>\n        &lt;profile>\n            &lt;id>contract&lt;\/id>\n            &lt;build>\n                &lt;plugins>\n                    &lt;plugin>\n                        &lt;artifactId>maven-surefire-plugin&lt;\/artifactId>\n                        &lt;version>${maven-surefire-plugin.version}&lt;\/version>\n                        &lt;configuration>\n                            &lt;excludedGroups>UnitTest&lt;\/excludedGroups>\n                        &lt;\/configuration>\n                    &lt;\/plugin>\n                    &lt;plugin>\n                        &lt;artifactId>maven-failsafe-plugin&lt;\/artifactId>\n                        &lt;version>${maven-failsafe-plugin.version}&lt;\/version>\n                        &lt;executions>\n                            &lt;execution>\n                                &lt;goals>\n                                    &lt;goal>integration-test&lt;\/goal>\n                                    &lt;goal>verify&lt;\/goal>\n                                &lt;\/goals>\n                            &lt;\/execution>\n                        &lt;\/executions>\n                    &lt;\/plugin>\n\n                &lt;\/plugins>\n            &lt;\/build>\n        &lt;\/profile>\n    &lt;\/profiles>\n...\n\n        &lt;!-- Contract Testing -->\n        &lt;dependency>\n            &lt;groupId>au.com.dius.pact.consumer&lt;\/groupId>\n            &lt;artifactId>junit5&lt;\/artifactId>\n            &lt;version>${pact.version}&lt;\/version>\n        &lt;\/dependency>\n        &lt;dependency>\n            &lt;groupId>au.com.dius.pact.provider&lt;\/groupId>\n            &lt;artifactId>junit5spring&lt;\/artifactId>\n            &lt;version>${pact.version}&lt;\/version>\n        &lt;\/dependency>\n...\n            &lt;plugin>\r\n                &lt;artifactId>maven-surefire-plugin&lt;\/artifactId>\r\n                &lt;version>${maven-surefire-plugin.version}&lt;\/version>\r\n                &lt;configuration>\r\n                    &lt;excludedGroups>ContractTest&lt;\/excludedGroups>\r\n                &lt;\/configuration>\r\n            &lt;\/plugin>\r\n            &lt;plugin>\r\n                &lt;groupId>au.com.dius.pact.provider&lt;\/groupId>\r\n                &lt;artifactId>maven&lt;\/artifactId>\r\n                &lt;version>${pact.maven.plugin.version}&lt;\/version>\r\n                &lt;configuration>\r\n                    &lt;pactBrokerUrl>${env.PACTFLOW_URL}&lt;\/pactBrokerUrl>\r\n                    &lt;pactBrokerToken>${env.PACTFLOW_TOKEN}&lt;\/pactBrokerToken>\r\n                    &lt;pactBrokerAuthenticationScheme>Bearer&lt;\/pactBrokerAuthenticationScheme>\r\n                &lt;\/configuration>\r\n            &lt;\/plugin><\/code><\/pre>\n\n\n\n<p>This time we&#8217;re doing quite a few things that may be new (they were to me).<\/p>\n\n\n\n<p>First, we&#8217;re adding the dependencies to create the pact provider tests.  We need these in order to get access to the classes that we&#8217;ll use to write the provider side tests (which are significantly different than the consumer tests).  Additionally, we need the pact provider plugin.  This gives us access to the functions we can call through maven to publish the test verifications as well as confirm that the contract has been met before we can deploy.<\/p>\n\n\n\n<p>Next, pact provider tests introduce a dependency on the pact broker.  We don&#8217;t necessarily want our unit tests to have to call out to pact broker every time we want to build and test a minor change that doesn&#8217;t affect the contract.  In fact, we want to limit those executions because they&#8217;re expensive and have an environment dependency (a connection to the pact broker).  So we&#8217;re introducing the surefire plugin configuration to ignore certain tests (annotated with the junit <code>Tag<\/code> annotation) and a new profile which will run those tests using a profile flag when we actually want them executed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tests<\/h2>\n\n\n\n<p>Lets first create the provider verification test in <code>src\/test\/java\/com\/bullyrooks\/messagegenerator\/controller\/MessageControllerContractIT.java<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.messagegenerator.contract;\r\n\r\nimport au.com.dius.pact.provider.junit5.HttpTestTarget;\r\nimport au.com.dius.pact.provider.junit5.PactVerificationContext;\r\nimport au.com.dius.pact.provider.junitsupport.IgnoreNoPactsToVerify;\r\nimport au.com.dius.pact.provider.junitsupport.Provider;\r\nimport au.com.dius.pact.provider.junitsupport.State;\r\nimport au.com.dius.pact.provider.junitsupport.loader.PactBroker;\r\nimport au.com.dius.pact.provider.junitsupport.loader.PactBrokerAuth;\r\nimport au.com.dius.pact.provider.junitsupport.loader.VersionSelector;\r\nimport au.com.dius.pact.provider.spring.junit5.PactVerificationSpringProvider;\r\nimport com.bullyrooks.messagegenerator.controller.dto.MessageResponseDTO;\r\nimport com.bullyrooks.messagegenerator.service.MessageService;\r\nimport com.bullyrooks.messagegenerator.service.model.MessageModel;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Tag;\r\nimport org.junit.jupiter.api.TestTemplate;\r\nimport org.junit.jupiter.api.extension.ExtendWith;\r\nimport org.mockito.Mockito;\r\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\r\nimport org.springframework.boot.test.context.SpringBootTest;\r\nimport org.springframework.boot.test.mock.mockito.MockBean;\r\nimport org.springframework.boot.web.server.LocalServerPort;\r\n\r\nimport java.time.Instant;\r\n\r\n\r\n@Provider(MessageControllerContractIT.PROVIDER)\r\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\r\n@PactBroker(\r\n        authentication = @PactBrokerAuth(token = \"${PACTFLOW_TOKEN}\"),\r\n        consumerVersionSelectors = {\r\n                @VersionSelector(tag = \"${PACT_CONSUMER_SELECTOR_TAG:okteto}\")\r\n        }\r\n)\r\n\r\n@AutoConfigureMockMvc\r\n@Tag(\"ContractTest\")\r\n@IgnoreNoPactsToVerify\r\npublic class MessageControllerContractIT {\r\n    final static String PROVIDER = \"message-generator\";\r\n    @MockBean\r\n    MessageService service;\r\n    @LocalServerPort\r\n    private int port;\r\n\r\n    @BeforeEach\r\n    void setup(PactVerificationContext context) {\r\n        if (null!=context) {\r\n            context.setTarget(new HttpTestTarget(\"localhost\", port));\r\n        }\r\n    }\r\n\r\n    @TestTemplate\r\n    @ExtendWith(PactVerificationSpringProvider.class)\r\n    void pactVerificationTestTemplate(PactVerificationContext context) {\r\n        if (null!=context) {\r\n            context.verifyInteraction();\r\n        }\r\n    }\r\n\r\n\r\n    @State(\"generator creates a message\")\r\n    public void shouldReturnMessage() {\r\n        \/\/@formatter:off\r\n        MessageModel dto = MessageModel.builder()\r\n                .message(\"All dwarfs are bastards in their father's eyes\")\r\n                .build();\r\n        Mockito.when(service.getMessage()).thenReturn(dto);\r\n        \/\/@formatter:on\r\n    }\r\n}\r\n<\/code><\/pre>\n\n\n\n<p>First, set our tag (<code>ContractTest<\/code>) and our pact configuration to setup a pact provider test that should talk to the pactflow pact broker.  We&#8217;re going to inject our token into the environment variables later.  Next we&#8217;re letting the test know to setup a pact server in <code>@BeforeEach<\/code>.  This server is going to take our contract, setup a client to make the requests the contract specifies and verify the response against the contract.  That&#8217;s what we&#8217;re doing with the <code>PactVerificationSpringProvider <\/code>(verifying the contract against the response).  Finally, we&#8217;re defining a <code>@State<\/code> test (which should match the state from the contract).  The only thing we have to do here is tell our controller to interact with our mock <code>MessageService <\/code>and force it to return the expected response to match the contract.<\/p>\n\n\n\n<p>Its actually really easy, but the hard part is figuring out where to mock and defining the behavior to return.  Some interactions are basic (like this one), but some contract tests may drive you to use more of your actual service behavior (like a behavior driven test).  The line between black box tests (behavior tests) and contract tests will be blurred.  I <em>prefer<\/em> to keep them separate because they perform separate functions and contract tests require environment configuration.  However, that introduces a risk that your contract test behavior could drift from your behavior tests and the contract tests <em>could<\/em> pass, but your service doesn&#8217;t actually exhibit the behavior they say they do.  You will have to find the balance for your team and organization.<\/p>\n\n\n\n<p>In all other unit tests add this annotation<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Tag(\"UnitTest\")<\/code><\/pre>\n\n\n\n<p>This will keep the contract test verification step from running them.<\/p>\n\n\n\n<p>You should be able to confirm both types of tests now (unit tests):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mvn clean test<\/code><\/pre>\n\n\n\n<p>should run successfully since it shouldn&#8217;t use any of the new contract test logic.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"674\" height=\"255\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-10.png?resize=674%2C255&#038;ssl=1\" alt=\"\" class=\"wp-image-1411\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-10.png?w=674&amp;ssl=1 674w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-10.png?resize=300%2C114&amp;ssl=1 300w\" sizes=\"auto, (max-width: 674px) 100vw, 674px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>Before we run the contract tests you&#8217;ll need to set the environment variables.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export PACTFLOW_TOKEN=&lt;your token&gt;\nexport PACTBROKER_HOST=bullyrooks.pactflow.io\nmvn verify -Pcontract<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"234\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-11-1024x250.png?resize=960%2C234&#038;ssl=1\" alt=\"\" class=\"wp-image-1412\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-11.png?resize=1024%2C250&amp;ssl=1 1024w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-11.png?resize=300%2C73&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-11.png?resize=768%2C187&amp;ssl=1 768w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-11.png?w=1242&amp;ssl=1 1242w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Github Action Updates<\/h2>\n\n\n\n<p>Make sure to add a secret for the <code>PACTFLOW_TOKEN <\/code>in the <code>message-generator<\/code> repository similar to what you did in the last course.<\/p>\n\n\n\n<p>update features.yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Cloud Application Feature Branch Build\r\n\r\non:\r\n  push:\r\n    branches-ignore:\r\n      - main\r\nenv:\r\n  PACTFLOW_URL: https:\/\/bullyrooks.pactflow.io\r\n  PACTFLOW_TOKEN: ${{secrets.PACTFLOW_TOKEN}}\r\n  PACTBROKER_HOST: bullyrooks.pactflow.io\r\n\r\njobs:\r\n  build:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n      - uses: actions\/checkout@v3\r\n        with:\r\n          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis\r\n      - name: Set environment variables\r\n        run: |\r\n          # Short name for current branch. For PRs, use target branch (base ref)\r\n          GIT_BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs\/heads\/}}\r\n          echo \"GIT_BRANCH=$GIT_BRANCH\" >> $GITHUB_ENV\r\n          echo \"VERSION=$GITHUB_SHA\"\r\n          echo \"VERSION=$GITHUB_SHA\" >> $GITHUB_ENV\r\n\r\n      - name: Set up JDK 11\r\n        uses: actions\/setup-java@v2.5.0\r\n        with:\r\n          java-version: '11'\r\n          distribution: 'adopt'\r\n          cache: maven\r\n\r\n      - name: Maven Tests\r\n        run: .\/mvnw -B test\n\r\n\r      - name: Create Pact Version Tag\r\n        run: |\r\n          .\/mvnw pact:create-version-tag \\\r\n          -Dpacticipant=message-generator \\\r\n          -DpacticipantVersion=${{ env.VERSION }} \\\r\n          -Dtag=initial\r\n\n      - name: Verify Contract Tests\r\n        run: |\r\n          .\/mvnw -B verify -Pcontract \\\r\n          -Dpactbroker.host=${{env.PACTBROKER_HOST}} \\\r\n          -Dpact.verifier.publishResults=true \\\r\n          -Dpact.provider.version=${{env.VERSION}} \\\r\n          -Dpact.provider.branch=${{env.GIT_BRANCH}} \\\r\n          -Dpact.provider.tag=okteto \\\r\n          -DPACT_CONSUMER_SELECTOR_TAG=okteto,pre-okteto\r\n        continue-on-error: true #verify may fail, but we're relying on can-i-deploy to control deploy\r\n\r\n      - name: Set up Docker Buildx\r\n        uses: docker\/setup-buildx-action@v1\r\n\r\n      - name: Cache Docker layers\r\n        uses: actions\/cache@v2\r\n        with:\r\n          path: \/tmp\/.buildx-cache\r\n          # Key is named differently to avoid collision\r\n          key: ${{ runner.os }}-multi-buildx-${{ github.sha }}\r\n          restore-keys: |\r\n            ${{ runner.os }}-multi-buildx\r\n\r\n      - name: Build and push\r\n        id: docker_build\r\n        uses: docker\/build-push-action@v2\r\n        with:\r\n          context: .\r\n          push: false\r\n          cache-from: type=local,src=\/tmp\/.buildx-cache\r\n          cache-to: type=local,mode=max,dest=\/tmp\/.buildx-cache-new\r\n        # This ugly bit is necessary if you don't want your cache to grow forever\r\n        # till it hits GitHub's limit of 5GB.\r\n        # Temp fix\r\n        # https:\/\/github.com\/docker\/build-push-action\/issues\/252\r\n        # https:\/\/github.com\/moby\/buildkit\/issues\/1896\r\n      - name: Move cache\r\n        run: |\r\n          rm -rf \/tmp\/.buildx-cache\r\n          mv \/tmp\/.buildx-cache-new \/tmp\/.buildx-cache\r\n\r\n      - name: Pact Can-i-deploy\r\n        run: |\r\n          docker run --rm pactfoundation\/pact-cli:latest \\\r\n          broker can-i-deploy \\\r\n          --pacticipant=message-generator  \\\r\n          --to-environment=okteto \\\r\n          --version=${{ env.VERSION }}  \\\r\n          --broker-base-url=${{ env.PACTFLOW_URL }} \\\r\n          --broker-token=${{ env.PACTFLOW_TOKEN }}<\/code><\/pre>\n\n\n\n<p>First, set the environment variables we&#8217;ll need.  Then I renamed the maven build task to signal that I was just running unit tests.  Next I am running the contract tests in a separate task.  You can see that the results are being published and that I&#8217;m running can I deploy at the end.  However, there&#8217;s an important piece here where I&#8217;m creating a version tag.  This signals to pact that I&#8217;ve got a new service and since our service is a provider it will be able to be promoted without needing to fulfill a contract if there&#8217;s no consumers.  If we don&#8217;t have this piece we&#8217;ll never be able to deploy since we won&#8217;t have a fulfilled contract.  Publishers <em>should<\/em> be able to publish if no one depends on them yet and that&#8217;s what we&#8217;re allowing.<\/p>\n\n\n\n<p>Next onto the main.yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Cloud Application Feature Branch Build\r\n\r\non:\r\n  push:\r\n    branches:\r\n      - main\r\nenv:\r\n  PACTFLOW_URL: https:\/\/bullyrooks.pactflow.io\r\n  PACTFLOW_TOKEN: ${{secrets.PACTFLOW_TOKEN}}\r\n  PACTBROKER_HOST: bullyrooks.pactflow.io\r\n\r\njobs:\r\n  build:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n      - uses: actions\/checkout@v3\r\n        with:\r\n          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis\r\n\r\n      - name: Set up JDK 11\r\n        uses: actions\/setup-java@v2.5.0\r\n        with:\r\n          java-version: '11'\r\n          distribution: 'adopt'\r\n          cache: maven\r\n\r\n      - name: find current version\r\n        uses: actions-ecosystem\/action-get-latest-tag@v1\r\n        id: get-latest-tag\r\n\r\n      - name: get current version tag\r\n        run: |\r\n          echo \"VERSION=${{ steps.get-latest-tag.outputs.tag }}\" >> $GITHUB_ENV\r\n          echo ${{ env.VERSION }}\r\n\r\n      - name: Echo current version tag\r\n        run: |\r\n          echo $VERSION\r\n          echo ${{ env.VERSION }}\r\n\r\n      - name: Bump version\r\n        run: |\r\n          git config --global user.email \"github+actions@gmail.com\"\r\n          git config --global user.name \"Actions\"\r\n          git fetch --tags\r\n          wget -O - https:\/\/raw.githubusercontent.com\/treeder\/bump\/master\/gitbump.sh | bash\r\n          echo \"VERSION=$(git tag --sort=-v:refname --list \"v&#91;0-9]*\" | head -n 1 | cut -c 2-)\" >> $GITHUB_ENV\r\n          echo ${{ env.VERSION }}\r\n\r\n      - name: Maven Tests\r\n        run: .\/mvnw -B test\r\n\r\n      - name: Create Pact Version Tag\r\n        run: |\r\n          .\/mvnw pact:create-version-tag \\\r\n          -Dpacticipant=message-generator \\\r\n          -DpacticipantVersion=${{ env.VERSION }} \\\r\n          -Dtag=initial\r\n\r\n      - name: Verify Contract Tests\r\n        run: |\r\n          .\/mvnw -B verify -Pcontract \\\r\n          -Dpactbroker.host=${{env.PACTBROKER_HOST}} \\\r\n          -Dpact.verifier.publishResults=true \\\r\n          -Dpact.provider.version=${{env.VERSION}} \\\r\n          -Dpact.provider.branch=main \\\r\n          -Dpact.provider.tag=okteto \\\r\n          -DPACT_CONSUMER_SELECTOR_TAG=okteto,pre-okteto\r\n        continue-on-error: true #verify may fail, but we're relying on can-i-deploy to control deploy\r\n\r\n      - name: Pact Can-i-deploy\r\n        run: |\r\n          docker run --rm pactfoundation\/pact-cli:latest \\\r\n          broker can-i-deploy \\\r\n          --pacticipant=message-generator  \\\r\n          --to-environment=okteto \\\r\n          --version=${{ env.VERSION }}  \\\r\n          --broker-base-url=${{ env.PACTFLOW_URL }} \\\r\n          --broker-token=${{ env.PACTFLOW_TOKEN }}\r\n\r\n      - name: Set up Docker Buildx\r\n        uses: docker\/setup-buildx-action@v1\r\n\r\n      - name: Login to canister.io\r\n        uses: docker\/login-action@v1\r\n        with:\r\n          registry: cloud.canister.io:5000\r\n          username: ${{ secrets.CANISTER_USERNAME }}\r\n          password: ${{ secrets.CANISTER_PASSWORD }}\r\n\r\n      - name: Extract metadata (tags, labels) for Docker\r\n        id: meta\r\n        uses: docker\/metadata-action@v3\r\n        with:\r\n          images: cloud.canister.io:5000\/bullyrooks\/message-generator\r\n          #setting value manually, but could come from git tag\r\n          tags: |\r\n            type=ref,event=tag\r\n\r\n      - name: Cache Docker layers\r\n        uses: actions\/cache@v2\r\n        with:\r\n          path: \/tmp\/.buildx-cache\r\n          # Key is named differently to avoid collision\r\n          key: ${{ runner.os }}-multi-buildx-${{ github.sha }}\r\n          restore-keys: |\r\n            ${{ runner.os }}-multi-buildx\r\n\r\n      - name: Build and push\r\n        id: docker_build\r\n        uses: docker\/build-push-action@v2\r\n        with:\r\n          context: .\r\n          push: true\r\n          tags: |\r\n            cloud.canister.io:5000\/bullyrooks\/message-generator:${{ env.VERSION }}\r\n          cache-from: type=local,src=\/tmp\/.buildx-cache\r\n          cache-to: type=local,mode=max,dest=\/tmp\/.buildx-cache-new\r\n        # This ugly bit is necessary if you don't want your cache to grow forever\r\n        # till it hits GitHub's limit of 5GB.\r\n        # Temp fix\r\n        # https:\/\/github.com\/docker\/build-push-action\/issues\/252\r\n        # https:\/\/github.com\/moby\/buildkit\/issues\/1896\r\n      - name: Move cache\r\n        run: |\r\n          rm -rf \/tmp\/.buildx-cache\r\n          mv \/tmp\/.buildx-cache-new \/tmp\/.buildx-cache\r\n\r\n      - name: Publish Helm chart\r\n        uses: stefanprodan\/helm-gh-pages@master\r\n        with:\r\n          token: ${{ secrets.CHART_TOKEN }}\r\n          charts_dir: helm\r\n          charts_url: https:\/\/bullyrooks.github.io\/helm-charts\/\r\n          repository: helm-charts\r\n          branch: gh-charts\r\n          app_version: ${{ env.VERSION }}\r\n          chart_version: ${{ env.VERSION }}\r\n\r\n      - name: Deploy\r\n        uses: WyriHaximus\/github-action-helm3@v2\r\n        with:\r\n          exec: |\r\n            helm repo add bullyrooks https:\/\/bullyrooks.github.io\/helm-charts\/\r\n            helm repo update\r\n            echo \"helm upgrade message-generator bullyrooks\/message-generator --install --version ${{ env.VERSION }}\"\r\n            sleep 60s\r\n            helm repo update\r\n            helm upgrade message-generator bullyrooks\/message-generator --install --version ${{ env.VERSION }}\r\n          kubeconfig: '${{ secrets.KUBECONFIG }}'\r\n\r\n      - name: Create Pact Release Record\r\n        run: |\r\n          docker run --rm pactfoundation\/pact-cli:latest \\\r\n          broker record-release \\\r\n          --environment=okteto \\\r\n          --pacticipant=message-generator \\\r\n          --version=${{ env.VERSION }} \\\r\n          --broker-base-url=${{ env.PACTFLOW_URL }} \\\r\n          --broker-token=${{ env.PACTFLOW_TOKEN }}\r\n\r\n      - name: Create Pact Deployment Record\r\n        run: |\r\n          docker run --rm pactfoundation\/pact-cli:latest \\\r\n          broker record-deployment \\\r\n          --environment=okteto \\\r\n          --pacticipant=message-generator \\\r\n          --version=${{ env.VERSION }} \\\r\n          --broker-base-url=${{ env.PACTFLOW_URL }} \\\r\n          --broker-token=${{ env.PACTFLOW_TOKEN }}\r\n<\/code><\/pre>\n\n\n\n<p>The first part is the same.  However, I need the version when I run the verify step here, so I&#8217;ve moved the &#8220;Bump Version&#8221; task.  This will actually run the tests and publish the results back to the pactflow service (<code>pact.verifier.publishResults=true<\/code>).  I&#8217;m telling it which version and branch I am running against so that the verification results can be stamped correctly.  Additionally, I&#8217;m stamping with my environment (okteto), so that can know &#8220;where&#8221; my contract verification is valid.<\/p>\n\n\n\n<p>The next part is the &#8216;can-i-deploy&#8217; check, which comes before the <code>Deploy <\/code>task.  This checks to see if the version that I&#8217;m about to deploy is compatible with all versions in my okteto environment.  This can get really tricky with rollback, so if that is important to you make sure you have a rollback plan!<\/p>\n\n\n\n<p>Finally, if everything works, I update the release and deploy record.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Build and Deploy<\/h2>\n\n\n\n<p>First, we need to create an &#8216;environment&#8217; so that pact knows what services need to interact with each other in each environment.  Lets make one for okteto<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker run --rm pactfoundation\/pact-cli:latest \\\r\nbroker \\\r\ncreate-environment \\\r\n--name=okteto \\\r\n--broker-base-url=https:\/\/bullyrooks.pactflow.io \\\r\n--broker-token=&lt;your pactflow token><\/code><\/pre>\n\n\n\n<p>Go ahead and commit your feature branch and lets go ahead and create a PR similar to what we did for the consumer.  It should pass once the build succeeds<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"827\" height=\"710\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-12.png?resize=827%2C710&#038;ssl=1\" alt=\"\" class=\"wp-image-1413\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-12.png?w=827&amp;ssl=1 827w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-12.png?resize=300%2C258&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-12.png?resize=768%2C659&amp;ssl=1 768w\" sizes=\"auto, (max-width: 827px) 100vw, 827px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p> and when that succeeds, go ahead and merge to main.  Watch this kick off.  You should see your contract get verified and deployed successfully.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"563\" height=\"241\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-13.png?resize=563%2C241&#038;ssl=1\" alt=\"\" class=\"wp-image-1416\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-13.png?w=563&amp;ssl=1 563w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-13.png?resize=300%2C128&amp;ssl=1 300w\" sizes=\"auto, (max-width: 563px) 100vw, 563px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>Also, you&#8217;ll see that the contract has <strong>not<\/strong> been fulfilled in pactflow<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"336\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-14-1024x358.png?resize=960%2C336&#038;ssl=1\" alt=\"\" class=\"wp-image-1417\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-14.png?resize=1024%2C358&amp;ssl=1 1024w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-14.png?resize=300%2C105&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-14.png?resize=768%2C268&amp;ssl=1 768w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-14.png?w=1030&amp;ssl=1 1030w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>So we need to get the consumer rebuilt now that we&#8217;ve got a provider in place.<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"entry-summary\">\nNow lets move over to message-generator repo and create a new branch&hellip;\n<\/div>\n<div class=\"link-more\"><a href=\"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-provider-contract-test-for-rest-endpoints\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Kube Cloud Pt6 | Provider Contract Test for REST Endpoints&rdquo;<\/span>&hellip;<\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[201,199,197,198,43],"course":[196],"class_list":["post-1387","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-can-i-deploy","tag-contract-testing","tag-pact","tag-pactflow","tag-spring-boot","course-kube-cloud-pt6-contract-testing","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":1069,"url":"https:\/\/bullyrooks.com\/index.php\/2021\/07\/23\/spring-boot-lambda-implementation\/","url_meta":{"origin":1387,"position":0},"title":"Spring Boot Lambda Implementation","author":"Bullyrook","date":"July 23, 2021","format":false,"excerpt":"Now we're going to add some code. I'm going to follow my ports and adapters method of building a DTO and value object that I've used previously. Yes, its a bit of overkill for this project (especially a hello world example), but if you're using this course as a springboard\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2021\/07\/image-4.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2021\/07\/image-4.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2021\/07\/image-4.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":835,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-6-c52f5247ba20\/","url_meta":{"origin":1387,"position":1},"title":"Documentation and Code Coverage","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"Before we move on to getting our service ready for deployment we need to do a little more housecleaning. Sometimes these tasks get de-prioritized so we might as well take care of it now, before we move on. Endpoint Documentation Using OpenAPI is a powerful tool for documenting our REST\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":827,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-1-d67f80487848\/","url_meta":{"origin":1387,"position":2},"title":"Setup: IDE and New Project","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"\u00a0Its very easy to get a spring boot microservice up and running. You can read any variety of articles on medium (or other service) on how to do that. However, there\u2019s little about how to do some of the more complicated things that you need in order to support a\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1377,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-consumer-contract-tests-for-rest-endpoints\/","url_meta":{"origin":1387,"position":3},"title":"Kube Cloud Pt6 | Consumer Contract Tests for REST Endpoints","author":"Bullyrook","date":"March 8, 2022","format":false,"excerpt":"Let's start with cloud-application, create a new branch git checkout -b client-contract Lets add the necessary dependencies to our pom.xml <pact.version>4.0.10<\/pact.version> <pact.provider.maven.plugin>4.3.5<\/pact.provider.maven.plugin> <\/properties> ... <!-- Contract Testing --> <dependency> <groupId>au.com.dius<\/groupId> <artifactId>pact-jvm-consumer-junit5<\/artifactId> <version>${pact.version}<\/version> <scope>test<\/scope> <\/dependency> ... <plugin> <groupId>au.com.dius.pact.provider<\/groupId> <artifactId>maven<\/artifactId> <version${pact.provider.maven.plugin}<\/version> <configuration> <pactBrokerUrl>${env.PACTFLOW_URL}<\/pactBrokerUrl> <pactBrokerToken>${env.PACTFLOW_TOKEN}<\/pactBrokerToken> <projectVersion>${env.PACT_PUBLISH_CONSUMER_VERSION}<\/projectVersion> <pactBrokerAuthenticationScheme>Bearer<\/pactBrokerAuthenticationScheme> <\/configuration> <\/plugin> Pact is mostly a\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1356,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-an-event-consumer\/","url_meta":{"origin":1387,"position":4},"title":"Kube Cloud Pt5 | Create an Event Consumer","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"Now that we've got messages being published to kafka, we are going to need to build our consumer that receives those events and stores them into the mongo database. Go ahead and create a new repository called message-repository according to the microservice startup course here. This is the pom.xml that\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1229,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/23\/kube-cloud-pt2-automated-testing-with-testcontainers\/","url_meta":{"origin":1387,"position":5},"title":"Kube Cloud Pt2 | Automated Testing with TestContainers","author":"Bullyrook","date":"January 23, 2022","format":false,"excerpt":"In the last section we implemented service endpoint that stored data in a mongodb backend. In this session we're going to build a component test to automatically verify that functionality. TestContainer Overview TestContainers allow us to mock external resources with a docker based implementation. This is similar to \"regular\" mocking\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/comments?post=1387"}],"version-history":[{"count":7,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1387\/revisions"}],"predecessor-version":[{"id":1418,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1387\/revisions\/1418"}],"wp:attachment":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/media?parent=1387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/categories?post=1387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/tags?post=1387"},{"taxonomy":"course","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/course?post=1387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}