Skip to content

Commit

Permalink
Add first pact verification for WDS integration.
Browse files Browse the repository at this point in the history
This pairs with
DataBiosphere/terra-workspace-data-service#372
to establish a contract between WDS and WSM, initially focused on
`ReferencedGcpResourceController`.
  • Loading branch information
jladieu committed Nov 1, 2023
1 parent 2e40588 commit 9efa0c9
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 1 deletion.
203 changes: 203 additions & 0 deletions .github/workflows/verify_consumer_pacts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
name: Verify consumer pacts
# The purpose of this workflow is to verify ANY consumer contract(s) dependent on workspacemanager provider using Pact
# 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)
#
#
# 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
env:
PACT_BROKER_URL: pact-broker.dsp-eng-tools.broadinstitute.org
spring_profiles_active: human-readable-logging
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" ]]; then
GITHUB_REF=${{ github.ref }}
GITHUB_SHA=${{ github.sha }}
elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
GITHUB_REF=refs/heads/${{ github.head_ref }}
GITHUB_SHA=${{ github.event.pull_request.head.sha }}
elif [[ "$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
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
can-i-deploy:
# The can-i-deploy job will run as a result of a jade-data-repo 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 }}" }'
2 changes: 2 additions & 0 deletions scripts/write-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ landingzone:
- [email protected]
- [email protected]
- [email protected]
pactbroker:
url: localhost:9292
EOF
else
Expand Down
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 @@ -179,6 +182,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 @@ -188,7 +205,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 @@ -350,6 +368,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 @@ -467,6 +486,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
16 changes: 16 additions & 0 deletions service/gradle/testing.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,19 @@ task pactTests(type: Test) {
environment.put('pact.provider.version', "$project.version")
}


// verify the provider side of pacts WSM has with other services
task verifyPacts(type: Test) {
useJUnitPlatform {
includeTags "pact-verification"
}

// 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 'pact.provider.version', System.getenv('PACT_PROVIDER_COMMIT')
systemProperty 'pact.provider.branch', System.getenv('PACT_PROVIDER_BRANCH')
systemProperty 'pact.verifier.publishResults', true
}
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

0 comments on commit 9efa0c9

Please sign in to comment.