serverengine 2.3.0 → 2.3.2

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 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