From c4f968e8b6484e7c15cfb9ec0c1d9b0411cff40b Mon Sep 17 00:00:00 2001
From: Beth Skurrie <beth@bethesque.com>
Date: Mon, 28 Sep 2020 10:41:22 +1000
Subject: [PATCH] fix: correct logic for determining if all interactions for a
 pact have been verified

Closes: https://github.com/pact-foundation/pact-ruby/issues/221
---
 lib/pact/provider/pact_source.rb              |  5 ++++
 .../provider/verification_results/create.rb   | 30 +++++++++++--------
 pact.gemspec                                  |  2 +-
 spec/integration/publish_verification_spec.rb |  9 ++++--
 .../verification_results/create_spec.rb       | 23 +++++++-------
 5 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/lib/pact/provider/pact_source.rb b/lib/pact/provider/pact_source.rb
index 866ee790..a1a14e27 100644
--- a/lib/pact/provider/pact_source.rb
+++ b/lib/pact/provider/pact_source.rb
@@ -1,6 +1,7 @@
 require 'pact/consumer_contract/pact_file'
 require 'pact/hal/http_client'
 require 'pact/hal/entity'
+require 'pact/consumer_contract'
 
 module Pact
   module Provider
@@ -24,6 +25,10 @@ def pending?
         uri.metadata[:pending]
       end
 
+      def consumer_contract
+        @consumer_contract ||= Pact::ConsumerContract.from_json(pact_json)
+      end
+
       def hal_entity
         http_client_keys = [:username, :password, :token]
         http_client_options = uri.options.reject{ |k, _| !http_client_keys.include?(k) }
diff --git a/lib/pact/provider/verification_results/create.rb b/lib/pact/provider/verification_results/create.rb
index 2ae5ced2..bf296729 100644
--- a/lib/pact/provider/verification_results/create.rb
+++ b/lib/pact/provider/verification_results/create.rb
@@ -28,7 +28,23 @@ def any_failures?
         end
 
         def publishable?
-          executed_interactions_count == all_interactions_count && all_interactions_count > 0
+          if defined?(@publishable)
+            @publishable
+          else
+            @publishable = pact_source.consumer_contract.interactions.all? do | interaction |
+              examples_for_pact_uri.any?{ |e| example_is_for_interaction?(e, interaction) }
+            end && examples_for_pact_uri.count > 0
+          end
+        end
+
+        def example_is_for_interaction?(example, interaction)
+          # Use the Pact Broker id if supported
+          if interaction._id
+            example[:pact_interaction]._id == interaction._id
+          else
+            # fall back to object equality (based on the field values of the interaction)
+            example[:pact_interaction] == interaction
+          end
         end
 
         def examples_for_pact_uri
@@ -39,18 +55,6 @@ def count_failures_for_pact_uri
           examples_for_pact_uri.count{ |e| e[:status] != 'passed' }
         end
 
