serverengine 2.3.0 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1c09d476bdc08a078882ba14ee74f487ab988a397d2228c3e83f611fff94df1
4
- data.tar.gz: 33732af3d1c591ec28c67249b1b67b16b142f80048f70c3cf5c769b3e267b76a
3
+ metadata.gz: 7350069b97302faf3d6c50118875bf055a7094bc31845185cd4e6b4d3e0a9f61
4
+ data.tar.gz: 02e1c1e261b6ea6dde6a77a984c8f94dccf237093dda7949174acd2658c9897b
5
5
  SHA512:
6
- metadata.gz: 383aaf8822f01aec3ce2e4a25243da8ca741da9d11f97c601c31cc6985e285743a088cafdd4fd918b58a966960376f65b28645b1fca74d0741e64052bd329ac8
7
- data.tar.gz: ca10bd75948760060c8ae433cb2021a7024d6b076d84157012db5ae6809d01c9a8bb2eb2bb1f9f8d84f0881e4cbaf3bebfb25ef959130574e0cf717550ee1867
6
+ metadata.gz: 66ae31cea3ff4779a648d64c00e54ff01e76912cd2a4ce1f6105b83657bdbdaea0e9b2c54972cc171ed2aa2a01794dd4c2c3b2e73fdb1754a7013cee2fd0c1a5
7
+ data.tar.gz: 8b023a4052650036480ce2f899ac367279dcc341a3d98536c7a3fc91cf227622a3707f7315a9eead3a0a2335792700723dda3a527aa422c5aa06d2ff27824b11
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.1', '3.0', '2.7' ]
14
+ ruby: [ '3.2', '3.1', '3.0', '2.7' ]
15
15
  os:
16
16
  - ubuntu-latest
17
17
  name: Unit testing with Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.1', '2.7' ]
14
+ ruby: [ '3.2', '3.1', '2.7' ]
15
15
  os:
16
16
  - windows-latest
17
17
  include:
data/Changelog CHANGED
@@ -1,3 +1,13 @@
1
+ 2023-03-14 version 2.3.2
2
+
3
+ * Accept `nil` for `ServerEngine::SocketManager::Server.open` to select path automatically
4
+ * Care excluded port ranges of Windows in `ServerEngine::SocketManager.generate_path`
5
+ * Update to Rake 13 and RSpec 3 to support running tests on Ruby 3.2
6
+
7
+ 2022-12-22 version 2.3.1
8
+
9
+ * Don't treat as error when worker shuts down with exit status 0
10
+
1
11
  2022-06-13 version 2.3.0
2
12
 
3
13
  * Add restart_worker_interval option to prevent workers restart immediately
@@ -13,6 +23,7 @@
13
23
  2022-01-13 version 2.2.5:
14
24
 
15
25
  * Fix DLL load error on Ruby 3.1 on Windows
26
+ * Treat as error when worker shuts down unexpectedly
16
27
 
17
28
  2021-05-24 version 2.2.4:
18
29
 
