Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add first pact verification for WDS integration. #1511

Merged
merged 6 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions .github/workflows/verify_consumer_pacts.yaml
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is copied from DataBiosphere/jade-data-repo#1528, I'll annotate the lines which are WSM-specific.

Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
name: Verify consumer pacts
# The purpose of this workflow is to verify ANY consumer contract(s) dependent on workspacemanager provider using Pact
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment adjusted to include workspacemanager pacticipant name, which must match the helmchart name.

# framework.
#
# The workflow meets the criteria of Pact Broker *Platinum* as described in https://docs.pact.io/pact_nirvana/step_6.
# The can-i-deploy job has been added to this workflow to gate the merge of PRs into develop branch.
#
# This workflow is triggered when
#
# 1. Consumer makes a change that results in a new pact published to Pact Broker (will verify ONLY the changed pact and publish the verification results back to the broker)
# 2. Provider makes a change (runs verification tests against ALL DEPLOYED consumer pact versions and publishes corresponding verification results)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ALL DEPLOYED consumer pact versions

doesn't this require some configuration/integration with beehive or sherlock? Is this already set up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I'm not sure...this file is the result of a blatant copypaste. I did check in https://beehive.dsp-devops.broadinstitute.org/charts/workspacemanager/contract-testing and confirmed that for workspacemanager contract testing is enabled:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll get to exercise some of the provider side again after this merges by integrating another couple pact verifications...hopefully I'll have more of a clue after that process.

#
#
# The workflow requires the following Pact broker credentials:
# - PACT_BROKER_USERNAME - the Pact Broker username
# - PACT_BROKER_PASSWORD - the Pact Broker password
# They are managed by Atlantis and were added to Terraform here:
# https://github.com/broadinstitute/terraform-ap-deployments/pull/1086
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included link to PR where wsm's creds were introduced.

env:
PACT_BROKER_URL: https://pact-broker.dsp-eng-tools.broadinstitute.org
spring_profiles_active: human-readable-logging
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added spring_profiles_active to get human friendly logs, which are important to interpreting pact verification failures.

on:
pull_request:
branches:
- develop
paths-ignore:
- 'README.md'
push:
branches:
- develop
paths-ignore:
- 'README.md'
workflow_dispatch:
inputs:
pb-event-type:
description: 'the Pact Broker event type that triggers this workflow'
required: true
type: string
consumer-name:
description: 'the consumer name'
required: true
type: string
consumer-version-number:
description: 'the version number of the most recent consumer version associated with the pact content'
required: true
type: string
provider-version-number:
description: 'the provider version number for the verification result'
required: false
type: string
consumer-version-tags:
description: 'the list of tag names for the most recent consumer version associated with the pact content, separated by ", "'
required: true
type: string
consumer-version-branch:
description: 'the name of the branch for most recent consumer version associated with the pact content'
required: true
type: string
provider-version-branch:
description: 'the name of the branch for the provider version associated with the verification result'
required: false
type: string
consumer-labels:
description: 'the list of labels for the consumer associated with the pact content, separated by ", "'
required: false
type: string
provider-labels:
description: 'the list of labels for the provider associated with the pact content, separated by ", "'
required: false
type: string
pact-url:
description: 'the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format'
required: true
type: string

jobs:
verify-consumer-pact:
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write'
outputs:
provider-sha: ${{ steps.verification-test.outputs.provider-sha }}

