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)
9 $unicorn_rails_bin = ENV['UNICORN_RAILS_TEST_BIN'] || "unicorn_rails"
10 redirect_test_io { do_test = system($unicorn_rails_bin, '-v') }
13 warn "#$unicorn_rails_bin not found in PATH=#{ENV['PATH']}, " \
18 warn "git not found in PATH=#{ENV['PATH']}, skipping this test"
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"
30 warn "RAILS_GIT_REPO not defined, don't know where to git clone from"
34 unless UNICORN_RAILS_TEST_VERSION = ENV['UNICORN_RAILS_TEST_VERSION']
35 warn 'UNICORN_RAILS_TEST_VERSION not defined in environment, ' \
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}"
46 ROR_V = UNICORN_RAILS_TEST_VERSION.split(/\./).map { |x| x.to_i }
47 RB_V = RUBY_VERSION.split(/\./).map { |x| x.to_i }
49 warn "skipping Ruby 2.0+ test with Rails <3"
51 elsif RB_V[0] >= 1 && RB_V[1] >= 9
53 warn "Ruby 1.9.2+ is not compatible with Rails 2.x"
56 unless ROR_V[0] >= 2 && ROR_V[1] >= 3
57 warn "skipping Ruby >=1.9 test with Rails <2.3"
62 class RailsTest < Test::Unit::TestCase
65 COMMON_TMP = Tempfile.new('unicorn_tmp') unless defined?(COMMON_TMP)
70 logger Logger.new('#{COMMON_TMP.path}')
75 @tmpfile = Tempfile.new('unicorn_rails_test')
76 @tmpdir = @tmpfile.path
78 assert_nothing_raised do
79 FileUtils.cp_r(RAILS_ROOT, @tmpdir, :preserve => true)
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}")
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)
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")
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']
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
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|
148 buf = fp.sysread(4096)
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"
160 resp = `curl -isSfN -Ffile=@#{tmp.path} http://#@addr:#@port/foo/xpost`
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
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']
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
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
223 @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", '-P/poo' }
225 wait_master_ready("test_stderr.#$$.log")
226 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
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']
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")
247 @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", "-c", tmp.path }
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
267 return if @start_pid != $$
270 Process.kill(:QUIT, @pid)
271 _, status = Process.waitpid2(@pid)
272 assert status.success?
276 FileUtils.rmtree(@tmpdir)
278 Process.kill('-QUIT', 0)
280 Process.waitpid(-1, Process::WNOHANG) or break