lib/pact/consumer/dsl.rb



require_relative 'consumer_contract_builders'

module Pact::Consumer
   module DSL

      module Configuration
        def add_provider_verification &block
          provider_verifications << block
        end
        def provider_verifications
          @provider_verifications ||= []
        end
      end

      def service_consumer name, &block
        ServiceConsumerDSL.new(name, &block).create_service_consumer
      end

      class ServiceConsumerDSL

        def initialize name, &block
          @name = name
          consumer = Pact::ServiceConsumer.new name: @name
          @app = nil
          @port = nil
          instance_eval(&block)
        end

        def validate
          raise "Please provide a consumer name" unless (@name && !@name.empty?)
          raise "Please provide a port for the consumer app" if @app && !@port
        end

        def app app
          @app = app
        end

        def port port
          @port = port
        end

        def has_pact_with service_provider_name, &block
          Provider.new(service_provider_name, @name, &block).create_consumer_contract_builder
        end

        def create_service_consumer
          validate
          register_consumer_app if @app
        end

        def register_consumer_app
          Pact::Consumer::AppManager.instance.register @app, @port
        end
      end




      #OLD ####
      def with_provider name, &block
         Provider.new(name, &block).create_consumer_contract_builder
      end

      alias_method :with_service_provider, :with_provider

      class Provider
         def initialize name, consumer_name = Pact.configuration.consumer.name, &block
            @name = name
            @service = nil
            @consumer_name = consumer_name
            instance_eval(&block)
         end

         def service name, &block
            @service = Service.new(name, &block)
         end

         alias_method :mock_service, :service

        def create_consumer_contract_builder
          validate
          consumer_contract_builder_from_attributes
        end

        def validate
          raise "Please configure a service for #{@name}" unless @service
        end

        def consumer_contract_builder_from_attributes
          consumer_contract_builder_fields = {
            :consumer_name => @consumer_name,
            :provider_name => @name,
            :pactfile_write_mode => Pact.configuration.pactfile_write_mode
            }
          @service.configure_consumer_contract_builder consumer_contract_builder_fields
        end
      end

      class Service
         def initialize name, &block
            @name = name
            @port = nil
            @standalone = false
            @verify = true
            instance_eval(&block)
         end

         def port port
            @port = port
         end

         def standalone standalone
            @standalone = standalone
         end

         def verify verify
            @verify = verify
         end

         def configure_consumer_contract_builder consumer_contract_builder_fields
            validate
            unless @standalone
              AppManager.instance.register_mock_service_for consumer_contract_builder_fields[:provider_name], "http://localhost:#{@port}"
            end
            consumer_contract_builder = Pact::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields.merge({port: @port})
            create_mock_services_module_method consumer_contract_builder
            setup_verification(consumer_contract_builder) if @verify
            consumer_contract_builder
         end


        def setup_verification consumer_contract_builder
          Pact.configuration.add_provider_verification do | example_description |
            consumer_contract_builder.verify example_description
          end
        end

         private

         # This makes the consumer_contract_builder available via a module method with the given identifier
         # as the method name.
         # I feel this should be defined somewhere else, but I'm not sure where
         def create_mock_services_module_method consumer_contract_builder
           Pact::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
             consumer_contract_builder
           end
         end

         def validate
            raise "Please provide a port for service #{@name}" unless @port
         end
      end
   end
end

Pact.send(:extend, Pact::Consumer::DSL)
Pact::Configuration.send(:include, Pact::Consumer::DSL::Configuration)