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 }
48 if RB_V[0] >= 1 && RB_V[1] >= 9
50 warn "Ruby 1.9.2+ is not compatible with Rails 2.x"
53 unless ROR_V[0] >= 2 && ROR_V[1] >= 3
54 warn "skipping Ruby >=1.9 test with Rails <2.3"
59 class RailsTest < Test::Unit::TestCase
62 COMMON_TMP = Tempfile.new('unicorn_tmp') unless defined?(COMMON_TMP)
67 logger Logger.new('#{COMMON_TMP.path}')
72 @tmpfile = Tempfile.new('unicorn_rails_test')
73 @tmpdir = @tmpfile.path
75 assert_nothing_raised do
76 FileUtils.cp_r(RAILS_ROOT, @tmpdir, :preserve => true)
79 system('git', 'clone', '-nsq', RAILS_GIT_REPO, 'vendor/rails')
80 Dir.chdir("#@tmpdir/vendor/rails") do
81 system('git', 'reset', '-q', '--hard', "v#{UNICORN_RAILS_TEST_VERSION}")
84 assert(system('rake', 'db:sessions:create'))
85 assert(system('rake', 'db:migrate'))
87 @addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
88 @port = unused_port(@addr)
94 tmp_dirs = %w(cache pids sessions sockets)
95 tmp_dirs.each { |dir| assert(! File.exist?("tmp/#{dir}")) }
96 redirect_test_io { @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port" } }
97 wait_master_ready("test_stderr.#$$.log")
100 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
101 assert_equal "FOO\n", res.body
102 assert_match %r{^text/html\b}, res['Content-Type']
103 assert_equal "4", res['Content-Length']
104 assert_equal "200 OK", res['Status']
107 tmp_dirs.each { |dir| assert(File.directory?("tmp/#{dir}")) }
109 # can we set cookies?
110 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xcookie"))
111 assert_equal "200", res.code
112 assert_equal "200 OK", res['Status']
113 cookies = res.get_fields('Set-Cookie')
114 assert_equal 2, cookies.size
115 assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
116 assert_equal 1, cookies.grep(/\Afoo=cookie/).size
118 # how about just a session?
119 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo/xnotice"))
120 assert_equal "200", res.code
121 assert_equal "200 OK", res['Status']
122 cookies = res.get_fields('Set-Cookie')
123 assert_equal 1, cookies.size
124 assert_equal 1, cookies.grep(/\A_unicorn_rails_test\./).size
127 uri = URI.parse("http://#@addr:#@port/foo/xpost")
128 wait_master_ready("test_stderr.#$$.log")
129 res = Net::HTTP.post_form(uri, {"a" => "b", "c"=>"d"})
130 assert_equal "200", res.code
131 params = res.body.split(/\n/).grep(/^params:/)
132 assert_equal 1, params.size
133 params = eval(params[0].gsub!(/\Aparams:/, ''))
134 assert_equal Hash, params.class
135 assert_equal 'b', params['a']
136 assert_equal 'd', params['c']
137 assert_equal "200 OK", res['Status']
139 # try uploading a big file
140 tmp = Tempfile.new('random')
141 sha1 = Digest::SHA1.new
142 assert_nothing_raised do
143 File.open("/dev/urandom", "rb") do |fp|
145 buf = fp.sysread(4096)
152 # fixed in Rack commit 44ed4640f077504a49b7f1cabf8d6ad7a13f6441,
153 # no released version of Rails or Rack has this fix
154 if RB_V[0] >= 1 && RB_V[1] >= 9
155 warn "multipart broken with Rack 1.0.0 and Rails 2.3.2.1 under 1.9"
157 resp = `curl -isSfN -Ffile=@#{tmp.path} http://#@addr:#@port/foo/xpost`
159 resp = resp.split(/\r?\n/)
160 grepped = resp.grep(/^sha1: (.{40})/)
161 assert_equal 1, grepped.size
162 assert_equal(sha1.hexdigest, /^sha1: (.{40})/.match(grepped.first)[1])
164 grepped = resp.grep(/^Content-Type:\s+(.+)/i)
165 assert_equal 1, grepped.size
166 assert_match %r{^text/plain}, grepped.first.split(/\s*:\s*/)[1]
167 assert_equal 1, resp.grep(/^Status:/i).size
170 # make sure we can get 403 responses, too
171 uri = URI.parse("http://#@addr:#@port/foo/xpost")
172 wait_master_ready("test_stderr.#$$.log")
173 res = Net::HTTP.get_response(uri)
174 assert_equal "403", res.code
175 assert_equal "403 Forbidden", res['Status']
177 # non existent controller
178 uri = URI.parse("http://#@addr:#@port/asdf")
179 res = Net::HTTP.get_response(uri)
180 assert_equal "404", res.code
181 assert_equal "404 Not Found", res['Status']
185 # ensure file we're about to serve is not there yet
186 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
187 assert_equal "404 Not Found", res['Status']
188 assert_equal '404', res.code
190 # can we serve text files based on suffix?
191 File.open("public/pid.txt", "wb") { |fp| fp.syswrite("#$$\n") }
192 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/pid.txt"))
193 assert_equal '200', res.code
194 assert_equal "200 OK", res['Status']
195 assert_match %r{^text/plain}, res['Content-Type']
196 assert_equal "#$$\n", res.body
198 # can we serve HTML files based on suffix?
199 assert File.exist?("public/500.html")
200 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500.html"))
201 assert_equal '200', res.code
202 assert_equal '200 OK', res['Status']
203 assert_match %r{^text/html}, res['Content-Type']
204 five_hundred_body = res.body
206 # lets try pretending 500 is a controller that got cached
207 assert ! File.exist?("public/500")
208 assert_equal five_hundred_body, File.read("public/500.html")
209 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/500"))
210 assert_equal '200', res.code
211 assert_equal '200 OK', res['Status']
212 assert_match %r{^text/html}, res['Content-Type']
213 assert_equal five_hundred_body, res.body
216 def test_alt_url_root
217 # cbf to actually work on this since I never use this feature (ewong)
218 return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
220 @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", '-P/poo' }
222 wait_master_ready("test_stderr.#$$.log")
223 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
226 # system 'cat', 'log/development.log'
227 assert_equal "200", res.code
228 assert_equal '200 OK', res['Status']
229 assert_equal "FOO\n", res.body
230 assert_match %r{^text/html\b}, res['Content-Type']
231 assert_equal "4", res['Content-Length']
233 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
234 assert_equal "404", res.code
235 assert_equal '404 Not Found', res['Status']
238 def test_alt_url_root_config_env
239 # cbf to actually work on this since I never use this feature (ewong)
240 return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
241 tmp = Tempfile.new('')
242 tmp.syswrite("ENV['RAILS_RELATIVE_URL_ROOT'] = '/poo'\n")
244 @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", "-c", tmp.path }
246 wait_master_ready("test_stderr.#$$.log")
247 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/foo"))
248 assert_equal "200", res.code
249 assert_equal '200 OK', res['Status']
250 assert_equal "FOO\n", res.body
251 assert_match %r{^text/html\b}, res['Content-Type']
252 assert_equal "4", res['Content-Length']
254 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/foo"))
255 assert_equal "404", res.code
256 assert_equal '404 Not Found', res['Status']
258 res = Net::HTTP.get_response(URI.parse("http://#@addr:#@port/poo/x.txt"))
259 assert_equal "200", res.code
260 assert_equal "HELLO\n", res.body
264 return if @start_pid != $$
267 Process.kill(:QUIT, @pid)
268 pid2, status = Process.waitpid2(@pid)
269 assert status.success?
273 FileUtils.rmtree(@tmpdir)
275 Process.kill('-QUIT', 0)
277 Process.waitpid(-1, Process::WNOHANG) or break