einhorn 0.8.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +10 -0
  3. data/{LICENSE → LICENSE.txt} +0 -0
  4. data/README.md +5 -36
  5. data/einhorn.gemspec +23 -21
  6. data/example/pool_worker.rb +2 -2
  7. data/example/thin_example +8 -8
  8. data/example/time_server +5 -5
  9. data/lib/einhorn/client.rb +8 -8
  10. data/lib/einhorn/command/interface.rb +92 -98
  11. data/lib/einhorn/command.rb +76 -85
  12. data/lib/einhorn/compat.rb +7 -7
  13. data/lib/einhorn/event/abstract_text_descriptor.rb +31 -35
  14. data/lib/einhorn/event/ack_timer.rb +2 -2
  15. data/lib/einhorn/event/command_server.rb +7 -9
  16. data/lib/einhorn/event/connection.rb +1 -3
  17. data/lib/einhorn/event/loop_breaker.rb +2 -1
  18. data/lib/einhorn/event/persistent.rb +2 -2
  19. data/lib/einhorn/event/timer.rb +4 -4
  20. data/lib/einhorn/event.rb +19 -19
  21. data/lib/einhorn/prctl.rb +2 -2
  22. data/lib/einhorn/prctl_linux.rb +13 -14
  23. data/lib/einhorn/safe_yaml.rb +17 -0
  24. data/lib/einhorn/version.rb +1 -1
  25. data/lib/einhorn/worker.rb +26 -30
  26. data/lib/einhorn/worker_pool.rb +9 -9
  27. data/lib/einhorn.rb +120 -125
  28. metadata +33 -117
  29. data/.gitignore +0 -17
  30. data/.travis.yml +0 -10
  31. data/CONTRIBUTORS +0 -6
  32. data/Gemfile +0 -11
  33. data/History.txt +0 -4
  34. data/README.md.in +0 -94
  35. data/Rakefile +0 -27
  36. data/test/_lib.rb +0 -12
  37. data/test/integration/_lib/fixtures/env_printer/env_printer.rb +0 -26
  38. data/test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb +0 -23
  39. data/test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb +0 -6
  40. data/test/integration/_lib/fixtures/pdeathsig_printer/pdeathsig_printer.rb +0 -29
  41. data/test/integration/_lib/fixtures/signal_timeout/sleepy_server.rb +0 -23
  42. data/test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb +0 -24
  43. data/test/integration/_lib/helpers/einhorn_helpers.rb +0 -148
  44. data/test/integration/_lib/helpers.rb +0 -4
  45. data/test/integration/_lib.rb +0 -6
  46. data/test/integration/pdeathsig.rb +0 -26
  47. data/test/integration/startup.rb +0 -31
  48. data/test/integration/upgrading.rb +0 -204
  49. data/test/unit/_lib/bad_worker.rb +0 -7
  50. data/test/unit/_lib/sleep_worker.rb +0 -5
  51. data/test/unit/einhorn/client.rb +0 -88
  52. data/test/unit/einhorn/command/interface.rb +0 -49
  53. data/test/unit/einhorn/command.rb +0 -135
  54. data/test/unit/einhorn/event.rb +0 -89
  55. data/test/unit/einhorn/worker_pool.rb +0 -39
  56. data/test/unit/einhorn.rb +0 -96