steps:
- name: Checkout current code
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Extract branch
id: extract-branch
run: |
GITHUB_EVENT_NAME=${{ github.event_name }}
if [[ "$GITHUB_EVENT_NAME" == "push" || "$GITHUB_EVENT_NAME" == "workflow_dispatch"]]; then
GITHUB_REF=${{ github.ref }} # The Git Ref that this workflow runs on
GITHUB_SHA=${{ github.sha }} # The Git Sha that this workflow runs on
elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
GITHUB_REF=refs/heads/${{ github.head_ref }}
GITHUB_SHA=${{ github.event.pull_request.head.sha }}
else
echo "Failed to extract branch information"
exit 1
fi
echo "CURRENT_BRANCH=${GITHUB_REF/refs\/heads\//""}" >> $GITHUB_ENV
echo "CURRENT_SHA=$GITHUB_SHA" >> $GITHUB_ENV
- name: "This step will only run when this workflow is triggered by a Pact Broker webhook event"
if: ${{ inputs.pb-event-type != '' }}
run: |
echo "pb-event-type=${{ inputs.pb-event-type }}"
echo "consumer-name=${{ inputs.consumer-name }}"
echo "consumer-version-branch/consumer-version-number=${{ inputs.consumer-version-branch }}/${{ inputs.consumer-version-number }}"
echo "provider-version-branch/provider-version-number=${{ inputs.provider-version-branch }}/${{ inputs.provider-version-number }}"
# The consumer-version-branch/consumer-version-number is practically sufficient.
# The pact-url is included here in case future pact4s client supports it.
echo "pact-url=${{ inputs.pact-url }}"
if [[ ! -z "${{ inputs.provider-version-branch }}" ]]; then
echo "PROVIDER_BRANCH=${{ inputs.provider-version-branch }}" >> $GITHUB_ENV
echo "CHECKOUT_BRANCH=${{ inputs.provider-version-branch }}" >> $GITHUB_ENV
fi
if [[ ! -z "${{ inputs.provider-version-number }}" ]]; then
echo "PROVIDER_SHA=${{ inputs.provider-version-number }}" >> $GITHUB_ENV
echo "CHECKOUT_SHA=${{ inputs.provider-version-number }}" >> $GITHUB_ENV
fi
echo "CONSUMER_NAME=${{ inputs.consumer-name }}" >> $GITHUB_ENV
echo "CONSUMER_BRANCH=${{ inputs.consumer-version-branch }}" >> $GITHUB_ENV
echo "CONSUMER_SHA=${{ inputs.consumer-version-number }}" >> $GITHUB_ENV
- name: Switch to appropriate branch
run: |
if [[ -z "${{ env.PROVIDER_BRANCH }}" ]]; then
echo "PROVIDER_BRANCH=${{ env.CURRENT_BRANCH }}" >> $GITHUB_ENV
fi
if [[ -z "${{ env.PROVIDER_SHA }}" ]]; then
echo "PROVIDER_SHA=${{ env.CURRENT_SHA }}" >> $GITHUB_ENV
fi
git fetch
if [[ ! -z "${{ env.CHECKOUT_BRANCH }}" ]] && [[ ! -z "${{ env.CHECKOUT_SHA }}" ]]; then
echo "git checkout -b ${{ env.CHECKOUT_BRANCH }} ${{ env.CHECKOUT_SHA }}"
git checkout -b ${{ env.CHECKOUT_BRANCH }} ${{ env.CHECKOUT_SHA }} || echo "already in ${{ env.CHECKOUT_BRANCH }}"
echo "git branch"
git branch
else
if [[ "${{ github.event_name }}" == "push" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "git checkout ${{ env.CURRENT_BRANCH }}"
git checkout ${{ env.CURRENT_BRANCH }}
else
echo "git checkout -b ${{ env.CURRENT_BRANCH }} ${{ env.CURRENT_SHA }}"
git checkout -b ${{ env.CURRENT_BRANCH }} ${{ env.CURRENT_SHA }}
fi
fi
echo "git rev-parse HEAD"
git rev-parse HEAD
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin'

- name: Gradle cache
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: v1-${{ runner.os }}-gradle-${{ github.ref }}-${{ github.sha }}
restore-keys: v1-${{ runner.os }}-gradle-${{ github.ref }}

- name: Verify consumer pacts and publish verification status to Pact Broker
id: verification-test
env:
PACT_PROVIDER_COMMIT: ${{ env.PROVIDER_SHA }}
PACT_PROVIDER_BRANCH: ${{ env.PROVIDER_BRANCH }}
PACT_BROKER_USERNAME: ${{ secrets.PACT_BROKER_USERNAME }}
PACT_BROKER_PASSWORD: ${{ secrets.PACT_BROKER_PASSWORD }}
run: |
echo "provider-sha=${{ env.PROVIDER_SHA }}" >> $GITHUB_OUTPUT
echo "env.CHECKOUT_BRANCH=${{ env.CHECKOUT_BRANCH }} # If not empty, this reflects the branch being checked out (generated by Pact Broker)"
echo "env.CHECKOUT_SHA=${{ env.CHECKOUT_SHA }} # If not empty, this reflects the git commit hash of the branch being checked out (generated by Pact Broker)"
echo "env.CURRENT_BRANCH=${{ env.CURRENT_BRANCH }} # This reflects the branch being checked out if CHECKOUT_BRANCH is empty"
echo "env.CURRENT_SHA=${{ env.CURRENT_SHA }} # This reflects the git commit hash of the branch being checked out if CHECKOUT_BRANCH is empty"
echo "env.PROVIDER_BRANCH=${{ env.PROVIDER_BRANCH }} # This reflects the provider branch for pact verification"
echo "env.PROVIDER_SHA=${{ env.PROVIDER_SHA }} # This reflects the provider version for pact verification"
echo "env.CONSUMER_BRANCH=${{ env.CONSUMER_BRANCH }} # This reflects the consumer branch for pact verification (generated by Pact Broker)"
echo "env.CONSUMER_SHA=${{ env.CONSUMER_SHA }} # This reflects the consumer version for pact verification (generated by Pact Broker)"
./gradlew --build-cache verifyPacts --scan
- name: Upload Test Reports
if: always()
uses: actions/upload-artifact@v1
with:
name: Test Reports
path: service/build/reports

can-i-deploy:
# The can-i-deploy job will run as a result of a workspace manager PR.
# It reports the pact verification statuses on all deployed environments.
runs-on: ubuntu-latest
if: ${{ inputs.pb-event-type == '' }}
needs: [ verify-consumer-pact ]
steps:
- name: Dispatch to terra-github-workflows
uses: broadinstitute/workflow-dispatch@v3
with:
workflow: .github/workflows/can-i-deploy.yaml
repo: broadinstitute/terra-github-workflows
ref: refs/heads/main
token: ${{ secrets.BROADBOT_TOKEN }} # github token for access to kick off a job in the private repo
inputs: '{ "pacticipant": "workspacemanager", "version": "${{ needs.verify-consumer-pact.outputs.provider-sha }}" }'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjusted pacticipant name to workspacemanager

22 changes: 21 additions & 1 deletion service/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ au.com.dius.pact.core:matchers:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact.core:model:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact.core:pactbroker:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact.core:support:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact.provider:junit5:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact.provider:junit5spring:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact:consumer:4.3.19=testCompileClasspath,testRuntimeClasspath
au.com.dius.pact:provider:4.3.19=testCompileClasspath,testRuntimeClasspath
bio.terra:billing-profile-manager-client:0.1.29-SNAPSHOT=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
bio.terra:datarepo-client:1.41.0-SNAPSHOT=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
bio.terra:stairway-gcp:0.0.76-SNAPSHOT=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
Expand Down Expand Up @@ -181,6 +184,20 @@ com.squareup.okhttp3:okhttp:4.9.3=compileClasspath,productionRuntimeClasspath,ru
com.squareup.okio:okio:2.8.0=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.typesafe:config:1.4.1=testRuntimeClasspath
com.vdurmont:semver4j:3.1.0=testRuntimeClasspath
com.vladsch.flexmark:flexmark-ext-tables:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-ast:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-builder:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-collection:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-data:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-dependency:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-format:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-html:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-misc:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-options:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-sequence:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util-visitor:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark-util:0.62.2=testRuntimeClasspath
com.vladsch.flexmark:flexmark:0.62.2=testRuntimeClasspath
com.zaxxer:HikariCP:4.0.3=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-beanutils:commons-beanutils:1.9.4=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-codec:commons-codec:1.15=compileClasspath,productionRuntimeClasspath,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
Expand All @@ -190,7 +207,8 @@ commons-io:commons-io:2.11.0=compileClasspath,productionRuntimeClasspath,runtime
commons-logging:commons-logging:1.2=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-validator:commons-validator:1.7=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
dk.brics.automaton:automaton:1.11-8=testRuntimeClasspath
io.github.classgraph:classgraph:4.8.69=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.github.classgraph:classgraph:4.8.129=testCompileClasspath,testRuntimeClasspath
io.github.classgraph:classgraph:4.8.69=compileClasspath,productionRuntimeClasspath,runtimeClasspath
io.github.java-diff-utils:java-diff-utils:4.12=testRuntimeClasspath
io.github.microutils:kotlin-logging-jvm:2.0.10=testCompileClasspath
io.github.microutils:kotlin-logging-jvm:2.0.11=testRuntimeClasspath
Expand Down Expand Up @@ -352,6 +370,7 @@ org.bouncycastle:bcutil-jdk18on:1.72=compileClasspath,productionRuntimeClasspath
org.broadinstitute.dsde.workbench:sam-client_2.13:0.1-fd8ee25=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-compat-qual:2.5.5=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.22.2=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.codehaus.groovy:groovy:3.0.19=testRuntimeClasspath
org.codehaus.mojo:animal-sniffer-annotations:1.21=productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.codehaus.plexus:plexus-utils:3.2.1=productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.codehaus.woodstox:stax2-api:4.2.1=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
Expand Down Expand Up @@ -469,6 +488,7 @@ org.springframework:spring-jdbc:5.3.29=compileClasspath,productionRuntimeClasspa
org.springframework:spring-test:5.3.29=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-tx:5.3.29=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-web:5.3.29=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-webflux:5.3.29=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-webmvc:5.3.29=compileClasspath,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:database-commons:1.17.5=testCompileClasspath,testRuntimeClasspath
org.testcontainers:jdbc:1.17.5=testCompileClasspath,testRuntimeClasspath
Expand Down
2 changes: 2 additions & 0 deletions service/gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ dependencies {

// pact
testImplementation 'au.com.dius.pact.consumer:junit5:4.3.19'
testImplementation 'au.com.dius.pact.provider:junit5:4.3.19'
testImplementation 'au.com.dius.pact.provider:junit5spring:4.3.19'

annotationProcessor group: "com.google.auto.value", name: "auto-value", version: "1.7.4"
annotationProcessor group: "org.springframework.boot", name: "spring-boot-configuration-processor", version: "2.6.6"
Expand Down
20 changes: 20 additions & 0 deletions service/gradle/testing.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,23 @@ task pactTests(type: Test) {
environment.put('pact.provider.version', "$project.version")
}

def boolean isCiServer = System.getenv().containsKey("CI")
// verify the provider side of pacts WSM has with other services
task verifyPacts(type: Test) {
useJUnitPlatform {
includeTags "pact-verification"
}
outputs.upToDateWhen { false }
if (isCiServer) {
systemProperty 'pact.verifier.publishResults', true
}
// to run a local pactbroker, see:
// https://broadworkbench.atlassian.net/wiki/spaces/IRT/pages/2829680649/Contract+Test+Local+Development
if (System.getenv().containsKey('PACT_BROKER_URL')) {
systemProperty 'pactbroker.url', System.getenv('PACT_BROKER_URL')
}
systemProperty 'pactbroker.auth.username', System.getenv('PACT_BROKER_USERNAME')
systemProperty 'pactbroker.auth.password', System.getenv('PACT_BROKER_PASSWORD')
systemProperty 'pact.provider.version', System.getenv('PACT_PROVIDER_COMMIT')
systemProperty 'pact.provider.branch', System.getenv('PACT_PROVIDER_BRANCH')
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import bio.terra.workspace.service.resource.controlled.ControlledResourceMetadataManager;
import bio.terra.workspace.service.resource.controlled.ControlledResourceService;
import bio.terra.workspace.service.resource.controlled.cloud.azure.AzureStorageAccessService;
import bio.terra.workspace.service.resource.referenced.ReferencedResourceService;
import bio.terra.workspace.service.spendprofile.SpendProfileId;
import bio.terra.workspace.service.workspace.WorkspaceService;
import com.azure.core.management.Region;
Expand All @@ -31,6 +32,7 @@ public class BaseAzureUnitTest extends BaseUnitTestMocks {
@MockBean private WorkspaceService mockWorkspaceService;
@MockBean private ControlledResourceMetadataManager mockControlledResourceMetadataManager;
@MockBean private ControlledResourceService mockControlledResourceService;
@MockBean private ReferencedResourceService mockReferencedResourceService;

public AzureStorageAccessService mockAzureStorageAccessService() {
return mockAzureStorageAccessService;
Expand All @@ -56,6 +58,10 @@ public ControlledResourceService getMockControlledResourceService() {
return mockControlledResourceService;
}

public ReferencedResourceService mockReferencedResourceService() {
return mockReferencedResourceService;
}

public void setupMockLandingZoneRegion(Region region) {
when(mockWorkspaceService().getWorkspace(any()))
.thenReturn(
Expand Down
Loading