Class: Rack::TestServer

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/test_server.rb,
lib/rack/test_server/version.rb,
lib/rack/test_server/signal_trap_interceptor.rb,
lib/rack/test_server/puma_signal_trap_interceptor.rb

Overview

An utility class for launching HTTP server with Rackup::Server#start and waiting for the server available with checking a healthcheck endpoint with net/http.

The most typical usage is:

server = Rack::TestServer.new(app: myapp, Port: 3000)
server.start_async
server.wait_for_ready

Defined Under Namespace

Modules: PumaSignalTrapInterceptor, SignalTrapInterceptor

Constant Summary collapse

VERSION =
'0.2.1'

Instance Method Summary collapse

Constructor Details

#initialize(app:, **options) ⇒ TestServer

Available options can be found here: github.com/rack/rack/blob/2.2.3/lib/rack/server.rb#L173

Parameters:

  • app (Proc)

    Rack application to run.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/rack/test_server.rb', line 24

def initialize(app:, **options)
  testapp = Rack::Builder.app(app) do
    map '/__ping' do
      run ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['OK']] }
    end
  end

  begin
    @server = Rackup::Server.new(app: testapp, **options)
  rescue NameError
    @server = Rack::Server.new(app: testapp, **options)
  end
  @host = @server.options[:Host] || @server.default_options[:Host]
  @port = @server.options[:Port] || @server.default_options[:Port]
end

Instance Method Details

#base_urlString

Returns:

  • (String)


41
42
43
44
45
46
47
# File 'lib/rack/test_server.rb', line 41

def base_url
  if @host == '0.0.0.0'
    "http://127.0.0.1:#{@port}"
  else
    "http://#{@host}:#{@port}"
  end
end

#ready?Boolean

Check if HTTP server actually responds.

Returns:

  • (Boolean)


87
88
89
90
91
92
# File 'lib/rack/test_server.rb', line 87

def ready?
  Net::HTTP.get(URI("#{base_url}/__ping"))
  true
rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EINVAL
  false
end

#startObject

Note:

This method will block the thread, and in most cases #start_async is suitable.

Start HTTP server with blocking current thread.



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rack/test_server.rb', line 52

def start
  # Disable SIGINT handler in Rackup::Server.
  # https://github.com/rack/rack/blob/2.2.3/lib/rack/server.rb#L319
  SignalTrapInterceptor.enable
  @server.start do |server|
    SignalTrapInterceptor.disable

    # server can be a Puma::Launcher, Webrick::Server, Thin::Server
    # They all happen to have 'stop' method for greaceful shutdown.
    # Remember the method as Proc here for stopping server manually.
    @stop_proc = -> { server.stop }
  end
end

#start_asyncObject

Start HTTP server, typically used together with #wait_for_ready method.

server = Rack::TestServer.new(app: myapp)
server.start_async
server.wait_for_ready


72
73
74
# File 'lib/rack/test_server.rb', line 72

def start_async
  Thread.new { start }
end

#stop_asyncObject

Note:

This method doesn’t wait for the shutdown process, and use #wait_for_stopped to ensure the server is actually stopped.

Stop HTTP server.



80
81
82
# File 'lib/rack/test_server.rb', line 80

def stop_async
  Thread.new { @stop_proc.call }
end

#wait_for_ready(timeout: 3) ⇒ Object

This method blocks until the HTTP server is ensured to respond to HTTP request.



95
96
97
98
99
# File 'lib/rack/test_server.rb', line 95

def wait_for_ready(timeout: 3)
  Timeout.timeout(timeout) do
    sleep 0.1 until ready?
  end
end

#wait_for_stopped(timeout: 5) ⇒ Object

This method returns after the server is shutdown.



102
103
104
105
106
# File 'lib/rack/test_server.rb', line 102

def wait_for_stopped(timeout: 5)
  Timeout.timeout(timeout) do
    sleep 0.1 if ready?
  end
end