pact-foundation / pact-ruby

Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://pact.io
MIT License
2.17k stars 216 forks source link

rails pact:verify runs tests and sends to broker, then hangs #300

Closed nktch1 closed 11 months ago

nktch1 commented 1 year ago

Hey, guys! I have a problem. I am using gem ruby pact 1.63.0. I run provider tests locally in a container and they complete successfully. But. When I try to run them in a Gitlab runner, the tests run successfully, the results are sent to the broker, but then the rails pact:verify command just hangs. The job only completes on timeout.

Maybe you have some ideas?

I attach pact file, provider test code, logs on local computer in container and logs in runner.

pact.json

{
  "consumer": {
    "name": "consumer-service-name"
  },
  "interactions": [
    {
      "description": "get all static pages",
      "providerState": "static pages exist",
      "request": {
        "matchingRules": {
          "$.query.$.page_number[0]": {
            "match": "type"
          },
          "$.query.$.per_page[0]": {
            "match": "type"
          },
          "$.query.$.q[0]": {
            "match": "type"
          },
          "$.query.$.visible[0]": {
            "match": "type"
          }
        },
        "method": "GET",
        "path": "/api/admin/pages",
        "query": "page_number=1&per_page=10&q=legal&visible=true"
      },
      "response": {
        "body": {
          "data": {
            "meta": {
              "current_page": 1,
              "next_page": 2,
              "per_page": 10,
              "total_count": 2,
              "total_pages": 10
            },
            "pages": [
              {
                "foreign_link": "testLink",
                "id": "123",
                "slug": "legal",
                "tenant": "some_tenant",
                "title": "Legality",
                "updated_at": "2020-01-01T00:00:00",
                "visible": true
              }
            ]
          }
        },
        "headers": {
          "Content-Type": "application/json; charset=utf-8"
        },
        "matchingRules": {
          "$.body.data.meta": {
            "match": "type"
          },
          "$.body.data.pages": {
            "match": "type",
            "min": 1
          },
          "$.body.data.pages[*].foreign_link": {
            "match": "type"
          },
          "$.body.data.pages[*].id": {
            "match": "type"
          },
          "$.body.data.pages[*].slug": {
            "match": "type"
          },
          "$.body.data.pages[*].tenant": {
            "match": "type"
          },
          "$.body.data.pages[*].title": {
            "match": "type"
          },
          "$.body.data.pages[*].updated_at": {
            "match": "type"
          }
        },
        "status": 200
      }
    }
  ],
  "metadata": {
    "pact-js": {
      "version": "12.1.0"
    },
    "pactRust": {
      "ffi": "0.4.9",
      "models": "1.1.11"
    },
    "pactSpecification": {
      "version": "2.0.0"
    }
  },
  "provider": {
    "name": "provider-service-name"
  }
}

pact_helper.rb

Pact.service_provider 'provider-service-name' do  
  pact_broker_url = ENV['PACT_BROKER_URL']  
  provider_version = ENV['PACT_PROVIDER_VERSION']  
  provider_version_branch = ENV['PACT_PROVIDER_VERSION_BRANCH'] # rubocop:disable Lint/UselessAssignment  
  pact_broker_auth = { username: ENV['PACT_BROKER_USERNAME'], password: ENV["PACT_BROKER_PASSWORD"] }  

  honours_pacts_from_pact_broker do  
    verbose true  
    app_version provider_version  
    publish_verification_results true  
    pact_broker_base_url pact_broker_url, pact_broker_auth  
  end  

  honours_pact_with 'consumer-service-name' do  
    version = ENV.fetch('PACT_CONSUMER_VERSION', 'latest')  
    path = '/pacts/provider/provider-service-name/consumer/consumer-service-name/version/'  
    broker_url = ENV['PACT_BROKER_URL']  

    pact_uri "#{broker_url}#{path}#{version}", { username: ENV['PACT_BROKER_USERNAME'], password: ENV["PACT_BROKER_PASSWORD"] }  
  end

pact_test.rb

Pact.provider_states_for 'consumer-service-name' do  
  provider_state 'static pages exist' do  
    set_up do  
      slug = 'legal'  
      page_params = FactoryBot.attributes_for(:page, slug: slug)  

      Page.create(page_params) unless Page.exists?(slug: slug)  
    end  
  end
end

Gitlab runner output:

    * latest version of consumer-service-name that has a pact with provider-service-name (c72d4cb8)
Verifying a pact between consumer-service-name and provider-service-name
  Given static pages exist
    get all static pages
      with GET /api/admin/pages?page_number=1&per_page=10&q=legal&visible=true
        returns a response which
          has status code 200
          has a matching body
          includes headers
            "Content-Type" which equals "application/json; charset=utf-8"
2 interactions, 0 failures
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['page_number'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['per_page'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['q'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['visible'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['page_number'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['per_page'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['q'][0]
WARN: Ignoring unsupported matching rules {"match"=>"type"} for path $['query']$['visible'][0]
INFO: Verification results published to https://pact-broker.io/pacts/provider/provider-service-name/consumer/consumer-service-name/pact-version/7e21f9c8ecc86178441416799d70b574ff2d57bf/verification-results/3425
INFO: Verification results published to https://pact-broker.io/pacts/provider/provider-service-name/consumer/consumer-service-name/pact-version/7e21f9c8ecc86178441416799d70b574ff2d57bf/verification-results/3426
bethesque commented 1 year ago

Nothing obvious stands out to me. It doesn't start any separate processes like on the consumer side (with the mock provider).

I would fork the pact-ruby gem, and add a bunch of puts into the following classes to see if you can work out where it stops.

Then in your Gemfile, use your forked repo by configuring gem "pact", git: "https://github.com/<your org>/pact-ruby"

nktch1 commented 1 year ago

Hi, this fix worked for us, for some reason exit exit_code was not working as expected. https://github.com/ilyasovd/pact-ruby/commit/5aba022ffd3d8de3fdeb38c05558973d907c028f

bethesque commented 11 months ago

Very odd. You're welcome to submit a PR with that change if you'd like it to be part of the standard ruby gem. It should be exactly the same thing!