Launching a web server inside ruby tests
Asked Answered
M

3

9

I'm writing a library to wrap tsung's functionality in a way that can be better used by rails applications. I want to write some integration tests that boil down to the following:

  1. launch a simple web server
  2. run tsung-recorder via the library
  3. launch selenium, with a firefox profile configured to use the tsung proxy, and have this fetch a page from the server launched in step 1
  4. examine the recorded library (it exists, it's in the correct location, etc.)

For step 1, while I could launch a vanilla rails app externally (e.g., %x{rails s} ), I'm pretty sure there's a better way to programmatically create a simple web server suitable for testing.

tl;dr - What's a way to programmatically launch a simple web server inside a test?

Mulcahy answered 15/4, 2012 at 22:13 Comment(2)
@NiklasB. I was thinking that would work well, but I'm not having an easy time finding an example (the rack tests use mocks from what I can tell).Mulcahy
Hm, unfortunately I can't point you at a minimal example, but I'm sure capybara uses this for its specs. Have a look at the server implementation at github.com/jnicklas/capybara/blob/master/lib/capybara/server.rb and the specs at github.com/jnicklas/capybara/blob/master/spec/server_spec.rb, they're quite informative :)Suki
S
6

capybara uses an ad-hoc Rack server for its specs:

Any Rack app (including Rails applications) can be served using this system, though the Rails configuration might get a bit tricky.

Suki answered 15/4, 2012 at 22:43 Comment(2)
I used the Timeout.timeout(60) { @server_thread.join(0.1) until responsive? } pattern, and it works great! THANKS!Backset
app = proc { |_env| [200, {}, ['Hello Server!']] }; Capybara::Server.new(app).boot. THANKS!Redford
I
12

You can roll your own simple server. Here's a quick example using thin and rspec (those gems, plus rack, must be installed):

# spec/support/test_server.rb
require 'rubygems'
require 'rack'

module MyApp
  module Test
    class Server
      def call(env)
        @root = File.expand_path(File.dirname(__FILE__))
        path = Rack::Utils.unescape(env['PATH_INFO'])
        path += 'index.html' if path == '/'
        file = @root + "#{path}"

        params = Rack::Utils.parse_nested_query(env['QUERY_STRING'])

        if File.exists?(file)
          [ 200, {"Content-Type" => "text/html"}, File.read(file) ]
        else
          [ 404, {'Content-Type' => 'text/plain'}, 'file not found' ]
        end
      end
    end
  end
end

Then in your spec_helper:

# Include all files under spec/support
Dir["./spec/support/**/*.rb"].each {|f| require f}

# Start a local rack server to serve up test pages.
@server_thread = Thread.new do
  Rack::Handler::Thin.run MyApp::Test::Server.new, :Port => 9292
end
sleep(1) # wait a sec for the server to be booted

This will serve any file that you store in the spec/support directory. Including itself. For all other requests it will return a 404.

This is basically what capybara does as mentioned in the previous answer, minus a lot of sophistication.

Inessa answered 12/10, 2012 at 21:41 Comment(1)
There may be a security concern here... just to be safe I'd change the File.exists? line to: File.exists?(file) && File.dirname(file) == @rootShifflett
S
6

capybara uses an ad-hoc Rack server for its specs:

Any Rack app (including Rails applications) can be served using this system, though the Rails configuration might get a bit tricky.

Suki answered 15/4, 2012 at 22:43 Comment(2)
I used the Timeout.timeout(60) { @server_thread.join(0.1) until responsive? } pattern, and it works great! THANKS!Backset
app = proc { |_env| [200, {}, ['Hello Server!']] }; Capybara::Server.new(app).boot. THANKS!Redford
F
2

stub_server is a real testing server that can serve pre-defined replies and is easy to spin up ... comes with ssl support too.

Fimbria answered 16/11, 2016 at 22:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.