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

Service Provider and Message Provider seem incompatible in pact_helper #260

Closed
victor-vineti opened this issue Mar 9, 2022 · 8 comments
Closed

Comments

@victor-vineti
Copy link

We're having an issue configuring a Pact.service_provider and a Pact.message_provider

1. The relevant versions of the gems you are using.:
- gem 'pact', '~> 1.57'
- gem 'pact-message', '~> 0.11'

1. The steps to recreate your issue.

  1. Configuredpact_helper.rb in the service_consumers folder
  2. Uploaded consumer contracts to Pact and are pulling.
  3. Run bundle exec rails pact:verify

Code example:

require 'pact/provider/rspec'
require 'pact/message'
require 'pact'
require 'rails_helper'
#requiring provider_states
require_relative '../concepts/permission_authz_events/authz_message_provider'
require_relative '../concepts/notification/webhook_message_provider'
require_relative '../service_consumers/provider_state_for_webhook_consumer'

CONFIG = {
  **AuthZMessageProvider::CONFIG, //These follow the message_provider examples
  **WebhookMessageProvider::CONFIG,
  **EmailMessageProvider::CONFIG,
  **SystemEventMessageProvider::CONFIG,
}.freeze


Pact.message_provider "Vineti Platform" do
  honours_pacts_from_pact_broker do
    pact_broker_base_url 'https://vineti.pactflow.io', { token: ENV["PACT_TOKEN"] }
    consumer_version_tags ENV["PACT_CONSUMER_VERSION_TAGS"].to_s.split(/,/)
    publish_verification_results ENV["PACT_PUBLISH"] == "true"
    app_version_tags ENV["PACT_VERSION_TAGS"].to_s.split(/,/)
    app_version ENV["PACT_VERSION"]
    enable_pending true
  end

  builder do |message_description|
    CONFIG[message_description.to_sym].call
  end
end

Pact.service_provider 'Ordering API' do
  honours_pacts_from_pact_broker do
    pact_broker_base_url 'https://vineti.pactflow.io', { token: ENV["PACT_TOKEN"] }
    consumer_version_tags 'SS-PR-874'
    publish_verification_results ENV["PACT_PUBLISH"] == "true"
    app_version_tags ENV["PACT_VERSION_TAGS"].to_s.split(/,/)
    app_version ENV["PACT_VERSION"]
    enable_pending true
  end
end

The issue is that Pact executes either the service_provider block correctly or the message_provider block in isolation but not both.

If the service_provider block is above the message_provider it runs the builder do block for the service provider. This produces this error:

 Failure/Error: CONFIG[message_description.to_sym].call
      
      NoMethodError:
        undefined method `to_sym' for nil:NilClass

I don't see why the service_provider should run a builder function as that isn't part of its configuration.

If the message_provider is ran before the service_provider, then this is the error.

      Failure/Error: @app.call(env)
      
      ActionController::RoutingError:
        No route matches [POST] "/"

I think the issue is because of the inheritance and this line:

def builder &block
self.app_block = lambda { RackToMessageAdapter.new(block) }
end
.

How should we configure this for both http requests and message requests?

@bethesque
Copy link
Member

That's a good question. You must be the first person to try it. I don't think I considered this when I wrote it. I'll have to look into it for you.

You may have some other issues because there is limited support for applications that are both message and http pact consumers/providers. What language and pact specification are you using to generate your pacts?

@victor-vineti
Copy link
Author

We are using Ruby for the language.

I am not quite sure how to look up the specific Pact specification. Gemfile.lock gives these if this can be mapped to the Pact specification:

pact-message (0.11.1)
      pact-mock_service (~> 3.1)
      pact-support (~> 1.8)
      thor (>= 0.20, < 2.0)
    pact-mock_service (3.9.1)
      filelock (~> 1.1)
      find_a_port (~> 1.0.1)
      json
      pact-support (~> 1.16, >= 1.16.4)
      rack (~> 2.0)
      rspec (>= 2.14)
      term-ansicolor (~> 1.0)
      thor (>= 0.19, < 2.0)
      webrick (~> 1.3)
    pact-support (1.16.7)
      awesome_print (~> 1.1)
      diff-lcs (~> 1.4)
      randexp (~> 0.1.7)
      term-ansicolor (~> 1.0)

The site says this: Pactflow Version: c63147d72.

@Jason-Wang-vineti
Copy link

@bethesque is there an available workaround? We were thinking of having two pact_helper.rb files, one for message pacts and one for http pacts, and separate verify commands for each as a potential workaround.

@bethesque
Copy link
Member

bethesque commented Mar 15, 2022

Hi Jason, yes there is a workaround. Make two separate pact_helper files, but make sure the second one isn't called "pact_helper.rb" or it will be automatically loaded.

Make a new pact verification task, and set the pact_helper file manually. Here are the docs for the custom task

https://docs.pact.io/implementation_guides/ruby/verifying_pacts#using-a-custom-pactverify-task

Pact::VerificationTask.new(:message) do | task |
  task.pact_helper '/path/to/your/message/pact/helper'
end

@Jason-Wang-vineti
Copy link

Jason-Wang-vineti commented Mar 15, 2022

This workaround worked! Thank you @bethesque, appreciate it.

If the consumer describes both HTTP and message based interactions for the provider, then running the custom pact verification task and the default one will both have pending failures because they are isolated to either HTTP or message. Does this mean I'll have to break out the consumer into two separate tests?

Before:

describe 'My Provider', pact: true do
  context 'HTTP based interactions' do
    ...
  end

  context 'message based interactions' do
    ...
  end
end

After:

describe 'My Provider HTTP', pact: true do
  ...
end

describe 'My Provider message', pact: true do
  ...
end

@bethesque
Copy link
Member

The spec tag for message pact is actually pact: :message. Does that make a difference?

@Jason-Wang-vineti
Copy link

Sorry for the late follow up, but that didn't work for us. For now, we're splitting our HTTP and message interactions within a service.

@YOU54F
Copy link
Member

YOU54F commented Aug 12, 2024

Message pact was introduced in pact V3 specification. one of the limitations was that a pact file could not contain both http and message pact interactions.

You may have some other issues because there is limited support for applications that are both message and http pact consumers/providers.

Which means this is still an issue with the pact v3 spec.

Pact v4 spec introduced multiple interaction types in a single pact file, mitigating this limitation. This should be considered during #319.

For now, if you are using pact-message-ruby for consumers, or pact-ruby for verifying providers, name http/message providers differently, and create 1 distinct helpers and 2 verification tasks, 1 for each type (http & message).

A useful interim measure would be to have a warning if a user has configured both a service_provider and message_provider in the same file.

@YOU54F YOU54F closed this as completed Aug 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants