hs-pact-mock_service 3.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +494 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +137 -0
  6. data/bin/pact-mock-service +3 -0
  7. data/bin/pact-stub-service +3 -0
  8. data/lib/pact/consumer/mock_service/cors_origin_header_middleware.rb +31 -0
  9. data/lib/pact/consumer/mock_service/error_handler.rb +31 -0
  10. data/lib/pact/consumer/mock_service/rack_request_helper.rb +65 -0
  11. data/lib/pact/consumer/mock_service/set_location.rb +28 -0
  12. data/lib/pact/consumer/server.rb +111 -0
  13. data/lib/pact/consumer_contract/consumer_contract_decorator.rb +53 -0
  14. data/lib/pact/consumer_contract/consumer_contract_writer.rb +181 -0
  15. data/lib/pact/consumer_contract/interaction_decorator.rb +40 -0
  16. data/lib/pact/consumer_contract/request_decorator.rb +88 -0
  17. data/lib/pact/consumer_contract/response_decorator.rb +47 -0
  18. data/lib/pact/mock_service/app.rb +85 -0
  19. data/lib/pact/mock_service/app_manager.rb +156 -0
  20. data/lib/pact/mock_service/cli/custom_thor.rb +74 -0
  21. data/lib/pact/mock_service/cli/pidfile.rb +99 -0
  22. data/lib/pact/mock_service/cli.rb +213 -0
  23. data/lib/pact/mock_service/client.rb +79 -0
  24. data/lib/pact/mock_service/control_server/app.rb +42 -0
  25. data/lib/pact/mock_service/control_server/delegator.rb +44 -0
  26. data/lib/pact/mock_service/control_server/index.rb +25 -0
  27. data/lib/pact/mock_service/control_server/mock_service_creator.rb +32 -0
  28. data/lib/pact/mock_service/control_server/mock_services.rb +26 -0
  29. data/lib/pact/mock_service/control_server/require_pacticipant_headers.rb +20 -0
  30. data/lib/pact/mock_service/control_server/run.rb +73 -0
  31. data/lib/pact/mock_service/errors.rb +9 -0
  32. data/lib/pact/mock_service/interaction_decorator.rb +49 -0
  33. data/lib/pact/mock_service/interactions/actual_interactions.rb +36 -0
  34. data/lib/pact/mock_service/interactions/candidate_interactions.rb +15 -0
  35. data/lib/pact/mock_service/interactions/expected_interactions.rb +18 -0
  36. data/lib/pact/mock_service/interactions/interaction_diff_message.rb +45 -0
  37. data/lib/pact/mock_service/interactions/interaction_mismatch.rb +74 -0
  38. data/lib/pact/mock_service/interactions/interactions_filter.rb +66 -0
  39. data/lib/pact/mock_service/interactions/verification.rb +52 -0
  40. data/lib/pact/mock_service/interactions/verified_interactions.rb +20 -0
  41. data/lib/pact/mock_service/logger.rb +40 -0
  42. data/lib/pact/mock_service/request_decorator.rb +36 -0
  43. data/lib/pact/mock_service/request_handlers/base_administration_request_handler.rb +42 -0
  44. data/lib/pact/mock_service/request_handlers/base_request_handler.rb +30 -0
  45. data/lib/pact/mock_service/request_handlers/index_get.rb +23 -0
  46. data/lib/pact/mock_service/request_handlers/interaction_delete.rb +38 -0
  47. data/lib/pact/mock_service/request_handlers/interaction_post.rb +43 -0
  48. data/lib/pact/mock_service/request_handlers/interaction_replay.rb +191 -0
  49. data/lib/pact/mock_service/request_handlers/interactions_put.rb +44 -0
  50. data/lib/pact/mock_service/request_handlers/log_get.rb +27 -0
  51. data/lib/pact/mock_service/request_handlers/missing_interactions_get.rb +33 -0
  52. data/lib/pact/mock_service/request_handlers/options.rb +64 -0
  53. data/lib/pact/mock_service/request_handlers/pact_post.rb +38 -0
  54. data/lib/pact/mock_service/request_handlers/session_delete.rb +32 -0
  55. data/lib/pact/mock_service/request_handlers/verification_get.rb +74 -0
  56. data/lib/pact/mock_service/request_handlers.rb +42 -0
  57. data/lib/pact/mock_service/response_decorator.rb +31 -0
  58. data/lib/pact/mock_service/run.rb +125 -0
  59. data/lib/pact/mock_service/server/respawn.rb +20 -0
  60. data/lib/pact/mock_service/server/spawn.rb +37 -0
  61. data/lib/pact/mock_service/server/wait_for_server_up.rb +44 -0
  62. data/lib/pact/mock_service/server/webrick_request_monkeypatch.rb +15 -0
  63. data/lib/pact/mock_service/session.rb +96 -0
  64. data/lib/pact/mock_service/spawn.rb +86 -0
  65. data/lib/pact/mock_service/version.rb +5 -0
  66. data/lib/pact/mock_service.rb +2 -0
  67. data/lib/pact/stub_service/cli.rb +71 -0
  68. data/lib/pact/support/expand_file_list.rb +26 -0
  69. metadata +399 -0
