einhorn 0.8.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +15 -0
  3. data/README.md +7 -38
  4. data/einhorn.gemspec +23 -21
  5. data/example/pool_worker.rb +2 -2
  6. data/example/thin_example +8 -8
  7. data/example/time_server +5 -5
  8. data/lib/einhorn/client.rb +8 -8
  9. data/lib/einhorn/command/interface.rb +92 -98
  10. data/lib/einhorn/command.rb +75 -85
  11. data/lib/einhorn/compat.rb +7 -7
  12. data/lib/einhorn/event/abstract_text_descriptor.rb +32 -36
  13. data/lib/einhorn/event/ack_timer.rb +2 -2
  14. data/lib/einhorn/event/command_server.rb +7 -9
  15. data/lib/einhorn/event/connection.rb +1 -3
  16. data/lib/einhorn/event/loop_breaker.rb +2 -1
  17. data/lib/einhorn/event/persistent.rb +2 -2
  18. data/lib/einhorn/event/timer.rb +4 -4
  19. data/lib/einhorn/event.rb +20 -20
  20. data/lib/einhorn/prctl.rb +2 -2
  21. data/lib/einhorn/prctl_linux.rb +13 -14
  22. data/lib/einhorn/safe_yaml.rb +17 -0
  23. data/lib/einhorn/version.rb +1 -1
  24. data/lib/einhorn/worker.rb +26 -30
  25. data/lib/einhorn/worker_pool.rb +9 -9
  26. data/lib/einhorn.rb +120 -125
  27. metadata +37 -110
  28. data/.gitignore +0 -17
  29. data/.travis.yml +0 -10
  30. data/CONTRIBUTORS +0 -6
  31. data/Gemfile +0 -11
  32. data/History.txt +0 -4
  33. data/README.md.in +0 -94
  34. data/Rakefile +0 -27
  35. data/test/_lib.rb +0 -12
  36. data/test/integration/_lib/fixtures/env_printer/env_printer.rb +0 -26
  37. data/test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb +0 -23
  38. data/test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb +0 -6
  39. data/test/integration/_lib/fixtures/pdeathsig_printer/pdeathsig_printer.rb +0 -29
  40. data/test/integration/_lib/fixtures/signal_timeout/sleepy_server.rb +0 -23
  41. data/test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb +0 -24
  42. data/test/integration/_lib/helpers/einhorn_helpers.rb +0 -148
  43. data/test/integration/_lib/helpers.rb +0 -4
  44. data/test/integration/_lib.rb +0 -6
  45. data/test/integration/pdeathsig.rb +0 -26
  46. data/test/integration/startup.rb +0 -31
  47. data/test/integration/upgrading.rb +0 -204
  48. data/test/unit/_lib/bad_worker.rb +0 -7
  49. data/test/unit/_lib/sleep_worker.rb +0 -5
  50. data/test/unit/einhorn/client.rb +0 -88
  51. data/test/unit/einhorn/command/interface.rb +0 -49
  52. data/test/unit/einhorn/command.rb +0 -135
  53. data/test/unit/einhorn/event.rb +0 -89
  54. data/test/unit/einhorn/worker_pool.rb +0 -39
  55. data/test/unit/einhorn.rb +0 -96
  56. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -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