pact-mock_service 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/pact/consumer/app_manager.rb +23 -35
  4. data/lib/pact/consumer/mock_service/app.rb +11 -75
  5. data/lib/pact/consumer/mock_service/error_handler.rb +28 -0
  6. data/lib/pact/consumer/mock_service/index_get.rb +22 -0
  7. data/lib/pact/consumer/mock_service/interaction_delete.rb +3 -3
  8. data/lib/pact/consumer/mock_service/interaction_post.rb +2 -2
  9. data/lib/pact/consumer/mock_service/log_get.rb +2 -2
  10. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +2 -3
  11. data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +11 -13
  12. data/lib/pact/consumer/mock_service/pact_post.rb +2 -2
  13. data/lib/pact/consumer/mock_service/request_handlers.rb +41 -0
  14. data/lib/pact/consumer/mock_service/verification_get.rb +2 -2
  15. data/lib/pact/consumer/mock_service.rb +41 -0
  16. data/lib/pact/consumer/server.rb +28 -7
  17. data/lib/pact/mock_service/cli/pidfile.rb +97 -0
  18. data/lib/pact/mock_service/cli.rb +109 -59
  19. data/lib/pact/mock_service/control_server/app.rb +42 -0
  20. data/lib/pact/mock_service/control_server/delegator.rb +55 -0
  21. data/lib/pact/mock_service/control_server/index.rb +25 -0
  22. data/lib/pact/mock_service/control_server/mock_service_creator.rb +34 -0
  23. data/lib/pact/mock_service/control_server/mock_services.rb +26 -0
  24. data/lib/pact/mock_service/control_server/require_pacticipant_headers.rb +20 -0
  25. data/lib/pact/mock_service/control_server/run.rb +68 -0
  26. data/lib/pact/mock_service/run.rb +81 -0
  27. data/lib/pact/mock_service/server/restart.rb +20 -0
  28. data/lib/pact/mock_service/server/spawn.rb +37 -0
  29. data/lib/pact/mock_service/server/wait_for_server_up.rb +35 -0
  30. data/lib/pact/mock_service/spawn.rb +68 -0
  31. data/lib/pact/mock_service/version.rb +1 -1
  32. metadata +18 -3
  33. data/lib/pact/consumer/mock_service/web_request_administration.rb +0 -27
@@ -0,0 +1,97 @@
1
+ require 'fileutils'
2
+
3
+ module Pact
4
+ module MockService
5
+ class CLI < Thor
6
+
7
+ class Pidfile
8
+
9
+ attr_accessor :pid_dir, :name, :pid
10
+
11
+ def initialize options
12
+ @pid_dir = options[:pid_dir] || 'tmp/pids'
13
+ @name = options[:name] || default_name
14
+ @pid = options[:pid] || Process.pid
15
+ end
16
+
17
+ def file_exists?
18
+ File.exist?(pidfile_path)
19
+ end
20
+
21
+ def process_running?
22
+ process_exists? pid_from_file
23
+ end
24
+
25
+ def pidfile_path
26
+ File.join(pid_dir, name)
27
+ end
28
+
29
+ def pid_from_file
30
+ File.read(pidfile_path).to_i
31
+ end
32
+
33
+ def default_name
34
+ File.basename($0, File.extname($0)) + ".pid"
35
+ end
36
+
37
+ def process_exists? pid
38
+ Process.kill 0, pid
39
+ true
40
+ rescue Errno::ESRCH
41
+ false
42
+ end
43
+
44
+ def file_exists_and_process_running?
45
+ file_exists? && process_running?
46
+ end
47
+
48
+ def can_start?
49
+ if file_exists? && process_running?
50
+ $stderr.puts "Server already running."
51
+ false
52
+ elsif file_exists?
53
+ $stderr.puts "WARN: PID file #{pidfile_path} already exists, but process is not running. Overwriting pidfile."
54
+ true
55
+ else
56
+ true
57
+ end
58
+ end
59
+
60
+ def write
61
+ FileUtils.mkdir_p pid_dir
62
+ File.open(pidfile_path, "w") { |file| file << pid }
63
+ end
64
+
65
+ def delete
66
+ FileUtils.rm pidfile_path
67
+ end
68
+
69
+ def waitpid
70
+ tries = 0
71
+ sleep_time = 0.1
72
+ while process_running? && tries < 100
73
+ sleep sleep_time
74
+ tries += 1
75
+ end
76
+ raise "Process #{pid_from_file} not stopped after {100 * sleep_time} seconds." if process_running?
77
+ end
78
+
79
+ def kill_process
80
+ if file_exists?
81
+ begin
82
+ `ps -ef | grep pact`
83
+ Process.kill 2, pid_from_file
84
+ waitpid
85
+ delete
86
+ rescue Errno::ESRCH
87
+ $stderr.puts "Process in PID file #{pidfile_path} not running. Deleting PID file."
88
+ delete
89
+ end
90
+ else
91
+ $stderr.puts "No PID file found at #{pidfile_path}, server probably not running. Use `ps -ef | grep pact` if you suspect the process is still running."
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,100 +1,150 @@
1
- require 'find_a_port'
2
1
  require 'thor'