@@ -0,0 +1,85 @@
1
+ require 'rack'
2
+ require 'uri'
3
+ require 'json'
4
+ require 'pact/mock_service/logger'
5
+ require 'pact/consumer/mock_service/cors_origin_header_middleware'
6
+ require 'pact/mock_service/request_handlers'
7
+ require 'pact/consumer/mock_service/error_handler'
8
+ require 'pact/mock_service/session'
9
+
10
+ module Pact
11
+ module MockService
12
+
13
+ def self.new *args
14
+ App.new(*args)
15
+ end
16
+
17
+ class App
18
+ def initialize options = {}
19
+ logger = Logger.from_options(options)
20
+ @options = options
21
+ stubbing = options[:stub_pactfile_paths] && options[:stub_pactfile_paths].any?
22
+ @name = options.fetch(:name, "MockService")
23
+ @session = Session.new(options.merge(logger: logger, warn_on_too_many_interactions: !stubbing))
24
+ setup_stub(options[:stub_pactfile_paths]) if stubbing
25
+ request_handlers = RequestHandlers.new(@name, logger, @session, options)
26
+ @app = Rack::Builder.app do
27
+ use Pact::Consumer::MockService::ErrorHandler, logger
28
+ use Pact::Consumer::CorsOriginHeaderMiddleware, options[:cors_enabled]
29
+ run request_handlers
30
+ end
31
+ end
32
+
33
+ def call env
34
+ @app.call env
35
+ end
36
+
37
+ def shutdown
38
+ write_pact_if_configured
39
+ end
40
+
41
+ def setup_stub stub_pactfile_paths
42
+ interactions = stub_pactfile_paths.collect do | pactfile_path |
43
+ $stdout.puts "INFO: Loading interactions from #{pactfile_path}"
44
+ hash_interactions = JSON.parse(Pact::PactFile.read(pactfile_path, pactfile_options))['interactions']
45
+ hash_interactions.collect { | hash | Interaction.from_hash(hash) }
46
+ end.flatten
47
+ @session.set_expected_interactions interactions
48
+ end
49
+
50
+ def write_pact_if_configured
51
+ consumer_contract_writer = ConsumerContractWriter.new(@session.consumer_contract_details, StdoutLogger.new)
52
+ if consumer_contract_writer.can_write? && !@session.pact_written?
53
+ $stdout.puts "INFO: Writing pact before shutting down"
54
+ consumer_contract_writer.write
55
+ end
56
+ end
57
+
58
+ def to_s
59
+ "#{@name} #{super.to_s}"
60
+ end
61
+
62
+ private
63
+
64
+ def pactfile_options
65
+ {
66
+ :token => broker_token,
67
+ :username => @options[:broker_username],
68
+ :password => @options[:broker_password],
69
+ }
70
+ end
71
+
72
+ def broker_token
73
+ @options[:broker_token] || ENV['PACT_BROKER_TOKEN']
74
+ end
75
+ end
76
+
77
+ # Can't write to a file in a TRAP, might deadlock
78
+ # Not sure why we can still write to the pact file though
79
+ class StdoutLogger
80
+ def info message
81
+ $stdout.puts "\n#{message}"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,156 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'pact/logging'
4
+ require 'pact/consumer/server'
5
+ require 'singleton'
6
+ require 'pact/mock_service/app'
7
+
8
+ module Pact
9
+ module MockService
10
+ class AppManager
11
+
12
+ include Pact::Logging
13
+
14
+ include Singleton
15
+
16
+ def initialize
17
+ @apps_spawned = false
18
+ @app_registrations = []
19
+ end
20
+
21
+ def register_mock_service_for(name, url, options = {})
22
+ uri = URI(url)
23
+ raise "Currently only http is supported" unless uri.scheme == 'http'
24
+ uri.port = nil if options[:find_available_port]
25
+
26
+ app = Pact::MockService.new(
27
+ name: name,
28
+ log_file: create_log_file(name),
29
+ pact_dir: pact_dir,
30
+ pact_specification_version: options.fetch(:pact_specification_version)
31
+ )
32
+ register(app, uri.host, uri.port)
33
+ end
34
+
35
+ def register(app, host, port = nil)
36
+ if port
37
+ existing = existing_app_on_host_and_port(host, port)
38
+ raise "Port #{port} is already being used by #{existing}" if existing and not existing == app
39
+ end
40
+ app_registration = register_app(app, host, port)
41
+ app_registration.spawn
42
+ app_registration.port
43
+ end
44
+
45
+ def urls_of_mock_services
46
+ app_registrations.find_all(&:is_a_mock_service?).collect{ |ar| "http://#{ar.host}:#{ar.port}" }
47
+ end
48
+
49
+ def kill_all
50
+ app_registrations.find_all(&:spawned?).collect(&:kill)
51
+ @apps_spawned = false
52
+ end
53
+
54
+ def clear_all
55
+ kill_all
56
+ @app_registrations = []
57
+ end
58
+
59
+ def spawn_all
60
+ app_registrations.find_all(&:not_spawned?).collect(&:spawn)
61
+ @apps_spawned = true
62
+ end
63
+
64
+ def app_registered_on?(port)
65
+ app_registrations.any? { |app_registration| app_registration.port == port }
66
+ end
67
+
68
+ private
69
+
70
+ def existing_app_on_host_and_port(host, port)
71
+ app_registration = registration_on_host_and_port(host, port)
72
+ app_registration ? app_registration.app : nil
73
+ end
74
+
75
+ def registration_on_host_and_port(host, port)
76
+ @app_registrations.find { |app_registration| app_registration.port == port && app_registration.host == host }
77
+ end
78
+
79
+ def pact_dir
80
+ Pact.configuration.pact_dir
81
+ end
82
+
83
+ def create_log_file(service_name)
84
+ FileUtils::mkdir_p(Pact.configuration.log_dir)
85
+ log = File.open(log_file_path(service_name), 'w')
86
+ log.sync = true
87
+ log
88
+ end
89
+
90
+ def log_file_path(service_name)
91
+ File.join(Pact.configuration.log_dir, "#{log_file_name(service_name)}.log")
92
+ end
93
+
94
+ def log_file_name(service_name)
95
+ lower_case_name = service_name.downcase.gsub(/\s+/, '_')
96
+ if lower_case_name.include?('_service')
97
+ lower_case_name.gsub('_service', '_mock_service')
98
+ else
99
+ lower_case_name + '_mock_service'
100
+ end
101
+ end
102
+
103
+ def app_registrations
104
+ @app_registrations
105
+ end
106
+
107
+ def register_app(app, host, port)
108
+ app_registration = AppRegistration.new(app: app, host: host, port: port)
109
+ app_registrations << app_registration
110
+ app_registration
111
+ end
112
+ end
113
+
114
+ class AppRegistration
115
+ include Pact::Logging
116
+ attr_accessor :host, :port, :app
117
+
118
+ def initialize(opts)
119
+ @max_wait = 10
120
+ @port = opts[:port]
121
+ @host = opts[:host]
122
+ @app = opts[:app]
123
+ @spawned = false
124
+ end
125
+
126
+ def kill
127
+ logger.debug "Supposed to be stopping"
128
+ @spawned = false
129
+ end
130
+
131
+ def not_spawned?
132
+ !spawned?
133
+ end
134
+
135
+ def spawned?
136
+ @spawned
137
+ end
138
+
139
+ def is_a_mock_service?
140
+ app.is_a?(Pact::MockService::App)
141
+ end
142
+
143
+ def to_s
144
+ "#{app} on port #{port}"
145
+ end
146
+
147
+ def spawn
148
+ logger.info "Starting app #{self}..."
149
+ @server = Pact::Server.new(app, host, port).boot
150
+ @port = @server.port
151
+ @spawned = true
152
+ logger.info "Started on port #{port}"
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,74 @@
1
+ require 'thor'
2
+
3
+ module Pact
4
+ module MockService
5
+ class CLI < Thor
6
+ ##
7
+ # Custom Thor task allows the following:
8
+ #
9
+ # `script arg1 arg2` to be interpreted as `script <default_task> arg1 arg2`
10
+ # `--option 1 --option 2` to be interpreted as `--option 1 2` (the standard Thor format for multiple value options)
11
+ # `script --help` to display the help for the default task instead of the command list
12
+ #
13
+ class CustomThor < ::Thor
14
+ def self.exit_on_failure? # Thor 1.0 deprecation guard
15
+ false
16
+ end
17
+
18
+ no_commands do
19
+ def self.start given_args = ARGV, config = {}
20
+ super(massage_args(given_args))
21
+ end
22
+
23
+ def help *args
24
+ if args.empty?
25
+ super(self.class.default_task)
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ def self.massage_args argv
32
+ prepend_default_task_name(turn_muliple_tag_options_into_array(argv))
33
+ end
34
+
35
+ def self.prepend_default_task_name argv
36
+ if known_first_arguments.include?(argv[0])
37
+ argv
38
+ else
39
+ [default_command] + argv
40
+ end
41
+ end
42
+
43
+ # other task names, help, and the help shortcuts
44
+ def self.known_first_arguments
45
+ @known_first_arguments ||= tasks.keys + ::Thor::HELP_MAPPINGS + ['help']
46
+ end
47
+
48
+ def self.turn_muliple_tag_options_into_array argv
49
+ new_argv = []
50
+ opt_name = nil
51
+ argv.each_with_index do | arg, i |
52
+ if arg.start_with?('-')
53
+ opt_name = arg
54
+ existing = new_argv.find { | a | a.first == opt_name }
55
+ if !existing
56
+ new_argv << [arg]
57
+ end
58
+ else
59
+ if opt_name
60
+ existing = new_argv.find { | a | a.first == opt_name }
61
+ existing << arg
62
+ opt_name = nil
63
+ else
64
+ new_argv << [arg]
65
+ end
66
+ end
67
+ end
68
+ new_argv.flatten
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,99 @@
1
+ require 'fileutils'
2
+
3
+ module Pact
4
+ module MockService
5
+ class CLI < Thor
6
+ def self.exit_on_failure? # Thor 1.0 deprecation guard
7
+ false
8
+ end
9
+
10
+ class Pidfile
11
+ attr_accessor :pid_dir, :name, :pid
12
+
13
+ def initialize options
14
+ @pid_dir = options[:pid_dir] || 'tmp/pids'
15
+ @name = options[:name] || default_name
16
+ @pid = options[:pid] || Process.pid
17
+ end
18
+
19
+ def file_exists?
20
+ File.exist?(pidfile_path)
21
+ end
22
+
23
+ def process_running?
24
+ process_exists? pid_from_file
25
+ end
26
+
27
+ def pidfile_path
28
+ File.join(pid_dir, name)
29
+ end
30
+
31
+ def pid_from_file
32
+ File.read(pidfile_path).to_i
33
+ end
34
+
35
+ def default_name
36
+ File.basename($0, File.extname($0)) + ".pid"
37
+ end
38
+
39
+ def process_exists? pid
40
+ Process.kill 0, pid
41
+ true
42
+ rescue Errno::ESRCH
43
+ false
44
+ end
45
+
46
+ def file_exists_and_process_running?
47
+ file_exists? && process_running?
48
+ end
49
+
50
+ def can_start?
51
+ if file_exists? && process_running?
52
+ $stderr.puts "Server already running."
53
+ false
54
+ elsif file_exists?
55
+ $stderr.puts "WARN: PID file #{pidfile_path} already exists, but process is not running. Overwriting pidfile."
56
+ true
57
+ else
58
+ true
59
+ end
60
+ end
61
+
62
+ def write
63
+ FileUtils.mkdir_p pid_dir
64
+ File.open(pidfile_path, "w") { |file| file << pid }
65
+ end
66
+
67
+ def delete
68
+ FileUtils.rm pidfile_path
69
+ end
70
+
71
+ def waitpid
72
+ tries = 0
73
+ sleep_time = 0.1
74
+ while process_running? && tries < 100
75
+ sleep sleep_time
76
+ tries += 1
77
+ end
78
+ raise "Process #{pid_from_file} not stopped after {100 * sleep_time} seconds." if process_running?
79
+ end
80
+
81
+ def kill_process
82
+ if file_exists?
83
+ begin
84
+ `ps -ef | grep pact`
85
+ Process.kill 2, pid_from_file
86
+ waitpid
87
+ delete
88
+ rescue Errno::ESRCH
89
+ $stderr.puts "Process in PID file #{pidfile_path} not running. Deleting PID file."
90
+ delete
91
+ end
92
+ else
93
+ $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."
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,213 @@
1
+ require 'thor'
2
+
3
+ module Pact
4
+ module MockService
5
+ class CLI < Thor
6
+ def self.exit_on_failure? # Thor 1.0 deprecation guard
7
+ false
8
+ end
9
+
10
+ PACT_FILE_WRITE_MODE_DESC = "`overwrite` or `merge`. Use `merge` when running multiple mock service instances in parallel for the same consumer/provider pair." +
11
+ " Ensure the pact file is deleted before running tests when using this option so that interactions deleted from the code are not maintained in the file."
12
+
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 (INT)."
14
+ method_option :consumer, desc: "Consumer name"
15
+ method_option :provider, desc: "Provider name"
16
+ method_option :port, aliases: "-p", desc: "Port on which to run the service"
17
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
18
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
19
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
20
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.", default: '2'
21
+ method_option :log, aliases: "-l", desc: "File to which to log output"
22
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
23
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
24
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
25
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
26
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
27
+ method_option :monkeypatch, hide: true
28
+
29
+ def service
30
+ require_common_dependencies
31
+ require 'pact/mock_service/run'
32
+ Run.(options)
33
+ end
34
+
35
+ desc 'control', "Run a Pact mock service control server."
36
+ method_option :port, aliases: "-p", desc: "Port on which to run the service"
37
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
38
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
39
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output"
40
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
41
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
42
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.", default: '2'
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 :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
45
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
46
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
47
+
48
+ def control
49
+ require_common_dependencies
50
+ require 'pact/mock_service/control_server/run'
51
+ ControlServer::Run.(options)
52
+ end
53
+
54
+ desc 'start', "Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown (INT)."
55
+ method_option :consumer, desc: "Consumer name"
56
+ method_option :provider, desc: "Provider name"
57
+ method_option :port, aliases: "-p", default: '1234', desc: "Port on which to run the service"
58
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
59
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
60
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
61
+ method_option :pid_dir, desc: "PID dir", default: 'tmp/pids'
62
+ method_option :log, aliases: "-l", desc: "File to which to log output"
63
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
64
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.", default: '2'
65
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
66
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
67
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
68
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
69
+ method_option :monkeypatch, hide: true
70
+
71
+ def start
72
+ require_common_dependencies
73
+ start_server(mock_service_pidfile) do
74
+ service
75
+ end
76
+ end
77
+
78
+ desc 'stop', "Stop a Pact mock service"
79
+ method_option :port, aliases: "-p", desc: "Port of the service to stop", default: '1234', required: true
80
+ method_option :pid_dir, desc: "PID dir, defaults to tmp/pids", default: "tmp/pids"
81
+
82
+ def stop
83
+ require_common_dependencies
84
+ mock_service_pidfile.kill_process
85
+ end
86
+
87
+ 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 (INT)."
88
+ method_option :consumer, desc: "Consumer name"
89
+ method_option :provider, desc: "Provider name"
90
+ method_option :port, aliases: "-p", default: '1234', desc: "Port on which to run the service"
91
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
92
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written"
93
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
94
+ method_option :pid_dir, desc: "PID dir", default: 'tmp/pids'
95
+ method_option :log, aliases: "-l", desc: "File to which to log output"
96
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
97
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.", default: '2'
98
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
99
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
100
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
101
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
102
+
103
+ def restart
104
+ require_common_dependencies
105
+ restart_server(mock_service_pidfile) do
106
+ service
107
+ end
108
+ end
109
+
110
+ desc 'control-start', "Start a Pact mock service control server."
111
+ method_option :port, aliases: "-p", desc: "Port on which to run the service", default: '1234'
112
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
113
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output", default: "log"
114
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
115
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
116
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact", default: '2'
117
+ method_option :pid_dir, desc: "PID dir", default: "tmp/pids"
118
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
119
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
120
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
121
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
122
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written", default: "."
123
+
124
+ def control_start
125
+ require_common_dependencies
126
+ start_server(control_server_pidfile) do
127
+ control
128
+ end
129
+ end
130
+
131
+ desc 'control-stop', "Stop a Pact mock service control server."
132
+ method_option :port, aliases: "-p", desc: "Port of control server to stop", default: "1234"
133
+ method_option :pid_dir, desc: "PID dir, defaults to tmp/pids", default: "tmp/pids"
134
+
135
+ def control_stop
136
+ require_common_dependencies
137
+ control_server_pidfile.kill_process
138
+ end
139
+
140
+ desc 'control-restart', "Start a Pact mock service control server."
141
+ method_option :port, aliases: "-p", desc: "Port on which to run the service", default: '1234'
142
+ method_option :host, aliases: "-h", desc: "Host on which to bind the service", default: 'localhost'
143
+ method_option :log_dir, aliases: "-l", desc: "File to which to log output", default: "log"
144
+ method_option :log_level, desc: "Log level. Options are DEBUG INFO WARN ERROR", default: "DEBUG"
145
+ method_option :pact_dir, aliases: "-d", desc: "Directory to which the pacts will be written", default: "."
146
+ method_option :pact_file_write_mode, aliases: "-m", desc: PACT_FILE_WRITE_MODE_DESC, type: :string, default: 'overwrite'
147
+ method_option :pact_specification_version, aliases: "-i", desc: "The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.", default: '2'
148
+ method_option :pid_dir, desc: "PID dir", default: "tmp/pids"
149
+ method_option :cors, aliases: "-o", desc: "Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses"
150
+ method_option :ssl, desc: "Use a self-signed SSL cert to run the service over HTTPS", type: :boolean, default: false
151
+ method_option :sslcert, desc: "Specify the path to the SSL cert to use when running the service over HTTPS"
152
+ method_option :sslkey, desc: "Specify the path to the SSL key to use when running the service over HTTPS"
153
+
154
+ def control_restart
155
+ require_common_dependencies
156
+ restart_server(control_server_pidfile) do
157
+ control
158
+ end
159
+ end
160
+
161
+ desc 'version', "Show the pact-mock-service gem version"
162
+
163
+ def version
164
+ require 'pact/mock_service/version.rb'
165
+ puts Pact::MockService::VERSION
166
+ end
167
+
168
+ default_task :service
169
+
170
+ no_commands do
171
+
172
+ def require_common_dependencies
173
+ require 'webrick/https'
174
+ require 'rack/handler/webrick'
175
+ require 'fileutils'
176
+ require 'pact/mock_service/server/wait_for_server_up'
177
+ require 'pact/mock_service/cli/pidfile'
178
+ require 'socket'
179
+ end
180
+
181
+ def control_server_pidfile
182
+ Pidfile.new(pid_dir: options[:pid_dir], name: control_pidfile_name)
183
+ end
184
+
185
+ def mock_service_pidfile
186
+ Pidfile.new(pid_dir: options[:pid_dir], name: mock_service_pidfile_name)
187
+ end
188
+
189
+ def mock_service_pidfile_name
190
+ "mock-service-#{options[:port]}.pid"
191
+ end
192
+
193
+ def control_pidfile_name
194
+ "mock-service-control-#{options[:port]}.pid"
195
+ end
196
+
197
+ def start_server pidfile
198
+ require 'pact/mock_service/server/spawn'
199
+ Pact::MockService::Server::Spawn.(pidfile, options[:host], options[:port], options[:ssl]) do
200
+ yield
201
+ end
202
+ end
203
+
204
+ def restart_server pidfile
205
+ require 'pact/mock_service/server/respawn'
206
+ Pact::MockService::Server::Respawn.(pidfile, options[:host], options[:port], options[:ssl]) do
207
+ yield
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end