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 Rack::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.0'

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
# 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

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

Instance Method Details

#base_urlString

Returns:

  • (String)


37
38
39
40
41
42
43
# File 'lib/rack/test_server.rb', line 37

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)


83
84
85
86
87
88
# File 'lib/rack/test_server.rb', line 83

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.



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/rack/test_server.rb', line 48

def start
  # Disable SIGINT handler in Rack::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


68
69
70
# File 'lib/rack/test_server.rb', line 68

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.



76
77
78
# File 'lib/rack/test_server.rb', line 76

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.



91
92
93
94
95
# File 'lib/rack/test_server.rb', line 91

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.



98
99
100
101
102
# File 'lib/rack/test_server.rb', line 98

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