3
- require 'thwait'
4
2
  require 'webrick/https'
5
3
  require 'rack/handler/webrick'
6
4
  require 'fileutils'
5
+ require 'pact/mock_service/server/wait_for_server_up'
6
+ require 'pact/mock_service/cli/pidfile'
7
+ require 'socket'
7
8
 
8
9
  module Pact
9
10
  module MockService
10
11
  class CLI < Thor
11
12
 
12
- desc 'execute', "Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown."
13
+ desc 'service', "Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown."
13
14
  method_option :port, aliases: "-p", desc: "Port on which to run the service"
14
- method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
15
15
  method_option :log, aliases: "-l", desc: "File to which to log output"
16
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
16
17
  method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
17
18
  method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
18
19
  method_option :consumer, desc: "Consumer name"
19
20
  method_option :provider, desc: "Provider name"
20
21
 
21
- def execute
22
- RunStandaloneMockService.call(options)
22
+ def service
23
+ require 'pact/mock_service/run'
24
+ Run.(options)
23
25
  end
24
26
 
25
- default_task :execute
27
+ desc 'control', "Run a Pact mock service control server."
28
+ method_option :port, aliases: "-p", desc: "Port on which to run the service"
29
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output"
30
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
31
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
32
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
26
33
 
27
- end
34
+ def control
35
+ require 'pact/mock_service/control_server/run'
36
+ ControlServer::Run.(options)
37
+ end
28
38
 
29
- class RunStandaloneMockService
39
+ desc 'start', "Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown."
40
+ method_option :port, aliases: "-p", default: '1234', desc: "Port on which to run the service"
41
+ method_option :log, aliases: "-l", desc: "File to which to log output"
42
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
43
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
44
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
45
+ method_option :consumer, desc: "Consumer name"
46
+ method_option :provider, desc: "Provider name"
47
+ method_option :pid_dir, desc: "PID dir", default: 'tmp/pids'
30
48
 
31
- def self.call options
32
- new(options).call
49
+ def start
50
+ start_server(mock_service_pidfile) do
51
+ service
52
+ end
33
53
  end
34
54
 
35
- def initialize options
36
- @options = options
37
- end
55
+ desc 'stop', "Stop a Pact mock service"
56
+ method_option :port, aliases: "-p", desc: "Port of the service to stop", default: '1234', required: true
57
+ method_option :pid_dir, desc: "PID dir, defaults to tmp/pids", default: "tmp/pids"
38
58
 
39
- def call
40
- require 'pact/consumer/mock_service/app'
59
+ def stop
60
+ mock_service_pidfile.kill_process
61
+ end
41
62
 
