rails: RAILS_RELATIVE_URL_ROOT may be set in Unicorn config
[unicorn.git] / test / rails / test_rails.rb
blob9502dcbd61c211a07c24c7f9dc0dd9fb25058f07
1 # -*- encoding: binary -*-
3 # Copyright (c) 2009 Eric Wong
4 require 'test/test_helper'
6 # don't call exit(0) since it may be run under rake (but gmake is recommended)
7 do_test = true
9 $unicorn_rails_bin = ENV['UNICORN_RAILS_TEST_BIN'] || "unicorn_rails"
10 redirect_test_io { do_test = system($unicorn_rails_bin, '-v') }
12 unless do_test
13   warn "#$unicorn_rails_bin not found in PATH=#{ENV['PATH']}, " \
14        "skipping this test"
15 end
17 unless which('git')
18   warn "git not found in PATH=#{ENV['PATH']}, skipping this test"
19   do_test = false
20 end
22 if RAILS_GIT_REPO = ENV['RAILS_GIT_REPO']
23   unless File.directory?(RAILS_GIT_REPO)
24     warn "#{RAILS_GIT_REPO} not found, create it with:\n" \
25          "\tgit clone --mirror git://github.com/rails/rails #{RAILS_GIT_REPO}" \
26          "skipping this test for now"
27     do_test = false
28   end
29 else
30   warn "RAILS_GIT_REPO not defined, don't know where to git clone from"
31   do_test = false
32 end
34 unless UNICORN_RAILS_TEST_VERSION = ENV['UNICORN_RAILS_TEST_VERSION']
35   warn 'UNICORN_RAILS_TEST_VERSION not defined in environment, ' \
36        'skipping this test'
37   do_test = false
38 end
40 RAILS_ROOT = "#{File.dirname(__FILE__)}/app-#{UNICORN_RAILS_TEST_VERSION}"
41 unless File.directory?(RAILS_ROOT)
42   warn "unsupported UNICORN_RAILS_TEST_VERSION=#{UNICORN_RAILS_TEST_VERSION}"
43   do_test = false
44 end
46 ROR_V = UNICORN_RAILS_TEST_VERSION.split(/\./).map { |x| x.to_i }
47 RB_V = RUBY_VERSION.split(/\./).map { |x| x.to_i }
48 if RB_V[0] >= 1 && RB_V[1] >= 9
49   unless ROR_V[0] >= 2 && ROR_V[1] >= 3
50     warn "skipping Ruby >=1.9 test with Rails <2.3"
51     do_test = false
52   end
53 end
55 class RailsTest < Test::Unit::TestCase
56   trap(:QUIT, 'IGNORE')
58   COMMON_TMP = Tempfile.new('unicorn_tmp') unless defined?(COMMON_TMP)
60   HEAVY_CFG = <<-EOS
61 worker_processes 2
62 timeout 30
63 logger Logger.new('#{COMMON_TMP.path}')
64   EOS
66   def setup
67     @pwd = Dir.pwd
68     @tmpfile = Tempfile.new('unicorn_rails_test')
69     @tmpdir = @tmpfile.path
70     @tmpfile.close!
71     assert_nothing_raised do
72       FileUtils.cp_r(RAILS_ROOT, @tmpdir, :preserve => true)
73     end
74     Dir.chdir(@tmpdir)
75     system('git', 'clone', '-nsq', RAILS_GIT_REPO, 'vendor/rails')
76     Dir.chdir("#@tmpdir/vendor/rails") do
77       system('git', 'reset', '-q', '--hard', "v#{UNICORN_RAILS_TEST_VERSION}")
78     end
80     assert(system('rake', 'db:sessions:create'))
81     assert(system('rake', 'db:migrate'))
83     @addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
84     @port = unused_port(@addr)
85     @start_pid = $$
86     @pid = nil
87   end
89   def test_launcher
90     tmp_dirs = %w(cache pids sessions sockets)
91     tmp_dirs.each { |dir| assert(! File.exist?("tmp/#{dir}")) }
92     redirect_test_io { @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port" } }
93     wait_master_ready("test_stderr.#$$.log")
95     # temp dirs exist
96     tmp_dirs.each { |dir| assert(File.directory?("tmp/#{dir}")) }
98     # basic GET
99     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
100     assert_equal "FOO\n", res.body
101     assert_match %r{^text/html\b}, res['Content-Type']
102     assert_equal "4", res['Content-Length']
103     assert_equal "200 OK", res['Status']
105     # can we set cookies?
106     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xcookie"))
107     assert_equal "200", res.code
108     assert_equal "200 OK", res['Status']
109     cookies = res.get_fields('Set-Cookie')
110     assert_equal 2, cookies.size
111     assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
112     assert_equal 1, cookies.grep(/\Afoo=cookie/).size
114     # how about just a session?
115     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xnotice"))
116     assert_equal "200", res.code
117     assert_equal "200 OK", res['Status']
118     cookies = res.get_fields('Set-Cookie')
119     assert_equal 1, cookies.size
120     assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
122     # posting forms?
123     uri = URI.parse("http://#@addr:#@port/foo/xpost")
124     wait_master_ready("test_stderr.#$$.log")
125     res = Net::HTTP.post_form(uri, {"a" => "b", "c"=>"d"})
126     assert_equal "200", res.code
127     params = res.body.split(/\n/).grep(/^params:/)
128     assert_equal 1, params.size
129     params = eval(params[0].gsub!(/\Aparams:/, ''))
130     assert_equal Hash, params.class
131     assert_equal 'b', params['a']
132     assert_equal 'd', params['c']
133     assert_equal "200 OK", res['Status']
135     # try uploading a big file
136     tmp = Tempfile.new('random')
137     sha1 = Digest::SHA1.new
138     assert_nothing_raised do
139       File.open("/dev/urandom", "rb") do |fp|
140         256.times do
141           buf = fp.sysread(4096)
142           sha1.update(buf)
143           tmp.syswrite(buf)
144         end
145       end
146     end
148     # fixed in Rack commit 44ed4640f077504a49b7f1cabf8d6ad7a13f6441,
149     # no released version of Rails or Rack has this fix
150     if RB_V[0] >= 1 && RB_V[1] >= 9
151       warn "multipart broken with Rack 1.0.0 and Rails 2.3.2.1 under 1.9"
152     else
153       resp = `curl -isSfN -Ffile=@#{tmp.path} http://#@addr:#@port/foo/xpost`
154       assert $?.success?
155       resp = resp.split(/\r?\n/)
156       grepped = resp.grep(/^sha1: (.{40})/)
157       assert_equal 1, grepped.size
158       assert_equal(sha1.hexdigest, /^sha1: (.{40})/.match(grepped.first)[1])
160       grepped = resp.grep(/^Content-Type:\s+(.+)/i)
161       assert_equal 1, grepped.size
162       assert_match %r{^text/plain}, grepped.first.split(/\s*:\s*/)[1]
163       assert_equal 1, resp.grep(/^Status:/i).size
164     end
166     # make sure we can get 403 responses, too
167     uri = URI.parse("http://#@addr:#@port/foo/xpost")
168     wait_master_ready("test_stderr.#$$.log")
169     res = Net::HTTP.get_response(uri)
170     assert_equal "403", res.code
171     assert_equal "403 Forbidden", res['Status']
173     # non existent controller
174     uri = URI.parse("http://#@addr:#@port/asdf")
175     res = Net::HTTP.get_response(uri)
176     assert_equal "404", res.code
177     assert_equal "404 Not Found", res['Status']
179     # static files
181     # ensure file we're about to serve is not there yet
182     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
183     assert_equal "404 Not Found", res['Status']
184     assert_equal '404', res.code
186     # can we serve text files based on suffix?
187     File.open("public/pid.txt", "wb") { |fp| fp.syswrite("#$$\n") }
188     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
189     assert_equal '200', res.code
190     assert_equal "200 OK", res['Status']
191     assert_match %r{^text/plain}, res['Content-Type']
192     assert_equal "#$$\n", res.body
194     # can we serve HTML files based on suffix?
195     assert File.exist?("public/500.html")
196     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500.html"))
197     assert_equal '200', res.code
198     assert_equal '200 OK', res['Status']
199     assert_match %r{^text/html}, res['Content-Type']
200     five_hundred_body = res.body
202     # lets try pretending 500 is a controller that got cached
203     assert ! File.exist?("public/500")
204     assert_equal five_hundred_body, File.read("public/500.html")
205     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500"))
206     assert_equal '200', res.code
207     assert_equal '200 OK', res['Status']
208     assert_match %r{^text/html}, res['Content-Type']
209     assert_equal five_hundred_body, res.body
210   end
212   def test_alt_url_root
213     # cbf to actually work on this since I never use this feature (ewong)
214     return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
215     redirect_test_io do
216       @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", '-P/poo' }
217     end
218     wait_master_ready("test_stderr.#$$.log")
219     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
220     # p res
221     # p res.body
222     # system 'cat', 'log/development.log'
223     assert_equal "200", res.code
224     assert_equal '200 OK', res['Status']
225     assert_equal "FOO\n", res.body
226     assert_match %r{^text/html\b}, res['Content-Type']
227     assert_equal "4", res['Content-Length']
229     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
230     assert_equal "404", res.code
231     assert_equal '404 Not Found', res['Status']
232   end
234   def test_alt_url_root_config_env
235     # cbf to actually work on this since I never use this feature (ewong)
236     return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
237     tmp = Tempfile.new(nil)
238     tmp.syswrite("ENV['RAILS_RELATIVE_URL_ROOT'] = '/poo'\n")
239     redirect_test_io do
240       @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", "-c", tmp.path }
241     end
242     wait_master_ready("test_stderr.#$$.log")
243     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
244     assert_equal "200", res.code
245     assert_equal '200 OK', res['Status']
246     assert_equal "FOO\n", res.body
247     assert_match %r{^text/html\b}, res['Content-Type']
248     assert_equal "4", res['Content-Length']
250     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
251     assert_equal "404", res.code
252     assert_equal '404 Not Found', res['Status']
254     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/x.txt"))
255     assert_equal "200", res.code
256     assert_equal "HELLO\n", res.body
257   end
259   def teardown
260     return if @start_pid != $$
262     if @pid
263       Process.kill(:QUIT, @pid)
264       pid2, status = Process.waitpid2(@pid)
265       assert status.success?
266     end
268     Dir.chdir(@pwd)
269     FileUtils.rmtree(@tmpdir)
270     loop do
271       Process.kill('-QUIT', 0)
272       begin
273         Process.waitpid(-1, Process::WNOHANG) or break
274       rescue Errno::ECHILD
275         break
276       end
277     end
278   end
280 end if do_test