9cf92c0a0baea61c8ad51093207d0f26f2e13fc3
[unicorn.git] / test / rails / test_rails.rb
blob9cf92c0a0baea61c8ad51093207d0f26f2e13fc3
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] >= 2
49   warn "skipping Ruby 2.0+ test with Rails <3"
50   do_test = false
51 elsif RB_V[0] >= 1 && RB_V[1] >= 9
52   if RB_V[2] >= 2
53     warn "Ruby 1.9.2+ is not compatible with Rails 2.x"
54     do_test = false
55   end
56   unless ROR_V[0] >= 2 && ROR_V[1] >= 3
57     warn "skipping Ruby >=1.9 test with Rails <2.3"
58     do_test = false
59   end
60 end
62 class RailsTest < Test::Unit::TestCase
63   trap(:QUIT, 'IGNORE')
65   COMMON_TMP = Tempfile.new('unicorn_tmp') unless defined?(COMMON_TMP)
67   HEAVY_CFG = <<-EOS
68 worker_processes 2
69 timeout 30
70 logger Logger.new('#{COMMON_TMP.path}')
71   EOS
73   def setup
74     @pwd = Dir.pwd
75     @tmpfile = Tempfile.new('unicorn_rails_test')
76     @tmpdir = @tmpfile.path
77     @tmpfile.close!
78     assert_nothing_raised do
79       FileUtils.cp_r(RAILS_ROOT, @tmpdir, :preserve => true)
80     end
81     Dir.chdir(@tmpdir)
82     system('git', 'clone', '-nsq', RAILS_GIT_REPO, 'vendor/rails')
83     Dir.chdir("#@tmpdir/vendor/rails") do
84       system('git', 'reset', '-q', '--hard', "v#{UNICORN_RAILS_TEST_VERSION}")
85     end
87     assert(system('rake', 'db:sessions:create'))
88     assert(system('rake', 'db:migrate'))
90     @addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
91     @port = unused_port(@addr)
92     @start_pid = $$
93     @pid = nil
94   end
96   def test_launcher
97     tmp_dirs = %w(cache pids sessions sockets)
98     tmp_dirs.each { |dir| assert(! File.exist?("tmp/#{dir}")) }
99     redirect_test_io { @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port" } }
100     wait_master_ready("test_stderr.#$$.log")
102     # basic GET
103     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
104     assert_equal "FOO\n", res.body
105     assert_match %r{^text/html\b}, res['Content-Type']
106     assert_equal "4", res['Content-Length']
107     assert_equal "200 OK", res['Status']
109     # temp dirs exist
110     tmp_dirs.each { |dir| assert(File.directory?("tmp/#{dir}")) }
112     # can we set cookies?
113     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xcookie"))
114     assert_equal "200", res.code
115     assert_equal "200 OK", res['Status']
116     cookies = res.get_fields('Set-Cookie')
117     assert_equal 2, cookies.size
118     assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
119     assert_equal 1, cookies.grep(/\Afoo=cookie/).size
121     # how about just a session?
122     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xnotice"))
123     assert_equal "200", res.code
124     assert_equal "200 OK", res['Status']
125     cookies = res.get_fields('Set-Cookie')
126     assert_equal 1, cookies.size
127     assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
129     # posting forms?
130     uri = URI.parse("http://#@addr:#@port/foo/xpost")
131     wait_master_ready("test_stderr.#$$.log")
132     res = Net::HTTP.post_form(uri, {"a" => "b", "c"=>"d"})
133     assert_equal "200", res.code
134     params = res.body.split(/\n/).grep(/^params:/)
135     assert_equal 1, params.size
136     params = eval(params[0].gsub!(/\Aparams:/, ''))
137     assert_equal Hash, params.class
138     assert_equal 'b', params['a']
139     assert_equal 'd', params['c']
140     assert_equal "200 OK", res['Status']
142     # try uploading a big file
143     tmp = Tempfile.new('random')
144     sha1 = Digest::SHA1.new
145     assert_nothing_raised do
146       File.open("/dev/urandom", "rb") do |fp|
147         256.times do
148           buf = fp.sysread(4096)
149           sha1.update(buf)
150           tmp.syswrite(buf)
151         end
152       end
153     end
155     # fixed in Rack commit 44ed4640f077504a49b7f1cabf8d6ad7a13f6441,
156     # no released version of Rails or Rack has this fix
157     if RB_V[0] >= 1 && RB_V[1] >= 9
158       warn "multipart broken with Rack 1.0.0 and Rails 2.3.2.1 under 1.9"
159     else
160       resp = `curl -isSfN -Ffile=@#{tmp.path} http://#@addr:#@port/foo/xpost`
161       assert $?.success?
162       resp = resp.split(/\r?\n/)
163       grepped = resp.grep(/^sha1: (.{40})/)
164       assert_equal 1, grepped.size
165       assert_equal(sha1.hexdigest, /^sha1: (.{40})/.match(grepped.first)[1])
167       grepped = resp.grep(/^Content-Type:\s+(.+)/i)
168       assert_equal 1, grepped.size
169       assert_match %r{^text/plain}, grepped.first.split(/\s*:\s*/)[1]
170       assert_equal 1, resp.grep(/^Status:/i).size
171     end
173     # make sure we can get 403 responses, too
174     uri = URI.parse("http://#@addr:#@port/foo/xpost")
175     wait_master_ready("test_stderr.#$$.log")
176     res = Net::HTTP.get_response(uri)
177     assert_equal "403", res.code
178     assert_equal "403 Forbidden", res['Status']
180     # non existent controller
181     uri = URI.parse("http://#@addr:#@port/asdf")
182     res = Net::HTTP.get_response(uri)
183     assert_equal "404", res.code
184     assert_equal "404 Not Found", res['Status']
186     # static files
188     # ensure file we're about to serve is not there yet
189     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
190     assert_equal "404 Not Found", res['Status']
191     assert_equal '404', res.code
193     # can we serve text files based on suffix?
194     File.open("public/pid.txt", "wb") { |fp| fp.syswrite("#$$\n") }
195     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
196     assert_equal '200', res.code
197     assert_equal "200 OK", res['Status']
198     assert_match %r{^text/plain}, res['Content-Type']
199     assert_equal "#$$\n", res.body
201     # can we serve HTML files based on suffix?
202     assert File.exist?("public/500.html")
203     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500.html"))
204     assert_equal '200', res.code
205     assert_equal '200 OK', res['Status']
206     assert_match %r{^text/html}, res['Content-Type']
207     five_hundred_body = res.body
209     # lets try pretending 500 is a controller that got cached
210     assert ! File.exist?("public/500")
211     assert_equal five_hundred_body, File.read("public/500.html")
212     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500"))
213     assert_equal '200', res.code
214     assert_equal '200 OK', res['Status']
215     assert_match %r{^text/html}, res['Content-Type']
216     assert_equal five_hundred_body, res.body
217   end
219   def test_alt_url_root
220     # cbf to actually work on this since I never use this feature (ewong)
221     return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
222     redirect_test_io do
223       @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", '-P/poo' }
224     end
225     wait_master_ready("test_stderr.#$$.log")
226     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
227     # p res
228     # p res.body
229     # system 'cat', 'log/development.log'
230     assert_equal "200", res.code
231     assert_equal '200 OK', res['Status']
232     assert_equal "FOO\n", res.body
233     assert_match %r{^text/html\b}, res['Content-Type']
234     assert_equal "4", res['Content-Length']
236     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
237     assert_equal "404", res.code
238     assert_equal '404 Not Found', res['Status']
239   end
241   def test_alt_url_root_config_env
242     # cbf to actually work on this since I never use this feature (ewong)
243     return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
244     tmp = Tempfile.new('')
245     tmp.syswrite("ENV['RAILS_RELATIVE_URL_ROOT'] = '/poo'\n")
246     redirect_test_io do
247       @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", "-c", tmp.path }
248     end
249     wait_master_ready("test_stderr.#$$.log")
250     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
251     assert_equal "200", res.code
252     assert_equal '200 OK', res['Status']
253     assert_equal "FOO\n", res.body
254     assert_match %r{^text/html\b}, res['Content-Type']
255     assert_equal "4", res['Content-Length']
257     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
258     assert_equal "404", res.code
259     assert_equal '404 Not Found', res['Status']
261     res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/x.txt"))
262     assert_equal "200", res.code
263     assert_equal "HELLO\n", res.body
264   end
266   def teardown
267     return if @start_pid != $$
269     if @pid
270       Process.kill(:QUIT, @pid)
271       _, status = Process.waitpid2(@pid)
272       assert status.success?
273     end
275     Dir.chdir(@pwd)
276     FileUtils.rmtree(@tmpdir)
277     loop do
278       Process.kill('-QUIT', 0)
279       begin
280         Process.waitpid(-1, Process::WNOHANG) or break
281       rescue Errno::ECHILD
282         break
283       end
284     end
285   end
287 end if do_test