42
- trap(:INT) { call_shutdown_hooks }
43
- trap(:TERM) { call_shutdown_hooks }
63
+ desc 'restart', "Start or restart a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown."
64
+ method_option :port, aliases: "-p", default: '1234', desc: "Port on which to run the service"
65
+ method_option :log, aliases: "-l", desc: "File to which to log output"
66
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
67
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
68
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
69
+ method_option :consumer, desc: "Consumer name"
70
+ method_option :provider, desc: "Provider name"
71
+ method_option :pid_dir, desc: "PID dir", default: 'tmp/pids'
44
72
 
45
- Rack::Handler::WEBrick.run(mock_service, webbrick_opts)
73
+ def restart
74
+ restart_server(mock_service_pidfile) do
75
+ service
76
+ end
46
77
  end
47
78
 
48
- private
79
+ desc 'control-start', "Start a Pact mock service control server."
80
+ method_option :port, aliases: "-p", desc: "Port on which to run the service", default: '1234'
81
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output", default: "log"
82
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
83
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
84
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written", default: "."
85
+ method_option :pid_dir, desc: "PID dir", default: "tmp/pids"
86
+
87
+ def control_start
88
+ start_server(control_server_pidfile) do
89
+ control
90
+ end
91
+ end
49
92
 
50
- attr_reader :options
93
+ desc 'control-stop', "Stop a Pact mock service control server."
94
+ method_option :port, aliases: "-p", desc: "Port of control server to stop", default: "1234"
95
+ method_option :pid_dir, desc: "PID dir, defaults to tmp/pids", default: "tmp/pids"
51
96
 
52
- def mock_service
53
- @mock_service ||= Pact::Consumer::MockService.new(service_options)
97
+ def control_stop
98
+ control_server_pidfile.kill_process
54
99
  end
55
100
 
56
- def call_shutdown_hooks
57
- begin
58
- mock_service.shutdown
59
- rescue StandardError => e
60
- $stderr.puts "Error writing pact on shutdown. #{e.class} - #{e.message}"
61
- $stderr.puts e.backtrace.join("\n")
101
+ desc 'control-restart', "Start a Pact mock service control server."
102
+ method_option :port, aliases: "-p", desc: "Port on which to run the service", default: '1234'
103
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output", default: "log"
104
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS"
105
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
106
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written", default: "."
107
+ method_option :pid_dir, desc: "PID dir", default: "tmp/pids"
108
+
109
+ def control_restart
110
+ restart_server(control_server_pidfile) do
111
+ control
62
112
  end
63
- Rack::Handler::WEBrick.shutdown
64
113
  end
65
114
 
66
- def service_options
67
- service_options = {
68
- pact_dir: options[:pact_dir],
69
- consumer: options[:consumer],
70
- provider: options[:provider],
71
- cors_enabled: options[:cors]
72
- }
73
- service_options[:log_file] = open_log_file if options[:log]
74
- service_options
75
- end
115
+ default_task :service
76
116
 
77
- def open_log_file
78
- FileUtils.mkdir_p File.dirname(options[:log])
79
- log = File.open(options[:log], 'w')
80
- log.sync = true
81
- log
82
- end
117
+ no_commands do
83
118
 
84
- def webbrick_opts
85
- opts = {
86
- :Port => options[:port] || FindAPort.available_port,
87
- :AccessLog => []
88
- }
89
- opts.merge!(ssl_opts) if options[:ssl]
90
- opts
91
- end
119
+ def control_server_pidfile
120
+ Pidfile.new(pid_dir: options[:pid_dir], name: control_pidfile_name)
121
+ end
122
+
123
+ def mock_service_pidfile
124
+ Pidfile.new(pid_dir: options[:pid_dir], name: mock_service_pidfile_name)
125
+ end
126
+
127
+ def mock_service_pidfile_name
128
+ "mock-service-#{options[:port]}.pid"
129
+ end
92
130
 