@@ -1,204 +0,0 @@
1
- require(File.expand_path('_lib', File.dirname(__FILE__)))
2
- require 'socket'
3
- require 'einhorn/client'
4
-
5
- class UpgradeTests < EinhornIntegrationTestCase
6
- include Helpers::EinhornHelpers
7
-
8
- describe 'when upgrading a running einhorn without preloading' do
9
- before do
10
- @dir = prepare_fixture_directory('upgrade_project')
11
- @port = find_free_port
12
- @server_program = File.join(@dir, "upgrading_server.rb")
13
- @socket_path = File.join(@dir, "einhorn.sock")
14
- end
15
- after { cleanup_fixtured_directories }
16
-
17
- it 'can restart' do
18
- File.open(File.join(@dir, "version"), 'w') { |f| f.write("0") }
19
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} -d #{@socket_path} -- ruby #{@server_program}}) do |process|
20
- wait_for_open_port
21
- assert_equal("0", read_from_port, "Should report the initial version")
22
-
23
- File.open(File.join(@dir, "version"), 'w') { |f| f.write("1") }
24
- einhornsh(%W{-d #{@socket_path} -e upgrade})
25
- assert_equal("1", read_from_port, "Should report the upgraded version")
26
-
27
- process.terminate
28
- end
29
- end
30
- end
31
-
32
- describe 'handling environments on upgrade' do
33
- before do
34
- @dir = prepare_fixture_directory('env_printer')
35
- @port = find_free_port
36
- @server_program = File.join(@dir, "env_printer.rb")
37
- @socket_path = File.join(@dir, "einhorn.sock")
38
- end
39
- after { cleanup_fixtured_directories }
40
-
41
- describe 'when running with --reexec-as' do
42
- it 'preserves environment variables across restarts' do
43
- # exec the new einhorn with the same environment:
44
- reexec_cmdline = 'env VAR=a bundle exec --keep-file-descriptors einhorn'
45
-
46
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --reexec-as=#{reexec_cmdline} -d #{@socket_path} -- ruby #{@server_program} VAR},
47
- :env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
48
-
49
- wait_for_open_port
50
- einhornsh(%W{-d #{@socket_path} -e upgrade})
51
- assert_equal("a", read_from_port, "Should report the upgraded version")
52
-
53
- process.terminate
54
- end
55
- end
56
-
57
- it 'cleans up if a child dies during the reexec' do
58
- # attempt to setup a scenario where a child exits in the
59
- # interlude after old einhorn has execed the reexec-as
60
- # command, but before the reexec-as command execs new einhorn
61
-
62
- @dir = prepare_fixture_directory('exit_during_upgrade')
63
- @server_program = File.join(@dir, "exiting_server.rb")
64
- @socket_path = File.join(@dir, "einhorn.sock")
65
-
66
- reexec_cmdline = File.join(@dir, 'upgrade_reexec.rb')
67
-
68
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --reexec-as=#{reexec_cmdline} -d #{@socket_path} -- ruby #{@server_program}}) do |process|
69
- wait_for_open_port
70
-
71
- Process.kill('USR2', read_from_port.to_i)
72
- einhornsh(%W{-d #{@socket_path} -e upgrade})
73
-
74
- client = Einhorn::Client.for_path(@socket_path)
75
- client.send_command('command' => 'state')
76
- resp = client.receive_message
77
-
78
- state = YAML.load(resp['message'])
79
- assert_equal(1, state[:state][:children].count)
80
-
81
- child = state[:state][:children].first.last
82
- assert_in_delta(child[:pinged_at], Time.now, 60)
83
- assert_equal("id-1", child[:pinged_request_id])
84
-
85
- process.terminate
86
- end
87
- end
88
-
89
- describe 'without preloading' do
90
- it 'can update environment variables when the reexec command line says to' do
91
- # exec the new einhorn with the same environment:
92
- reexec_cmdline = 'env VAR=b OINK=b bundle exec --keep-file-descriptors einhorn'
93
-
94
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --reexec-as=#{reexec_cmdline} -d #{@socket_path} -- ruby #{@server_program} VAR},
95
- :env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
96
-
97
- wait_for_open_port
98
- einhornsh(%W{-d #{@socket_path} -e upgrade})
99
- assert_equal("b", read_from_port, "Should report the upgraded version")
100
-
101
- process.terminate
102
- end
103
- end
104
- end
105
-
106
- describe 'with preloading' do
107
- it 'can update environment variables on preloaded code when the reexec command line says to' do
108
- # exec the new einhorn with the same environment:
109
- reexec_cmdline = 'env VAR=b OINK=b bundle exec --keep-file-descriptors einhorn'
110
-
111
- with_running_einhorn(%W{einhorn -m manual -p #{@server_program} -b 127.0.0.1:#{@port} --reexec-as=#{reexec_cmdline} -d #{@socket_path} -- ruby #{@server_program} VAR},
112
- :env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
113
-
114
- wait_for_open_port
115
- einhornsh(%W{-d #{@socket_path} -e upgrade})
116
- assert_equal("b", read_from_port, "Should report the upgraded version")
117
-
118
- process.terminate
119
- end
120
- end
121
- end
122
- end
123
- end
124
-
125
- describe 'when invoked with --drop-env-var' do
126
- before do
127
- @dir = prepare_fixture_directory('env_printer')
128
- @port = find_free_port
129
- @server_program = File.join(@dir, "env_printer.rb")
130
- @socket_path = File.join(@dir, "einhorn.sock")
131
- end
132
- after { cleanup_fixtured_directories }
133
-
134
- it %{removes the variable from its children's environment} do
135
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --drop-env-var=VAR -d #{@socket_path} -- ruby #{@server_program} VAR},
136
- :env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
137
- wait_for_open_port
138
- assert_equal("a", read_from_port, "Should report $VAR initially")
139
-
140
- einhornsh(%W{-d #{@socket_path} -e upgrade})
141
- assert_equal("", read_from_port, "Should have dropped the variable post-upgrade")
142
-
143
- process.terminate
144
- end
145
- end
146
-
147
- it %{causes an upgrade with --reexec-as to not clobber the new environment} do
148
- reexec_cmdline = 'env VAR2=b bundle exec --keep-file-descriptors einhorn'
149
- with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --drop-env-var=VAR1 --drop-env-var=VAR2 -d #{@socket_path} --reexec-as=#{reexec_cmdline} -- ruby #{@server_program} VAR1 VAR2},
150
- :env => ENV.to_hash.merge({'VAR1' => 'a', 'VAR2' => 'a'})) do |process|
151
- wait_for_open_port
152
- assert_equal("aa", read_from_port, "Should report both $VAR1 and $VAR2 initially")
153
-
154
- einhornsh(%W{-d #{@socket_path} -e upgrade})
155
- assert_equal("b", read_from_port, "Should have dropped $VAR1 post-upgrade and re-set $VAR2")
156
-
157
- process.terminate
158
- end
159
- end
160
- end
161
-
162
- describe "with --signal-timeout" do
163
- before do
164
- @dir = prepare_fixture_directory('signal_timeout')
165
- @port = find_free_port
166
- @server_program = File.join(@dir, "sleepy_server.rb")
167
- @socket_path = File.join(@dir, "einhorn.sock")
168
- end
169
-
170
- after { cleanup_fixtured_directories }
171
-
172
- it 'issues a SIGKILL to outdated children when signal-timeout has passed' do
173
- signal_timeout = 2
174
- sleep_for = 10
175
- cmd = %W{
176
- einhorn
177
- -b 127.0.0.1:#{@port}
178
- -d #{@socket_path}
179
- --signal-timeout #{signal_timeout}
180
- -- ruby #{@server_program}
181
- }
182
-
183
- with_running_einhorn(cmd, env: ENV.to_h.merge({'TRAP_SLEEP' => sleep_for.to_s})) do |process|
184
- wait_for_open_port
185
- client = Einhorn::Client.for_path(@socket_path)
186
- einhornsh(%W{-d #{@socket_path} -e upgrade})
187
-
188
- state = get_state(client)
189
- assert_equal(2, state[:children].count)
190
- signaled_children = state[:children].select{|_,c| c[:signaled].length > 0}
191
- assert_equal(1, signaled_children.length)
192
-
193
- sleep(signal_timeout * 2)
194
-
195
- state = get_state(client)
196
- assert_equal(1, state[:children].count)
197
- signaled_children = state[:children].select{|_,c| c[:signaled].length > 0}
198
- assert_equal(0, signaled_children.length)
199
-
200
- process.terminate
201
- end
202
- end
203
- end
204
- end
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- raise 'This worker has an error during preload'
4
-
5
- def einhorn_main
6
-
7
- end
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- def einhorn_main
4
- sleep 1
5
- end
@@ -1,88 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../_lib'))
2
-
3
- require 'einhorn'
4
-
5
- class ClientTest < EinhornTestCase
6
- def unserialized_message
7
- {:foo => ['%bar', '%baz']}
8
- end
9
-
10
- def serialized_1_8
11
- "--- %0A:foo: %0A- \"%25bar\"%0A- \"%25baz\"%0A\n"
12
- end
13
-
14
- def serialized_1_9
15
- "---%0A:foo:%0A- ! '%25bar'%0A- ! '%25baz'%0A\n"
16
- end
17
-
18
- def serialized_2_0
19
- "---%0A:foo:%0A- '%25bar'%0A- '%25baz'%0A\n"
20
- end
21
-
22
- def serialized_2_1
23
- "---%0A:foo:%0A- \"%25bar\"%0A- \"%25baz\"%0A\n"
24
- end
25
-
26
- def serialized_options
27
- [serialized_1_8, serialized_1_9, serialized_2_0, serialized_2_1]
28
- end
29
-
30
- describe "when sending a message" do
31
- it "writes a serialized line" do
32
- socket = mock
33
- socket.expects(:write).with {|write| serialized_options.include?(write)}
34
- Einhorn::Client::Transport.send_message(socket, unserialized_message)
35
- end
36
- end
37
-
38
- describe "when receiving a message" do
39
- it "deserializes a single 1.8-style line" do
40
- socket = mock
41
- socket.expects(:readline).returns(serialized_1_8)
42
- result = Einhorn::Client::Transport.receive_message(socket)
43
- assert_equal(result, unserialized_message)
44
- end
45
-
46
- it "deserializes a single 1.9-style line" do
47
- socket = mock
48
- socket.expects(:readline).returns(serialized_1_9)
49
- result = Einhorn::Client::Transport.receive_message(socket)
50
- assert_equal(result, unserialized_message)
51
- end
52
- end
53
-
54
- describe "when {de,}serializing a message" do
55
- it "serializes and escape a message as expected" do
56
- actual = Einhorn::Client::Transport.serialize_message(unserialized_message)
57
- assert(serialized_options.include?(actual), "Actual message is #{actual.inspect}")
58
- end
59
-
60
- it "deserializes and unescape a 1.8-style message as expected" do
61
- actual = Einhorn::Client::Transport.deserialize_message(serialized_1_8)
62
- assert_equal(unserialized_message, actual)
63
- end
64
-
65
- it "deserializes and unescape a 1.9-style message as expected" do
66
- actual = Einhorn::Client::Transport.deserialize_message(serialized_1_9)
67
- assert_equal(unserialized_message, actual)
68
- end
69
-
70
- it "deserializes and unescapes a 2.0-style message as expected" do
71
- actual = Einhorn::Client::Transport.deserialize_message(serialized_2_0)
72
- assert_equal(unserialized_message, actual)
73
- end
74
-
75
- it "deserializes and unescapes a 2.1-style message as expected" do
76
- actual = Einhorn::Client::Transport.deserialize_message(serialized_2_1)
77
- assert_equal(unserialized_message, actual)
78
- end
79
-
80
- it "raises an error when deserializing invalid YAML" do
81
- invalid_serialized = "-%0A\t-"
82
- begin
83
- Einhorn::Client::Transport.deserialize_message(invalid_serialized)
84
- rescue Einhorn::Client::Transport::ParseError
85
- end
86
- end
87
- end
88
- end
@@ -1,49 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../../_lib'))
2
-
3
- require 'einhorn'
4
-
5
- class InterfaceTest < EinhornTestCase
6
- include Einhorn::Command
7
-
8
- describe "when a command is received" do
9
- it "calls that command" do
10
- conn = stub(:log_debug => nil)
11
- conn.expects(:write).once.with do |message|
12
- # Remove trailing newline
13
- message = message[0...-1]
14
- parsed = YAML.load(URI.unescape(message))
15
- parsed['message'] =~ /Welcome, gdb/
16
- end
17
- request = {
18
- 'command' => 'ehlo',
19
- 'user' => 'gdb'
20
- }
21
- Interface.process_command(conn, YAML.dump(request))
22
- end
23
- end
24
-
25
- describe "when an unrecognized command is received" do
26
- it "calls the unrecognized_command method" do
27
- conn = stub(:log_debug => nil)
28
- Interface.expects(:unrecognized_command).once
29
- request = {
30
- 'command' => 'made-up',
31
- }
32
- Interface.process_command(conn, YAML.dump(request))
33
- end
34
- end
35
-
36
- describe "when a worker ack is received" do
37
- it "registers ack and close the connection" do
38
- conn = stub(:log_debug => nil)
39
- conn.expects(:close).once
40
- conn.expects(:write).never
41
- request = {
42
- 'command' => 'worker:ack',
43
- 'pid' => 1234
44
- }
45
- Einhorn::Command.expects(:register_manual_ack).once.with(1234)
46
- Interface.process_command(conn, YAML.dump(request))
47
- end
48
- end
49
- end
@@ -1,135 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../_lib'))
2
-
3
- require 'einhorn'
4
-
5
- class CommandTest < EinhornTestCase
6
- include Einhorn
7
-
8
- describe "when running quieter" do
9
- it "increases the verbosity threshold" do
10
- Einhorn::State.stubs(:verbosity => 1)
11
- Einhorn::State.expects(:verbosity=).once.with(2).returns(2)
12
- Command.quieter
13
- end
14
-
15
- it "maxes out at 2" do
16
- Einhorn::State.stubs(:verbosity => 2)
17
- Einhorn::State.expects(:verbosity=).never
18
- Command.quieter
19
- end
20
- end
21
-
22
- describe "resignal_timeout" do
23
- it "does not kill any children" do
24
- Einhorn::State.stubs(signal_timeout: 5 * 60)
25
- Einhorn::State.stubs(children: {
26
- 12345 => {last_signaled_at: nil},
27
- 12346 => {signaled: Set.new(["USR1"]), last_signaled_at: Time.now - (2 * 60)},
28
- })
29
-
30
- Process.expects(:kill).never
31
- Einhorn::Command.kill_expired_signaled_workers
32
-
33
- refute(Einhorn::State.children[12346][:signaled].include?("KILL"), "Process was KILLed when it shouldn't have been")
34
- end
35
-
36
- it "KILLs stuck child processes" do
37
- Time.stub :now, Time.at(0) do
38
- Process.stub(:kill, true) do
39
- Einhorn::State.stubs(signal_timeout: 60)
40
- Einhorn::State.stubs(children: {
41
- 12346 => {signaled: Set.new(["USR2"]), last_signaled_at: Time.now - (2 * 60)},
42
- })
43
-
44
- Einhorn::Command.kill_expired_signaled_workers
45
-
46
- child = Einhorn::State.children[12346]
47
- assert(child[:signaled].include?("KILL"), "Process was not KILLed as expected")
48
- assert(child[:last_signaled_at] == Time.now, "The last_processed_at was not updated as expected")
49
- end
50
- end
51
- end
52
- end
53
-
54
- describe "trigger_spinup?" do
55
- it "is true by default" do
56
- assert(Einhorn::Command.trigger_spinup?(1))
57
- end
58
-
59
- it "is false if unacked >= max_unacked" do
60
- Einhorn::State.stubs(children: {12346 => {type: :worker, acked: false, signaled: Set.new}})
61
- assert(Einhorn::Command.trigger_spinup?(1))
62
- end
63
-
64
- it "is false if capacity is exceeded" do
65
- Einhorn::State.stubs(config: {max_upgrade_additional: 1, number: 1})
66
- Einhorn::State.stubs(
67
- children: {
68
- 1 => {type: :worker, acked: true, signaled: Set.new},
69
- 2 => {type: :worker, acked: true, signaled: Set.new},
70
- 3 => {type: :worker, acked: true, signaled: Set.new},
71
- }
72
- )
73
- refute(Einhorn::Command.trigger_spinup?(1))
74
- end
75
-
76
- it "is true if under capacity" do
77
- Einhorn::State.stubs(config: {max_upgrade_additional: 2, number: 1})
78
- Einhorn::State.stubs(children: {1 => {type: :worker, acked: true, signaled: Set.new}})
79
- assert(Einhorn::Command.trigger_spinup?(1))
80
- end
81
- end
82
-
83
- describe "replenish_gradually" do
84
- it "does nothing if an outstanding spinup timer exists" do
85
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: true)
86
- Einhorn::Command.expects(:spinup).never
87
- Einhorn::Command.replenish_gradually
88
- end
89
- it "does nothing if the worker pool is full" do
90
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
91
- Einhorn::WorkerPool.stubs(missing_worker_count: 0)
92
- Einhorn::Command.expects(:spinup).never
93
- Einhorn::Command.replenish_gradually
94
- end
95
-
96
- it "does nothing if we have not reached the spinup interval" do
97
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
98
- Einhorn::WorkerPool.stubs(missing_worker_count: 1)
99
- Einhorn::State.stubs(last_spinup: Time.now)
100
- Einhorn::Command.expects(:spinup).never
101
- Einhorn::Command.replenish_gradually
102
- end
103
-
104
- it "calls trigger_spinup? if we have reached the spinup interval" do
105
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
106
- Einhorn::State.stubs(config: {seconds: 1, max_unacked: 2, number: 1})
107
- Einhorn::WorkerPool.stubs(missing_worker_count: 1)
108
- Einhorn::State.stubs(last_spinup: Time.now - 2) # 2 seconds ago
109
- Einhorn::Command.expects(:trigger_spinup?).with(2).returns(false)
110
- Einhorn::Command.replenish_gradually
111
- end
112
-
113
- it "can handle sub-second spinup intervals" do
114
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
115
- Einhorn::State.stubs(config: {seconds: 0.1, max_unacked: 2, number: 1})
116
- Einhorn::WorkerPool.stubs(missing_worker_count: 1)
117
- Einhorn::State.stubs(last_spinup: Time.now - 0.5) # Half a second ago
118
- Einhorn::Command.stubs(trigger_spinup?: true)
119
- Einhorn::Command.expects(:spinup)
120
- Einhorn::Command.replenish_gradually
121
- end
122
-
123
- it "registers a timer to run again at spinup interval" do
124
- Einhorn::TransientState.stubs(has_outstanding_spinup_timer: false)
125
- Einhorn::State.stubs(config: {seconds: 0.1, max_unacked: 2, number: 1})
126
- Einhorn::WorkerPool.stubs(missing_worker_count: 1)
127
- Einhorn::State.stubs(last_spinup: Time.now - 1)
128
- Einhorn::Command.stubs(trigger_spinup?: true)
129
- Einhorn::Command.stubs(:spinup)
130
- Einhorn::TransientState.expects(:has_outstanding_spinup_timer=).with(true)
131
- Einhorn::Event::Timer.expects(:open).with(0.1)
132
- Einhorn::Command.replenish_gradually
133
- end
134
- end
135
- end
@@ -1,89 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../_lib'))
2
-
3
- require 'set'
4
- require 'einhorn'
5
-
6
- module Einhorn::Event
7
- def self.reset
8
- @@loopbreak_reader = nil
9
- @@loopbreak_writer = nil
10
- @@readable = {}
11
- @@writeable = {}
12
- @@timers = {}
13
- end
14
- end
15
-
16
- class EventTest < EinhornTestCase
17
- describe "when running the event loop" do
18
- before do
19
- Einhorn::Event.reset
20
- end
21
-
22
- after do
23
- Einhorn::Event.reset
24
- end
25
-
26
- it "selects on readable descriptors" do
27
- sock1 = stub(:fileno => 4)
28
- sock2 = stub(:fileno => 5)
29
-
30
- conn1 = Einhorn::Event::Connection.open(sock1)
31
- conn2 = Einhorn::Event::Connection.open(sock2)
32
-
33
- IO.expects(:select).once.with do |readers, writers, errs, timeout|
34
- Set.new(readers) == Set.new([sock1, sock2]) &&
35
- writers == [] &&
36
- errs == nil &&
37
- timeout == nil
38
- end.returns([[], [], []])
39
-
40
- Einhorn::Event.loop_once
41
- end
42
-
43
- it "selects on writeable descriptors" do
44
- sock1 = stub(:fileno => 4)
45
- sock2 = stub(:fileno => 5)
46
-
47
- conn1 = Einhorn::Event::Connection.open(sock1)
48
- conn2 = Einhorn::Event::Connection.open(sock2)
49
-
50
- sock2.expects(:write_nonblock).once.raises(Errno::EWOULDBLOCK.new)
51
- conn2.write('Hello!')
52
-
53
- IO.expects(:select).once.with do |readers, writers, errs, timeout|
54
- Set.new(readers) == Set.new([sock1, sock2]) &&
55
- writers == [sock2] &&
56
- errs == nil &&
57
- timeout == nil
58
- end.returns([[], [], []])
59
-
60
- Einhorn::Event.loop_once
61
- end
62
-
63
- it "runs callbacks for ready selectables" do
64
- sock1 = stub(:fileno => 4)
65
- sock2 = stub(:fileno => 5)
66
-
67
- conn1 = Einhorn::Event::Connection.open(sock1)
68
- conn2 = Einhorn::Event::Connection.open(sock2)
69
-
70
- sock2.expects(:write_nonblock).once.raises(Errno::EWOULDBLOCK.new)
71
- conn2.write('Hello!')
72
-
73
- IO.expects(:select).once.with do |readers, writers, errs, timeout|
74
- Set.new(readers) == Set.new([sock1, sock2]) &&
75
- writers == [sock2] &&
76
- errs == nil &&
77
- timeout == nil
78
- end.returns([[sock1], [sock2], []])
79
-
80
- conn1.expects(:notify_readable).once
81
- conn2.expects(:notify_writeable).never
82
-
83
- conn1.expects(:notify_readable).never
84
- conn2.expects(:notify_writeable).once
85
-
86
- Einhorn::Event.loop_once
87
- end
88
- end
89
- end
@@ -1,39 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../_lib'))
2
-
3
- require 'einhorn'
4
-
5
- class WorkerPoolTest < EinhornTestCase
6
- def stub_children
7
- Einhorn::State.stubs(:children).returns(
8
- 1234 => {:type => :worker, :signaled => Set.new(['INT'])},
9
- 1235 => {:type => :state_passer},
10
- 1236 => {:type => :worker, :signaled => Set.new}
11
- )
12
- end
13
-
14
- describe "#workers_with_state" do
15
- before do
16
- stub_children
17
- end
18
-
19
- it "selects only the workers" do
20
- workers_with_state = Einhorn::WorkerPool.workers_with_state
21
- # Sort only needed for Ruby 1.8
22
- assert_equal([
23
- [1234, {:type => :worker, :signaled => Set.new(['INT'])}],
24
- [1236, {:type => :worker, :signaled => Set.new}]
25
- ], workers_with_state.sort)
26
- end
27
- end
28
-
29
- describe "#unsignaled_workers" do
30
- before do
31
- stub_children
32
- end
33
-
34
- it "selects unsignaled workers" do
35
- unsignaled_workers = Einhorn::WorkerPool.unsignaled_workers
36
- assert_equal([1236], unsignaled_workers)
37
- end
38
- end
39
- end