Skip to content

Commit

Permalink
fix: implement pending logic for provider branches
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque authored Oct 18, 2022
1 parent d122fa6 commit 7cdf1a7
Show file tree
Hide file tree
Showing 9 changed files with 357 additions and 24 deletions.
8 changes: 7 additions & 1 deletion lib/pact_broker/domain/pact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ def select_pending_provider_version_tags(provider_version_tags)
provider_version_tags - tags_with_successful_verifications_from_that_branch - tags_with_previous_successful_verifications_from_other_branches
end

def pending?
# @param [String] branch_name the name of the provider branch that will be verifying the pacts
# @return Boolean whether or not the pact is in pending state (ie. the build should not fail if the verification fails)
def pending_for_provider_branch?(branch_name)
pact_version.pending_for_provider_branch?(branch_name)
end

def pending_for_any_provider_branch?
!pact_version.verified_successfully_by_any_provider_version?
end

Expand Down
39 changes: 39 additions & 0 deletions lib/pact_broker/pacts/pact_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ def join_provider_version_tags_for_tag(tag)
}
join(:tags, tags_join)
end

def join_branch_versions_for_branch_name_to_verifications(branch_name)
branch_versions_join = {
Sequel[:branch_versions][:version_id] => Sequel[:verifications][:provider_version_id],
Sequel[:branch_versions][:branch_name] => branch_name
}
join(:branch_versions, branch_versions_join)
end
end

def name
Expand All @@ -106,6 +114,10 @@ def latest_consumer_version_number
latest_consumer_version.number
end

def pending_for_provider_branch?(branch_name)
!any_successful_verifications_from_provider_branch?(branch_name) && !any_successful_verifications_from_another_branch_from_before_this_branch_created?(branch_name)
end

def select_provider_tags_with_successful_verifications_from_another_branch_from_before_this_branch_created(tags)
tags.select do | tag |
first_tag_with_name = PactBroker::Domain::Tag.where(pacticipant_id: provider_id, name: tag).order(:created_at).first
Expand Down Expand Up @@ -157,6 +169,33 @@ def set_interactions_and_messages_counts!
)
end
end

def any_successful_verifications_from_provider_branch?(branch_name)
PactVersion.where(Sequel[:pact_versions][:id] => id)
.join_successful_verifications
.join_branch_versions_for_branch_name_to_verifications(branch_name)
.any?
end

def any_successful_verifications_from_another_branch_from_before_this_branch_created?(branch_name)
branch = PactBroker::Versions::Branch.where(pacticipant_id: provider_id, name: branch_name).single_record

verifications_join = {
Sequel[:verifications][:pact_version_id] => Sequel[:pact_versions][:id],
Sequel[:verifications][:success] => true
}
query = PactVersion.where(Sequel[:pact_versions][:id] => id)
.join(:verifications, verifications_join)
.join(:branch_versions, Sequel[:branch_versions][:version_id] => Sequel[:verifications][:provider_version_id]) do
Sequel.lit("branch_versions.branch_name != ?", branch_name)
end

if branch
query = query.where { Sequel[:verifications][:created_at] < branch.created_at }
end