-        def executed_interactions_count
-          examples_for_pact_uri
-            .collect { |e| e[:pact_interaction].object_id }
-            .uniq
-            .count
-        end
-
-        def all_interactions_count
-          interactions = (pact_source.pact_hash['interactions'] || pact_source.pact_hash['messages'])
-          interactions ? interactions.count : 0
-        end
-
         def test_results_hash_for_pact_uri
           {
             tests: examples_for_pact_uri.collect{ |e| clean_example(e) },
diff --git a/pact.gemspec b/pact.gemspec
index 97d49578..9ca52b6d 100644
--- a/pact.gemspec
+++ b/pact.gemspec
@@ -32,7 +32,7 @@ Gem::Specification.new do |gem|
   gem.add_runtime_dependency 'webrick', '~> 1.3'
   gem.add_runtime_dependency 'term-ansicolor', '~> 1.0'
 
-  gem.add_runtime_dependency 'pact-support', '~> 1.9'
+  gem.add_runtime_dependency 'pact-support', '~> 1.15'
   gem.add_runtime_dependency 'pact-mock_service', '~> 3.0', '>= 3.3.1'
 
   gem.add_development_dependency 'rake', '~> 13.0'
diff --git a/spec/integration/publish_verification_spec.rb b/spec/integration/publish_verification_spec.rb
index 088974e8..bf1684df 100644
--- a/spec/integration/publish_verification_spec.rb
+++ b/spec/integration/publish_verification_spec.rb
@@ -2,7 +2,6 @@
 require 'pact/provider/pact_uri'
 
 describe "publishing verifications" do
-
   before do
     allow(Pact.configuration).to receive(:provider).and_return(provider_configuration)
     allow($stdout).to receive(:puts)
@@ -16,13 +15,16 @@
   end
 
   let(:pact_sources) do
-    [instance_double('Pact::Provider::PactSource', pact_hash: pact_hash, uri: pact_uri)]
+    [instance_double('Pact::Provider::PactSource', consumer_contract: consumer_contract, pact_hash: pact_hash, uri: pact_uri)]
   end
 
   let(:pact_uri) do
     instance_double('Pact::Provider::PactURI', uri: 'pact.json', options: {}, metadata: metadata)
   end
 
+  let(:consumer_contract) { instance_double('Pact::ConsumerContract', interactions: [pact_interaction])}
+  let(:pact_interaction) { instance_double('Pact::Interaction', _id: "1") }
+
   let(:metadata) { { notices: notices} }
   let(:notices) { instance_double('Pact::PactBroker::Notices', after_verification_notices_text: ['hello'] ) }
 
@@ -53,7 +55,8 @@
         {
           testDescription: '1',
           status: 'passed',
-          pact_uri: pact_uri
+          pact_uri: pact_uri,
+          pact_interaction: pact_interaction
         }
       ]
     }
diff --git a/spec/lib/pact/provider/verification_results/create_spec.rb b/spec/lib/pact/provider/verification_results/create_spec.rb
index 55b5e846..7da50fa5 100644
--- a/spec/lib/pact/provider/verification_results/create_spec.rb
+++ b/spec/lib/pact/provider/verification_results/create_spec.rb
@@ -14,21 +14,25 @@ module VerificationResults
           double('provider_configuration', application_version: '1.2.3')
         end
         let(:pact_source_1) do
-          instance_double('Pact::Provider::PactSource', uri: pact_uri_1, pact_hash: pact_hash_1)
+          instance_double('Pact::Provider::PactSource', uri: pact_uri_1, consumer_contract: consumer_contract)
         end
+        let(:consumer_contract) { instance_double('Pact::ConsumerContract', interactions: interactions)}
+        let(:interactions) { [interaction_1] }
+        let(:interaction_1) { instance_double('Pact::Interaction', _id: "1") }
+        let(:interaction_2) { instance_double('Pact::Interaction', _id: "2") }
         let(:pact_uri_1) { instance_double('Pact::Provider::PactURI', uri: URI('foo')) }
         let(:pact_uri_2) { instance_double('Pact::Provider::PactURI', uri: URI('bar')) }
         let(:example_1) do
           {
             pact_uri: pact_uri_1,
-            pact_interaction: double('interaction'),
+            pact_interaction: interaction_1,
             status: 'passed'
           }
         end
         let(:example_2) do
           {
             pact_uri: pact_uri_2,
-            pact_interaction: double('interaction'),
+            pact_interaction: interaction_2,
             status: 'passed'
           }
         end
@@ -37,11 +41,6 @@ module VerificationResults
             tests: [example_1, example_2]
           }
         end
-        let(:pact_hash_1) do
-          {
-            'interactions' => [{}]
-          }
-        end
 
         subject { Create.call(pact_source_1, test_results_hash) }
 
@@ -78,11 +77,9 @@ module VerificationResults
         end
 
         context "when not every interaction has been executed" do
-          let(:pact_hash_1) do
-            {
-              'interactions' => [{}, {}]
-            }
-          end
+          let(:interaction_3) { instance_double('Pact::Interaction', _id: "3") }
+          let(:interactions) { [interaction_1, interaction_2]}
+
           it "sets publishable to false" do
             expect(VerificationResult).to receive(:new).with(false, anything, anything, anything)
             subject