require 'uri' require 'json/add/regexp' require 'pact/logging' require 'pact/consumer/mock_service_client' require_relative 'interactions_filter' module Pact module Consumer class ConsumerContractBuilder include Pact::Logging attr_reader :consumer_contract, :mock_service_base_url def initialize(attributes) @interaction_builder = nil @mock_service_client = MockServiceClient.new(attributes[:provider_name], attributes[:port]) @consumer_contract = Pact::ConsumerContract.new( :consumer => ServiceConsumer.new(name: attributes[:consumer_name]), :provider => ServiceProvider.new(name: attributes[:provider_name]) ) @consumer_contract.interactions = interactions_for_new_consumer_contract(attributes[:pactfile_write_mode]) @interactions_filter = filter(@consumer_contract.interactions, attributes[:pactfile_write_mode]) @mock_service_base_url = "http://localhost:#{attributes[:port]}" end def given(provider_state) interaction_builder.given(provider_state) end def upon_receiving(description) interaction_builder.upon_receiving(description) end def interaction_builder @interaction_builder ||= begin interaction_builder = InteractionBuilder.new interaction_builder.on_interaction_fully_defined do | interaction | self.handle_interaction_fully_defined(interaction) end interaction_builder end end def verify example_description mock_service_client.verify example_description end def log msg mock_service_client.log msg end def wait_for_interactions options wait_max_seconds = options.fetch(:wait_max_seconds, 3) poll_interval = options.fetch(:poll_interval, 0.1) mock_service_client.wait_for_interactions wait_max_seconds, poll_interval end def handle_interaction_fully_defined interaction interactions_filter << interaction mock_service_client.add_expected_interaction interaction #TODO: What will happen if duplicate added? consumer_contract.update_pactfile self.interaction_builder = nil end private attr_reader :mock_service_client attr_reader :interactions_filter attr_writer :interaction_builder def interactions_for_new_consumer_contract pactfile_write_mode pactfile_write_mode == :update ? existing_interactions : [] end def filter interactions, pactfile_write_mode if pactfile_write_mode == :update UpdatableInteractionsFilter.new(interactions) else DistinctInteractionsFilter.new(interactions) end end def warn_and_stderr msg $stderr.puts msg logger.warn msg end def info_and_puts msg $stdout.puts msg logger.info msg end def existing_interactions interactions = [] if pactfile_exists? begin interactions = existing_consumer_contract.interactions info_and_puts "*****************************************************************************" info_and_puts "Updating existing file .#{consumer_contract.pactfile_path.gsub(Dir.pwd, '')} as config.pactfile_write_mode is :update" info_and_puts "Only interactions defined in this test run will be updated." info_and_puts "As interactions are identified by description and provider state, pleased note that if either of these have changed, the old interactions won't be removed from the pact file until the specs are next run with :pactfile_write_mode => :overwrite." info_and_puts "*****************************************************************************" rescue StandardError => e warn_and_stderr "Could not load existing consumer contract from #{consumer_contract.pactfile_path} due to #{e}" warn_and_stderr "Creating a new file." end end interactions end def pactfile_exists? File.exist?(consumer_contract.pactfile_path) end def existing_consumer_contract Pact::ConsumerContract.from_uri(consumer_contract.pactfile_path) end end end end