fluentd 1.12.2-x86-mingw32 → 1.13.2-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +69 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +38 -0
- data/.github/workflows/linux-test.yaml +1 -1
- data/.github/workflows/windows-test.yaml +19 -3
- data/.gitlab-ci.yml +19 -19
- data/CHANGELOG.md +153 -0
- data/CONTRIBUTING.md +2 -2
- data/MAINTAINERS.md +1 -1
- data/README.md +8 -5
- data/bin/fluentd +8 -1
- data/example/counter.conf +1 -1
- data/fluentd.gemspec +4 -3
- data/lib/fluent/command/cat.rb +19 -3
- data/lib/fluent/command/fluentd.rb +1 -2
- data/lib/fluent/command/plugin_generator.rb +42 -2
- data/lib/fluent/config.rb +1 -1
- data/lib/fluent/config/section.rb +5 -0
- data/lib/fluent/config/types.rb +15 -0
- data/lib/fluent/config/v1_parser.rb +3 -2
- data/lib/fluent/env.rb +2 -1
- data/lib/fluent/log.rb +1 -0
- data/lib/fluent/oj_options.rb +62 -0
- data/lib/fluent/plugin/file_wrapper.rb +49 -4
- data/lib/fluent/plugin/formatter.rb +1 -0
- data/lib/fluent/plugin/formatter_json.rb +9 -7
- data/lib/fluent/plugin/in_http.rb +10 -0
- data/lib/fluent/plugin/in_tail.rb +150 -39
- data/lib/fluent/plugin/in_tail/position_file.rb +15 -1
- data/lib/fluent/plugin/out_forward.rb +14 -33
- data/lib/fluent/plugin/output.rb +11 -9
- data/lib/fluent/plugin/parser_csv.rb +2 -2
- data/lib/fluent/plugin/parser_json.rb +2 -3
- data/lib/fluent/plugin/parser_syslog.rb +2 -2
- data/lib/fluent/plugin/service_discovery.rb +0 -15
- data/lib/fluent/plugin/storage_local.rb +1 -1
- data/lib/fluent/plugin_helper/http_server/router.rb +1 -1
- data/lib/fluent/plugin_helper/server.rb +4 -2
- data/lib/fluent/plugin_helper/service_discovery.rb +39 -1
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +11 -5
- data/lib/fluent/plugin_helper/socket_option.rb +2 -2
- data/lib/fluent/supervisor.rb +15 -0
- data/lib/fluent/system_config.rb +14 -0
- data/lib/fluent/test/driver/storage.rb +30 -0
- data/lib/fluent/version.rb +1 -1
- data/templates/new_gem/fluent-plugin.gemspec.erb +3 -3
- data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
- data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
- data/test/command/test_cat.rb +99 -0
- data/test/command/test_plugin_generator.rb +2 -1
- data/test/config/test_section.rb +9 -0
- data/test/config/test_system_config.rb +46 -0
- data/test/config/test_types.rb +7 -0
- data/test/plugin/in_tail/test_io_handler.rb +4 -4
- data/test/plugin/in_tail/test_position_file.rb +54 -0
- data/test/plugin/out_forward/test_connection_manager.rb +0 -6
- data/test/plugin/test_file_wrapper.rb +115 -0
- data/test/plugin/test_in_forward.rb +59 -83
- data/test/plugin/test_in_http.rb +58 -40
- data/test/plugin/test_in_syslog.rb +66 -56
- data/test/plugin/test_in_tail.rb +329 -10
- data/test/plugin/test_in_tcp.rb +45 -32
- data/test/plugin/test_in_udp.rb +47 -33
- data/test/plugin/test_out_forward.rb +138 -105
- data/test/plugin/test_out_stream.rb +18 -8
- data/test/plugin/test_output.rb +15 -3
- data/test/plugin/test_output_as_buffered_backup.rb +2 -0
- data/test/plugin/test_parser_csv.rb +14 -0
- data/test/plugin/test_parser_syslog.rb +14 -0
- data/test/plugin_helper/http_server/test_route.rb +1 -1
- data/test/plugin_helper/service_discovery/test_manager.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +1 -1
- data/test/plugin_helper/test_http_server_helper.rb +34 -27
- data/test/plugin_helper/test_server.rb +144 -139
- data/test/plugin_helper/test_service_discovery.rb +74 -14
- data/test/plugin_helper/test_socket.rb +16 -9
- data/test/test_config.rb +2 -1
- data/test/test_event_time.rb +2 -2
- data/test/test_oj_options.rb +55 -0
- data/test/test_output.rb +2 -2
- data/test/test_supervisor.rb +35 -0
- metadata +41 -11
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
data/test/plugin/test_in_udp.rb
CHANGED
@@ -5,21 +5,33 @@ require 'fluent/plugin/in_udp'
|
|
5
5
|
class UdpInputTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
7
|
Fluent::Test.setup
|
8
|
+
@port = unused_port
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
def teardown
|
12
|
+
@port = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_config
|
16
|
+
%[
|
17
|
+
port #{@port}
|
18
|
+
tag udp
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def ipv4_config
|
23
|
+
base_config + %!
|
24
|
+
bind 127.0.0.1
|
25
|
+
format /^\\[(?<time>[^\\]]*)\\] (?<message>.*)/
|
26
|
+
!
|
27
|
+
end
|
28
|
+
|
29
|
+
def ipv6_config
|
30
|
+
base_config + %!
|
31
|
+
bind ::1
|
32
|
+
format /^\\[(?<time>[^\\]]*)\\] (?<message>.*)/
|
33
|
+
!
|
34
|
+
end
|
23
35
|
|
24
36
|
def create_driver(conf)
|
25
37
|
Fluent::Test::Driver::Input.new(Fluent::Plugin::UdpInput).configure(conf)
|
@@ -45,15 +57,16 @@ class UdpInputTest < Test::Unit::TestCase
|
|
45
57
|
end
|
46
58
|
|
47
59
|
data(
|
48
|
-
'ipv4' => [
|
49
|
-
'ipv6' => [
|
60
|
+
'ipv4' => ['127.0.0.1', :ipv4],
|
61
|
+
'ipv6' => ['::1', :ipv6],
|
50
62
|
)
|
51
63
|
test 'configure' do |data|
|
52
|
-
|
64
|
+
bind, protocol = data
|
65
|
+
conf = send("#{protocol}_config")
|
53
66
|
omit "IPv6 is not supported on this environment" if protocol == :ipv6 && !ipv6_enabled?
|
54
67
|
|
55
68
|
d = create_driver(conf)
|
56
|
-
assert_equal
|
69
|
+
assert_equal @port, d.instance.port
|
57
70
|
assert_equal bind, d.instance.bind
|
58
71
|
assert_equal 4096, d.instance.message_length_limit
|
59
72
|
assert_equal nil, d.instance.receive_buffer_size
|
@@ -61,16 +74,17 @@ class UdpInputTest < Test::Unit::TestCase
|
|
61
74
|
|
62
75
|
test ' configure w/o parse section' do
|
63
76
|
assert_raise(Fluent::ConfigError.new("<parse> section is required.")) {
|
64
|
-
create_driver(
|
77
|
+
create_driver(base_config)
|
65
78
|
}
|
66
79
|
end
|
67
80
|
|
68
81
|
data(
|
69
|
-
'ipv4' => [
|
70
|
-
'ipv6' => [
|
82
|
+
'ipv4' => ['127.0.0.1', :ipv4],
|
83
|
+
'ipv6' => ['::1', :ipv6],
|
71
84
|
)
|
72
85
|
test 'time_format' do |data|
|
73
|
-
|
86
|
+
bind, protocol = data
|
87
|
+
conf = send("#{protocol}_config")
|
74
88
|
omit "IPv6 is not supported on this environment" if protocol == :ipv6 && !ipv6_enabled?
|
75
89
|
|
76
90
|
d = create_driver(conf)
|
@@ -81,7 +95,7 @@ class UdpInputTest < Test::Unit::TestCase
|
|
81
95
|
]
|
82
96
|
|
83
97
|
d.run(expect_records: 2) do
|
84
|
-
create_udp_socket(bind,
|
98
|
+
create_udp_socket(bind, @port) do |u|
|
85
99
|
tests.each do |test|
|
86
100
|
u.send(test['msg'], 0)
|
87
101
|
end
|
@@ -100,7 +114,7 @@ class UdpInputTest < Test::Unit::TestCase
|
|
100
114
|
)
|
101
115
|
test 'message_length_limit/body_size_limit compatibility' do |param|
|
102
116
|
|
103
|
-
d = create_driver(
|
117
|
+
d = create_driver(ipv4_config + param)
|
104
118
|
assert_equal 2048, d.instance.message_length_limit
|
105
119
|
end
|
106
120
|
|
@@ -141,9 +155,9 @@ class UdpInputTest < Test::Unit::TestCase
|
|
141
155
|
payloads = data['payloads']
|
142
156
|
expecteds = data['expecteds']
|
143
157
|
|
144
|
-
d = create_driver(
|
158
|
+
d = create_driver(base_config + "format #{format}")
|
145
159
|
d.run(expect_records: 2) do
|
146
|
-
create_udp_socket('127.0.0.1',
|
160
|
+
create_udp_socket('127.0.0.1', @port) do |u|
|
147
161
|
payloads.each do |payload|
|
148
162
|
u.send(payload, 0)
|
149
163
|
end
|
@@ -159,13 +173,13 @@ class UdpInputTest < Test::Unit::TestCase
|
|
159
173
|
end
|
160
174
|
|
161
175
|
test 'remove_newline' do
|
162
|
-
d = create_driver(
|
176
|
+
d = create_driver(base_config + %!
|
163
177
|
format none
|
164
178
|
remove_newline false
|
165
179
|
!)
|
166
180
|
payloads = ["test1\n", "test2\n"]
|
167
181
|
d.run(expect_records: 2) do
|
168
|
-
create_udp_socket('127.0.0.1',
|
182
|
+
create_udp_socket('127.0.0.1', @port) do |u|
|
169
183
|
payloads.each do |payload|
|
170
184
|
u.send(payload, 0)
|
171
185
|
end
|
@@ -182,13 +196,13 @@ class UdpInputTest < Test::Unit::TestCase
|
|
182
196
|
end
|
183
197
|
|
184
198
|
test 'source_hostname_key' do
|
185
|
-
d = create_driver(
|
199
|
+
d = create_driver(base_config + %!
|
186
200
|
format none
|
187
201
|
source_hostname_key host
|
188
202
|
!)
|
189
203
|
hostname = nil
|
190
204
|
d.run(expect_records: 1) do
|
191
|
-
create_udp_socket('127.0.0.1',
|
205
|
+
create_udp_socket('127.0.0.1', @port) do |u|
|
192
206
|
u.send("test", 0)
|
193
207
|
hostname = u.peeraddr[2]
|
194
208
|
end
|
@@ -201,13 +215,13 @@ class UdpInputTest < Test::Unit::TestCase
|
|
201
215
|
end
|
202
216
|
|
203
217
|
test 'source_address_key' do
|
204
|
-
d = create_driver(
|
218
|
+
d = create_driver(base_config + %!
|
205
219
|
format none
|
206
220
|
source_address_key addr
|
207
221
|
!)
|
208
222
|
address = nil
|
209
223
|
d.run(expect_records: 1) do
|
210
|
-
create_udp_socket('127.0.0.1',
|
224
|
+
create_udp_socket('127.0.0.1', @port) do |u|
|
211
225
|
u.send("test", 0)
|
212
226
|
address = u.peeraddr[3]
|
213
227
|
end
|
@@ -223,7 +237,7 @@ class UdpInputTest < Test::Unit::TestCase
|
|
223
237
|
# doesn't check exact value because it depends on platform and condition
|
224
238
|
|
225
239
|
# check if default socket and in_udp's one without receive_buffer_size have same size buffer
|
226
|
-
d0 = create_driver(
|
240
|
+
d0 = create_driver(base_config + %!
|
227
241
|
format none
|
228
242
|
!)
|
229
243
|
d0.run do
|
@@ -237,7 +251,7 @@ class UdpInputTest < Test::Unit::TestCase
|
|
237
251
|
end
|
238
252
|
|
239
253
|
# check if default socket and in_udp's one with receive_buffer_size have different size buffer
|
240
|
-
d1 = create_driver(
|
254
|
+
d1 = create_driver(base_config + %!
|
241
255
|
format none
|
242
256
|
receive_buffer_size 1001
|
243
257
|
!)
|
@@ -12,32 +12,38 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
12
12
|
FileUtils.rm_rf(TMP_DIR)
|
13
13
|
FileUtils.mkdir_p(TMP_DIR)
|
14
14
|
@d = nil
|
15
|
+
@target_port = unused_port
|
15
16
|
end
|
16
17
|
|
17
18
|
def teardown
|
18
19
|
@d.instance_shutdown if @d
|
20
|
+
@port = nil
|
19
21
|
end
|
20
22
|
|
21
23
|
TMP_DIR = File.join(__dir__, "../tmp/out_forward#{ENV['TEST_ENV_NUMBER']}")
|
22
24
|
|
23
25
|
TARGET_HOST = '127.0.0.1'
|
24
|
-
TARGET_PORT = unused_port
|
25
|
-
CONFIG = %[
|
26
|
-
send_timeout 51
|
27
|
-
heartbeat_type udp
|
28
|
-
<server>
|
29
|
-
name test
|
30
|
-
host #{TARGET_HOST}
|
31
|
-
port #{TARGET_PORT}
|
32
|
-
</server>
|
33
|
-
]
|
34
26
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
27
|
+
def config
|
28
|
+
%[
|
29
|
+
send_timeout 51
|
30
|
+
heartbeat_type udp
|
31
|
+
<server>
|
32
|
+
name test
|
33
|
+
host #{TARGET_HOST}
|
34
|
+
port #{@target_port}
|
35
|
+
</server>
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
def target_config
|
40
|
+
%[
|
41
|
+
port #{@target_port}
|
42
|
+
bind #{TARGET_HOST}
|
43
|
+
]
|
44
|
+
end
|
39
45
|
|
40
|
-
def create_driver(conf=
|
46
|
+
def create_driver(conf=config)
|
41
47
|
Fluent::Test::Driver::Output.new(Fluent::Plugin::ForwardOutput) {
|
42
48
|
attr_reader :sent_chunk_ids, :ack_handler, :discovery_manager
|
43
49
|
|
@@ -60,7 +66,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
60
66
|
<server>
|
61
67
|
name test
|
62
68
|
host #{TARGET_HOST}
|
63
|
-
port #{
|
69
|
+
port #{@target_port}
|
64
70
|
</server>
|
65
71
|
])
|
66
72
|
nodes = d.instance.nodes
|
@@ -71,7 +77,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
71
77
|
node = nodes.first
|
72
78
|
assert_equal "test", node.name
|
73
79
|
assert_equal '127.0.0.1', node.host
|
74
|
-
assert_equal
|
80
|
+
assert_equal @target_port, node.port
|
75
81
|
end
|
76
82
|
|
77
83
|
test 'configure_traditional' do
|
@@ -80,7 +86,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
80
86
|
<server>
|
81
87
|
name test
|
82
88
|
host #{TARGET_HOST}
|
83
|
-
port #{
|
89
|
+
port #{@target_port}
|
84
90
|
</server>
|
85
91
|
buffer_chunk_limit 10m
|
86
92
|
EOL
|
@@ -100,7 +106,7 @@ EOL
|
|
100
106
|
ack_response_timeout 20
|
101
107
|
<server>
|
102
108
|
host #{TARGET_HOST}
|
103
|
-
port #{
|
109
|
+
port #{@target_port}
|
104
110
|
</server>
|
105
111
|
])
|
106
112
|
assert_equal 30, d.instance.send_timeout
|
@@ -110,33 +116,33 @@ EOL
|
|
110
116
|
end
|
111
117
|
|
112
118
|
test 'configure_udp_heartbeat' do
|
113
|
-
@d = d = create_driver(
|
119
|
+
@d = d = create_driver(config + "\nheartbeat_type udp")
|
114
120
|
assert_equal :udp, d.instance.heartbeat_type
|
115
121
|
end
|
116
122
|
|
117
123
|
test 'configure_none_heartbeat' do
|
118
|
-
@d = d = create_driver(
|
124
|
+
@d = d = create_driver(config + "\nheartbeat_type none")
|
119
125
|
assert_equal :none, d.instance.heartbeat_type
|
120
126
|
end
|
121
127
|
|
122
128
|
test 'configure_expire_dns_cache' do
|
123
|
-
@d = d = create_driver(
|
129
|
+
@d = d = create_driver(config + "\nexpire_dns_cache 5")
|
124
130
|
assert_equal 5, d.instance.expire_dns_cache
|
125
131
|
end
|
126
132
|
|
127
133
|
test 'configure_dns_round_robin udp' do
|
128
134
|
assert_raise(Fluent::ConfigError) do
|
129
|
-
create_driver(
|
135
|
+
create_driver(config + "\nheartbeat_type udp\ndns_round_robin true")
|
130
136
|
end
|
131
137
|
end
|
132
138
|
|
133
139
|
test 'configure_dns_round_robin transport' do
|
134
|
-
@d = d = create_driver(
|
140
|
+
@d = d = create_driver(config + "\nheartbeat_type transport\ndns_round_robin true")
|
135
141
|
assert_equal true, d.instance.dns_round_robin
|
136
142
|
end
|
137
143
|
|
138
144
|
test 'configure_dns_round_robin none' do
|
139
|
-
@d = d = create_driver(
|
145
|
+
@d = d = create_driver(config + "\nheartbeat_type none\ndns_round_robin true")
|
140
146
|
assert_equal true, d.instance.dns_round_robin
|
141
147
|
end
|
142
148
|
|
@@ -176,7 +182,7 @@ EOL
|
|
176
182
|
#{param} #{dummy_cert_path}
|
177
183
|
<server>
|
178
184
|
host #{TARGET_HOST}
|
179
|
-
port #{
|
185
|
+
port #{@target_port}
|
180
186
|
</server>
|
181
187
|
]
|
182
188
|
|
@@ -195,7 +201,7 @@ EOL
|
|
195
201
|
tls_cert_thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b
|
196
202
|
<server>
|
197
203
|
host #{TARGET_HOST}
|
198
|
-
port #{
|
204
|
+
port #{@target_port}
|
199
205
|
</server>
|
200
206
|
]
|
201
207
|
|
@@ -210,7 +216,7 @@ EOL
|
|
210
216
|
transport tls
|
211
217
|
<server>
|
212
218
|
host #{TARGET_HOST}
|
213
|
-
port #{
|
219
|
+
port #{@target_port}
|
214
220
|
</server>
|
215
221
|
]
|
216
222
|
|
@@ -232,7 +238,7 @@ EOL
|
|
232
238
|
tls_cert_logical_store_name Root
|
233
239
|
<server>
|
234
240
|
host #{TARGET_HOST}
|
235
|
-
port #{
|
241
|
+
port #{@target_port}
|
236
242
|
</server>
|
237
243
|
]
|
238
244
|
|
@@ -250,7 +256,7 @@ EOL
|
|
250
256
|
tls_cert_thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b
|
251
257
|
<server>
|
252
258
|
host #{TARGET_HOST}
|
253
|
-
port #{
|
259
|
+
port #{@target_port}
|
254
260
|
</server>
|
255
261
|
]
|
256
262
|
|
@@ -277,11 +283,16 @@ EOL
|
|
277
283
|
</service_discovery>
|
278
284
|
])
|
279
285
|
|
280
|
-
|
281
|
-
assert_equal
|
282
|
-
|
283
|
-
|
284
|
-
|
286
|
+
|
287
|
+
assert_equal(
|
288
|
+
[
|
289
|
+
{ host: '127.0.0.1', port: 1234 },
|
290
|
+
{ host: '127.0.0.1', port: 1235 },
|
291
|
+
],
|
292
|
+
d.instance.discovery_manager.services.collect do |service|
|
293
|
+
{ host: service.host, port: service.port }
|
294
|
+
end
|
295
|
+
)
|
285
296
|
end
|
286
297
|
|
287
298
|
test 'pass username and password as empty string to HandshakeProtocol' do
|
@@ -316,7 +327,7 @@ EOL
|
|
316
327
|
end
|
317
328
|
|
318
329
|
test 'set_compress_is_gzip' do
|
319
|
-
@d = d = create_driver(
|
330
|
+
@d = d = create_driver(config + %[compress gzip])
|
320
331
|
assert_equal :gzip, d.instance.compress
|
321
332
|
assert_equal :gzip, d.instance.buffer.compress
|
322
333
|
|
@@ -328,7 +339,7 @@ EOL
|
|
328
339
|
mock = flexmock($log)
|
329
340
|
mock.should_receive(:log).with("buffer is compressed. If you also want to save the bandwidth of a network, Add `compress` configuration in <match>")
|
330
341
|
|
331
|
-
@d = d = create_driver(
|
342
|
+
@d = d = create_driver(config + %[
|
332
343
|
<buffer>
|
333
344
|
type memory
|
334
345
|
compress gzip
|
@@ -342,7 +353,7 @@ EOL
|
|
342
353
|
end
|
343
354
|
|
344
355
|
test 'phi_failure_detector disabled' do
|
345
|
-
@d = d = create_driver(
|
356
|
+
@d = d = create_driver(config + %[phi_failure_detector false \n phi_threshold 0])
|
346
357
|
node = d.instance.nodes.first
|
347
358
|
stub(node.failure).phi { raise 'Should not be called' }
|
348
359
|
node.tick
|
@@ -350,20 +361,20 @@ EOL
|
|
350
361
|
end
|
351
362
|
|
352
363
|
test 'phi_failure_detector enabled' do
|
353
|
-
@d = d = create_driver(
|
364
|
+
@d = d = create_driver(config + %[phi_failure_detector true \n phi_threshold 0])
|
354
365
|
node = d.instance.nodes.first
|
355
366
|
node.tick
|
356
367
|
assert_false node.available?
|
357
368
|
end
|
358
369
|
|
359
370
|
test 'require_ack_response is disabled in default' do
|
360
|
-
@d = d = create_driver(
|
371
|
+
@d = d = create_driver(config)
|
361
372
|
assert_equal false, d.instance.require_ack_response
|
362
373
|
assert_equal 190, d.instance.ack_response_timeout
|
363
374
|
end
|
364
375
|
|
365
376
|
test 'require_ack_response can be enabled' do
|
366
|
-
@d = d = create_driver(
|
377
|
+
@d = d = create_driver(config + %[
|
367
378
|
require_ack_response true
|
368
379
|
ack_response_timeout 2s
|
369
380
|
])
|
@@ -373,7 +384,7 @@ EOL
|
|
373
384
|
end
|
374
385
|
|
375
386
|
test 'suspend_flush is disable before before_shutdown' do
|
376
|
-
@d = d = create_driver(
|
387
|
+
@d = d = create_driver(config + %[
|
377
388
|
require_ack_response true
|
378
389
|
ack_response_timeout 2s
|
379
390
|
])
|
@@ -382,7 +393,7 @@ EOL
|
|
382
393
|
end
|
383
394
|
|
384
395
|
test 'suspend_flush should be enabled and try_flush returns nil after before_shutdown' do
|
385
|
-
@d = d = create_driver(
|
396
|
+
@d = d = create_driver(config + %[
|
386
397
|
require_ack_response true
|
387
398
|
ack_response_timeout 2s
|
388
399
|
])
|
@@ -393,12 +404,12 @@ EOL
|
|
393
404
|
end
|
394
405
|
|
395
406
|
test 'verify_connection_at_startup is disabled in default' do
|
396
|
-
@d = d = create_driver(
|
407
|
+
@d = d = create_driver(config)
|
397
408
|
assert_false d.instance.verify_connection_at_startup
|
398
409
|
end
|
399
410
|
|
400
411
|
test 'verify_connection_at_startup can be enabled' do
|
401
|
-
@d = d = create_driver(
|
412
|
+
@d = d = create_driver(config + %[
|
402
413
|
verify_connection_at_startup true
|
403
414
|
])
|
404
415
|
assert_true d.instance.verify_connection_at_startup
|
@@ -407,7 +418,7 @@ EOL
|
|
407
418
|
test 'send tags in str (utf-8 strings)' do
|
408
419
|
target_input_driver = create_target_input_driver
|
409
420
|
|
410
|
-
@d = d = create_driver(
|
421
|
+
@d = d = create_driver(config + %[flush_interval 1s])
|
411
422
|
|
412
423
|
time = event_time("2011-01-02 13:14:15 UTC")
|
413
424
|
|
@@ -440,7 +451,7 @@ EOL
|
|
440
451
|
test 'send_with_time_as_integer' do
|
441
452
|
target_input_driver = create_target_input_driver
|
442
453
|
|
443
|
-
@d = d = create_driver(
|
454
|
+
@d = d = create_driver(config + %[flush_interval 1s])
|
444
455
|
|
445
456
|
time = event_time("2011-01-02 13:14:15 UTC")
|
446
457
|
|
@@ -468,7 +479,7 @@ EOL
|
|
468
479
|
test 'send_without_time_as_integer' do
|
469
480
|
target_input_driver = create_target_input_driver
|
470
481
|
|
471
|
-
@d = d = create_driver(
|
482
|
+
@d = d = create_driver(config + %[
|
472
483
|
flush_interval 1s
|
473
484
|
time_as_integer false
|
474
485
|
])
|
@@ -498,7 +509,7 @@ EOL
|
|
498
509
|
test 'send_comprssed_message_pack_stream_if_compress_is_gzip' do
|
499
510
|
target_input_driver = create_target_input_driver
|
500
511
|
|
501
|
-
@d = d = create_driver(
|
512
|
+
@d = d = create_driver(config + %[
|
502
513
|
flush_interval 1s
|
503
514
|
compress gzip
|
504
515
|
])
|
@@ -528,7 +539,7 @@ EOL
|
|
528
539
|
test 'send_to_a_node_supporting_responses' do
|
529
540
|
target_input_driver = create_target_input_driver
|
530
541
|
|
531
|
-
@d = d = create_driver(
|
542
|
+
@d = d = create_driver(config + %[flush_interval 1s])
|
532
543
|
|
533
544
|
time = event_time("2011-01-02 13:14:15 UTC")
|
534
545
|
|
@@ -554,7 +565,7 @@ EOL
|
|
554
565
|
test 'send_to_a_node_not_supporting_responses' do
|
555
566
|
target_input_driver = create_target_input_driver
|
556
567
|
|
557
|
-
@d = d = create_driver(
|
568
|
+
@d = d = create_driver(config + %[flush_interval 1s])
|
558
569
|
|
559
570
|
time = event_time("2011-01-02 13:14:15 UTC")
|
560
571
|
|
@@ -580,38 +591,43 @@ EOL
|
|
580
591
|
test 'a node supporting responses' do
|
581
592
|
target_input_driver = create_target_input_driver
|
582
593
|
|
583
|
-
@d = d = create_driver(
|
594
|
+
@d = d = create_driver(config + %[
|
584
595
|
require_ack_response true
|
585
596
|
ack_response_timeout 1s
|
586
597
|
<buffer tag>
|
587
598
|
flush_mode immediate
|
588
599
|
retry_type periodic
|
589
600
|
retry_wait 30s
|
590
|
-
flush_at_shutdown
|
601
|
+
flush_at_shutdown true
|
591
602
|
</buffer>
|
592
603
|
])
|
593
604
|
|
594
605
|
time = event_time("2011-01-02 13:14:15 UTC")
|
595
606
|
|
596
607
|
acked_chunk_ids = []
|
608
|
+
nacked = false
|
597
609
|
mock.proxy(d.instance.ack_handler).read_ack_from_sock(anything) do |info, success|
|
598
610
|
if success
|
599
611
|
acked_chunk_ids << info.chunk_id
|
612
|
+
else
|
613
|
+
nacked = true
|
600
614
|
end
|
601
|
-
[
|
615
|
+
[info, success]
|
602
616
|
end
|
603
617
|
|
604
618
|
records = [
|
605
619
|
{"a" => 1},
|
606
620
|
{"a" => 2}
|
607
621
|
]
|
608
|
-
target_input_driver.run(expect_records: 2) do
|
609
|
-
d.end_if { acked_chunk_ids.size > 0 }
|
622
|
+
target_input_driver.run(expect_records: 2, timeout: 5) do
|
623
|
+
d.end_if { acked_chunk_ids.size > 0 || nacked }
|
610
624
|
d.run(default_tag: 'test', wait_flush_completion: false, shutdown: false) do
|
611
625
|
d.feed([[time, records[0]], [time,records[1]]])
|
612
626
|
end
|
613
627
|
end
|
614
628
|
|
629
|
+
assert(!nacked, d.instance.log.logs.join)
|
630
|
+
|
615
631
|
events = target_input_driver.events
|
616
632
|
assert_equal ['test', time, records[0]], events[0]
|
617
633
|
assert_equal ['test', time, records[1]], events[1]
|
@@ -623,33 +639,36 @@ EOL
|
|
623
639
|
test 'a node supporting responses after stop' do
|
624
640
|
target_input_driver = create_target_input_driver
|
625
641
|
|
626
|
-
@d = d = create_driver(
|
642
|
+
@d = d = create_driver(config + %[
|
627
643
|
require_ack_response true
|
628
|
-
ack_response_timeout
|
644
|
+
ack_response_timeout 10s
|
629
645
|
<buffer tag>
|
630
646
|
flush_mode immediate
|
631
647
|
retry_type periodic
|
632
648
|
retry_wait 30s
|
633
|
-
flush_at_shutdown
|
649
|
+
flush_at_shutdown true
|
634
650
|
</buffer>
|
635
651
|
])
|
636
652
|
|
637
653
|
time = event_time("2011-01-02 13:14:15 UTC")
|
638
654
|
|
639
655
|
acked_chunk_ids = []
|
656
|
+
nacked = false
|
640
657
|
mock.proxy(d.instance.ack_handler).read_ack_from_sock(anything) do |info, success|
|
641
658
|
if success
|
642
659
|
acked_chunk_ids << info.chunk_id
|
660
|
+
else
|
661
|
+
nacked = true
|
643
662
|
end
|
644
|
-
[
|
663
|
+
[info, success]
|
645
664
|
end
|
646
665
|
|
647
666
|
records = [
|
648
667
|
{"a" => 1},
|
649
668
|
{"a" => 2}
|
650
669
|
]
|
651
|
-
target_input_driver.run(expect_records: 2) do
|
652
|
-
d.end_if { acked_chunk_ids.size > 0 }
|
670
|
+
target_input_driver.run(expect_records: 2, timeout: 5) do
|
671
|
+
d.end_if { acked_chunk_ids.size > 0 || nacked }
|
653
672
|
d.run(default_tag: 'test', wait_flush_completion: false, shutdown: false) do
|
654
673
|
d.instance.stop
|
655
674
|
d.feed([[time, records[0]], [time,records[1]]])
|
@@ -659,6 +678,8 @@ EOL
|
|
659
678
|
end
|
660
679
|
end
|
661
680
|
|
681
|
+
assert(!nacked, d.instance.log.logs.join)
|
682
|
+
|
662
683
|
events = target_input_driver.events
|
663
684
|
assert_equal ['test', time, records[0]], events[0]
|
664
685
|
assert_equal ['test', time, records[1]], events[1]
|
@@ -672,7 +693,7 @@ EOL
|
|
672
693
|
test 'TLS transport and ack parameter combination' do |ack|
|
673
694
|
omit "TLS and 'ack false' always fails on AppVeyor. Need to debug" if Fluent.windows? && !ack
|
674
695
|
|
675
|
-
input_conf =
|
696
|
+
input_conf = target_config + %[
|
676
697
|
<transport tls>
|
677
698
|
insecure true
|
678
699
|
</transport>
|
@@ -686,7 +707,7 @@ EOL
|
|
686
707
|
tls_insecure_mode true
|
687
708
|
<server>
|
688
709
|
host #{TARGET_HOST}
|
689
|
-
port #{
|
710
|
+
port #{@target_port}
|
690
711
|
</server>
|
691
712
|
<buffer>
|
692
713
|
#flush_mode immediate
|
@@ -715,7 +736,7 @@ EOL
|
|
715
736
|
test 'a destination node not supporting responses by just ignoring' do
|
716
737
|
target_input_driver = create_target_input_driver(response_stub: ->(_option) { nil }, disconnect: false)
|
717
738
|
|
718
|
-
@d = d = create_driver(
|
739
|
+
@d = d = create_driver(config + %[
|
719
740
|
require_ack_response true
|
720
741
|
ack_response_timeout 1s
|
721
742
|
<buffer tag>
|
@@ -760,7 +781,7 @@ EOL
|
|
760
781
|
test 'a destination node not supporting responses by disconnection' do
|
761
782
|
target_input_driver = create_target_input_driver(response_stub: ->(_option) { nil }, disconnect: true)
|
762
783
|
|
763
|
-
@d = d = create_driver(
|
784
|
+
@d = d = create_driver(config + %[
|
764
785
|
require_ack_response true
|
765
786
|
ack_response_timeout 1s
|
766
787
|
<buffer tag>
|
@@ -803,7 +824,7 @@ EOL
|
|
803
824
|
end
|
804
825
|
|
805
826
|
test 'authentication_with_shared_key' do
|
806
|
-
input_conf =
|
827
|
+
input_conf = target_config + %[
|
807
828
|
<security>
|
808
829
|
self_hostname in.localhost
|
809
830
|
shared_key fluentd-sharedkey
|
@@ -823,7 +844,7 @@ EOL
|
|
823
844
|
<server>
|
824
845
|
name test
|
825
846
|
host #{TARGET_HOST}
|
826
|
-
port #{
|
847
|
+
port #{@target_port}
|
827
848
|
shared_key fluentd-sharedkey
|
828
849
|
</server>
|
829
850
|
]
|
@@ -850,7 +871,7 @@ EOL
|
|
850
871
|
end
|
851
872
|
|
852
873
|
test 'keepalive + shared_key' do
|
853
|
-
input_conf =
|
874
|
+
input_conf = target_config + %[
|
854
875
|
<security>
|
855
876
|
self_hostname in.localhost
|
856
877
|
shared_key fluentd-sharedkey
|
@@ -868,7 +889,7 @@ EOL
|
|
868
889
|
<server>
|
869
890
|
name test
|
870
891
|
host #{TARGET_HOST}
|
871
|
-
port #{
|
892
|
+
port #{@target_port}
|
872
893
|
</server>
|
873
894
|
]
|
874
895
|
@d = d = create_driver(output_conf)
|
@@ -898,7 +919,7 @@ EOL
|
|
898
919
|
end
|
899
920
|
|
900
921
|
test 'authentication_with_user_auth' do
|
901
|
-
input_conf =
|
922
|
+
input_conf = target_config + %[
|
902
923
|
<security>
|
903
924
|
self_hostname in.localhost
|
904
925
|
shared_key fluentd-sharedkey
|
@@ -923,7 +944,7 @@ EOL
|
|
923
944
|
<server>
|
924
945
|
name test
|
925
946
|
host #{TARGET_HOST}
|
926
|
-
port #{
|
947
|
+
port #{@target_port}
|
927
948
|
shared_key fluentd-sharedkey
|
928
949
|
username fluentd
|
929
950
|
password fluentd
|
@@ -953,7 +974,7 @@ EOL
|
|
953
974
|
|
954
975
|
# This test is not 100% but test failed with previous Node implementation which has race condition
|
955
976
|
test 'Node with security is thread-safe on multi threads' do
|
956
|
-
input_conf =
|
977
|
+
input_conf = target_config + %[
|
957
978
|
<security>
|
958
979
|
self_hostname in.localhost
|
959
980
|
shared_key fluentd-sharedkey
|
@@ -972,7 +993,7 @@ EOL
|
|
972
993
|
<server>
|
973
994
|
name test
|
974
995
|
host #{TARGET_HOST}
|
975
|
-
port #{
|
996
|
+
port #{@target_port}
|
976
997
|
shared_key fluentd-sharedkey
|
977
998
|
</server>
|
978
999
|
]
|
@@ -993,10 +1014,12 @@ EOL
|
|
993
1014
|
end
|
994
1015
|
|
995
1016
|
logs = d.logs
|
996
|
-
assert_false(logs.any? { |log|
|
1017
|
+
assert_false(logs.any? { |log|
|
1018
|
+
log.include?("invalid format for PONG message") || log.include?("shared key mismatch")
|
1019
|
+
}, "Actual log:\n#{logs.join}")
|
997
1020
|
end
|
998
1021
|
|
999
|
-
def create_target_input_driver(response_stub: nil, disconnect: false, conf:
|
1022
|
+
def create_target_input_driver(response_stub: nil, disconnect: false, conf: target_config)
|
1000
1023
|
require 'fluent/plugin/in_forward'
|
1001
1024
|
|
1002
1025
|
# TODO: Support actual TCP heartbeat test
|
@@ -1012,7 +1035,7 @@ EOL
|
|
1012
1035
|
end
|
1013
1036
|
|
1014
1037
|
test 'heartbeat_type_none' do
|
1015
|
-
@d = d = create_driver(
|
1038
|
+
@d = d = create_driver(config + "\nheartbeat_type none")
|
1016
1039
|
node = d.instance.nodes.first
|
1017
1040
|
assert_equal Fluent::Plugin::ForwardOutput::NoneHeartbeatNode, node.class
|
1018
1041
|
|
@@ -1026,7 +1049,7 @@ EOL
|
|
1026
1049
|
end
|
1027
1050
|
|
1028
1051
|
test 'heartbeat_type_udp' do
|
1029
|
-
@d = d = create_driver(
|
1052
|
+
@d = d = create_driver(config + "\nheartbeat_type udp")
|
1030
1053
|
|
1031
1054
|
d.instance_start
|
1032
1055
|
usock = d.instance.instance_variable_get(:@usock)
|
@@ -1037,7 +1060,7 @@ EOL
|
|
1037
1060
|
assert servers.find{|s| s.title == :out_forward_heartbeat_receiver }
|
1038
1061
|
assert timers.include?(:out_forward_heartbeat_request)
|
1039
1062
|
|
1040
|
-
mock(usock).send("\0", 0, Socket.pack_sockaddr_in(
|
1063
|
+
mock(usock).send("\0", 0, Socket.pack_sockaddr_in(@target_port, '127.0.0.1')).once
|
1041
1064
|
d.instance.send(:on_heartbeat_timer)
|
1042
1065
|
end
|
1043
1066
|
|
@@ -1061,11 +1084,9 @@ EOL
|
|
1061
1084
|
end
|
1062
1085
|
|
1063
1086
|
test 'when out_forward has @id' do
|
1064
|
-
omit "Proxy of RR doesn't support kwargs of Ruby 3 yet" if RUBY_VERSION.split('.')[0].to_i >= 3
|
1065
|
-
|
1066
1087
|
# cancel https://github.com/fluent/fluentd/blob/077508ac817b7637307434d0c978d7cdc3d1c534/lib/fluent/plugin_id.rb#L43-L53
|
1067
1088
|
# it always return true in test
|
1068
|
-
mock.proxy(Fluent::Plugin).new_sd(
|
1089
|
+
mock.proxy(Fluent::Plugin).new_sd('static', parent: anything) { |v|
|
1069
1090
|
stub(v).plugin_id_for_test? { false }
|
1070
1091
|
}.once
|
1071
1092
|
|
@@ -1076,7 +1097,7 @@ EOL
|
|
1076
1097
|
}
|
1077
1098
|
|
1078
1099
|
assert_nothing_raised do
|
1079
|
-
output.configure(
|
1100
|
+
output.configure(config + %[
|
1080
1101
|
@id unique_out_forward
|
1081
1102
|
])
|
1082
1103
|
end
|
@@ -1084,7 +1105,7 @@ EOL
|
|
1084
1105
|
|
1085
1106
|
sub_test_case 'verify_connection_at_startup' do
|
1086
1107
|
test 'nodes are not available' do
|
1087
|
-
@d = d = create_driver(
|
1108
|
+
@d = d = create_driver(config + %[
|
1088
1109
|
verify_connection_at_startup true
|
1089
1110
|
])
|
1090
1111
|
e = assert_raise Fluent::UnrecoverableError do
|
@@ -1100,7 +1121,7 @@ EOL
|
|
1100
1121
|
end
|
1101
1122
|
|
1102
1123
|
test 'nodes_shared_key_miss_match' do
|
1103
|
-
input_conf =
|
1124
|
+
input_conf = target_config + %[
|
1104
1125
|
<security>
|
1105
1126
|
self_hostname in.localhost
|
1106
1127
|
shared_key fluentd-sharedkey
|
@@ -1117,7 +1138,7 @@ EOL
|
|
1117
1138
|
|
1118
1139
|
<server>
|
1119
1140
|
host #{TARGET_HOST}
|
1120
|
-
port #{
|
1141
|
+
port #{@target_port}
|
1121
1142
|
</server>
|
1122
1143
|
]
|
1123
1144
|
@d = d = create_driver(output_conf)
|
@@ -1131,7 +1152,7 @@ EOL
|
|
1131
1152
|
end
|
1132
1153
|
|
1133
1154
|
test 'nodes_shared_key_miss_match with TLS' do
|
1134
|
-
input_conf =
|
1155
|
+
input_conf = target_config + %[
|
1135
1156
|
<security>
|
1136
1157
|
self_hostname in.localhost
|
1137
1158
|
shared_key fluentd-sharedkey
|
@@ -1152,7 +1173,7 @@ EOL
|
|
1152
1173
|
|
1153
1174
|
<server>
|
1154
1175
|
host #{TARGET_HOST}
|
1155
|
-
port #{
|
1176
|
+
port #{@target_port}
|
1156
1177
|
</server>
|
1157
1178
|
]
|
1158
1179
|
@d = d = create_driver(output_conf)
|
@@ -1167,7 +1188,7 @@ EOL
|
|
1167
1188
|
end
|
1168
1189
|
|
1169
1190
|
test 'nodes_shared_key_match' do
|
1170
|
-
input_conf =
|
1191
|
+
input_conf = target_config + %[
|
1171
1192
|
<security>
|
1172
1193
|
self_hostname in.localhost
|
1173
1194
|
shared_key fluentd-sharedkey
|
@@ -1183,7 +1204,7 @@ EOL
|
|
1183
1204
|
<server>
|
1184
1205
|
name test
|
1185
1206
|
host #{TARGET_HOST}
|
1186
|
-
port #{
|
1207
|
+
port #{@target_port}
|
1187
1208
|
</server>
|
1188
1209
|
]
|
1189
1210
|
@d = d = create_driver(output_conf)
|
@@ -1207,16 +1228,19 @@ EOL
|
|
1207
1228
|
end
|
1208
1229
|
|
1209
1230
|
test 'Create new connection per send_data' do
|
1210
|
-
|
1211
|
-
|
1212
|
-
target_input_driver = create_target_input_driver(conf: TARGET_CONFIG)
|
1213
|
-
output_conf = CONFIG
|
1231
|
+
target_input_driver = create_target_input_driver(conf: target_config)
|
1232
|
+
output_conf = config
|
1214
1233
|
d = create_driver(output_conf)
|
1215
1234
|
d.instance_start
|
1216
1235
|
|
1217
1236
|
begin
|
1218
1237
|
chunk = Fluent::Plugin::Buffer::MemoryChunk.new(Fluent::Plugin::Buffer::Metadata.new(nil, nil, nil))
|
1219
|
-
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST,
|
1238
|
+
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST, @target_port,
|
1239
|
+
linger_timeout: anything,
|
1240
|
+
send_timeout: anything,
|
1241
|
+
recv_timeout: anything,
|
1242
|
+
connect_timeout: anything
|
1243
|
+
) { |sock| mock(sock).close.once; sock }.twice
|
1220
1244
|
|
1221
1245
|
target_input_driver.run(timeout: 15) do
|
1222
1246
|
d.run(shutdown: false) do
|
@@ -1238,7 +1262,7 @@ EOL
|
|
1238
1262
|
name test
|
1239
1263
|
standby
|
1240
1264
|
host #{TARGET_HOST}
|
1241
|
-
port #{
|
1265
|
+
port #{@target_port}
|
1242
1266
|
</server>
|
1243
1267
|
])
|
1244
1268
|
d.instance_start
|
@@ -1247,10 +1271,8 @@ EOL
|
|
1247
1271
|
|
1248
1272
|
sub_test_case 'keepalive' do
|
1249
1273
|
test 'Do not create connection per send_data' do
|
1250
|
-
|
1251
|
-
|
1252
|
-
target_input_driver = create_target_input_driver(conf: TARGET_CONFIG)
|
1253
|
-
output_conf = CONFIG + %[
|
1274
|
+
target_input_driver = create_target_input_driver(conf: target_config)
|
1275
|
+
output_conf = config + %[
|
1254
1276
|
keepalive true
|
1255
1277
|
keepalive_timeout 2
|
1256
1278
|
]
|
@@ -1259,7 +1281,12 @@ EOL
|
|
1259
1281
|
|
1260
1282
|
begin
|
1261
1283
|
chunk = Fluent::Plugin::Buffer::MemoryChunk.new(Fluent::Plugin::Buffer::Metadata.new(nil, nil, nil))
|
1262
|
-
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST,
|
1284
|
+
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST, @target_port,
|
1285
|
+
linger_timeout: anything,
|
1286
|
+
send_timeout: anything,
|
1287
|
+
recv_timeout: anything,
|
1288
|
+
connect_timeout: anything
|
1289
|
+
) { |sock| mock(sock).close.once; sock }.once
|
1263
1290
|
|
1264
1291
|
target_input_driver.run(timeout: 15) do
|
1265
1292
|
d.run(shutdown: false) do
|
@@ -1275,7 +1302,7 @@ EOL
|
|
1275
1302
|
end
|
1276
1303
|
|
1277
1304
|
test 'create timer of purging obsolete sockets' do
|
1278
|
-
output_conf =
|
1305
|
+
output_conf = config + %[keepalive true]
|
1279
1306
|
d = create_driver(output_conf)
|
1280
1307
|
|
1281
1308
|
mock(d.instance).timer_execute(:out_forward_heartbeat_request, 1).once
|
@@ -1285,8 +1312,8 @@ EOL
|
|
1285
1312
|
|
1286
1313
|
sub_test_case 'with require_ack_response' do
|
1287
1314
|
test 'Create connection per send_data' do
|
1288
|
-
target_input_driver = create_target_input_driver(conf:
|
1289
|
-
output_conf =
|
1315
|
+
target_input_driver = create_target_input_driver(conf: target_config)
|
1316
|
+
output_conf = config + %[
|
1290
1317
|
require_ack_response true
|
1291
1318
|
keepalive true
|
1292
1319
|
keepalive_timeout 2
|
@@ -1296,7 +1323,13 @@ EOL
|
|
1296
1323
|
|
1297
1324
|
begin
|
1298
1325
|
chunk = Fluent::Plugin::Buffer::MemoryChunk.new(Fluent::Plugin::Buffer::Metadata.new(nil, nil, nil))
|
1299
|
-
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST,
|
1326
|
+
mock.proxy(d.instance).socket_create_tcp(TARGET_HOST, @target_port,
|
1327
|
+
linger_timeout: anything,
|
1328
|
+
send_timeout: anything,
|
1329
|
+
recv_timeout: anything,
|
1330
|
+
connect_timeout: anything) { |sock|
|
1331
|
+
mock(sock).close.once; sock
|
1332
|
+
}.twice
|
1300
1333
|
|
1301
1334
|
target_input_driver.run(timeout: 15) do
|
1302
1335
|
d.run(shutdown: false) do
|