data/README.md CHANGED
@@ -370,8 +370,8 @@ se.run
370
370
  ```ruby
371
371
  module MyServer
372
372
  def before_run
373
- @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
374
- @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
373
+ @socket_manager_server = ServerEngine::SocketManager::Server.open
374
+ @socket_manager_path = @socket_manager_server.path
375
375
  end
376
376
 
377
377
  def after_run
data/examples/server.rb CHANGED
@@ -41,8 +41,8 @@ module MyServer
41
41
  attr_reader :socket_manager_path
42
42
 
43
43
  def before_run
44
- @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
45
- @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
44
+ @socket_manager_server = ServerEngine::SocketManager::Server.open
45
+ @socket_manager_path = @socket_manager_server.path
46
46
  rescue Exception => e
47
47
  logger.error "unexpected error in server, class #{e.class}: #{e.message}"
48
48
  raise
@@ -147,7 +147,11 @@ module ServerEngine
147
147
  if @stop
148
148
  @worker.logger.info "Worker #{@wid} finished with #{ServerEngine.format_join_status(stat)}"
149
149
  else
150
- @worker.logger.error "Worker #{@wid} finished unexpectedly with #{ServerEngine.format_join_status(stat)}"
150
+ if stat.is_a?(Process::Status) && stat.success?
151
+ @worker.logger.info "Worker #{@wid} exited with #{ServerEngine.format_join_status(stat)}"
152
+ else
153
+ @worker.logger.error "Worker #{@wid} exited unexpectedly with #{ServerEngine.format_join_status(stat)}"
154
+ end
151
155
  end
152
156
  if stat.is_a?(Process::Status) && stat.exited? && @unrecoverable_exit_codes.include?(stat.exitstatus)
153
157
  @unrecoverable_exit = true
@@ -77,19 +77,23 @@ module ServerEngine
77
77
  port = ENV['SERVERENGINE_SOCKETMANAGER_PORT']
78
78
  return port.to_i if port
79
79
 
80
- for port in get_dynamic_port_range
81
- if `netstat -na | findstr "#{port}"`.length == 0
82
- return port
83
- end
84
- end
80
+ excluded_port_ranges = get_excluded_port_ranges
81
+ get_dynamic_port_range
82
+ .reject { |port| excluded_port_ranges.any? { |range| range.cover?(port) } }
83
+ .find { |port| `netstat -na | findstr "#{port}"`.length == 0 }
85
84
  else
86
85
  base_dir = (ENV['SERVERENGINE_SOCKETMANAGER_SOCK_DIR'] || '/tmp')
87
86
  File.join(base_dir, 'SERVERENGINE_SOCKETMANAGER_' + Time.now.utc.iso8601 + '_' + Process.pid.to_s)
88
87
  end
89
88
  end
90
89
 
91
- def self.open(path)
92
- new(path)
90
+ def self.open(path = nil)
91
+ return new(path) unless path.nil?
92
+ if ServerEngine.windows?
93
+ new(0)
94
+ else
95
+ new(self.generate_path)
96
+ end
93
97
  end
94
98
 
95
99
  def initialize(path)
@@ -198,6 +202,27 @@ module ServerEngine
198
202
  return 49152..65535
199
203
  end
200
204
  end
205
+
206
+ def self.get_excluded_port_ranges
207
+ # Example output of netsh:
208
+ #
209
+ # Protocol tcp Port Exclusion Ranges
210
+ #
211
+ # Start Port End Port
212
+ # ---------- --------
213
+ # 2869 2869
214
+ # 49152 49251
215
+ # 50000 50059 *
216
+ # 57095 57194
217
+ #
218
+ # * - Administered port exclusions.
219
+ #
220
+ `netsh int ipv4 show excludedportrange tcp`
221
+ .force_encoding("ASCII-8BIT")
222
+ .lines
223
+ .map { |line| line.match(/\s*(\d+)\s*(\d+)[\s\*]*/) ? $1.to_i..$2.to_i : nil }
224
+ .compact
225
+ end
201
226
  end
202
227
  end
203
228
 
@@ -108,8 +108,9 @@ module ServerEngine
108
108
  end
109
109
 
110
110
  def start_server(addr)
111
- # TODO: use TCPServer, but this is risky because using not conflict path is easy,
112
- # but using not conflict port is difficult. Then We had better implement using NamedPipe.
111
+ # We need to take care about selecting an available port.
112
+ # By passing `nil` or `0` as `addr`, an available port is automatically selected.
113
+ # However, we should consider using NamedPipe instead of TCPServer.
113
114
  @server = TCPServer.new("127.0.0.1", addr)
114
115
  @thread = Thread.new do
115
116
  begin
@@ -123,7 +124,7 @@ module ServerEngine
123
124
  end
124
125
  end
125
126
 
126
- return path
127
+ return @server.addr[1]
127
128
  end
128
129
 
129
130
  def stop_server
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "2.3.0"
2
+ VERSION = "2.3.2"
3
3
  end
data/serverengine.gemspec CHANGED
@@ -16,16 +16,17 @@ Gem::Specification.new do |gem|
16
16
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
17
  gem.require_paths = ["lib"]
18
18
 
19
- gem.required_ruby_version = ">= 2.1.0"
19
+ gem.required_ruby_version = ">= 2.3.0"
20
20
 
21
21
  gem.add_dependency "sigdump", ["~> 0.2.2"]
22
22
 
23
23
  # rake v12.x doesn't work with rspec 2. rspec should be updated to 3
24
- gem.add_development_dependency "rake", ["~> 11.0"]
25
- gem.add_development_dependency "rspec", ["~> 2.13.0"]
24
+ gem.add_development_dependency "rake", ["~> 13.0"]
25
+ gem.add_development_dependency "rspec", ["~> 3.12.0"]
26
26
 
27
27
  gem.add_development_dependency 'rake-compiler-dock', ['~> 0.5.0']
28
28
  gem.add_development_dependency 'rake-compiler', ['~> 0.9.4']
29
29
 
30
30
  gem.add_development_dependency "timecop", ["~> 0.9.5"]
31
+ gem.add_development_dependency "rr", ["~> 3.1"]
31
32
  end
@@ -150,7 +150,7 @@ describe ServerEngine::DaemonLogger do
150
150
  end
151
151
 
152
152
  it 'inter-process locking on rotation' do
153
- pending "fork is not implemented in Windows" if ServerEngine.windows?
153
+ skip "fork is not implemented in Windows" if ServerEngine.windows?
154
154
 
155
155
  log = DaemonLogger.new("tmp/se4.log", level: 'trace', log_rotate_age: 3, log_rotate_size: 10)
156
156
  r, w = IO.pipe
@@ -175,7 +175,7 @@ describe ServerEngine::DaemonLogger do
175
175
  end
176
176
 
177
177
  it 'reopen log when path is renamed' do
178
- pending "rename isn't supported on windows" if ServerEngine.windows?
178
+ skip "rename isn't supported on windows" if ServerEngine.windows?
179
179
 
180
180
  log = DaemonLogger.new("tmp/rotate.log", { level: 'info', log_rotate_age: 0 })
181
181
 
data/spec/daemon_spec.rb CHANGED
@@ -2,8 +2,16 @@
2
2
  describe ServerEngine::Daemon do
3
3
  include_context 'test server and worker'
4
4
 
5
+ before do
6
+ @log_path = "tmp/multi-worker-test-#{SecureRandom.hex(10)}.log"
7
+ end
8
+
9
+ after do
10
+ FileUtils.rm_rf(@log_path)
11
+ end
12
+
5
13
  it 'run and graceful stop by signal' do
6
- pending "not supported signal base commands on Windows" if ServerEngine.windows?
14
+ skip "not supported signal base commands on Windows" if ServerEngine.windows?
7
15
 
8
16
  dm = Daemon.new(TestServer, TestWorker, daemonize: true, pid_path: "tmp/pid", command_sender: "signal")
9
17
  dm.main
@@ -25,7 +33,7 @@ describe ServerEngine::Daemon do
25
33
  end
26
34
 
27
35
  it 'signals' do
28
- pending "not supported signal base commands on Windows" if ServerEngine.windows?
36
+ skip "not supported signal base commands on Windows" if ServerEngine.windows?
29
37
  dm = Daemon.new(TestServer, TestWorker, daemonize: true, pid_path: "tmp/pid", command_sender: "signal")
30
38
  dm.main
31
39
 
@@ -104,13 +112,14 @@ describe ServerEngine::Daemon do
104
112
  end
105
113
 
106
114
  it 'exits with status 0 when it was stopped normally' do
107
- pending "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
115
+ skip "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
108
116
  dm = Daemon.new(
109
117
  TestServer,
110
118
  TestWorker,
111
119
  daemonize: false,
112
120
  supervisor: false,
113
121
  pid_path: "tmp/pid",
122
+ logger: ServerEngine::DaemonLogger.new(@log_path),
114
123
  log_stdout: false,
115
124
  log_stderr: false,
116
125
  unrecoverable_exit_codes: [3,4,5],
@@ -126,7 +135,7 @@ describe ServerEngine::Daemon do
126
135
  end
127
136
 
128
137
  it 'exits with status of workers if worker exits with status specified in unrecoverable_exit_codes, without supervisor' do
129
- pending "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
138
+ skip "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
130
139
 
131
140
  dm = Daemon.new(
132
141
  TestServer,
@@ -135,6 +144,7 @@ describe ServerEngine::Daemon do
135
144
  supervisor: false,
136
145
  worker_type: 'process',
137
146
  pid_path: "tmp/pid",
147
+ logger: ServerEngine::DaemonLogger.new(@log_path),
138
148
  log_stdout: false,
139
149
  log_stderr: false,
140
150
  unrecoverable_exit_codes: [3,4,5],
@@ -149,7 +159,7 @@ describe ServerEngine::Daemon do
149
159
  end
150
160
 
151
161
  it 'exits with status of workers if worker exits with status specified in unrecoverable_exit_codes, with supervisor' do
152
- pending "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
162
+ skip "worker type process(fork) cannot be used in Windows" if ServerEngine.windows?
153
163
 
154
164
  dm = Daemon.new(
155
165
  TestServer,
@@ -158,6 +168,7 @@ describe ServerEngine::Daemon do
158
168
  supervisor: true,
159
169
  worker_type: 'process',
160
170
  pid_path: "tmp/pid",
171
+ logger: ServerEngine::DaemonLogger.new(@log_path),
161
172
  log_stdout: false,
162
173
  log_stderr: false,
163
174
  unrecoverable_exit_codes: [3,4,5],
@@ -1,13 +1,30 @@
1
+ require 'timeout'
2
+ require 'securerandom'
3
+
1
4
  [ServerEngine::MultiThreadServer, ServerEngine::MultiProcessServer].each do |impl_class|
2
5
  # MultiProcessServer uses fork(2) internally, then it doesn't support Windows.
3
6
 
4
7
  describe impl_class do
5
8
  include_context 'test server and worker'
6
9
 
10
+ before do
11
+ @log_path = "tmp/multi-worker-test-#{SecureRandom.hex(10)}.log"
12
+ @logger = ServerEngine::DaemonLogger.new(@log_path)
13
+ end
14
+
15
+ after do
16
+ FileUtils.rm_rf(@log_path)
17
+ end
18
+
7
19
  it 'scale up' do
8
- pending "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
20
+ skip "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
9
21
 
10
- config = {workers: 2, log_stdout: false, log_stderr: false}
22
+ config = {
23
+ workers: 2,
24
+ logger: @logger,
25
+ log_stdout: false,
26
+ log_stderr: false,
27
+ }
11
28
 
12
29
  s = impl_class.new(TestWorker) { config.dup }
13
30
  t = Thread.new { s.main }
@@ -33,9 +50,14 @@
33
50
  end
34
51
 
35
52
  it 'scale down' do
36
- pending "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
53
+ skip "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
37
54
 
38
- config = {workers: 2, log_stdout: false, log_stderr: false}
55
+ config = {
56
+ workers: 2,
57
+ logger: @logger,
58
+ log_stdout: false,
59
+ log_stderr: false
60
+ }
39
61
 
40
62
  s = impl_class.new(TestWorker) { config.dup }
41
63
  t = Thread.new { s.main }
@@ -59,12 +81,32 @@
59
81
 
60
82
  test_state(:worker_stop).should == 3
61
83
  end
84
+ end
85
+ end
86
+
87
+ [ServerEngine::MultiProcessServer].each do |impl_class|
88
+ describe impl_class do
89
+ include_context 'test server and worker'
90
+
91
+ before do
92
+ @log_path = "tmp/multi-worker-test-#{SecureRandom.hex(10)}.log"
93
+ @logger = ServerEngine::DaemonLogger.new(@log_path)
94
+ end
95
+
96
+ after do
97
+ FileUtils.rm_rf(@log_path)
98
+ end
62
99
 
63
100
  it 'raises SystemExit when all workers exit with specified code by unrecoverable_exit_codes' do
64
- pending "unrecoverable_exit_codes supported only for multi process workers" if impl_class == ServerEngine::MultiThreadServer
65
- pending "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
101
+ skip "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
66
102
 
67
- config = {workers: 4, log_stdout: false, log_stderr: false, unrecoverable_exit_codes: [3, 4, 5]}
103
+ config = {
104
+ workers: 4,
105
+ logger: @logger,
106
+ log_stdout: false,
107
+ log_stderr: false,
108
+ unrecoverable_exit_codes: [3, 4, 5]
109
+ }
68
110
 
69
111
  s = impl_class.new(TestExitWorker) { config.dup }
70
112
  raised_error = nil
@@ -85,10 +127,16 @@
85
127
  end
86
128
 
87
129
  it 'raises SystemExit immediately when a worker exits if stop_immediately_at_unrecoverable_exit specified' do
88
- pending "unrecoverable_exit_codes supported only for multi process workers" if impl_class == ServerEngine::MultiThreadServer
89
- pending "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
130
+ skip "Windows environment does not support fork" if ServerEngine.windows? && impl_class == ServerEngine::MultiProcessServer
90
131
 
91
- config = {workers: 4, log_stdout: false, log_stderr: false, unrecoverable_exit_codes: [3, 4, 5], stop_immediately_at_unrecoverable_exit: true}
132
+ config = {
133
+ workers: 4,
134
+ logger: @logger,
135
+ log_stdout: false,
136
+ log_stderr: false,
137
+ unrecoverable_exit_codes: [3, 4, 5],
138
+ stop_immediately_at_unrecoverable_exit: true
139
+ }
92
140
 
93
141
  s = impl_class.new(TestExitWorker) { config.dup }
94
142
  raised_error = nil
@@ -111,3 +159,101 @@
111
159
  end
112
160
  end
113
161
  end
162
+
163
+ describe "log level for exited proccess" do
164
+ include_context 'test server and worker'
165
+
166
+ before do
167
+ @log_path = "tmp/multi-process-log-level-test-#{SecureRandom.hex(10)}.log"
168
+ end
169
+
170
+ after do
171
+ FileUtils.rm_rf(@log_path)
172
+ end
173
+
174
+ it 'stop' do
175
+ skip "Windows environment does not support fork" if ServerEngine.windows?
176
+
177
+ config = {
178
+ workers: 1,
179
+ logger: ServerEngine::DaemonLogger.new(@log_path),
180
+ log_stdout: false,
181
+ log_stderr: false,
182
+ }
183
+
184
+ s = ServerEngine::MultiProcessServer.new(TestWorker) { config.dup }
185
+ t = Thread.new { s.main }
186
+
187
+ begin
188
+ wait_for_fork
189
+ test_state(:worker_run).should == 1
190
+ ensure
191
+ s.stop(true)
192
+ t.join
193
+ end
194
+
195
+ log_lines = File.read(@log_path).split("\n")
196
+ expect(log_lines[2]).to match(/^I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+ #\d+\] INFO -- : Worker 0 finished with status 0$/)
197
+ end
198
+
199
+ it 'non zero exit status' do
200
+ skip "Windows environment does not support fork" if ServerEngine.windows?
201
+
202
+ config = {
203
+ workers: 1,
204
+ logger: ServerEngine::DaemonLogger.new(@log_path),
205
+ log_stdout: false,
206
+ log_stderr: false,
207
+ unrecoverable_exit_codes: [5],
208
+ }
209
+
210
+ s = ServerEngine::MultiProcessServer.new(TestExitWorker) { config.dup }
211
+ raised_error = nil
212
+ Thread.new do
213
+ begin
214
+ s.main
215
+ rescue SystemExit => e
216
+ raised_error = e
217
+ end
218
+ end.join
219
+
220
+ test_state(:worker_stop).to_i.should == 0
221
+ raised_error.status.should == 5
222
+ log_lines = File.read(@log_path).split("\n")
223
+ expect(log_lines[1]).to match(/^E, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+ #\d+\] ERROR -- : Worker 0 exited unexpectedly with status 5$/)
224
+ end
225
+
226
+ module TestNormalExitWorker
227
+ include TestExitWorker
228
+ def initialize
229
+ super
230
+ @exit_code = 0
231
+ end
232
+ end
233
+
234
+ it 'zero exit status' do
235
+ skip "Windows environment does not support fork" if ServerEngine.windows?
236
+
237
+ config = {
238
+ workers: 1,
239
+ logger: ServerEngine::DaemonLogger.new(@log_path),
240
+ log_stdout: false,
241
+ log_stderr: false,
242
+ }
243
+
244
+ s = ServerEngine::MultiProcessServer.new(TestNormalExitWorker) { config.dup }
245
+ t = Thread.new { s.main }
246
+
247
+ begin
248
+ Timeout.timeout(5) do
249
+ sleep 1 until File.read(@log_path).include?("INFO -- : Worker 0 exited with status 0")
250
+ end
251
+ ensure
252
+ s.stop(true)
253
+ t.join
254
+ end
255
+
256
+ log_lines = File.read(@log_path).split("\n")
257
+ expect(log_lines[1]).to match(/^I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+ #\d+\] INFO -- : Worker 0 exited with status 0$/)
258
+ end
259
+ end
@@ -4,10 +4,25 @@ require 'timecop'
4
4
  describe ServerEngine::MultiSpawnServer do
5
5
  include_context 'test server and worker'
6
6
 
7
+ before do
8
+ @log_path = "tmp/multi-worker-test-#{SecureRandom.hex(10)}.log"
9
+ @logger = ServerEngine::DaemonLogger.new(@log_path)
10
+ end
11
+
12
+ after do
13
+ FileUtils.rm_rf(@log_path)
14
+ end
15
+
7
16
  describe 'starts worker processes' do
8
17
  context 'with command_sender=pipe' do
9
18
  it do
10
- config = {workers: 2, command_sender: 'pipe', log_stdout: false, log_stderr: false}
19
+ config = {
20
+ workers: 2,
21
+ command_sender: 'pipe',
22
+ logger: @logger,
23
+ log_stdout: false,
24
+ log_stderr: false
25
+ }
11
26
 
12
27
  s = ServerEngine::MultiSpawnServer.new(TestWorker) { config.dup }
13
28
  t = Thread.new { s.main }
@@ -32,6 +47,7 @@ describe ServerEngine::MultiSpawnServer do
32
47
  {
33
48
  workers: workers,
34
49
  command_sender: 'pipe',
50
+ logger: @logger,
35
51
  log_stdout: false,
36
52
  log_stderr: false,
37
53
  start_worker_delay: start_worker_delay,
@@ -1,4 +1,5 @@
1
1
  require 'socket'
2
+ require 'rr'
2
3
 
3
4
  describe ServerEngine::SocketManager do
4
5
  include_context 'test server and worker'
@@ -21,9 +22,23 @@ describe ServerEngine::SocketManager do
21
22
 
22
23
  if ServerEngine.windows?
23
24
  context 'Server.generate_path' do
24
- it 'returns socket path as port number' do
25
- path = SocketManager::Server.generate_path
26
- expect(path).to be_between(49152, 65535)
25
+ context 'with socket path as port number' do
26
+ it 'returns a port in the dynamic port range' do
27
+ path = SocketManager::Server.generate_path
28
+ expect(path).to be_between(49152, 65535)
29
+ end
30
+
31
+ it 'returns a port which is not excluded' do
32
+ excluded_port_ranges = [
33
+ 49152..49251,
34
+ 50000..50059,
35
+ ]
36
+ RR.stub(SocketManager::Server).get_excluded_port_ranges { excluded_port_ranges }
37
+ path = SocketManager::Server.generate_path
38
+ excluded_port_ranges.each do |range|
39
+ expect(path).not_to be_between(range.first, range.last)
40
+ end
41
+ end
27
42
  end
28
43
 
29
44
  it 'can be changed via environment variable' do
@@ -33,6 +48,13 @@ describe ServerEngine::SocketManager do
33
48
  ENV.delete('SERVERENGINE_SOCKETMANAGER_PORT')
34
49
  end
35
50
  end
51
+
52
+ context 'Server.open' do
53
+ it 'returns server with automatically selected socket path as port number' do
54
+ server = SocketManager::Server.open
55
+ expect(server.path).to be_between(49152, 65535)
56
+ end
57
+ end
36
58
  else
37
59
  context 'Server.generate_path' do
38
60
  it 'returns socket path under /tmp' do
@@ -47,6 +69,13 @@ describe ServerEngine::SocketManager do
47
69
  ENV.delete('SERVERENGINE_SOCKETMANAGER_SOCK_DIR')
48
70
  end
49
71
  end
72
+
73
+ context 'Server.open' do
74
+ it 'returns server with automatically selected socket path under /tmp' do
75
+ server = SocketManager::Server.open
76
+ expect(server.path).to include('/tmp/SERVERENGINE_SOCKETMANAGER_')
77
+ end
78
+ end
50
79
  end
51
80
 
52
81
  context 'with thread' do
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  require 'bundler'
2
2
  require 'rspec'
3
-
4
- RSpec.configure do |config|
5
- config.color_enabled = true
6
- end
3
+ require 'fileutils'
7
4
 
8
5
  begin
9
6
  Bundler.setup(:default, :test)
@@ -1,8 +1,12 @@
1
+ require 'rr'
1
2
 
2
3
  describe ServerEngine::Supervisor do
3
4
  include_context 'test server and worker'
4
5
 
5
6
  def start_supervisor(worker = nil, **config)
7
+ config[:log] ||= @log_path
8
+ config[:log_stdout] ||= false
9
+ config[:log_stderr] ||= false
6
10
  if ServerEngine.windows?
7
11
  config[:windows_daemon_cmdline] = windows_supervisor_cmdline(nil, worker, config)
8
12
  end
@@ -13,6 +17,8 @@ describe ServerEngine::Supervisor do
13
17
  end
14
18
 
15
19
  def start_daemon(**config)
20
+ config[:log_stdout] ||= false
21
+ config[:log_stderr] ||= false
16
22
  if ServerEngine.windows?
17
23
  config[:windows_daemon_cmdline] = windows_daemon_cmdline
18
24
  end
@@ -22,9 +28,17 @@ describe ServerEngine::Supervisor do
22
28
  return daemon, t
23
29
  end
24
30
 
31
+ before do
32
+ @log_path = "tmp/supervisor-test-#{SecureRandom.hex(10)}.log"
33
+ end
34
+
35
+ after do
36
+ FileUtils.rm_rf(@log_path)
37
+ end
38
+
25
39
  context 'when :log=IO option is given' do
26
40
  it 'can start' do
27
- daemon, t = start_daemon(log: STDOUT)
41
+ daemon, t = start_daemon(log: File.open(@log_path, "wb"))
28
42
 
29
43
  begin
30
44
  wait_for_fork
@@ -40,7 +54,7 @@ describe ServerEngine::Supervisor do
40
54
 
41
55
  context 'when :logger option is given' do
42
56
  it 'uses specified logger instance' do
43
- logger = ServerEngine::DaemonLogger.new(STDOUT)
57
+ logger = ServerEngine::DaemonLogger.new(@log_path)
44
58
  daemon, t = start_daemon(logger: logger)
45
59
 
46
60
  begin
@@ -57,7 +71,7 @@ describe ServerEngine::Supervisor do
57
71
 
58
72
  context 'when both :logger and :log options are given' do
59
73
  it 'start ignoring :log' do
60
- logger = ServerEngine::DaemonLogger.new(STDOUT)
74
+ logger = ServerEngine::DaemonLogger.new(@log_path)
61
75
  daemon, t = start_daemon(logger: logger, log: STDERR)
62
76
 
63
77
  begin
@@ -76,7 +90,7 @@ describe ServerEngine::Supervisor do
76
90
  context "when using #{sender} as command_sender" do
77
91
 
78
92
  it 'start and graceful stop' do
79
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
93
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
80
94
 
81
95
  sv, t = start_supervisor(command_sender: sender)
82
96
 
@@ -99,7 +113,7 @@ describe ServerEngine::Supervisor do
99
113
  end
100
114
 
101
115
  it 'immediate stop' do
102
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
116
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
103
117
 
104
118
  sv, t = start_supervisor(command_sender: sender)
105
119
 
@@ -117,7 +131,7 @@ describe ServerEngine::Supervisor do
117
131
  end
118
132
 
119
133
  it 'graceful restart' do
120
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
134
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
121
135
 
122
136
  sv, t = start_supervisor(command_sender: sender)
123
137
 
@@ -141,7 +155,7 @@ describe ServerEngine::Supervisor do
141
155
  end
142
156
 
143
157
  it 'immediate restart' do
144
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
158
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
145
159
 
146
160
  sv, t = start_supervisor(command_sender: sender)
147
161
 
@@ -165,7 +179,7 @@ describe ServerEngine::Supervisor do
165
179
  end
166
180
 
167
181
  it 'reload' do
168
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
182
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
169
183
 
170
184
  sv, t = start_supervisor(command_sender: sender)
171
185
 
@@ -186,7 +200,9 @@ describe ServerEngine::Supervisor do
186
200
  # TODO detach
187
201
 
188
202
  it 'auto restart in limited ratio' do
189
- pending 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
203
+ skip 'not supported on Windows' if ServerEngine.windows? && sender == 'signal'
204
+
205
+ RR.stub(ServerEngine).dump_uncaught_error
190
206
 
191
207
  sv, t = start_supervisor(RunErrorWorker, server_restart_wait: 1, command_sender: sender)
192
208
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serverengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-13 00:00:00.000000000 Z
11
+ date: 2023-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sigdump
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '11.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '11.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.13.0
47
+ version: 3.12.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.13.0
54
+ version: 3.12.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake-compiler-dock
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.9.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: rr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.1'
97
111
  description: A framework to implement robust multiprocess servers like Unicorn
98
112
  email:
99
113
  - frsyuki@gmail.com
@@ -161,14 +175,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
175
  requirements:
162
176
  - - ">="
163
177
  - !ruby/object:Gem::Version
164
- version: 2.1.0
178
+ version: 2.3.0
165
179
  required_rubygems_version: !ruby/object:Gem::Requirement
166
180
  requirements:
167
181
  - - ">="
168
182
  - !ruby/object:Gem::Version
169
183
  version: '0'
170
184
  requirements: []
171
- rubygems_version: 3.3.7
185
+ rubygems_version: 3.4.1
172
186
  signing_key:
173
187
  specification_version: 4
174
188
  summary: ServerEngine - multiprocess server framework