thin 1.2.3-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

Files changed (137) hide show
  1. data/CHANGELOG +263 -0
  2. data/COPYING +18 -0
  3. data/README +69 -0
  4. data/Rakefile +36 -0
  5. data/benchmark/abc +51 -0
  6. data/benchmark/benchmarker.rb +80 -0
  7. data/benchmark/runner +82 -0
  8. data/bin/thin +6 -0
  9. data/example/adapter.rb +32 -0
  10. data/example/async_app.ru +126 -0
  11. data/example/async_chat.ru +247 -0
  12. data/example/async_tailer.ru +100 -0
  13. data/example/config.ru +22 -0
  14. data/example/monit_sockets +20 -0
  15. data/example/monit_unixsock +20 -0
  16. data/example/myapp.rb +1 -0
  17. data/example/ramaze.ru +12 -0
  18. data/example/thin.god +80 -0
  19. data/example/thin_solaris_smf.erb +36 -0
  20. data/example/thin_solaris_smf.readme.txt +150 -0
  21. data/example/vlad.rake +64 -0
  22. data/ext/thin_parser/common.rl +55 -0
  23. data/ext/thin_parser/ext_help.h +14 -0
  24. data/ext/thin_parser/extconf.rb +6 -0
  25. data/ext/thin_parser/parser.c +452 -0
  26. data/ext/thin_parser/parser.h +49 -0
  27. data/ext/thin_parser/parser.rl +157 -0
  28. data/ext/thin_parser/thin.c +433 -0
  29. data/lib/rack/adapter/loader.rb +79 -0
  30. data/lib/rack/adapter/rails.rb +181 -0
  31. data/lib/thin.rb +46 -0
  32. data/lib/thin/backends/base.rb +141 -0
  33. data/lib/thin/backends/swiftiply_client.rb +56 -0
  34. data/lib/thin/backends/tcp_server.rb +29 -0
  35. data/lib/thin/backends/unix_server.rb +51 -0
  36. data/lib/thin/command.rb +53 -0
  37. data/lib/thin/connection.rb +222 -0
  38. data/lib/thin/controllers/cluster.rb +127 -0
  39. data/lib/thin/controllers/controller.rb +183 -0
  40. data/lib/thin/controllers/service.rb +75 -0
  41. data/lib/thin/controllers/service.sh.erb +39 -0
  42. data/lib/thin/daemonizing.rb +174 -0
  43. data/lib/thin/headers.rb +39 -0
  44. data/lib/thin/logging.rb +54 -0
  45. data/lib/thin/request.rb +153 -0
  46. data/lib/thin/response.rb +101 -0
  47. data/lib/thin/runner.rb +209 -0
  48. data/lib/thin/server.rb +247 -0
  49. data/lib/thin/stats.html.erb +216 -0
  50. data/lib/thin/stats.rb +52 -0
  51. data/lib/thin/statuses.rb +43 -0
  52. data/lib/thin/version.rb +32 -0
  53. data/lib/thin_parser.so +0 -0
  54. data/spec/backends/swiftiply_client_spec.rb +66 -0
  55. data/spec/backends/tcp_server_spec.rb +33 -0
  56. data/spec/backends/unix_server_spec.rb +37 -0
  57. data/spec/command_spec.rb +25 -0
  58. data/spec/configs/cluster.yml +9 -0
  59. data/spec/configs/single.yml +9 -0
  60. data/spec/connection_spec.rb +106 -0
  61. data/spec/controllers/cluster_spec.rb +235 -0
  62. data/spec/controllers/controller_spec.rb +129 -0
  63. data/spec/controllers/service_spec.rb +50 -0
  64. data/spec/daemonizing_spec.rb +192 -0
  65. data/spec/headers_spec.rb +40 -0
  66. data/spec/logging_spec.rb +46 -0
  67. data/spec/perf/request_perf_spec.rb +50 -0
  68. data/spec/perf/response_perf_spec.rb +19 -0
  69. data/spec/perf/server_perf_spec.rb +39 -0
  70. data/spec/rack/loader_spec.rb +29 -0
  71. data/spec/rack/rails_adapter_spec.rb +106 -0
  72. data/spec/rails_app/app/controllers/application.rb +10 -0
  73. data/spec/rails_app/app/controllers/simple_controller.rb +19 -0
  74. data/spec/rails_app/app/helpers/application_helper.rb +3 -0
  75. data/spec/rails_app/app/views/simple/index.html.erb +15 -0
  76. data/spec/rails_app/config/boot.rb +109 -0
  77. data/spec/rails_app/config/environment.rb +64 -0
  78. data/spec/rails_app/config/environments/development.rb +18 -0
  79. data/spec/rails_app/config/environments/production.rb +19 -0
  80. data/spec/rails_app/config/environments/test.rb +22 -0
  81. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  82. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  83. data/spec/rails_app/config/routes.rb +35 -0
  84. data/spec/rails_app/public/404.html +30 -0
  85. data/spec/rails_app/public/422.html +30 -0
  86. data/spec/rails_app/public/500.html +30 -0
  87. data/spec/rails_app/public/dispatch.cgi +10 -0
  88. data/spec/rails_app/public/dispatch.fcgi +24 -0
  89. data/spec/rails_app/public/dispatch.rb +10 -0
  90. data/spec/rails_app/public/favicon.ico +0 -0
  91. data/spec/rails_app/public/images/rails.png +0 -0
  92. data/spec/rails_app/public/index.html +277 -0
  93. data/spec/rails_app/public/javascripts/application.js +2 -0
  94. data/spec/rails_app/public/javascripts/controls.js +963 -0
  95. data/spec/rails_app/public/javascripts/dragdrop.js +972 -0
  96. data/spec/rails_app/public/javascripts/effects.js +1120 -0
  97. data/spec/rails_app/public/javascripts/prototype.js +4225 -0
  98. data/spec/rails_app/public/robots.txt +5 -0
  99. data/spec/rails_app/script/about +3 -0
  100. data/spec/rails_app/script/console +3 -0
  101. data/spec/rails_app/script/destroy +3 -0
  102. data/spec/rails_app/script/generate +3 -0
  103. data/spec/rails_app/script/performance/benchmarker +3 -0
  104. data/spec/rails_app/script/performance/profiler +3 -0
  105. data/spec/rails_app/script/performance/request +3 -0
  106. data/spec/rails_app/script/plugin +3 -0
  107. data/spec/rails_app/script/process/inspector +3 -0
  108. data/spec/rails_app/script/process/reaper +3 -0
  109. data/spec/rails_app/script/process/spawner +3 -0
  110. data/spec/rails_app/script/runner +3 -0
  111. data/spec/rails_app/script/server +3 -0
  112. data/spec/request/mongrel_spec.rb +39 -0
  113. data/spec/request/parser_spec.rb +215 -0
  114. data/spec/request/persistent_spec.rb +35 -0
  115. data/spec/request/processing_spec.rb +45 -0
  116. data/spec/response_spec.rb +91 -0
  117. data/spec/runner_spec.rb +168 -0
  118. data/spec/server/builder_spec.rb +44 -0
  119. data/spec/server/pipelining_spec.rb +110 -0
  120. data/spec/server/robustness_spec.rb +34 -0
  121. data/spec/server/stopping_spec.rb +55 -0
  122. data/spec/server/swiftiply.yml +6 -0
  123. data/spec/server/swiftiply_spec.rb +32 -0
  124. data/spec/server/tcp_spec.rb +57 -0
  125. data/spec/server/threaded_spec.rb +27 -0
  126. data/spec/server/unix_socket_spec.rb +26 -0
  127. data/spec/server_spec.rb +96 -0
  128. data/spec/spec_helper.rb +219 -0
  129. data/tasks/announce.rake +22 -0
  130. data/tasks/deploy.rake +13 -0
  131. data/tasks/email.erb +30 -0
  132. data/tasks/gem.rake +74 -0
  133. data/tasks/rdoc.rake +25 -0
  134. data/tasks/site.rake +15 -0
  135. data/tasks/spec.rake +49 -0
  136. data/tasks/stats.rake +28 -0
  137. metadata +246 -0