query.any?
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/pacts/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def find_for_verification(provider_name, provider_version_branch, provider_versi
.find_for_verification(provider_name, consumer_version_selectors)
.collect do | selected_pact |
# Todo move this into the repository
squash_pacts_for_verification(provider_version_tags, selected_pact, options[:include_pending_status])
squash_pacts_for_verification(provider_version_tags, provider_version_branch, selected_pact, options[:include_pending_status])
end

verifiable_wip_pacts = if options[:include_wip_pacts_since]
Expand Down
11 changes: 7 additions & 4 deletions lib/pact_broker/pacts/squash_pacts_for_verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,28 @@
module PactBroker
module Pacts
module SquashPactsForVerification
def self.call(provider_version_tags, selected_pact, include_pending_status = false)
def self.call(provider_version_tags, provider_version_branch, selected_pact, include_pending_status = false)
domain_pact = selected_pact.pact

if include_pending_status
pending_provider_tags = []
pending = nil
if provider_version_tags.any?
if provider_version_branch
pending = domain_pact.pending_for_provider_branch?(provider_version_branch)
elsif provider_version_tags.any?
pending_provider_tags = domain_pact.select_pending_provider_version_tags(provider_version_tags)
pending = pending_provider_tags.any?
else
pending = domain_pact.pending?
pending = domain_pact.pending_for_any_provider_branch?
end
non_pending_provider_tags = provider_version_tags - pending_provider_tags
VerifiablePact.new(
domain_pact,
selected_pact.selectors,
pending,
pending_provider_tags,
non_pending_provider_tags
non_pending_provider_tags,
provider_version_branch
)
else
VerifiablePact.new(
Expand Down
40 changes: 28 additions & 12 deletions lib/pact_broker/test/test_data_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -399,22 +399,13 @@ def create_verification parameters = {}
verification = PactBroker::Domain::Verification.new(parameters)
pact_version = PactBroker::Pacts::Repository.new.find_pact_version(@consumer, @provider, pact.pact_version_sha)
@provider_version = version_repository.find_by_pacticipant_id_and_number_or_create(provider.id, provider_version_number)
PactBroker::Versions::BranchVersionRepository.new.add_branch(@provider_version, branch) if branch
branch_version = PactBroker::Versions::BranchVersionRepository.new.add_branch(@provider_version, branch) if branch

if tag_names.any?
tag_names.each do | tag_name |
PactBroker::Domain::Tag.new(name: tag_name, version: @provider_version, version_order: @provider_version.order).insert_ignore
set_created_at_if_set(parameters[:created_at], :tags, version_id: @provider_version.id, name: tag_name)
end
end
set_created_at_for_provider_tags(parameters, tag_names)

@verification = PactBroker::Verifications::Repository.new.create(verification, provider_version_number, pact_version)

set_created_at_if_set(parameters[:created_at], :verifications, id: @verification.id)
set_created_at_if_set(parameters[:created_at], :versions, id: @provider_version.id)
set_created_at_if_set(parameters[:created_at], :latest_verification_id_for_pact_version_and_provider_version, pact_version_id: pact_version_id, provider_version_id: @provider_version.id)
set_created_at_if_set(parameters[:created_at], :pact_version_provider_tag_successful_verifications, { verification_id: @verification.id }, :execution_date)

set_created_at_for_verification_resources(parameters, pact_version.id, branch, branch_version)
self
end

Expand Down Expand Up @@ -674,6 +665,31 @@ def webhook_pacticipant(name, params)
[nil, Domain::WebhookPacticipant.new(label: label)]
end
end

def set_created_at_for_provider_tags(parameters, tag_names)
if tag_names.any?
tag_names.each do | tag_name |
PactBroker::Domain::Tag.new(name: tag_name, version: @provider_version, version_order: @provider_version.order).insert_ignore
set_created_at_if_set(parameters[:created_at], :tags, version_id: @provider_version.id, name: tag_name)
end
end
end

def set_created_at_for_verification_resources(parameters, pact_version_id, branch, branch_version)
if branch
set_created_at_if_set(parameters[:created_at], :branch_versions, id: branch_version.id)

# if the branch has just been created...
if branch_version.branch.branch_versions.size == 1
set_created_at_if_set(parameters[:created_at], :branches, id: branch_version.branch.id)
end
end

set_created_at_if_set(parameters[:created_at], :verifications, id: @verification.id)
set_created_at_if_set(parameters[:created_at], :versions, id: @provider_version.id)
set_created_at_if_set(parameters[:created_at], :latest_verification_id_for_pact_version_and_provider_version, pact_version_id: pact_version_id, provider_version_id: @provider_version.id)
set_created_at_if_set(parameters[:created_at], :pact_version_provider_tag_successful_verifications, { verification_id: @verification.id }, :execution_date)
end
end
end
end
1 change: 1 addition & 0 deletions lib/pact_broker/versions/branch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Branch < Sequel::Model(:branches)
plugin :insert_ignore, identifying_columns: [:name, :pacticipant_id]

associate(:many_to_one, :pacticipant, :class => "PactBroker::Domain::Pacticipant", :key => :pacticipant_id, :primary_key => :id)
associate(:one_to_many, :branch_versions, :class => "PactBroker::Versions::BranchVersion", :key => :branch_id, :primary_key => :id)

dataset_module do
include PactBroker::Repositories::Helpers
Expand Down
137 changes: 137 additions & 0 deletions spec/features/pending_pacts_with_branches_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
RSpec.describe "the pending lifecycle of a pact (with tags)" do
let(:pact_content_1) { { some: "interactions" }.to_json }
let(:pact_content_2) { { some: "other interactions" }.to_json }
let(:request_headers) { { "CONTENT_TYPE" => "application/json", "HTTP_ACCEPT" => "application/hal+json"} }
let(:failed_verification_results) do
{
providerApplicationVersion: "2",
success: false
}.to_json
end
let(:successful_verification_results) do
{
providerApplicationVersion: "2",
success: true
}.to_json
end

def publish_pact
put("/pacts/provider/Bar/consumer/Foo/version/1", pact_content_1, request_headers)
end

def get_pacts_for_verification(provider_version_branch = "main")
post("/pacts/provider/Bar/for-verification", { includePendingStatus: true, providerVersionBranch: provider_version_branch }.to_json, request_headers)
end

def pact_url_from(pacts_for_verification_response)
JSON.parse(pacts_for_verification_response.body)["_embedded"]["pacts"][0]["_links"]["self"]["href"]
end

def get_pact(pact_url)
get pact_url, nil, request_headers
end

def verification_results_url_from(pact_response)
JSON.parse(pact_response.body)["_links"]["pb:publish-verification-results"]["href"]
end

def publish_verification_results(verification_results_url, results)
put("/pacticipants/Bar/branches/main/versions/#{JSON.parse(results)["providerApplicationVersion"]}", nil, { "CONTENT_TYPE" => "application/json" })
post(verification_results_url, results, request_headers)
end

def pending_status_from(pacts_for_verification_response)
JSON.parse(pacts_for_verification_response.body)["_embedded"]["pacts"][0]["verificationProperties"]["pending"]
end

context "a pact" do
describe "when it is first published" do
it "is pending" do
publish_pact
pacts_for_verification_response = get_pacts_for_verification
expect(pending_status_from(pacts_for_verification_response)).to be true
end
end

describe "when it is verified unsuccessfully" do
it "is still pending" do
# CONSUMER BUILD
# publish pact
publish_pact

# PROVIDER BUILD
# fetch pacts to verify
pacts_for_verification_response = get_pacts_for_verification
pact_url = pact_url_from(pacts_for_verification_response)
pact_response = get_pact(pact_url)

# verify pact... failure...

# publish failure verification results
verification_results_url = verification_results_url_from(pact_response)
publish_verification_results(verification_results_url, failed_verification_results)

# ANOTHER PROVIDER BUILD
# get pacts for verification
pacts_for_verification_response = get_pacts_for_verification
# still pending
expect(pending_status_from(pacts_for_verification_response)).to be true
end
end

describe "when it is verified successfully" do
it "is no longer pending" do
# CONSUMER BUILD
publish_pact

# PROVIDER BUILD
pacts_for_verification_response = get_pacts_for_verification

# fetch pact
pact_url = pact_url_from(pacts_for_verification_response)
pact_response = get_pact(pact_url)

# verify pact... success!

# publish failure verification results
verification_results_url = verification_results_url_from(pact_response)
publish_verification_results(verification_results_url, successful_verification_results)

# ANOTHER PROVIDER BUILD 2
# get pacts for verification
# publish successful verification results
pacts_for_verification_response = get_pacts_for_verification
# not pending any more
expect(pending_status_from(pacts_for_verification_response)).to be false
end
end


describe "when it is verified successfully by one branch, and then another branch of the provider is created" do
it "is not pending for the new branch" do
# CONSUMER BUILD
publish_pact

# PROVIDER BUILD
pacts_for_verification_response = get_pacts_for_verification

# fetch pact
pact_url = pact_url_from(pacts_for_verification_response)
pact_response = get_pact(pact_url)

# verify pact... success!

# publish failure verification results
verification_results_url = verification_results_url_from(pact_response)
publish_verification_results(verification_results_url, successful_verification_results)

# ANOTHER PROVIDER BUILD 2 from another branch
# get pacts for verification
# publish successful verification results
pacts_for_verification_response = get_pacts_for_verification("feat/foo")
# not pending
expect(pending_status_from(pacts_for_verification_response)).to be false
end
end
end
end
Loading

0 comments on commit 7cdf1a7

Please sign in to comment.