require 'find_a_port' require 'thor' require 'thwait' require 'webrick/https' require 'rack/handler/webrick' require 'fileutils' module Pact module MockService class CLI < Thor desc 'execute', "Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown." method_option :port, aliases: "-p", desc: "Port on which to run the service" method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS" method_option :log, aliases: "-l", desc: "File to which to log output" method_option :cors_enabled, aliases: "-o", desc: "If true, mocks requests will have access control origin headers set to '*'" method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written" method_option :consumer, desc: "Consumer name" method_option :provider, desc: "Provider name" def execute RunStandaloneMockService.call(options) end default_task :execute end class RunStandaloneMockService def self.call options new(options).call end def initialize options @options = options end def call require 'pact/consumer/mock_service/app' trap(:INT) { call_shutdown_hooks } trap(:TERM) { call_shutdown_hooks } Rack::Handler::WEBrick.run(mock_service, webbrick_opts) end private attr_reader :options def mock_service @mock_service ||= Pact::Consumer::MockService.new(service_options) end def call_shutdown_hooks begin mock_service.write_pact_if_configured rescue StandardError => e $stderr.puts "Error writing pact on shutdown. #{e.class} - #{e.message}" $stderr.puts e.backtrace.join("\n") end Rack::Handler::WEBrick.shutdown end def service_options service_options = { pact_dir: options[:pact_dir], consumer: options[:consumer], provider: options[:provider], cors_enabled: options[:cors_enabled] } service_options[:log_file] = open_log_file if options[:log] service_options end def open_log_file FileUtils.mkdir_p File.dirname(options[:log]) log = File.open(options[:log], 'w') log.sync = true log end def webbrick_opts opts = { :Port => options[:port] || FindAPort.available_port, :AccessLog => [] } opts.merge!(ssl_opts) if options[:ssl] opts end def ssl_opts { :SSLEnable => true, :SSLCertName => [ %w[CN localhost] ] } end end end end