93
- def ssl_opts
94
- {
95
- :SSLEnable => true,
96
- :SSLCertName => [ %w[CN localhost] ]
97
- }
131
+ def control_pidfile_name
132
+ "mock-service-control-#{options[:port]}.pid"
133
+ end
134
+
135
+ def start_server pidfile
136
+ require 'pact/mock_service/server/spawn'
137
+ Pact::MockService::Server::Spawn.(pidfile, options[:port]) do
138
+ yield
139
+ end
140
+ end
141
+
142
+ def restart_server pidfile
143
+ require 'pact/mock_service/server/respawn'
144
+ Pact::MockService::Server::Respawn.(pidfile, options[:port]) do
145
+ yield
146
+ end
147
+ end
98
148
  end
99
149
  end
100
150
  end
@@ -0,0 +1,42 @@
1
+ require 'pact/consumer/mock_service/rack_request_helper'
2
+ require 'pact/mock_service/control_server/require_pacticipant_headers'
3
+ require 'pact/mock_service/control_server/index'
4
+ require 'pact/mock_service/control_server/mock_services'
5
+ require 'pact/mock_service/control_server/mock_service_creator'
6
+ require 'rack'
7
+ require 'rack/cascade'
8
+
9
+ module Pact
10
+ module MockService
11
+ module ControlServer
12
+ class App
13
+
14
+ include Pact::Consumer::RackRequestHelper
15
+
16
+ def initialize options = {}
17
+ @mock_services = mock_services = MockServices.new([])
18
+ @app = Rack::Builder.new {
19
+ run Rack::Cascade.new([
20
+ Index.new,
21
+ Rack::Builder.new {
22
+ use RequirePacticipantHeaders
23
+ run Rack::Cascade.new([
24
+ mock_services,
25
+ MockServiceCreator.new(mock_services, options)
26
+ ])
27
+ }
28
+ ])
29
+ }
30
+ end
31
+
32
+ def call env
33
+ @app.call(env)
34
+ end
35
+
36
+ def shutdown
37
+ @mock_services.shutdown
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ # Delegates the incoming request that was sent to the control server
2
+ # to the underlying MockService
3
+ # if the X-Pact-Consumer and X-Pact-Provider headers match
4
+ # the consumer and provider for this MockService.
5
+
6
+ module Pact
7
+ module MockService
8
+ module ControlServer
9
+
10
+ class Delegator
11
+
12
+ HTTP_X_PACT_CONSUMER = 'HTTP_X_PACT_CONSUMER'.freeze
13
+ HTTP_X_PACT_PROVIDER = 'HTTP_X_PACT_PROVIDER'.freeze
14
+ LOCATION = 'X-Pact-Mock-Service-Location'.freeze
15
+ PACT_MOCK_SERVICE_HEADER = {'HTTP_X_PACT_MOCK_SERVICE' => 'true'}.freeze
16
+ NOT_FOUND_RESPONSE = [404, {}, []].freeze
17
+
18
+ def initialize app, base_url, consumer_name, provider_name
19
+ @app = app
20
+ @base_url = base_url
21
+ @consumer_name = consumer_name
22
+ @provider_name = provider_name
23
+ @location_header = {LOCATION => @base_url}.freeze
24
+ end
25
+
26
+ def call env
27
+ return NOT_FOUND_RESPONSE unless consumer_and_provider_headers_match?(env)
28
+ delegate env
29
+ end
30
+
31
+ def shutdown
32
+ @app.shutdown
33
+ end
34
+
35
+ private
36
+
37
+ def consumer_and_provider_headers_match? env
38
+ env[HTTP_X_PACT_CONSUMER] == @consumer_name && env[HTTP_X_PACT_PROVIDER] == @provider_name
39
+ end
40
+
41
+ def delegate env
42
+ add_location_header_to_response(call_app(env))
43
+ end
44
+
45
+ def call_app env
46
+ @app.call(env.merge(PACT_MOCK_SERVICE_HEADER))
47
+ end
48
+
49
+ def add_location_header_to_response response
50
+ [response.first, response[1].merge(@location_header), response.last]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+ module Pact
2
+ module MockService
3
+ module ControlServer
4
+ class Index
5
+
6
+ HTTP_X_PACT_MOCK_SERVICE = 'HTTP_X_PACT_MOCK_SERVICE'
7
+ PATH_INFO = 'PATH_INFO'
8
+ INDEX_RESPONSE = [200, {'Content-Type' => 'text/plain'}, ['Control server running']].freeze
9
+ NOT_FOUND_RESPONSE = [404, {}, []].freeze
10
+
11
+ def call env
12
+ if is_index_request_with_mock_service_header? env
13
+ INDEX_RESPONSE
14
+ else
15
+ NOT_FOUND_RESPONSE
16
+ end
17
+ end
18
+
19
+ def is_index_request_with_mock_service_header? env
20
+ env[HTTP_X_PACT_MOCK_SERVICE] && env[PATH_INFO].chomp("/").size == 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ require 'pact/mock_service/spawn'
2
+ require 'pact/mock_service/control_server/delegator'
3
+ require 'find_a_port'
4
+ require 'pact/mock_service/server/wait_for_server_up'
5
+
6
+ # Create a new MockService on a random port and delegate the incoming request to it
7
+
8
+ module Pact
9
+ module MockService
10
+ module ControlServer
11
+
12
+ class MockServiceCreator
13
+
14
+ attr_reader :options
15
+
16
+ def initialize mock_services, options
17
+ @mock_services = mock_services
18
+ @options = options
19
+ end
20
+
21
+ def call env
22
+ consumer_name = env['HTTP_X_PACT_CONSUMER']
23
+ provider_name = env['HTTP_X_PACT_PROVIDER']
24
+ port = FindAPort.available_port
25
+ mock_service = Pact::MockService::Spawn.(consumer_name, provider_name, port, options)
26
+ delegator = Delegator.new(mock_service, "http://localhost:#{port}", consumer_name, provider_name)
27
+ @mock_services.add(delegator)
28
+ response = delegator.call(env)
29
+ response
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ require 'rack'
2
+ require 'rack/cascade'
3
+
4
+ module Pact
5
+ module MockService
6
+ module ControlServer
7
+ class MockServices < Rack::Cascade
8
+
9
+ def add app
10
+ mock_services << app
11
+ super
12
+ end
13
+
14
+ def shutdown
15
+ mock_services.each(&:shutdown)
16
+ end
17
+
18
+ private
19
+
20
+ def mock_services
21
+ @mock_services ||= []
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module Pact
2
+ module MockService
3
+ module ControlServer
4
+ class RequirePacticipantHeaders
5
+
6
+ def initialize app
7
+ @app = app
8
+ end
9
+
10
+ def call env
11
+ if env['HTTP_X_PACT_CONSUMER'] && env['HTTP_X_PACT_PROVIDER']
12
+ @app.call(env)
13
+ else
14
+ [500, {}, ["Please specify the consumer name and the provider name by setting the X-Pact-Consumer and X-Pact-Provider headers"]]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,68 @@
1
+ require 'pact/mock_service/control_server/app'
2
+
3
+ module Pact
4
+ module MockService
5
+ module ControlServer
6
+ class Run
7
+
8
+ def self.call options
9
+ new(options).call
10
+ end
11
+
12
+ def initialize options
13
+ @options = options
14
+ end
15
+
16
+ def call
17
+ trap(:INT) { shutdown }
18
+ trap(:TERM) { shutdown }
19
+
20
+ # https://github.com/rack/rack/blob/ae78184e5c1fcf4ac133171ed4b47b0548cd9b44/lib/rack/handler/webrick.rb#L32
21
+ # Rack adapter for webrick uses class variable for the server which contains the port,
22
+ # so if we use it more than once in the same process, we lose the reference to the first
23
+ # server, and can't shut it down. So, keep a manual reference to the Webrick server, and
24
+ # shut it down directly rather than use Rack::Handler::WEBrick.shutdown
25
+ # Ruby!
26
+ Rack::Handler::WEBrick.run(control_server, webbrick_opts) do | server |
27
+ @webrick_server = server
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :options
34
+
35
+ def control_server
36
+ @control_server ||= Pact::MockService::ControlServer::App.new control_server_options
37
+ end
38
+
39
+ def shutdown
40
+ unless @shutting_down
41
+ @shutting_down = true
42
+ begin
43
+ @control_server.shutdown
44
+ ensure
45
+ @webrick_server.shutdown
46
+ end
47
+ end
48
+ end
49
+
50
+ def control_server_options
51
+ {
52
+ log_dir: options[:log_dir] || "log",
53
+ pact_dir: options[:pact_dir] || ".",
54
+ cors_enabled: options[:cors] || false,
55
+ ssl: options[:ssl]
56
+ }
57
+ end
58
+
59
+ def webbrick_opts
60
+ {
61
+ :Port => options[:port],
62
+ :AccessLog => []
63
+ }
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,81 @@
1
+ require 'find_a_port'
2
+ require 'pact/consumer/mock_service'
3
+
4
+ module Pact
5
+ module MockService
6
+ class Run
7
+
8
+ def self.call options
9
+ new(options).call
10
+ end
11
+
12
+ def initialize options
13
+ @options = options
14
+ end
15
+
16
+ def call
17
+ require 'pact/consumer/mock_service'
18
+
19
+ trap(:INT) { call_shutdown_hooks }
20
+ trap(:TERM) { call_shutdown_hooks }
21
+
22
+ Rack::Handler::WEBrick.run(mock_service, webbrick_opts)
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :options
28
+
29
+ def mock_service
30
+ @mock_service ||= begin
31
+ Pact::Consumer::MockService.new(service_options)
32
+ end
33
+ end
34
+
35
+ def call_shutdown_hooks
36
+ unless @shutting_down
37
+ @shutting_down = true
38
+ begin
39
+ mock_service.shutdown
40
+ ensure
41
+ Rack::Handler::WEBrick.shutdown
42
+ end
43
+ end
44
+ end
45
+
46
+ def service_options
47
+ service_options = {
48
+ pact_dir: options[:pact_dir],
49
+ consumer: options[:consumer],
50
+ provider: options[:provider],
51
+ cors_enabled: options[:cors]
52
+ }
53
+ service_options[:log_file] = open_log_file if options[:log]
54
+ service_options
55
+ end
56
+
57
+ def open_log_file
58
+ FileUtils.mkdir_p File.dirname(options[:log])
59
+ log = File.open(options[:log], 'w')
60
+ log.sync = true
61
+ log
62
+ end
63
+
64
+ def webbrick_opts
65
+ opts = {
66
+ :Port => options[:port] || FindAPort.available_port,
67
+ :AccessLog => []
68
+ }
69
+ opts.merge!(ssl_opts) if options[:ssl]
70
+ opts
71
+ end
72
+
73
+ def ssl_opts
74
+ {
75
+ :SSLEnable => true,
76
+ :SSLCertName => [ %w[CN localhost] ]
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,20 @@
1
+ require 'pact/mock_service/server/spawn'
2
+
3
+ module Pact
4
+ module MockService
5
+ module Server
6
+ class Respawn
7
+
8
+ def self.call pidfile, port
9
+ if pidfile.file_exists_and_process_running?
10
+ pidfile.kill_process
11
+ end
12
+
13
+ Spawn.(pidfile, port) do
14
+ yield
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end