einhorn 0.7.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Changes.md +10 -0
- data/README.md +36 -30
- data/bin/einhorn +17 -2
- data/einhorn.gemspec +23 -21
- data/example/pool_worker.rb +1 -1
- data/example/thin_example +8 -8
- data/example/time_server +5 -5
- data/lib/einhorn/client.rb +8 -9
- data/lib/einhorn/command/interface.rb +100 -95
- data/lib/einhorn/command.rb +167 -88
- data/lib/einhorn/compat.rb +7 -7
- data/lib/einhorn/event/abstract_text_descriptor.rb +31 -35
- data/lib/einhorn/event/ack_timer.rb +2 -2
- data/lib/einhorn/event/command_server.rb +7 -9
- data/lib/einhorn/event/connection.rb +1 -3
- data/lib/einhorn/event/loop_breaker.rb +2 -1
- data/lib/einhorn/event/persistent.rb +2 -2
- data/lib/einhorn/event/timer.rb +4 -4
- data/lib/einhorn/event.rb +29 -20
- data/lib/einhorn/prctl.rb +26 -0
- data/lib/einhorn/prctl_linux.rb +48 -0
- data/lib/einhorn/safe_yaml.rb +17 -0
- data/lib/einhorn/version.rb +1 -1
- data/lib/einhorn/worker.rb +67 -49
- data/lib/einhorn/worker_pool.rb +9 -9
- data/lib/einhorn.rb +155 -126
- metadata +42 -137
- data/.gitignore +0 -17
- data/.travis.yml +0 -10
- data/CONTRIBUTORS +0 -6
- data/Gemfile +0 -11
- data/History.txt +0 -4
- data/README.md.in +0 -76
- data/Rakefile +0 -27
- data/test/_lib.rb +0 -12
- data/test/integration/_lib/fixtures/env_printer/env_printer.rb +0 -26
- data/test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb +0 -22
- data/test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb +0 -6
- data/test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb +0 -22
- data/test/integration/_lib/helpers/einhorn_helpers.rb +0 -143
- data/test/integration/_lib/helpers.rb +0 -4
- data/test/integration/_lib.rb +0 -6
- data/test/integration/startup.rb +0 -31
- data/test/integration/upgrading.rb +0 -157
- data/test/unit/einhorn/client.rb +0 -88
- data/test/unit/einhorn/command/interface.rb +0 -49
- data/test/unit/einhorn/command.rb +0 -21
- data/test/unit/einhorn/event.rb +0 -89
- data/test/unit/einhorn/worker_pool.rb +0 -39
- data/test/unit/einhorn.rb +0 -58
- /data/{LICENSE → LICENSE.txt} +0 -0
data/test/integration/startup.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require(File.expand_path('_lib', File.dirname(__FILE__)))
|
2
|
-
|
3
|
-
class StartupTest < EinhornIntegrationTestCase
|
4
|
-
include Helpers::EinhornHelpers
|
5
|
-
|
6
|
-
describe 'when invoked without args' do
|
7
|
-
it 'prints usage and exits with 1' do
|
8
|
-
assert_raises(Subprocess::NonZeroExit) do
|
9
|
-
Subprocess.check_call(default_einhorn_command,
|
10
|
-
:stdout => Subprocess::PIPE,
|
11
|
-
:stderr => Subprocess::PIPE) do |einhorn|
|
12
|
-
stdout, stderr = einhorn.communicate
|
13
|
-
assert_match(/\A## Usage/, stdout)
|
14
|
-
assert_equal(1, einhorn.wait.exitstatus)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe 'when invoked with --upgrade-check' do
|
21
|
-
it 'successfully exits' do
|
22
|
-
Subprocess.check_call(default_einhorn_command + %w[--upgrade-check],
|
23
|
-
:stdout => Subprocess::PIPE,
|
24
|
-
:stderr => Subprocess::PIPE) do |einhorn|
|
25
|
-
stdout, stderr = einhorn.communicate
|
26
|
-
status = einhorn.wait
|
27
|
-
assert_equal(0, status.exitstatus)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,157 +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
|
-
process.terminate
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
describe 'without preloading' do
|
86
|
-
it 'can update environment variables when the reexec command line says to' do
|
87
|
-
# exec the new einhorn with the same environment:
|
88
|
-
reexec_cmdline = 'env VAR=b OINK=b bundle exec --keep-file-descriptors einhorn'
|
89
|
-
|
90
|
-
with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --reexec-as=#{reexec_cmdline} -d #{@socket_path} -- ruby #{@server_program} VAR},
|
91
|
-
:env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
|
92
|
-
|
93
|
-
wait_for_open_port
|
94
|
-
einhornsh(%W{-d #{@socket_path} -e upgrade})
|
95
|
-
assert_equal("b", read_from_port, "Should report the upgraded version")
|
96
|
-
|
97
|
-
process.terminate
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe 'with preloading' do
|
103
|
-
it 'can update environment variables on preloaded code when the reexec command line says to' do
|
104
|
-
# exec the new einhorn with the same environment:
|
105
|
-
reexec_cmdline = 'env VAR=b OINK=b bundle exec --keep-file-descriptors einhorn'
|
106
|
-
|
107
|
-
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},
|
108
|
-
:env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
|
109
|
-
|
110
|
-
wait_for_open_port
|
111
|
-
einhornsh(%W{-d #{@socket_path} -e upgrade})
|
112
|
-
assert_equal("b", read_from_port, "Should report the upgraded version")
|
113
|
-
|
114
|
-
process.terminate
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe 'when invoked with --drop-env-var' do
|
122
|
-
before do
|
123
|
-
@dir = prepare_fixture_directory('env_printer')
|
124
|
-
@port = find_free_port
|
125
|
-
@server_program = File.join(@dir, "env_printer.rb")
|
126
|
-
@socket_path = File.join(@dir, "einhorn.sock")
|
127
|
-
end
|
128
|
-
after { cleanup_fixtured_directories }
|
129
|
-
|
130
|
-
it %{removes the variable from its children's environment} do
|
131
|
-
with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} --drop-env-var=VAR -d #{@socket_path} -- ruby #{@server_program} VAR},
|
132
|
-
:env => ENV.to_hash.merge({'VAR' => 'a'})) do |process|
|
133
|
-
wait_for_open_port
|
134
|
-
assert_equal("a", read_from_port, "Should report $VAR initially")
|
135
|
-
|
136
|
-
einhornsh(%W{-d #{@socket_path} -e upgrade})
|
137
|
-
assert_equal("", read_from_port, "Should have dropped the variable post-upgrade")
|
138
|
-
|
139
|
-
process.terminate
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
it %{causes an upgrade with --reexec-as to not clobber the new environment} do
|
144
|
-
reexec_cmdline = 'env VAR2=b bundle exec --keep-file-descriptors einhorn'
|
145
|
-
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},
|
146
|
-
:env => ENV.to_hash.merge({'VAR1' => 'a', 'VAR2' => 'a'})) do |process|
|
147
|
-
wait_for_open_port
|
148
|
-
assert_equal("aa", read_from_port, "Should report both $VAR1 and $VAR2 initially")
|
149
|
-
|
150
|
-
einhornsh(%W{-d #{@socket_path} -e upgrade})
|
151
|
-
assert_equal("b", read_from_port, "Should have dropped $VAR1 post-upgrade and re-set $VAR2")
|
152
|
-
|
153
|
-
process.terminate
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
data/test/unit/einhorn/client.rb
DELETED
@@ -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,21 +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
|
-
end
|
data/test/unit/einhorn/event.rb
DELETED
@@ -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
|
data/test/unit/einhorn.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '../_lib'))
|
2
|
-
|
3
|
-
require 'einhorn'
|
4
|
-
|
5
|
-
class EinhornTest < EinhornTestCase
|
6
|
-
describe "when sockifying" do
|
7
|
-
after do
|
8
|
-
Einhorn::State.sockets = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
it "correctly parses srv: arguments" do
|
12
|
-
cmd = ['foo', 'srv:1.2.3.4:123,llama,test', 'bar']
|
13
|
-
Einhorn.expects(:bind).once.with('1.2.3.4', '123', ['llama', 'test']).returns(4)
|
14
|
-
|
15
|
-
Einhorn.socketify!(cmd)
|
16
|
-
|
17
|
-
assert_equal(['foo', '4', 'bar'], cmd)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "correctly parses --opt=srv: arguments" do
|
21
|
-
cmd = ['foo', '--opt=srv:1.2.3.4:456', 'baz']
|
22
|
-
Einhorn.expects(:bind).once.with('1.2.3.4', '456', []).returns(5)
|
23
|
-
|
24
|
-
Einhorn.socketify!(cmd)
|
25
|
-
|
26
|
-
assert_equal(['foo', '--opt=5', 'baz'], cmd)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "uses the same fd number for the same server spec" do
|
30
|
-
cmd = ['foo', '--opt=srv:1.2.3.4:8910', 'srv:1.2.3.4:8910']
|
31
|
-
Einhorn.expects(:bind).once.with('1.2.3.4', '8910', []).returns(10)
|
32
|
-
|
33
|
-
Einhorn.socketify!(cmd)
|
34
|
-
|
35
|
-
assert_equal(['foo', '--opt=10', '10'], cmd)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe '.update_state' do
|
40
|
-
it 'correctly updates keys to match new default state hash' do
|
41
|
-
Einhorn::State.stubs(:default_state).returns(:baz => 23, :foo => 1)
|
42
|
-
old_state = {:foo => 2, :bar => 2}
|
43
|
-
|
44
|
-
updated_state, message = Einhorn.update_state(Einhorn::State, 'einhorn', old_state)
|
45
|
-
assert_equal({:baz => 23, :foo => 2}, updated_state)
|
46
|
-
assert_match(/State format for einhorn has changed/, message)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'does not change the state if the format has not changed' do
|
50
|
-
Einhorn::State.stubs(:default_state).returns(:baz => 23, :foo => 1)
|
51
|
-
old_state = {:baz => 14, :foo => 1234}
|
52
|
-
|
53
|
-
updated_state, message = Einhorn.update_state(Einhorn::State, 'einhorn', old_state)
|
54
|
-
assert_equal({:baz => 14, :foo => 1234}, updated_state)
|
55
|
-
assert(message.nil?)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
/data/{LICENSE → LICENSE.txt}
RENAMED
File without changes
|