Class: StubServer

Inherits:
Object
  • Object
show all
Defined in:
lib/stub_server.rb,
lib/stub_server/version.rb

Constant Summary collapse

VERSION =
"0.5.0"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(port, replies, ssl: false, json: false, webrick: {}) ⇒ StubServer

Returns a new instance of StubServer.



14
15
16
17
18
19
20
21
22
23
# File 'lib/stub_server.rb', line 14

def initialize(port, replies, ssl: false, json: false, webrick: {})
  @port = port
  @replies = replies
  @ssl = ssl
  @json = json
  @webrick = webrick
  @started = false
  @server = nil
  @thread = nil
end

Class Method Details

.open(port, replies, **options) ⇒ Object



6
7
8
9
10
11
12
# File 'lib/stub_server.rb', line 6

def self.open(port, replies, **options)
  server = new(port, replies, **options)
  server.boot
  yield server
ensure
  server.shutdown
end

Instance Method Details

#bootObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/stub_server.rb', line 25

def boot
  @thread = Thread.new do
    options = {
      Port: @port,
      Logger: WEBrick::Log.new("/dev/null"),
      AccessLog: [],
      DoNotReverseLookup: true, # http://stackoverflow.com/questions/1156759/webrick-is-very-slow-to-respond-how-to-speed-it-up
      StartCallback: -> { @started = true }
    }

    if @ssl
      require 'webrick/https'
      require 'openssl' # can be slow / break ... so keeping it nested

      options.merge!(
        SSLEnable: true,
        SSLVerifyClient: OpenSSL::SSL::VERIFY_NONE,
        SSLCertificate: OpenSSL::X509::Certificate.new(@ssl.fetch(:cert)),
        SSLPrivateKey: OpenSSL::PKey::RSA.new(@ssl.fetch(:key)),
        SSLCertName: [["CN", 'not-a-valid-cert']]
      )
    end

    options.merge!(@webrick)

    Rack::Handler::WEBrick.run(self, **options) { |s| @server = s }
  end
end

#call(env) ⇒ Object



58
59
60
61
62
63
64
65
66
67
# File 'lib/stub_server.rb', line 58

def call(env)
  path = env.fetch("PATH_INFO")
  code, headers, body = @replies[path]
  unless code
    warn "StubServer #{@port}: Missing reply for path #{path}" # some clients does not show current url when failing
    raise
  end
  body = [body.to_json] if @json
  [code, headers, body]
end

#shutdownObject



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/stub_server.rb', line 69

def shutdown
  @server&.shutdown
  @thread.join # need to wait here and cannot simpliy kill or webbrick keeps running

  # TimeoutHandler keeps running forever which breaks tests that assert no extra threads
  # we should only stop it if it is empty, otherwise we are still waiting for other servers
  # ideally we'd use WEBrick::Utils::TimeoutHandler::TimeoutMutex.synchronize to avoid race conditions,
  # but that is also used in .terminate and would lead to deadlocks ...
  # TODO: open ruby issue for race-condition free terminate_if_empty
  return if RUBY_VERSION < "2.4.0"
  if WEBrick::Utils::TimeoutHandler.instance.instance_variable_get(:@timeout_info).empty?
    WEBrick::Utils::TimeoutHandler.terminate
  end
end

#waitObject



54
55
56
# File 'lib/stub_server.rb', line 54

def wait
  Timeout.timeout(10) { sleep 0.1 until @started }
end