pact-mock_service 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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