einhorn 0.7.4 → 1.0.0
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.
- 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
|