@@ -0,0 +1,52 @@
1
+ require 'erb'
2
+
3
+ module Thin
4
+ module Stats
5
+ # Rack adapter to log stats about a Rack application.
6
+ class Adapter
7
+ include ERB::Util
8
+
9
+ def initialize(app, path='/stats')
10
+ @app = app
11
+ @path = path
12
+
13
+ @template = ERB.new(File.read(File.dirname(__FILE__) + '/stats.html.erb'))
14
+
15
+ @requests = 0
16
+ @requests_finished = 0
17
+ @start_time = Time.now
18
+ end
19
+
20
+ def call(env)
21
+ if env['PATH_INFO'].index(@path) == 0
22
+ serve(env)
23
+ else
24
+ log(env) { @app.call(env) }
25
+ end
26
+ end
27
+
28
+ def log(env)
29
+ @requests += 1
30
+ @last_request = Rack::Request.new(env)
31
+ request_started_at = Time.now
32
+
33
+ response = yield
34
+
35
+ @requests_finished += 1
36
+ @last_request_time = Time.now - request_started_at
37
+
38
+ response
39
+ end
40
+
41
+ def serve(env)
42
+ body = @template.result(binding)
43
+
44
+ [
45
+ 200,
46
+ { 'Content-Type' => 'text/html' },
47
+ [body]
48
+ ]
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ module Thin
2
+ # Every standard HTTP code mapped to the appropriate message.
3
+ # Stolent from Mongrel.
4
+ HTTP_STATUS_CODES = {
5
+ 100 => 'Continue',
6
+ 101 => 'Switching Protocols',
7
+ 200 => 'OK',
8
+ 201 => 'Created',
9
+ 202 => 'Accepted',
10
+ 203 => 'Non-Authoritative Information',
11
+ 204 => 'No Content',
12
+ 205 => 'Reset Content',
13
+ 206 => 'Partial Content',
14
+ 300 => 'Multiple Choices',
15
+ 301 => 'Moved Permanently',
16
+ 302 => 'Moved Temporarily',
17
+ 303 => 'See Other',
18
+ 304 => 'Not Modified',
19
+ 305 => 'Use Proxy',
20
+ 400 => 'Bad Request',
21
+ 401 => 'Unauthorized',
22
+ 402 => 'Payment Required',
23
+ 403 => 'Forbidden',
24
+ 404 => 'Not Found',
25
+ 405 => 'Method Not Allowed',
26
+ 406 => 'Not Acceptable',
27
+ 407 => 'Proxy Authentication Required',
28
+ 408 => 'Request Time-out',
29
+ 409 => 'Conflict',
30
+ 410 => 'Gone',
31
+ 411 => 'Length Required',
32
+ 412 => 'Precondition Failed',
33
+ 413 => 'Request Entity Too Large',
34
+ 414 => 'Request-URI Too Large',
35
+ 415 => 'Unsupported Media Type',
36
+ 500 => 'Internal Server Error',
37
+ 501 => 'Not Implemented',
38
+ 502 => 'Bad Gateway',
39
+ 503 => 'Service Unavailable',
40
+ 504 => 'Gateway Time-out',
41
+ 505 => 'HTTP Version not supported'
42
+ }
43
+ end
@@ -0,0 +1,32 @@
1
+ module Thin
2
+ # Raised when a feature is not supported on the
3
+ # current platform.
4
+ class PlatformNotSupported < RuntimeError; end
5
+
6
+ module VERSION #:nodoc:
7
+ MAJOR = 1
8
+ MINOR = 2
9
+ TINY = 3
10
+
11
+ STRING = [MAJOR, MINOR, TINY].join('.')
12
+
13
+ CODENAME = "Flaming Astroboy".freeze
14
+
15
+ RACK = [1, 0].freeze # Rack protocol version
16
+ end
17
+
18
+ NAME = 'thin'.freeze
19
+ SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
20
+
21
+ def self.win?
22
+ RUBY_PLATFORM =~ /mswin|mingw/
23
+ end
24
+
25
+ def self.linux?
26
+ RUBY_PLATFORM =~ /linux/
27
+ end
28
+
29
+ def self.ruby_18?
30
+ RUBY_VERSION =~ /^1\.8/
31
+ end
32
+ end
Binary file
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Backends::SwiftiplyClient do
4
+ before do
5
+ @backend = Backends::SwiftiplyClient.new('0.0.0.0', 3333)
6
+ @backend.server = mock('server', :null_object => true)
7
+ end
8
+
9
+ it "should connect" do
10
+ EventMachine.run do
11
+ @backend.connect
12
+ EventMachine.stop
13
+ end
14
+ end
15
+
16
+ it "should disconnect" do
17
+ EventMachine.run do
18
+ @backend.connect
19
+ @backend.disconnect
20
+ EventMachine.stop
21
+ end
22
+ end
23
+ end
24
+
25
+ describe SwiftiplyConnection do
26
+ before do
27
+ @connection = SwiftiplyConnection.new(nil)
28
+ @connection.backend = Backends::SwiftiplyClient.new('0.0.0.0', 3333)
29
+ @connection.backend.server = mock('server', :null_object => true)
30
+ end
31
+
32
+ it do
33
+ @connection.should be_persistent
34
+ end
35
+
36
+ it "should send handshake on connection_completed" do
37
+ @connection.should_receive(:send_data).with('swiftclient000000000d0500')
38
+ @connection.connection_completed
39
+ end
40
+
41
+ it "should reconnect on unbind" do
42
+ @connection.backend.stub!(:running?).and_return(true)
43
+ @connection.stub!(:rand).and_return(0) # Make sure we don't wait
44
+
45
+ @connection.should_receive(:reconnect).with('0.0.0.0', 3333)
46
+
47
+ EventMachine.run do
48
+ @connection.unbind
49
+ EventMachine.add_timer(0) { EventMachine.stop }
50
+ end
51
+ end
52
+
53
+ it "should not reconnect when not running" do
54
+ @connection.backend.stub!(:running?).and_return(false)
55
+ EventMachine.should_not_receive(:add_timer)
56
+ @connection.unbind
57
+ end
58
+
59
+ it "should have a host_ip" do
60
+ @connection.send(:host_ip).should == [0, 0, 0, 0]
61
+ end
62
+
63
+ it "should generate swiftiply_handshake based on key" do
64
+ @connection.send(:swiftiply_handshake, 'key').should == 'swiftclient000000000d0503key'
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Backends::TcpServer do
4
+ before do
5
+ @backend = Backends::TcpServer.new('0.0.0.0', 3333)
6
+ end
7
+
8
+ it "should not use epoll" do
9
+ @backend.no_epoll = true
10
+ EventMachine.should_not_receive(:epoll)
11
+ @backend.config
12
+ end
13
+
14
+ it "should use epoll" do
15
+ EventMachine.should_receive(:epoll)
16
+ @backend.config
17
+ end
18
+
19
+ it "should connect" do
20
+ EventMachine.run do
21
+ @backend.connect
22
+ EventMachine.stop
23
+ end
24
+ end
25
+
26
+ it "should disconnect" do
27
+ EventMachine.run do
28
+ @backend.connect
29
+ @backend.disconnect
30
+ EventMachine.stop
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Backends::UnixServer do
4
+ before do
5
+ @backend = Backends::UnixServer.new('/tmp/thin-test.sock')
6
+ end
7
+
8
+ it "should connect" do
9
+ EventMachine.run do
10
+ @backend.connect
11
+ EventMachine.stop
12
+ end
13
+ end
14
+
15
+ it "should disconnect" do
16
+ EventMachine.run do
17
+ @backend.connect
18
+ @backend.disconnect
19
+ EventMachine.stop
20
+ end
21
+ end
22
+
23
+ it "should remove socket file on close" do
24
+ @backend.close
25
+ File.exist?('/tmp/thin-test.sock').should be_false
26
+ end
27
+ end
28
+
29
+ describe UnixConnection do
30
+ before do
31
+ @connection = UnixConnection.new(nil)
32
+ end
33
+
34
+ it "should return 127.0.0.1 as remote_address" do
35
+ @connection.remote_address.should == '127.0.0.1'
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Command do
4
+ before do
5
+ Command.script = 'thin'
6
+ @command = Command.new(:start, :port => 3000, :daemonize => true, :log => 'hi.log',
7
+ :require => %w(rubygems thin), :no_epoll => true)
8
+ end
9
+
10
+ it 'should shellify command' do
11
+ out = @command.shellify
12
+ out.should include('--port=3000', '--daemonize', '--log="hi.log"', 'thin start --')
13
+ out.should_not include('--pid')
14
+ end
15
+
16
+ it 'should shellify Array argument to multiple parameters' do
17
+ out = @command.shellify
18
+ out.should include('--require="rubygems"', '--require="thin"')
19
+ end
20
+
21
+ it 'should convert _ to - in option name' do
22
+ out = @command.shellify
23
+ out.should include('--no-epoll')
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ ---
2
+ pid: tmp/pids/thin.pid
3
+ log: log/thin.log
4
+ timeout: 60
5
+ port: 5000
6
+ chdir: spec/rails_app
7
+ environment: production
8
+ servers: 3
9
+ address: 127.0.0.1
@@ -0,0 +1,9 @@
1
+ ---
2
+ pid: tmp/pids/thin.pid
3
+ log: log/thin.log
4
+ timeout: 60
5
+ port: 6000
6
+ chdir: spec/rails_app
7
+ environment: production
8
+ daemonize: true
9
+ address: 127.0.0.1
@@ -0,0 +1,106 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Connection do
4
+ before do
5
+ @connection = Connection.new(mock('EM', :null_object => true))
6
+ @connection.post_init
7
+ @connection.app = proc do |env|
8
+ [200, {}, ['']]
9
+ end
10
+ end
11
+
12
+ it "should parse on receive_data" do
13
+ @connection.request.should_receive(:parse).with('GET')
14
+ @connection.receive_data('GET')
15
+ end
16
+
17
+ it "should close connection on InvalidRequest error in receive_data" do
18
+ @connection.request.stub!(:parse).and_raise(InvalidRequest)
19
+ @connection.should_receive(:close_connection)
20
+ @connection.receive_data('')
21
+ end
22
+
23
+ it "should process when parsing complete" do
24
+ @connection.request.should_receive(:parse).and_return(true)
25
+ @connection.should_receive(:process)
26
+ @connection.receive_data('GET')
27
+ end
28
+
29
+ it "should process" do
30
+ @connection.process
31
+ end
32
+
33
+ it "should rescue error in process" do
34
+ @connection.app.should_receive(:call).and_raise(StandardError)
35
+ @connection.process
36
+ end
37
+
38
+ it "should rescue Timeout error in process" do
39
+ @connection.app.should_receive(:call).and_raise(Timeout::Error.new("timeout error not rescued"))
40
+ @connection.process
41
+ end
42
+
43
+ it "should not return HTTP_X_FORWARDED_FOR as remote_address" do
44
+ @connection.request.env['HTTP_X_FORWARDED_FOR'] = '1.2.3.4'
45
+ @connection.stub!(:socket_address).and_return("127.0.0.1")
46
+ @connection.remote_address.should == "127.0.0.1"
47
+ end
48
+
49
+ it "should return nil on error retreiving remote_address" do
50
+ @connection.stub!(:get_peername).and_raise(RuntimeError)
51
+ @connection.remote_address.should be_nil
52
+ end
53
+
54
+ it "should return nil on nil get_peername" do
55
+ @connection.stub!(:get_peername).and_return(nil)
56
+ @connection.remote_address.should be_nil
57
+ end
58
+
59
+ it "should return nil on empty get_peername" do
60
+ @connection.stub!(:get_peername).and_return('')
61
+ @connection.remote_address.should be_nil
62
+ end
63
+
64
+ it "should return remote_address" do
65
+ @connection.stub!(:get_peername).and_return(Socket.pack_sockaddr_in(3000, '127.0.0.1'))
66
+ @connection.remote_address.should == '127.0.0.1'
67
+ end
68
+
69
+ it "should not be persistent" do
70
+ @connection.should_not be_persistent
71
+ end
72
+
73
+ it "should be persistent when response is and allowed" do
74
+ @connection.response.stub!(:persistent?).and_return(true)
75
+ @connection.can_persist!
76
+ @connection.should be_persistent
77
+ end
78
+
79
+ it "should not be persistent when response is but not allowed" do
80
+ @connection.response.persistent!
81
+ @connection.should_not be_persistent
82
+ end
83
+
84
+ it "should set request env as rack.multithread" do
85
+ EventMachine.should_receive(:defer)
86
+
87
+ @connection.threaded = true
88
+ @connection.process
89
+
90
+ @connection.request.env["rack.multithread"].should == true
91
+ end
92
+
93
+ it "should set as threaded when app.deferred? is true" do
94
+ @connection.app.should_receive(:deferred?).and_return(true)
95
+ @connection.should be_threaded
96
+ end
97
+
98
+ it "should not set as threaded when app.deferred? is false" do
99
+ @connection.app.should_receive(:deferred?).and_return(false)
100
+ @connection.should_not be_threaded
101
+ end
102
+
103
+ it "should not set as threaded when app do not respond to deferred?" do
104
+ @connection.should_not be_threaded
105
+ end
106
+ end
@@ -0,0 +1,235 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ include Controllers
3
+
4
+ describe Cluster, "with host and port" do
5
+ before do
6
+ @cluster = Cluster.new(:chdir => '/rails_app',
7
+ :address => '0.0.0.0',
8
+ :port => 3000,
9
+ :servers => 3,
10
+ :timeout => 10,
11
+ :log => 'thin.log',
12
+ :pid => 'thin.pid'
13
+ )
14
+ end
15
+
16
+ it 'should include port number in file names' do
17
+ @cluster.send(:include_server_number, 'thin.log', 3000).should == 'thin.3000.log'
18
+ @cluster.send(:include_server_number, 'thin.pid', 3000).should == 'thin.3000.pid'
19
+ end
20
+
21
+ it 'should call each server' do
22
+ calls = []
23
+ @cluster.send(:with_each_server) do |port|
24
+ calls << port
25
+ end
26
+ calls.should == [3000, 3001, 3002]
27
+ end
28
+
29
+ it 'should start on each port' do
30
+ Command.should_receive(:run).with(:start, options_for_port(3000))
31
+ Command.should_receive(:run).with(:start, options_for_port(3001))
32
+ Command.should_receive(:run).with(:start, options_for_port(3002))
33
+
34
+ @cluster.start
35
+ end
36
+
37
+ it 'should stop on each port' do
38
+ Command.should_receive(:run).with(:stop, options_for_port(3000))
39
+ Command.should_receive(:run).with(:stop, options_for_port(3001))
40
+ Command.should_receive(:run).with(:stop, options_for_port(3002))
41
+
42
+ @cluster.stop
43
+ end
44
+
45
+ private
46
+ def options_for_port(port)
47
+ { :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "/rails_app" }
48
+ end
49
+ end
50
+
51
+ describe Cluster, "with UNIX socket" do
52
+ before do
53
+ @cluster = Cluster.new(:chdir => '/rails_app',
54
+ :socket => '/tmp/thin.sock',
55
+ :address => '0.0.0.0',
56
+ :port => 3000,
57
+ :servers => 3,
58
+ :timeout => 10,
59
+ :log => 'thin.log',
60
+ :pid => 'thin.pid'
61
+ )
62
+ end
63
+
64
+ it 'should include socket number in file names' do
65
+ @cluster.send(:include_server_number, 'thin.sock', 0).should == 'thin.0.sock'
66
+ @cluster.send(:include_server_number, 'thin', 0).should == 'thin.0'
67
+ end
68
+
69
+ it "should exclude :address and :port options" do
70
+ @cluster.options.should_not have_key(:address)
71
+ @cluster.options.should_not have_key(:port)
72
+ end
73
+
74
+ it 'should call each server' do
75
+ calls = []
76
+ @cluster.send(:with_each_server) do |n|
77
+ calls << n
78
+ end
79
+ calls.should == [0, 1, 2]
80
+ end
81
+
82
+ it 'should start each server' do
83
+ Command.should_receive(:run).with(:start, options_for_socket(0))
84
+ Command.should_receive(:run).with(:start, options_for_socket(1))
85
+ Command.should_receive(:run).with(:start, options_for_socket(2))
86
+
87
+ @cluster.start
88
+ end
89
+
90
+ it 'should stop each server' do
91
+ Command.should_receive(:run).with(:stop, options_for_socket(0))
92
+ Command.should_receive(:run).with(:stop, options_for_socket(1))
93
+ Command.should_receive(:run).with(:stop, options_for_socket(2))
94
+
95
+ @cluster.stop
96
+ end
97
+
98
+
99
+ private
100
+ def options_for_socket(number)
101
+ { :daemonize => true, :log => "thin.#{number}.log", :timeout => 10, :socket => "/tmp/thin.#{number}.sock", :pid => "thin.#{number}.pid", :chdir => "/rails_app" }
102
+ end
103
+ end
104
+
105
+ describe Cluster, "controlling only one server" do
106
+ before do
107
+ @cluster = Cluster.new(:chdir => '/rails_app',
108
+ :address => '0.0.0.0',
109
+ :port => 3000,
110
+ :servers => 3,
111
+ :timeout => 10,
112
+ :log => 'thin.log',
113
+ :pid => 'thin.pid',
114
+ :only => 3001
115
+ )
116
+ end
117
+
118
+ it 'should call only specified server' do
119
+ calls = []
120
+ @cluster.send(:with_each_server) do |n|
121
+ calls << n
122
+ end
123
+ calls.should == [3001]
124
+ end
125
+
126
+ it "should start only specified server" do
127
+ Command.should_receive(:run).with(:start, options_for_port(3001))
128
+
129
+ @cluster.start
130
+ end
131
+
132
+ private
133
+ def options_for_port(port)
134
+ { :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "/rails_app" }
135
+ end
136
+ end
137
+
138
+ describe Cluster, "controlling only one server with UNIX socket" do
139
+ before do
140
+ @cluster = Cluster.new(:chdir => '/rails_app',
141
+ :socket => '/tmp/thin.sock',
142
+ :address => '0.0.0.0',
143
+ :port => 3000,
144
+ :servers => 3,
145
+ :timeout => 10,
146
+ :log => 'thin.log',
147
+ :pid => 'thin.pid',
148
+ :only => 1
149
+ )
150
+ end
151
+
152
+ it 'should call only specified server' do
153
+ calls = []
154
+ @cluster.send(:with_each_server) do |n|
155
+ calls << n
156
+ end
157
+ calls.should == [1]
158
+ end
159
+ end
160
+
161
+ describe Cluster, "controlling only one server, by sequence number" do
162
+ before do
163
+ @cluster = Cluster.new(:chdir => '/rails_app',
164
+ :address => '0.0.0.0',
165
+ :port => 3000,
166
+ :servers => 3,
167
+ :timeout => 10,
168
+ :log => 'thin.log',
169
+ :pid => 'thin.pid',
170
+ :only => 1
171
+ )
172
+ end
173
+
174
+ it 'should call only specified server' do
175
+ calls = []
176
+ @cluster.send(:with_each_server) do |n|
177
+ calls << n
178
+ end
179
+ calls.should == [3001]
180
+ end
181
+
182
+ it "should start only specified server" do
183
+ Command.should_receive(:run).with(:start, options_for_port(3001))
184
+
185
+ @cluster.start
186
+ end
187
+
188
+ private
189
+ def options_for_port(port)
190
+ { :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "/rails_app" }
191
+ end
192
+ end
193
+
194
+ describe Cluster, "with Swiftiply" do
195
+ before do
196
+ @cluster = Cluster.new(:chdir => '/rails_app',
197
+ :address => '0.0.0.0',
198
+ :port => 3000,
199
+ :servers => 3,
200
+ :timeout => 10,
201
+ :log => 'thin.log',
202
+ :pid => 'thin.pid',
203
+ :swiftiply => true
204
+ )
205
+ end
206
+
207
+ it 'should call each server' do
208
+ calls = []
209
+ @cluster.send(:with_each_server) do |n|
210
+ calls << n
211
+ end
212
+ calls.should == [0, 1, 2]
213
+ end
214
+
215
+ it 'should start each server' do
216
+ Command.should_receive(:run).with(:start, options_for_swiftiply(0))
217
+ Command.should_receive(:run).with(:start, options_for_swiftiply(1))
218
+ Command.should_receive(:run).with(:start, options_for_swiftiply(2))
219
+
220
+ @cluster.start
221
+ end
222
+
223
+ it 'should stop each server' do
224
+ Command.should_receive(:run).with(:stop, options_for_swiftiply(0))
225
+ Command.should_receive(:run).with(:stop, options_for_swiftiply(1))
226
+ Command.should_receive(:run).with(:stop, options_for_swiftiply(2))
227
+
228
+ @cluster.stop
229
+ end
230
+
231
+ private
232
+ def options_for_swiftiply(number)
233
+ { :address => '0.0.0.0', :port => 3000, :daemonize => true, :log => "thin.#{number}.log", :timeout => 10, :pid => "thin.#{number}.pid", :chdir => "/rails_app", :swiftiply => true }
234
+ end
235
+ end