stripe-ruby/test/stripe_mock.rb
Brandur ad20248ee3 Have stripe-mock select a port number
When starting a stripe-mock for a custom OpenAPI spec, pass `-http-port
0` on startup, which tells stripe-mock to select a port, then extract
that port from its output.

This is not a total win because we now have to rely on string matching,
but it is better in that (1) it gets a port more efficiently, (2) it
eliminates a race condition where another process could take the port we
found before stripe-mock gets to start, and (3) it starts a little
faster as we take advantage of the fact that we know stripe-mock has
started when we've found a port in its output (in my tests it took ~0.2
to 0.3 seconds compared to a 1 second sleep).
2019-01-18 16:38:52 -08:00

78 lines
1.9 KiB
Ruby

# frozen_string_literal: true
module Stripe
class StripeMock
include Singleton
PATH_SPEC = "#{::File.dirname(__FILE__)}/openapi/spec3.json".freeze
PATH_FIXTURES = "#{::File.dirname(__FILE__)}/openapi/fixtures3.json".freeze
@pid = nil
@port = -1
# Starts stripe-mock, if necessary. Returns the port on which stripe-mock is listening.
def self.start
unless ::File.exist?(PATH_SPEC)
port = ENV["STRIPE_MOCK_PORT"] || 12_111
puts("No custom spec file found, assuming stripe-mock is already running on port #{port}")
return port
end
unless @pid.nil?
puts("stripe-mock already running on port #{@port}")
return @port
end
puts("Starting stripe-mock...")
@stdout, @child_stdout = ::IO.pipe
@stderr, @child_stderr = ::IO.pipe
@pid = ::Process.spawn(
["stripe-mock", "stripe-mock"],
"-http-port",
"0", # have stripe-mock select a port
"-spec",
PATH_SPEC,
"-fixtures",
PATH_FIXTURES,
out: @child_stdout,
err: @child_stderr
)
[@child_stdout, @child_stderr].each(&:close)
# Look for port in "Listening for HTTP on port: 50602"
buffer = ""
loop do
buffer += @stdout.readpartial(4096)
if (matches = buffer.match(/ port: (\d+)/))
@port = matches[1]
break
end
sleep(0.1)
end
status = (::Process.wait2(@pid, ::Process::WNOHANG) || []).last
if status.nil?
puts("Started stripe-mock, PID = #{@pid}")
else
abort("stripe-mock terminated early: #{status}")
end
@port
end
# Stops stripe-mock, if necessary.
def self.stop
return if @pid.nil?
puts("Stopping stripe-mock...")
::Process.kill(:SIGTERM, @pid)
::Process.waitpid2(@pid)
@pid = nil
@port = -1
puts("Stopped stripe-mock")
end
end
end