fluentd 0.12.40 → 1.6.2

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.

Files changed (428) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  4. data/.github/ISSUE_TEMPLATE.md +17 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  6. data/.gitignore +5 -0
  7. data/.gitlab/cicd-template.yaml +10 -0
  8. data/.gitlab-ci.yml +147 -0
  9. data/.travis.yml +56 -20
  10. data/ADOPTERS.md +5 -0
  11. data/CHANGELOG.md +1369 -0
  12. data/CONTRIBUTING.md +16 -5
  13. data/GOVERNANCE.md +55 -0
  14. data/Gemfile +5 -0
  15. data/GithubWorkflow.md +78 -0
  16. data/LICENSE +202 -0
  17. data/MAINTAINERS.md +7 -0
  18. data/README.md +23 -11
  19. data/Rakefile +48 -2
  20. data/Vagrantfile +17 -0
  21. data/appveyor.yml +37 -0
  22. data/bin/fluent-binlog-reader +7 -0
  23. data/bin/fluent-ca-generate +6 -0
  24. data/bin/fluent-plugin-config-format +5 -0
  25. data/bin/fluent-plugin-generate +5 -0
  26. data/bin/fluentd +3 -0
  27. data/code-of-conduct.md +3 -0
  28. data/example/copy_roundrobin.conf +39 -0
  29. data/example/counter.conf +18 -0
  30. data/example/in_dummy_blocks.conf +17 -0
  31. data/example/in_dummy_with_compression.conf +23 -0
  32. data/example/in_forward.conf +7 -0
  33. data/example/in_forward_client.conf +37 -0
  34. data/example/in_forward_shared_key.conf +15 -0
  35. data/example/in_forward_tls.conf +14 -0
  36. data/example/in_forward_users.conf +24 -0
  37. data/example/in_forward_workers.conf +21 -0
  38. data/example/in_http.conf +3 -1
  39. data/example/in_out_forward.conf +17 -0
  40. data/example/logevents.conf +25 -0
  41. data/example/multi_filters.conf +61 -0
  42. data/example/out_exec_filter.conf +42 -0
  43. data/example/out_forward.conf +13 -13
  44. data/example/out_forward_buf_file.conf +23 -0
  45. data/example/out_forward_client.conf +109 -0
  46. data/example/out_forward_heartbeat_none.conf +16 -0
  47. data/example/out_forward_shared_key.conf +36 -0
  48. data/example/out_forward_tls.conf +18 -0
  49. data/example/out_forward_users.conf +65 -0
  50. data/example/out_null.conf +36 -0
  51. data/example/secondary_file.conf +42 -0
  52. data/example/suppress_config_dump.conf +7 -0
  53. data/example/worker_section.conf +36 -0
  54. data/fluent.conf +29 -0
  55. data/fluentd.gemspec +21 -11
  56. data/lib/fluent/agent.rb +67 -90
  57. data/lib/fluent/clock.rb +62 -0
  58. data/lib/fluent/command/binlog_reader.rb +244 -0
  59. data/lib/fluent/command/ca_generate.rb +181 -0
  60. data/lib/fluent/command/cat.rb +42 -18
  61. data/lib/fluent/command/debug.rb +12 -10
  62. data/lib/fluent/command/fluentd.rb +153 -5
  63. data/lib/fluent/command/plugin_config_formatter.rb +292 -0
  64. data/lib/fluent/command/plugin_generator.rb +324 -0
  65. data/lib/fluent/compat/call_super_mixin.rb +67 -0
  66. data/lib/fluent/compat/detach_process_mixin.rb +33 -0
  67. data/lib/fluent/compat/exec_util.rb +129 -0
  68. data/lib/fluent/compat/file_util.rb +54 -0
  69. data/lib/fluent/compat/filter.rb +68 -0
  70. data/lib/fluent/compat/formatter.rb +111 -0
  71. data/lib/fluent/compat/formatter_utils.rb +85 -0
  72. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
  73. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  74. data/lib/fluent/compat/input.rb +49 -0
  75. data/lib/fluent/compat/output.rb +718 -0
  76. data/lib/fluent/compat/output_chain.rb +60 -0
  77. data/lib/fluent/compat/parser.rb +310 -0
  78. data/lib/fluent/compat/parser_utils.rb +40 -0
  79. data/lib/fluent/compat/propagate_default.rb +62 -0
  80. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  81. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  82. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  83. data/lib/fluent/compat/socket_util.rb +165 -0
  84. data/lib/fluent/compat/string_util.rb +34 -0
  85. data/lib/fluent/compat/structured_format_mixin.rb +26 -0
  86. data/lib/fluent/compat/type_converter.rb +90 -0
  87. data/lib/fluent/config/configure_proxy.rb +210 -62
  88. data/lib/fluent/config/dsl.rb +12 -5
  89. data/lib/fluent/config/element.rb +107 -9
  90. data/lib/fluent/config/literal_parser.rb +9 -3
  91. data/lib/fluent/config/parser.rb +4 -4
  92. data/lib/fluent/config/section.rb +51 -14
  93. data/lib/fluent/config/types.rb +28 -13
  94. data/lib/fluent/config/v1_parser.rb +3 -5
  95. data/lib/fluent/config.rb +23 -20
  96. data/lib/fluent/configurable.rb +79 -21
  97. data/lib/fluent/counter/base_socket.rb +46 -0
  98. data/lib/fluent/counter/client.rb +297 -0
  99. data/lib/fluent/counter/error.rb +86 -0
  100. data/lib/fluent/counter/mutex_hash.rb +163 -0
  101. data/lib/fluent/counter/server.rb +273 -0
  102. data/lib/fluent/counter/store.rb +205 -0
  103. data/lib/fluent/counter/validator.rb +145 -0
  104. data/lib/fluent/counter.rb +23 -0
  105. data/lib/fluent/daemon.rb +15 -0
  106. data/lib/fluent/engine.rb +102 -65
  107. data/lib/fluent/env.rb +7 -3
  108. data/lib/fluent/error.rb +30 -0
  109. data/lib/fluent/event.rb +197 -21
  110. data/lib/fluent/event_router.rb +93 -10
  111. data/lib/fluent/filter.rb +2 -50
  112. data/lib/fluent/formatter.rb +4 -293
  113. data/lib/fluent/input.rb +2 -32
  114. data/lib/fluent/label.rb +10 -2
  115. data/lib/fluent/load.rb +3 -3
  116. data/lib/fluent/log.rb +348 -81
  117. data/lib/fluent/match.rb +37 -36
  118. data/lib/fluent/mixin.rb +12 -176
  119. data/lib/fluent/msgpack_factory.rb +62 -0
  120. data/lib/fluent/output.rb +10 -612
  121. data/lib/fluent/output_chain.rb +23 -0
  122. data/lib/fluent/parser.rb +4 -800
  123. data/lib/fluent/plugin/bare_output.rb +63 -0
  124. data/lib/fluent/plugin/base.rb +192 -0
  125. data/lib/fluent/plugin/buf_file.rb +128 -174
  126. data/lib/fluent/plugin/buf_memory.rb +9 -92
  127. data/lib/fluent/plugin/buffer/chunk.rb +221 -0
  128. data/lib/fluent/plugin/buffer/file_chunk.rb +383 -0
  129. data/lib/fluent/plugin/buffer/memory_chunk.rb +90 -0
  130. data/lib/fluent/plugin/buffer.rb +779 -0
  131. data/lib/fluent/plugin/compressable.rb +92 -0
  132. data/lib/fluent/plugin/exec_util.rb +3 -108
  133. data/lib/fluent/plugin/file_util.rb +4 -34
  134. data/lib/fluent/plugin/file_wrapper.rb +120 -0
  135. data/lib/fluent/plugin/filter.rb +93 -0
  136. data/lib/fluent/plugin/filter_grep.rb +117 -34
  137. data/lib/fluent/plugin/filter_parser.rb +85 -62
  138. data/lib/fluent/plugin/filter_record_transformer.rb +27 -39
  139. data/lib/fluent/plugin/filter_stdout.rb +15 -12
  140. data/lib/fluent/plugin/formatter.rb +50 -0
  141. data/lib/fluent/plugin/formatter_csv.rb +52 -0
  142. data/lib/fluent/plugin/formatter_hash.rb +33 -0
  143. data/lib/fluent/plugin/formatter_json.rb +55 -0
  144. data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
  145. data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
  146. data/lib/fluent/plugin/formatter_out_file.rb +51 -0
  147. data/lib/fluent/plugin/formatter_single_value.rb +34 -0
  148. data/lib/fluent/plugin/formatter_stdout.rb +76 -0
  149. data/lib/fluent/plugin/formatter_tsv.rb +38 -0
  150. data/lib/fluent/plugin/in_debug_agent.rb +17 -6
  151. data/lib/fluent/plugin/in_dummy.rb +47 -20
  152. data/lib/fluent/plugin/in_exec.rb +55 -123
  153. data/lib/fluent/plugin/in_forward.rb +299 -216
  154. data/lib/fluent/plugin/in_gc_stat.rb +14 -36
  155. data/lib/fluent/plugin/in_http.rb +204 -91
  156. data/lib/fluent/plugin/in_monitor_agent.rb +186 -258
  157. data/lib/fluent/plugin/in_object_space.rb +13 -41
  158. data/lib/fluent/plugin/in_syslog.rb +112 -134
  159. data/lib/fluent/plugin/in_tail.rb +408 -745
  160. data/lib/fluent/plugin/in_tcp.rb +66 -9
  161. data/lib/fluent/plugin/in_udp.rb +60 -11
  162. data/lib/fluent/plugin/{in_stream.rb → in_unix.rb} +8 -4
  163. data/lib/fluent/plugin/input.rb +37 -0
  164. data/lib/fluent/plugin/multi_output.rb +158 -0
  165. data/lib/fluent/plugin/out_copy.rb +23 -35
  166. data/lib/fluent/plugin/out_exec.rb +67 -70
  167. data/lib/fluent/plugin/out_exec_filter.rb +204 -271
  168. data/lib/fluent/plugin/out_file.rb +267 -73
  169. data/lib/fluent/plugin/out_forward.rb +854 -325
  170. data/lib/fluent/plugin/out_null.rb +42 -9
  171. data/lib/fluent/plugin/out_relabel.rb +9 -5
  172. data/lib/fluent/plugin/out_roundrobin.rb +18 -37
  173. data/lib/fluent/plugin/out_secondary_file.rb +133 -0
  174. data/lib/fluent/plugin/out_stdout.rb +43 -10
  175. data/lib/fluent/plugin/out_stream.rb +7 -2
  176. data/lib/fluent/plugin/output.rb +1498 -0
  177. data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
  178. data/lib/fluent/plugin/parser.rb +191 -0
  179. data/lib/fluent/plugin/parser_apache.rb +28 -0
  180. data/lib/fluent/plugin/parser_apache2.rb +88 -0
  181. data/lib/fluent/plugin/parser_apache_error.rb +26 -0
  182. data/lib/fluent/plugin/parser_csv.rb +39 -0
  183. data/lib/fluent/plugin/parser_json.rb +94 -0
  184. data/lib/fluent/plugin/parser_ltsv.rb +49 -0
  185. data/lib/fluent/plugin/parser_msgpack.rb +50 -0
  186. data/lib/fluent/plugin/parser_multiline.rb +106 -0
  187. data/lib/fluent/plugin/parser_nginx.rb +28 -0
  188. data/lib/fluent/plugin/parser_none.rb +36 -0
  189. data/lib/fluent/plugin/parser_regexp.rb +68 -0
  190. data/lib/fluent/plugin/parser_syslog.rb +142 -0
  191. data/lib/fluent/plugin/parser_tsv.rb +42 -0
  192. data/lib/fluent/plugin/socket_util.rb +3 -143
  193. data/lib/fluent/plugin/storage.rb +84 -0
  194. data/lib/fluent/plugin/storage_local.rb +164 -0
  195. data/lib/fluent/plugin/string_util.rb +3 -15
  196. data/lib/fluent/plugin.rb +122 -121
  197. data/lib/fluent/plugin_helper/cert_option.rb +178 -0
  198. data/lib/fluent/plugin_helper/child_process.rb +364 -0
  199. data/lib/fluent/plugin_helper/compat_parameters.rb +333 -0
  200. data/lib/fluent/plugin_helper/counter.rb +51 -0
  201. data/lib/fluent/plugin_helper/event_emitter.rb +93 -0
  202. data/lib/fluent/plugin_helper/event_loop.rb +170 -0
  203. data/lib/fluent/plugin_helper/extract.rb +104 -0
  204. data/lib/fluent/plugin_helper/formatter.rb +147 -0
  205. data/lib/fluent/plugin_helper/http_server/app.rb +79 -0
  206. data/lib/fluent/plugin_helper/http_server/compat/server.rb +81 -0
  207. data/lib/fluent/plugin_helper/http_server/compat/webrick_handler.rb +58 -0
  208. data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
  209. data/lib/fluent/plugin_helper/http_server/request.rb +42 -0
  210. data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
  211. data/lib/fluent/plugin_helper/http_server/server.rb +87 -0
  212. data/lib/fluent/plugin_helper/http_server.rb +76 -0
  213. data/lib/fluent/plugin_helper/inject.rb +151 -0
  214. data/lib/fluent/plugin_helper/parser.rb +147 -0
  215. data/lib/fluent/plugin_helper/record_accessor.rb +210 -0
  216. data/lib/fluent/plugin_helper/retry_state.rb +205 -0
  217. data/lib/fluent/plugin_helper/server.rb +807 -0
  218. data/lib/fluent/plugin_helper/socket.rb +250 -0
  219. data/lib/fluent/plugin_helper/socket_option.rb +80 -0
  220. data/lib/fluent/plugin_helper/storage.rb +349 -0
  221. data/lib/fluent/plugin_helper/thread.rb +179 -0
  222. data/lib/fluent/plugin_helper/timer.rb +92 -0
  223. data/lib/fluent/plugin_helper.rb +73 -0
  224. data/lib/fluent/plugin_id.rb +80 -0
  225. data/lib/fluent/process.rb +3 -489
  226. data/lib/fluent/registry.rb +52 -10
  227. data/lib/fluent/root_agent.rb +204 -42
  228. data/lib/fluent/supervisor.rb +597 -359
  229. data/lib/fluent/system_config.rb +131 -42
  230. data/lib/fluent/test/base.rb +6 -54
  231. data/lib/fluent/test/driver/base.rb +224 -0
  232. data/lib/fluent/test/driver/base_owned.rb +70 -0
  233. data/lib/fluent/test/driver/base_owner.rb +135 -0
  234. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  235. data/lib/fluent/test/driver/filter.rb +57 -0
  236. data/lib/fluent/test/driver/formatter.rb +30 -0
  237. data/lib/fluent/test/driver/input.rb +31 -0
  238. data/lib/fluent/test/driver/multi_output.rb +53 -0
  239. data/lib/fluent/test/driver/output.rb +102 -0
  240. data/lib/fluent/test/driver/parser.rb +30 -0
  241. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  242. data/lib/fluent/test/filter_test.rb +0 -1
  243. data/lib/fluent/test/formatter_test.rb +4 -1
  244. data/lib/fluent/test/helpers.rb +58 -10
  245. data/lib/fluent/test/input_test.rb +27 -19
  246. data/lib/fluent/test/log.rb +79 -0
  247. data/lib/fluent/test/output_test.rb +28 -39
  248. data/lib/fluent/test/parser_test.rb +3 -1
  249. data/lib/fluent/test/startup_shutdown.rb +46 -0
  250. data/lib/fluent/test.rb +33 -1
  251. data/lib/fluent/time.rb +450 -1
  252. data/lib/fluent/timezone.rb +27 -3
  253. data/lib/fluent/{status.rb → unique_id.rb} +15 -24
  254. data/lib/fluent/version.rb +1 -1
  255. data/lib/fluent/winsvc.rb +85 -0
  256. data/templates/new_gem/Gemfile +3 -0
  257. data/templates/new_gem/README.md.erb +43 -0
  258. data/templates/new_gem/Rakefile +13 -0
  259. data/templates/new_gem/fluent-plugin.gemspec.erb +27 -0
  260. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
  261. data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
  262. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
  263. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
  264. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
  265. data/templates/new_gem/test/helper.rb.erb +8 -0
  266. data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
  267. data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
  268. data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
  269. data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
  270. data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
  271. data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
  272. data/templates/plugin_config_formatter/param.md.erb +34 -0
  273. data/templates/plugin_config_formatter/section.md.erb +12 -0
  274. data/test/command/test_binlog_reader.rb +346 -0
  275. data/test/command/test_ca_generate.rb +70 -0
  276. data/test/command/test_fluentd.rb +901 -0
  277. data/test/command/test_plugin_config_formatter.rb +276 -0
  278. data/test/command/test_plugin_generator.rb +92 -0
  279. data/test/compat/test_calls_super.rb +166 -0
  280. data/test/compat/test_parser.rb +92 -0
  281. data/test/config/test_config_parser.rb +126 -2
  282. data/test/config/test_configurable.rb +946 -187
  283. data/test/config/test_configure_proxy.rb +424 -74
  284. data/test/config/test_dsl.rb +11 -11
  285. data/test/config/test_element.rb +500 -0
  286. data/test/config/test_literal_parser.rb +8 -0
  287. data/test/config/test_plugin_configuration.rb +56 -0
  288. data/test/config/test_section.rb +79 -7
  289. data/test/config/test_system_config.rb +122 -35
  290. data/test/config/test_types.rb +38 -0
  291. data/test/counter/test_client.rb +559 -0
  292. data/test/counter/test_error.rb +44 -0
  293. data/test/counter/test_mutex_hash.rb +179 -0
  294. data/test/counter/test_server.rb +589 -0
  295. data/test/counter/test_store.rb +258 -0
  296. data/test/counter/test_validator.rb +137 -0
  297. data/test/helper.rb +89 -6
  298. data/test/helpers/fuzzy_assert.rb +89 -0
  299. data/test/plugin/test_bare_output.rb +118 -0
  300. data/test/plugin/test_base.rb +115 -0
  301. data/test/plugin/test_buf_file.rb +823 -460
  302. data/test/plugin/test_buf_memory.rb +32 -194
  303. data/test/plugin/test_buffer.rb +1233 -0
  304. data/test/plugin/test_buffer_chunk.rb +198 -0
  305. data/test/plugin/test_buffer_file_chunk.rb +844 -0
  306. data/test/plugin/test_buffer_memory_chunk.rb +338 -0
  307. data/test/plugin/test_compressable.rb +84 -0
  308. data/test/plugin/test_filter.rb +357 -0
  309. data/test/plugin/test_filter_grep.rb +540 -29
  310. data/test/plugin/test_filter_parser.rb +439 -452
  311. data/test/plugin/test_filter_record_transformer.rb +123 -166
  312. data/test/plugin/test_filter_stdout.rb +160 -72
  313. data/test/plugin/test_formatter_csv.rb +111 -0
  314. data/test/plugin/test_formatter_hash.rb +35 -0
  315. data/test/plugin/test_formatter_json.rb +51 -0
  316. data/test/plugin/test_formatter_ltsv.rb +62 -0
  317. data/test/plugin/test_formatter_msgpack.rb +28 -0
  318. data/test/plugin/test_formatter_out_file.rb +95 -0
  319. data/test/plugin/test_formatter_single_value.rb +38 -0
  320. data/test/plugin/test_formatter_tsv.rb +68 -0
  321. data/test/plugin/test_in_debug_agent.rb +24 -1
  322. data/test/plugin/test_in_dummy.rb +111 -18
  323. data/test/plugin/test_in_exec.rb +200 -113
  324. data/test/plugin/test_in_forward.rb +990 -387
  325. data/test/plugin/test_in_gc_stat.rb +10 -8
  326. data/test/plugin/test_in_http.rb +600 -224
  327. data/test/plugin/test_in_monitor_agent.rb +690 -0
  328. data/test/plugin/test_in_object_space.rb +24 -8
  329. data/test/plugin/test_in_syslog.rb +154 -215
  330. data/test/plugin/test_in_tail.rb +1006 -707
  331. data/test/plugin/test_in_tcp.rb +125 -48
  332. data/test/plugin/test_in_udp.rb +204 -63
  333. data/test/plugin/{test_in_stream.rb → test_in_unix.rb} +14 -13
  334. data/test/plugin/test_input.rb +126 -0
  335. data/test/plugin/test_metadata.rb +89 -0
  336. data/test/plugin/test_multi_output.rb +180 -0
  337. data/test/plugin/test_out_copy.rb +117 -112
  338. data/test/plugin/test_out_exec.rb +258 -53
  339. data/test/plugin/test_out_exec_filter.rb +538 -115
  340. data/test/plugin/test_out_file.rb +865 -178
  341. data/test/plugin/test_out_forward.rb +998 -210
  342. data/test/plugin/test_out_null.rb +105 -0
  343. data/test/plugin/test_out_relabel.rb +28 -0
  344. data/test/plugin/test_out_roundrobin.rb +36 -29
  345. data/test/plugin/test_out_secondary_file.rb +458 -0
  346. data/test/plugin/test_out_stdout.rb +135 -37
  347. data/test/plugin/test_out_stream.rb +18 -0
  348. data/test/plugin/test_output.rb +984 -0
  349. data/test/plugin/test_output_as_buffered.rb +2021 -0
  350. data/test/plugin/test_output_as_buffered_backup.rb +312 -0
  351. data/test/plugin/test_output_as_buffered_compress.rb +165 -0
  352. data/test/plugin/test_output_as_buffered_overflow.rb +250 -0
  353. data/test/plugin/test_output_as_buffered_retries.rb +911 -0
  354. data/test/plugin/test_output_as_buffered_secondary.rb +874 -0
  355. data/test/plugin/test_output_as_standard.rb +374 -0
  356. data/test/plugin/test_owned_by.rb +35 -0
  357. data/test/plugin/test_parser.rb +359 -0
  358. data/test/plugin/test_parser_apache.rb +42 -0
  359. data/test/plugin/test_parser_apache2.rb +47 -0
  360. data/test/plugin/test_parser_apache_error.rb +45 -0
  361. data/test/plugin/test_parser_csv.rb +103 -0
  362. data/test/plugin/test_parser_json.rb +138 -0
  363. data/test/plugin/test_parser_labeled_tsv.rb +145 -0
  364. data/test/plugin/test_parser_multiline.rb +100 -0
  365. data/test/plugin/test_parser_nginx.rb +88 -0
  366. data/test/plugin/test_parser_none.rb +52 -0
  367. data/test/plugin/test_parser_regexp.rb +289 -0
  368. data/test/plugin/test_parser_syslog.rb +441 -0
  369. data/test/plugin/test_parser_tsv.rb +122 -0
  370. data/test/plugin/test_storage.rb +167 -0
  371. data/test/plugin/test_storage_local.rb +335 -0
  372. data/test/plugin_helper/data/cert/cert-key.pem +27 -0
  373. data/test/plugin_helper/data/cert/cert-with-no-newline.pem +19 -0
  374. data/test/plugin_helper/data/cert/cert.pem +19 -0
  375. data/test/plugin_helper/http_server/test_app.rb +65 -0
  376. data/test/plugin_helper/http_server/test_route.rb +32 -0
  377. data/test/plugin_helper/test_cert_option.rb +16 -0
  378. data/test/plugin_helper/test_child_process.rb +794 -0
  379. data/test/plugin_helper/test_compat_parameters.rb +353 -0
  380. data/test/plugin_helper/test_event_emitter.rb +51 -0
  381. data/test/plugin_helper/test_event_loop.rb +52 -0
  382. data/test/plugin_helper/test_extract.rb +194 -0
  383. data/test/plugin_helper/test_formatter.rb +255 -0
  384. data/test/plugin_helper/test_http_server_helper.rb +205 -0
  385. data/test/plugin_helper/test_inject.rb +519 -0
  386. data/test/plugin_helper/test_parser.rb +264 -0
  387. data/test/plugin_helper/test_record_accessor.rb +197 -0
  388. data/test/plugin_helper/test_retry_state.rb +442 -0
  389. data/test/plugin_helper/test_server.rb +1714 -0
  390. data/test/plugin_helper/test_storage.rb +542 -0
  391. data/test/plugin_helper/test_thread.rb +164 -0
  392. data/test/plugin_helper/test_timer.rb +132 -0
  393. data/test/scripts/exec_script.rb +0 -6
  394. data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +7 -0
  395. data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +7 -0
  396. data/test/scripts/fluent/plugin/out_test.rb +23 -15
  397. data/test/scripts/fluent/plugin/out_test2.rb +80 -0
  398. data/test/test_clock.rb +164 -0
  399. data/test/test_config.rb +16 -7
  400. data/test/test_configdsl.rb +2 -2
  401. data/test/test_event.rb +360 -13
  402. data/test/test_event_router.rb +108 -11
  403. data/test/test_event_time.rb +199 -0
  404. data/test/test_filter.rb +48 -6
  405. data/test/test_formatter.rb +11 -391
  406. data/test/test_input.rb +1 -1
  407. data/test/test_log.rb +591 -31
  408. data/test/test_mixin.rb +1 -1
  409. data/test/test_output.rb +121 -185
  410. data/test/test_plugin.rb +251 -0
  411. data/test/test_plugin_classes.rb +177 -10
  412. data/test/test_plugin_helper.rb +81 -0
  413. data/test/test_plugin_id.rb +101 -0
  414. data/test/test_process.rb +8 -42
  415. data/test/test_root_agent.rb +766 -21
  416. data/test/test_supervisor.rb +481 -0
  417. data/test/test_test_drivers.rb +135 -0
  418. data/test/test_time_formatter.rb +282 -0
  419. data/test/test_time_parser.rb +231 -0
  420. data/test/test_unique_id.rb +47 -0
  421. metadata +454 -60
  422. data/COPYING +0 -14
  423. data/ChangeLog +0 -666
  424. data/lib/fluent/buffer.rb +0 -365
  425. data/lib/fluent/plugin/in_status.rb +0 -76
  426. data/test/plugin/test_in_status.rb +0 -38
  427. data/test/test_buffer.rb +0 -624
  428. data/test/test_parser.rb +0 -1305
@@ -0,0 +1,1714 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin_helper/server'
3
+ require 'fluent/plugin_helper/cert_option' # to create certs for tests
4
+ require 'fluent/plugin/base'
5
+ require 'timeout'
6
+
7
+ require 'serverengine'
8
+ require 'fileutils'
9
+
10
+ class ServerPluginHelperTest < Test::Unit::TestCase
11
+ class Dummy < Fluent::Plugin::TestBase
12
+ helpers :server
13
+ end
14
+
15
+ TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp/plugin_helper_server")
16
+
17
+ PORT = unused_port
18
+
19
+ setup do
20
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
21
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
22
+ FileUtils.rm_f @socket_manager_path
23
+ end
24
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
25
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
26
+
27
+ @d = Dummy.new
28
+ @d.start
29
+ @d.after_start
30
+ end
31
+
32
+ teardown do
33
+ (@d.stopped? || @d.stop) rescue nil
34
+ (@d.before_shutdown? || @d.before_shutdown) rescue nil
35
+ (@d.shutdown? || @d.shutdown) rescue nil
36
+ (@d.after_shutdown? || @d.after_shutdown) rescue nil
37
+ (@d.closed? || @d.close) rescue nil
38
+ (@d.terminated? || @d.terminate) rescue nil
39
+
40
+ @socket_manager_server.close
41
+ if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
42
+ FileUtils.rm_f @socket_manager_path
43
+ end
44
+ end
45
+
46
+ sub_test_case 'plugin instance' do
47
+ test 'can be instantiated to be able to create threads' do
48
+ d = Dummy.new
49
+ assert d.respond_to?(:_servers)
50
+ assert d._servers.empty?
51
+
52
+ assert d.respond_to?(:server_wait_until_start)
53
+ assert d.respond_to?(:server_wait_until_stop)
54
+ assert d.respond_to?(:server_create_connection)
55
+ assert d.respond_to?(:server_create)
56
+ assert d.respond_to?(:server_create_tcp)
57
+ assert d.respond_to?(:server_create_udp)
58
+ assert d.respond_to?(:server_create_tls)
59
+ end
60
+
61
+ test 'can be configured' do
62
+ d = Dummy.new
63
+ assert_nothing_raised do
64
+ d.configure(config_element())
65
+ end
66
+ assert d.plugin_id
67
+ assert d.log
68
+ end
69
+ end
70
+
71
+ # run tests for tcp, udp, tls and unix
72
+ sub_test_case '#server_create and #server_create_connection' do
73
+ methods = {server_create: :server_create, server_create_connection: :server_create_connection}
74
+
75
+ data(methods)
76
+ test 'raise error if title is not specified or not a symbol' do |m|
77
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
78
+ @d.__send__(m, nil, PORT){|x| x }
79
+ end
80
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
81
+ @d.__send__(m, "", PORT){|x| x }
82
+ end
83
+ assert_raise(ArgumentError.new("BUG: title must be a symbol")) do
84
+ @d.__send__(m, "title", PORT){|x| x }
85
+ end
86
+ assert_nothing_raised do
87
+ @d.__send__(m, :myserver, PORT){|x| x }
88
+ end
89
+ end
90
+
91
+ data(methods)
92
+ test 'raise error if port is not specified or not an integer' do |m|
93
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
94
+ @d.__send__(m, :myserver, nil){|x| x }
95
+ end
96
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
97
+ @d.__send__(m, :myserver, "1"){|x| x }
98
+ end
99
+ assert_raise(ArgumentError.new("BUG: port must be an integer")) do
100
+ @d.__send__(m, :myserver, 1.5){|x| x }
101
+ end
102
+ assert_nothing_raised do
103
+ @d.__send__(m, :myserver, PORT){|x| x }
104
+ end
105
+ end
106
+
107
+ data(methods)
108
+ test 'raise error if block is not specified' do |m|
109
+ assert_raise(ArgumentError) do
110
+ @d.__send__(m, :myserver, PORT)
111
+ end
112
+ assert_nothing_raised do
113
+ @d.__send__(m, :myserver, PORT){|x| x }
114
+ end
115
+ end
116
+
117
+ data(methods)
118
+ test 'creates tcp server, binds 0.0.0.0 in default' do |m|
119
+ @d.__send__(m, :myserver, PORT){|x| x }
120
+
121
+ assert_equal 1, @d._servers.size
122
+
123
+ created_server_info = @d._servers.first
124
+
125
+ assert_equal :myserver, created_server_info.title
126
+ assert_equal PORT, created_server_info.port
127
+
128
+ assert_equal :tcp, created_server_info.proto
129
+ assert_equal "0.0.0.0", created_server_info.bind
130
+
131
+ created_server = created_server_info.server
132
+
133
+ assert created_server.is_a?(Coolio::TCPServer)
134
+ assert_equal "0.0.0.0", created_server.instance_eval{ @listen_socket }.addr[3]
135
+ end
136
+
137
+ data(methods)
138
+ test 'creates tcp server if specified in proto' do |m|
139
+ @d.__send__(m, :myserver, PORT, proto: :tcp){|x| x }
140
+
141
+ created_server_info = @d._servers.first
142
+ assert_equal :tcp, created_server_info.proto
143
+ created_server = created_server_info.server
144
+ assert created_server.is_a?(Coolio::TCPServer)
145
+ end
146
+
147
+ data(methods)
148
+ test 'creates tls server in default if transport section and tcp protocol specified' do |m|
149
+ @d = d = Dummy.new
150
+ transport_conf = config_element('transport', 'tcp', {}, [])
151
+ d.configure(config_element('ROOT', '', {}, [transport_conf]))
152
+ d.start
153
+ d.after_start
154
+
155
+ d.__send__(m, :myserver, PORT){|x| x }
156
+
157
+ created_server_info = @d._servers.first
158
+ assert_equal :tcp, created_server_info.proto
159
+ created_server = created_server_info.server
160
+ assert created_server.is_a?(Coolio::TCPServer)
161
+ end
162
+
163
+ data(methods)
164
+ test 'creates tls server if specified in proto' do |m|
165
+ assert_raise(ArgumentError.new("BUG: TLS transport specified, but certification options are not specified")) do
166
+ @d.__send__(m, :myserver, PORT, proto: :tls){|x| x }
167
+ end
168
+ @d.__send__(m, :myserver, PORT, proto: :tls, tls_options: {insecure: true}){|x| x }
169
+
170
+ created_server_info = @d._servers.first
171
+ assert_equal :tls, created_server_info.proto
172
+ created_server = created_server_info.server
173
+ assert created_server.is_a?(Coolio::TCPServer) # yes, TCP here
174
+ end
175
+
176
+ data(methods)
177
+ test 'creates tls server in default if transport section and tls protocol specified' do |m|
178
+ @d = d = Dummy.new
179
+ transport_conf = config_element('transport', 'tls', {'insecure' => 'true'}, [])
180
+ d.configure(config_element('ROOT', '', {}, [transport_conf]))
181
+ d.start
182
+ d.after_start
183
+
184
+ d.__send__(m, :myserver, PORT){|x| x }
185
+
186
+ created_server_info = @d._servers.first
187
+ assert_equal :tls, created_server_info.proto
188
+ created_server = created_server_info.server
189
+ assert created_server.is_a?(Coolio::TCPServer) # OK, it's Coolio::TCPServer
190
+ end
191
+
192
+ data(methods)
193
+ test 'creates unix server if specified in proto' do |m|
194
+ # pend "not implemented yet"
195
+ end
196
+
197
+ data(methods)
198
+ test 'raise error if unknown protocol specified' do |m|
199
+ assert_raise(ArgumentError.new("BUG: invalid protocol name")) do
200
+ @d.__send__(m, :myserver, PORT, proto: :quic){|x| x }
201
+ end
202
+ end
203
+
204
+ data(
205
+ 'server_create tcp' => [:server_create, :tcp],
206
+ 'server_create tls' => [:server_create, :tls],
207
+ # 'server_create unix' => [:server_create, :unix],
208
+ 'server_create_connection tcp' => [:server_create_connection, :tcp],
209
+ 'server_create_connection tls' => [:server_create_connection, :tls],
210
+ # 'server_create_connection tcp' => [:server_create_connection, :unix],
211
+ )
212
+ test 'raise error if udp options specified for tcp/tls/unix' do |(m, proto)|
213
+ assert_raise ArgumentError do
214
+ @d.__send__(m, :myserver, PORT, proto: proto, max_bytes: 128){|x| x }
215
+ end
216
+ assert_raise ArgumentError do
217
+ @d.__send__(m, :myserver, PORT, proto: proto, flags: 1){|x| x }
218
+ end
219
+ end
220
+
221
+ data(
222
+ 'server_create udp' => [:server_create, :udp],
223
+ )
224
+ test 'raise error if tcp/tls options specified for udp' do |(m, proto)|
225
+ assert_raise(ArgumentError.new("BUG: linger_timeout is available for tcp/tls")) do
226
+ @d.__send__(m, :myserver, PORT, proto: proto, linger_timeout: 1, max_bytes: 128){|x| x }
227
+ end
228
+ end
229
+
230
+ data(
231
+ 'server_create udp' => [:server_create, :udp],
232
+ )
233
+ test 'raise error if tcp/tls/unix backlog options specified for udp' do |(m, proto)|
234
+ assert_raise(ArgumentError.new("BUG: backlog is available for tcp/tls")) do
235
+ @d.__send__(m, :myserver, PORT, proto: proto, backlog: 500){|x| x }
236
+ end
237
+ assert_raise(ArgumentError.new("BUG: send_keepalive_packet is available for tcp")) do
238
+ @d.__send__(m, :myserver, PORT, proto: proto, send_keepalive_packet: true){|x| x }
239
+ end
240
+ end
241
+
242
+ data(
243
+ 'server_create tcp' => [:server_create, :tcp, {}],
244
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
245
+ # 'server_create unix' => [:server_create, :unix, {}],
246
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
247
+ # 'server_create_connection unix' => [:server_create_connection, :unix, {}],
248
+ )
249
+ test 'raise error if tls options specified for tcp/udp/unix' do |(m, proto, kwargs)|
250
+ assert_raise(ArgumentError.new("BUG: tls_options is available only for tls")) do
251
+ @d.__send__(m, :myserver, PORT, proto: proto, tls_options: {}, **kwargs){|x| x }
252
+ end
253
+ end
254
+
255
+ data(
256
+ 'server_create tcp' => [:server_create, :tcp, {}],
257
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
258
+ 'server_create tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
259
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
260
+ 'server_create_connection tls' => [:server_create_connection, :tls, {tls_options: {insecure: true}}],
261
+ )
262
+ test 'can bind specified IPv4 address' do |(m, proto, kwargs)|
263
+ @d.__send__(m, :myserver, PORT, proto: proto, bind: "127.0.0.1", **kwargs){|x| x }
264
+ assert_equal "127.0.0.1", @d._servers.first.bind
265
+ assert_equal "127.0.0.1", @d._servers.first.server.instance_eval{ instance_variable_defined?(:@listen_socket) ? @listen_socket : @_io }.addr[3]
266
+ end
267
+
268
+ data(
269
+ 'server_create tcp' => [:server_create, :tcp, {}],
270
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
271
+ 'server_create tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
272
+ 'server_create_connection tcp' => [:server_create_connection, :tcp, {}],
273
+ 'server_create_connection tls' => [:server_create_connection, :tls, {tls_options: {insecure: true}}],
274
+ )
275
+ test 'can bind specified IPv6 address' do |(m, proto, kwargs)| # if available
276
+ omit "IPv6 unavailable here" unless ipv6_enabled?
277
+ @d.__send__(m, :myserver, PORT, proto: proto, bind: "::1", **kwargs){|x| x }
278
+ assert_equal "::1", @d._servers.first.bind
279
+ assert_equal "::1", @d._servers.first.server.instance_eval{ instance_variable_defined?(:@listen_socket) ? @listen_socket : @_io }.addr[3]
280
+ end
281
+
282
+ data(
283
+ 'server_create tcp' => [:server_create, :tcp, {}],
284
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
285
+ 'server_create tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
286
+ # 'server_create unix' => [:server_create, :unix, {}],
287
+ 'server_create_connection tcp' => [:server_create, :tcp, {}],
288
+ 'server_create_connection tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
289
+ # 'server_create_connection unix' => [:server_create, :unix, {}],
290
+ )
291
+ test 'can create 2 or more servers which share same bind address and port if shared option is true' do |(m, proto, kwargs)|
292
+ begin
293
+ d2 = Dummy.new; d2.start; d2.after_start
294
+
295
+ assert_nothing_raised do
296
+ @d.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
297
+ d2.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
298
+ end
299
+ ensure
300
+ d2.stop; d2.before_shutdown; d2.shutdown; d2.after_shutdown; d2.close; d2.terminate
301
+ end
302
+ end
303
+
304
+ data(
305
+ 'server_create tcp' => [:server_create, :tcp, {}],
306
+ 'server_create udp' => [:server_create, :udp, {max_bytes: 128}],
307
+ 'server_create tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
308
+ # 'server_create unix' => [:server_create, :unix, {}],
309
+ 'server_create_connection tcp' => [:server_create, :tcp, {}],
310
+ 'server_create_connection tls' => [:server_create, :tls, {tls_options: {insecure: true}}],
311
+ # 'server_create_connection unix' => [:server_create, :unix, {}],
312
+ )
313
+ test 'cannot create 2 or more servers using same bind address and port if shared option is false' do |(m, proto, kwargs)|
314
+ begin
315
+ d2 = Dummy.new; d2.start; d2.after_start
316
+
317
+ assert_nothing_raised do
318
+ @d.__send__(m, :myserver, PORT, proto: proto, shared: false, **kwargs){|x| x }
319
+ end
320
+ assert_raise(Errno::EADDRINUSE, Errno::EACCES) do
321
+ d2.__send__(m, :myserver, PORT, proto: proto, **kwargs){|x| x }
322
+ end
323
+ ensure
324
+ d2.stop; d2.before_shutdown; d2.shutdown; d2.after_shutdown; d2.close; d2.terminate
325
+ end
326
+ end
327
+ end
328
+
329
+ sub_test_case '#server_create' do
330
+ data(
331
+ 'tcp' => [:tcp, {}],
332
+ 'udp' => [:udp, {max_bytes: 128}],
333
+ 'tls' => [:tls, {tls_options: {insecure: true}}],
334
+ # 'unix' => [:unix, {}],
335
+ )
336
+ test 'raise error if block argument is not specified or too many' do |(proto, kwargs)|
337
+ assert_raise(ArgumentError.new("BUG: block must have 1 or 2 arguments")) do
338
+ @d.server_create(:myserver, PORT, proto: proto, **kwargs){ 1 }
339
+ end
340
+ assert_raise(ArgumentError.new("BUG: block must have 1 or 2 arguments")) do
341
+ @d.server_create(:myserver, PORT, proto: proto, **kwargs){|sock, conn, what_is_this| 1 }
342
+ end
343
+ end
344
+
345
+ test 'creates udp server if specified in proto' do
346
+ @d.server_create(:myserver, PORT, proto: :udp, max_bytes: 512){|x| x }
347
+
348
+ created_server_info = @d._servers.first
349
+ assert_equal :udp, created_server_info.proto
350
+ created_server = created_server_info.server
351
+ assert created_server.is_a?(Fluent::PluginHelper::Server::EventHandler::UDPServer)
352
+ end
353
+ end
354
+
355
+ sub_test_case '#server_create_tcp' do
356
+ test 'can accept all keyword arguments valid for tcp server' do
357
+ assert_nothing_raised do
358
+ @d.server_create_tcp(:s, PORT, bind: '127.0.0.1', shared: false, resolve_name: true, linger_timeout: 10, backlog: 500, send_keepalive_packet: true) do |data, conn|
359
+ # ...
360
+ end
361
+ end
362
+ end
363
+
364
+ test 'creates a tcp server just to read data' do
365
+ received = ""
366
+ @d.server_create_tcp(:s, PORT) do |data|
367
+ received << data
368
+ end
369
+ 3.times do
370
+ sock = TCPSocket.new("127.0.0.1", PORT)
371
+ sock.puts "yay"
372
+ sock.puts "foo"
373
+ sock.close
374
+ end
375
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
376
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
377
+ end
378
+
379
+ test 'creates a tcp server to read and write data' do
380
+ received = ""
381
+ responses = []
382
+ @d.server_create_tcp(:s, PORT) do |data, conn|
383
+ received << data
384
+ conn.write "ack\n"
385
+ end
386
+ 3.times do
387
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
388
+ sock.puts "yay"
389
+ sock.puts "foo"
390
+ responses << sock.readline
391
+ end
392
+ end
393
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
394
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
395
+ assert_equal ["ack\n","ack\n","ack\n"], responses
396
+ end
397
+
398
+ test 'creates a tcp server to read and write data using IPv6' do
399
+ omit "IPv6 unavailable here" unless ipv6_enabled?
400
+
401
+ received = ""
402
+ responses = []
403
+ @d.server_create_tcp(:s, PORT, bind: "::1") do |data, conn|
404
+ received << data
405
+ conn.write "ack\n"
406
+ end
407
+ 3.times do
408
+ TCPSocket.open("::1", PORT) do |sock|
409
+ sock.puts "yay"
410
+ sock.puts "foo"
411
+ responses << sock.readline
412
+ end
413
+ end
414
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
415
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
416
+ assert_equal ["ack\n","ack\n","ack\n"], responses
417
+ end
418
+
419
+ test 'does not resolve name of client address in default' do
420
+ received = ""
421
+ sources = []
422
+ @d.server_create_tcp(:s, PORT) do |data, conn|
423
+ received << data
424
+ sources << conn.remote_host
425
+ end
426
+ 3.times do
427
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
428
+ sock.puts "yay"
429
+ end
430
+ end
431
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
432
+ assert_equal "yay\nyay\nyay\n", received
433
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
434
+ end
435
+
436
+ test 'does resolve name of client address if resolve_name is true' do
437
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
438
+
439
+ received = ""
440
+ sources = []
441
+ @d.server_create_tcp(:s, PORT, resolve_name: true) do |data, conn|
442
+ received << data
443
+ sources << conn.remote_host
444
+ end
445
+ 3.times do
446
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
447
+ sock.puts "yay"
448
+ end
449
+ end
450
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
451
+ assert_equal "yay\nyay\nyay\n", received
452
+ assert{ sources.all?{|s| s == hostname } }
453
+ end
454
+
455
+ test 'can keep connections alive for tcp if keepalive specified' do
456
+ # pend "not implemented yet"
457
+ end
458
+
459
+ test 'raises error if plugin registers data callback for connection object from #server_create' do
460
+ received = ""
461
+ errors = []
462
+ @d.server_create_tcp(:s, PORT) do |data, conn|
463
+ received << data
464
+ begin
465
+ conn.data{|d| received << d.upcase }
466
+ rescue => e
467
+ errors << e
468
+ end
469
+ end
470
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
471
+ sock.puts "foo"
472
+ end
473
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
474
+ assert_equal "foo\n", received
475
+ assert{ errors.size > 0 } # it might be called twice (or more) when connection was accepted, and then data arrived (or more)
476
+ assert_equal "data callback can be registered just once, but registered twice", errors.first.message
477
+ end
478
+
479
+ test 'can call write_complete callback if registered' do
480
+ buffer = ""
481
+ lines = []
482
+ responses = []
483
+ response_completes = []
484
+ @d.server_create_tcp(:s, PORT) do |data, conn|
485
+ conn.on(:write_complete){|c| response_completes << true }
486
+ buffer << data
487
+ if idx = buffer.index("\n")
488
+ lines << buffer.slice!(0,idx+1)
489
+ conn.write "ack\n"
490
+ end
491
+ end
492
+ 3.times do
493
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
494
+ sock.write "yay"
495
+ sock.write "foo\n"
496
+ begin
497
+ responses << sock.readline
498
+ rescue EOFError, IOError, Errno::ECONNRESET
499
+ # ignore
500
+ end
501
+ sock.close
502
+ end
503
+ end
504
+ waiting(10){ sleep 0.1 until lines.size == 3 && response_completes.size == 3 }
505
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
506
+ assert_equal ["ack\n","ack\n","ack\n"], responses
507
+ assert_equal [true, true, true], response_completes
508
+ end
509
+
510
+ test 'can call close callback if registered' do
511
+ buffer = ""
512
+ lines = []
513
+ callback_results = []
514
+ @d.server_create_tcp(:s, PORT) do |data, conn|
515
+ conn.on(:close){|c| callback_results << "closed" }
516
+ buffer << data
517
+ if idx = buffer.index("\n")
518
+ lines << buffer.slice!(0,idx+1)
519
+ conn.write "ack\n"
520
+ end
521
+ end
522
+ 3.times do
523
+ TCPSocket.open("127.0.0.1", PORT) do |sock|
524
+ sock.write "yay"
525
+ sock.write "foo\n"
526
+ begin
527
+ while line = sock.readline
528
+ if line == "ack\n"
529
+ sock.close
530
+ end
531
+ end
532
+ rescue EOFError, IOError, Errno::ECONNRESET
533
+ # ignore
534
+ end
535
+ end
536
+ end
537
+ waiting(10){ sleep 0.1 until lines.size == 3 && callback_results.size == 3 }
538
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
539
+ assert_equal ["closed", "closed", "closed"], callback_results
540
+ end
541
+ end
542
+
543
+ sub_test_case '#server_create_udp' do
544
+ test 'can accept all keyword arguments valid for udp server' do
545
+ assert_nothing_raised do
546
+ @d.server_create_udp(:s, PORT, bind: '127.0.0.1', shared: false, resolve_name: true, max_bytes: 100, flags: 1) do |data, conn|
547
+ # ...
548
+ end
549
+ end
550
+ end
551
+
552
+ test 'creates a udp server just to read data' do
553
+ received = ""
554
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data|
555
+ received << data
556
+ end
557
+ bind_port = unused_port(protocol: :udp, bind: "127.0.0.1")
558
+ 3.times do
559
+ sock = UDPSocket.new(Socket::AF_INET)
560
+ sock.bind("127.0.0.1", bind_port)
561
+ sock.connect("127.0.0.1", PORT)
562
+ sock.puts "yay"
563
+ sock.puts "foo"
564
+ sock.close
565
+ end
566
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
567
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
568
+ end
569
+
570
+ test 'creates a udp server to read and write data' do
571
+ received = ""
572
+ responses = []
573
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
574
+ received << data
575
+ sock.write "ack\n"
576
+ end
577
+ bind_port = unused_port
578
+ 3.times do
579
+ begin
580
+ sock = UDPSocket.new(Socket::AF_INET)
581
+ sock.bind("127.0.0.1", bind_port)
582
+ sock.connect("127.0.0.1", PORT)
583
+ th = Thread.new do
584
+ while true
585
+ begin
586
+ in_data, _addr = sock.recvfrom_nonblock(16)
587
+ if in_data
588
+ responses << in_data
589
+ break
590
+ end
591
+ rescue IO::WaitReadable
592
+ IO.select([sock])
593
+ end
594
+ end
595
+ true
596
+ end
597
+ sock.write "yay\nfoo\n"
598
+ th.join(5)
599
+ ensure
600
+ sock.close
601
+ end
602
+ end
603
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
604
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
605
+ assert_equal ["ack\n","ack\n","ack\n"], responses
606
+ end
607
+
608
+ test 'creates a udp server to read and write data using IPv6' do
609
+ omit "IPv6 unavailable here" unless ipv6_enabled?
610
+
611
+ received = ""
612
+ responses = []
613
+ @d.server_create_udp(:s, PORT, bind: "::1", max_bytes: 128) do |data, sock|
614
+ received << data
615
+ sock.write "ack\n"
616
+ end
617
+ bind_port = unused_port
618
+ 3.times do
619
+ begin
620
+ sock = UDPSocket.new(Socket::AF_INET6)
621
+ sock.bind("::1", bind_port)
622
+ th = Thread.new do
623
+ responses << sock.recv(16)
624
+ true
625
+ end
626
+ sock.connect("::1", PORT)
627
+ sock.write "yay\nfoo\n"
628
+ th.join(5)
629
+ ensure
630
+ sock.close
631
+ end
632
+ end
633
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
634
+ assert_equal "yay\nfoo\nyay\nfoo\nyay\nfoo\n", received
635
+ assert_equal ["ack\n","ack\n","ack\n"], responses
636
+ end
637
+
638
+ test 'does not resolve name of client address in default' do
639
+ received = ""
640
+ sources = []
641
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
642
+ received << data
643
+ sources << sock.remote_host
644
+ end
645
+ 3.times do
646
+ sock = UDPSocket.new(Socket::AF_INET)
647
+ sock.connect("127.0.0.1", PORT)
648
+ sock.puts "yay"
649
+ sock.close
650
+ end
651
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
652
+ assert_equal "yay\nyay\nyay\n", received
653
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
654
+ end
655
+
656
+ test 'does resolve name of client address if resolve_name is true' do
657
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
658
+
659
+ received = ""
660
+ sources = []
661
+ @d.server_create_udp(:s, PORT, resolve_name: true, max_bytes: 128) do |data, sock|
662
+ received << data
663
+ sources << sock.remote_host
664
+ end
665
+ 3.times do
666
+ sock = UDPSocket.new(Socket::AF_INET)
667
+ sock.connect("127.0.0.1", PORT)
668
+ sock.puts "yay"
669
+ sock.close
670
+ end
671
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
672
+ assert_equal "yay\nyay\nyay\n", received
673
+ assert{ sources.all?{|s| s == hostname } }
674
+ end
675
+
676
+ test 'raises error if plugin registers data callback for connection object from #server_create' do
677
+ received = ""
678
+ errors = []
679
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
680
+ received << data
681
+ begin
682
+ sock.data{|d| received << d.upcase }
683
+ rescue => e
684
+ errors << e
685
+ end
686
+ end
687
+ sock = UDPSocket.new(Socket::AF_INET)
688
+ sock.connect("127.0.0.1", PORT)
689
+ sock.write "foo\n"
690
+ sock.close
691
+
692
+ waiting(10){ sleep 0.1 until received.bytesize == 4 && errors.size == 1 }
693
+ assert_equal "foo\n", received
694
+ assert_equal 1, errors.size
695
+ assert_equal "BUG: this event is disabled for udp: data", errors.first.message
696
+ end
697
+
698
+ test 'raise error if plugin registers write_complete callback for udp' do
699
+ received = ""
700
+ errors = []
701
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
702
+ received << data
703
+ begin
704
+ sock.on(:write_complete){|conn| "" }
705
+ rescue => e
706
+ errors << e
707
+ end
708
+ end
709
+ sock = UDPSocket.new(Socket::AF_INET)
710
+ sock.connect("127.0.0.1", PORT)
711
+ sock.write "foo\n"
712
+ sock.close
713
+
714
+ waiting(10){ sleep 0.1 until received.bytesize == 4 && errors.size == 1 }
715
+ assert_equal "foo\n", received
716
+ assert_equal 1, errors.size
717
+ assert_equal "BUG: this event is disabled for udp: write_complete", errors.first.message
718
+ end
719
+
720
+ test 'raises error if plugin registers close callback for udp' do
721
+ received = ""
722
+ errors = []
723
+ @d.server_create_udp(:s, PORT, max_bytes: 128) do |data, sock|
724
+ received << data
725
+ begin
726
+ sock.on(:close){|d| "" }
727
+ rescue => e
728
+ errors << e
729
+ end
730
+ end
731
+ sock = UDPSocket.new(Socket::AF_INET)
732
+ sock.connect("127.0.0.1", PORT)
733
+ sock.write "foo\n"
734
+ sock.close
735
+
736
+ waiting(10){ sleep 0.1 until received.bytesize == 4 && errors.size == 1 }
737
+ assert_equal "foo\n", received
738
+ assert_equal 1, errors.size
739
+ assert_equal "BUG: this event is disabled for udp: close", errors.first.message
740
+ end
741
+ end
742
+
743
+ module CertUtil
744
+ extend Fluent::PluginHelper::CertOption
745
+ end
746
+
747
+ def create_ca_options
748
+ {
749
+ private_key_length: 2048,
750
+ country: 'US',
751
+ state: 'CA',
752
+ locality: 'Mountain View',
753
+ common_name: 'ca.testing.fluentd.org',
754
+ expiration: 30 * 86400,
755
+ digest: :sha256,
756
+ }
757
+ end
758
+
759
+ def create_server_options
760
+ {
761
+ private_key_length: 2048,
762
+ country: 'US',
763
+ state: 'CA',
764
+ locality: 'Mountain View',
765
+ common_name: 'server.testing.fluentd.org',
766
+ expiration: 30 * 86400,
767
+ digest: :sha256,
768
+ }
769
+ end
770
+
771
+ def write_cert_and_key(cert_path, cert, key_path, key, passphrase)
772
+ File.open(cert_path, "w"){|f| f.write(cert.to_pem) }
773
+ # Write the secret key (raw or encrypted by AES256) in PEM format
774
+ key_str = passphrase ? key.export(OpenSSL::Cipher.new("AES-256-CBC"), passphrase) : key.export
775
+ File.open(key_path, "w"){|f| f.write(key_str) }
776
+ File.chmod(0600, cert_path, key_path)
777
+ end
778
+
779
+ def create_server_pair_signed_by_self(cert_path, private_key_path, passphrase)
780
+ cert, key, _ = CertUtil.cert_option_generate_server_pair_self_signed(create_server_options)
781
+ write_cert_and_key(cert_path, cert, private_key_path, key, passphrase)
782
+ return cert
783
+ end
784
+
785
+ def create_ca_pair_signed_by_self(cert_path, private_key_path, passphrase)
786
+ cert, key, _ = CertUtil.cert_option_generate_ca_pair_self_signed(create_ca_options)
787
+ write_cert_and_key(cert_path, cert, private_key_path, key, passphrase)
788
+ end
789
+
790
+ def create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, passphrase)
791
+ cert, key, _ = CertUtil.cert_option_generate_server_pair_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, create_server_options)
792
+ write_cert_and_key(cert_path, cert, private_key_path, key, passphrase)
793
+ return cert
794
+ end
795
+
796
+ def create_server_pair_chained_with_root_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, passphrase)
797
+ root_cert, root_key, _ = CertUtil.cert_option_generate_ca_pair_self_signed(create_ca_options)
798
+ write_cert_and_key(ca_cert_path, root_cert, ca_key_path, root_key, ca_key_passphrase)
799
+
800
+ intermediate_ca_options = create_ca_options
801
+ intermediate_ca_options[:common_name] = 'ca2.testing.fluentd.org'
802
+ chain_cert, chain_key = CertUtil.cert_option_generate_pair(intermediate_ca_options, root_cert.subject)
803
+ chain_cert.add_extension OpenSSL::X509::Extension.new('basicConstraints', OpenSSL::ASN1.Sequence([OpenSSL::ASN1::Boolean(true)]))
804
+ chain_cert.sign(root_key, "sha256")
805
+
806
+ server_cert, server_key, _ = CertUtil.cert_option_generate_pair(create_server_options, chain_cert.subject)
807
+ server_cert.add_extension OpenSSL::X509::Extension.new('basicConstraints', OpenSSL::ASN1.Sequence([OpenSSL::ASN1::Boolean(false)]))
808
+ server_cert.add_extension OpenSSL::X509::Extension.new('nsCertType', 'server')
809
+ server_cert.sign(chain_key, "sha256")
810
+
811
+ # write chained cert
812
+ File.open(cert_path, "w") do |f|
813
+ f.write server_cert.to_pem
814
+ f.write chain_cert.to_pem
815
+ end
816
+ key_str = passphrase ? server_key.export(OpenSSL::Cipher.new("AES-256-CBC"), passphrase) : server_key.export
817
+ File.open(private_key_path, "w"){|f| f.write(key_str) }
818
+ File.chmod(0600, cert_path, private_key_path)
819
+ end
820
+
821
+ def open_tls_session(addr, port, verify: true, cert_path: nil, selfsigned: true, hostname: nil)
822
+ context = OpenSSL::SSL::SSLContext.new
823
+ context.set_params({})
824
+ if verify
825
+ cert_store = OpenSSL::X509::Store.new
826
+ cert_store.set_default_paths
827
+ if selfsigned && OpenSSL::X509.const_defined?('V_FLAG_CHECK_SS_SIGNATURE')
828
+ cert_store.flags = OpenSSL::X509::V_FLAG_CHECK_SS_SIGNATURE
829
+ end
830
+ if cert_path
831
+ cert_store.add_file(cert_path)
832
+ end
833
+ context.verify_mode = OpenSSL::SSL::VERIFY_PEER
834
+ context.cert_store = cert_store
835
+ if !hostname && context.respond_to?(:verify_hostname=)
836
+ context.verify_hostname = false # In test code, using hostname to be connected is very difficult
837
+ end
838
+ else
839
+ context.verify_mode = OpenSSL::SSL::VERIFY_NONE
840
+ end
841
+
842
+ sock = OpenSSL::SSL::SSLSocket.new(TCPSocket.new(addr, port), context)
843
+ sock.hostname = hostname if hostname && sock.respond_to?(:hostname)
844
+ sock.connect
845
+ yield sock
846
+ ensure
847
+ sock.close rescue nil
848
+ end
849
+
850
+ def assert_certificate(cert, expected_extensions)
851
+ get_extension = lambda do |oid|
852
+ cert.extensions.detect { |e| e.oid == oid }
853
+ end
854
+
855
+ assert_true cert.serial > 1
856
+ assert_equal 2, cert.version
857
+
858
+ expected_extensions.each do |ext|
859
+ expected_oid, expected_value = ext
860
+ assert_equal expected_value, get_extension.call(expected_oid).value
861
+ end
862
+ end
863
+
864
+ sub_test_case '#server_create_tls with various certificate options' do
865
+ setup do
866
+ @d = Dummy.new # to get plugin not configured/started yet
867
+
868
+ @certs_dir = File.join(TMP_DIR, "tls_certs")
869
+ @server_cert_dir = File.join(@certs_dir, "server")
870
+ FileUtils.rm_rf @certs_dir
871
+ FileUtils.mkdir_p @server_cert_dir
872
+ end
873
+
874
+ sub_test_case 'using tls_options arguments to specify cert options' do
875
+ setup do
876
+ @d.configure(config_element()); @d.start; @d.after_start
877
+ end
878
+
879
+ test 'create dynamic self-signed cert/key pair (without any verification from clients)' do
880
+ # insecure
881
+ tls_options = {
882
+ protocol: :tls,
883
+ version: 'TLSv1_2',
884
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
885
+ insecure: true,
886
+ generate_private_key_length: 2048,
887
+ generate_cert_country: 'US',
888
+ generate_cert_state: 'CA',
889
+ generate_cert_locality: 'Mountain View',
890
+ generate_cert_common_name: 'myserver.testing.fluentd.org',
891
+ generate_cert_expiration: 10 * 365 * 86400,
892
+ generate_cert_digest: :sha256,
893
+ }
894
+
895
+ received = ""
896
+ @d.server_create_tls(:s, PORT, tls_options: tls_options) do |data, conn|
897
+ received << data
898
+ end
899
+ assert_raise "" do
900
+ open_tls_session('127.0.0.1', PORT) do |sock|
901
+ sock.post_connection_check('myserver.testing.fluentd.org')
902
+ # cannot connect ....
903
+ end
904
+ end
905
+ open_tls_session('127.0.0.1', PORT, verify: false) do |sock|
906
+ sock.puts "yay"
907
+ sock.puts "foo"
908
+ end
909
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
910
+ assert_equal "yay\nfoo\n", received
911
+ end
912
+
913
+ data('with passphrase' => 'yaaaaaaaaaaaaaaaaaaay',
914
+ 'without passphrase' => nil)
915
+ test 'load self-signed cert/key pair (files), verified from clients using cert files' do |private_key_passphrase|
916
+ cert_path = File.join(@server_cert_dir, "cert.pem")
917
+ private_key_path = File.join(@certs_dir, "server.key.pem")
918
+ cert = create_server_pair_signed_by_self(cert_path, private_key_path, private_key_passphrase)
919
+
920
+ assert_certificate(cert,[
921
+ ['basicConstraints', 'CA:FALSE'],
922
+ ['nsCertType', 'SSL Server']
923
+ ])
924
+
925
+ tls_options = {
926
+ protocol: :tls,
927
+ version: 'TLSv1_2',
928
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
929
+ insecure: false,
930
+ cert_path: cert_path,
931
+ private_key_path: private_key_path,
932
+ }
933
+ tls_options[:private_key_passphrase] = private_key_passphrase if private_key_passphrase
934
+ received = ""
935
+ @d.server_create_tls(:s, PORT, tls_options: tls_options) do |data, conn|
936
+ received << data
937
+ end
938
+ assert_raise "" do
939
+ open_tls_session('127.0.0.1', PORT) do |sock|
940
+ sock.post_connection_check('server.testing.fluentd.org')
941
+ # cannot connect by failing verification without server cert
942
+ end
943
+ end
944
+ open_tls_session('127.0.0.1', PORT, cert_path: cert_path) do |sock|
945
+ sock.puts "yay"
946
+ sock.puts "foo"
947
+ end
948
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
949
+ assert_equal "yay\nfoo\n", received
950
+ end
951
+
952
+ data('with passphrase' => "fooooooooooooooooooooooooo",
953
+ 'without passphrase' => nil)
954
+ test 'create dynamic server cert by private CA cert file, verified from clients using CA cert file' do |ca_key_passphrase|
955
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
956
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
957
+ create_ca_pair_signed_by_self(ca_cert_path, ca_key_path, ca_key_passphrase)
958
+
959
+ tls_options = {
960
+ protocol: :tls,
961
+ version: 'TLSv1_2',
962
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
963
+ insecure: false,
964
+ ca_cert_path: ca_cert_path,
965
+ ca_private_key_path: ca_key_path,
966
+ generate_private_key_length: 2048,
967
+ }
968
+ tls_options[:ca_private_key_passphrase] = ca_key_passphrase if ca_key_passphrase
969
+ received = ""
970
+ @d.server_create_tls(:s, PORT, tls_options: tls_options) do |data, conn|
971
+ received << data
972
+ end
973
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
974
+ sock.puts "yay"
975
+ sock.puts "foo"
976
+ end
977
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
978
+ assert_equal "yay\nfoo\n", received
979
+ end
980
+
981
+ data('with passphrase' => ["foooooooo", "yaaaaaaaaaaaaaaaaaaay"],
982
+ 'without passphrase' => [nil, nil])
983
+ test 'load static server cert by private CA cert file, verified from clients using CA cert file' do |(ca_key_passphrase, private_key_passphrase)|
984
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
985
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
986
+ create_ca_pair_signed_by_self(ca_cert_path, ca_key_path, ca_key_passphrase)
987
+
988
+ cert_path = File.join(@server_cert_dir, "cert.pem")
989
+ private_key_path = File.join(@certs_dir, "server.key.pem")
990
+ cert = create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)
991
+
992
+ assert_certificate(cert,[
993
+ ['basicConstraints', 'CA:FALSE'],
994
+ ['nsCertType', 'SSL Server'],
995
+ ['keyUsage', 'Digital Signature, Key Encipherment'],
996
+ ['extendedKeyUsage', 'TLS Web Server Authentication']
997
+ ])
998
+
999
+ tls_options = {
1000
+ protocol: :tls,
1001
+ version: 'TLSv1_2',
1002
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
1003
+ insecure: false,
1004
+ cert_path: cert_path,
1005
+ private_key_path: private_key_path,
1006
+ }
1007
+ tls_options[:private_key_passphrase] = private_key_passphrase if private_key_passphrase
1008
+ received = ""
1009
+ @d.server_create_tls(:s, PORT, tls_options: tls_options) do |data, conn|
1010
+ received << data
1011
+ end
1012
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
1013
+ sock.puts "yay"
1014
+ sock.puts "foo"
1015
+ end
1016
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1017
+ assert_equal "yay\nfoo\n", received
1018
+ end
1019
+
1020
+ data('with passphrase' => ["foooooooo", "yaaaaaaaaaaaaaaaaaaay"],
1021
+ 'without passphrase' => [nil, nil])
1022
+ test 'load chained server cert by private CA cert file, verified from clients using CA cert file as root' do |(ca_key_passphrase, private_key_passphrase)|
1023
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
1024
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
1025
+ cert_path = File.join(@server_cert_dir, "cert.pem")
1026
+ private_key_path = File.join(@certs_dir, "server.key.pem")
1027
+ create_server_pair_chained_with_root_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)
1028
+
1029
+ tls_options = {
1030
+ protocol: :tls,
1031
+ version: 'TLSv1_2',
1032
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
1033
+ insecure: false,
1034
+ cert_path: cert_path,
1035
+ private_key_path: private_key_path,
1036
+ }
1037
+ tls_options[:private_key_passphrase] = private_key_passphrase if private_key_passphrase
1038
+ received = ""
1039
+ @d.server_create_tls(:s, PORT, tls_options: tls_options) do |data, conn|
1040
+ received << data
1041
+ end
1042
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
1043
+ sock.puts "yay"
1044
+ sock.puts "foo"
1045
+ end
1046
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1047
+ assert_equal "yay\nfoo\n", received
1048
+ end
1049
+ end
1050
+
1051
+ sub_test_case 'using configurations to specify cert options' do
1052
+ test 'create dynamic self-signed cert/key pair (without any verification from clients)' do
1053
+ # insecure
1054
+ transport_opts = {
1055
+ 'insecure' => 'true',
1056
+ }
1057
+ transport_conf = config_element('transport', 'tls', transport_opts)
1058
+ conf = config_element('match', 'tag.*', {}, [transport_conf])
1059
+
1060
+ @d.configure(conf); @d.start; @d.after_start
1061
+
1062
+ received = ""
1063
+ @d.server_create_tls(:s, PORT) do |data, conn|
1064
+ received << data
1065
+ end
1066
+ assert_raise "" do
1067
+ open_tls_session('127.0.0.1', PORT) do |sock|
1068
+ sock.post_connection_check('myserver.testing.fluentd.org')
1069
+ # cannot connect ....
1070
+ end
1071
+ end
1072
+ open_tls_session('127.0.0.1', PORT, verify: false) do |sock|
1073
+ sock.puts "yay"
1074
+ sock.puts "foo"
1075
+ end
1076
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1077
+ assert_equal "yay\nfoo\n", received
1078
+ end
1079
+
1080
+ data('with passphrase' => "yaaaaaaaaaaaaaaaaaaay",
1081
+ 'without passphrase' => nil)
1082
+ test 'load self-signed cert/key pair (files), verified from clients using cert files' do |private_key_passphrase|
1083
+ cert_path = File.join(@server_cert_dir, "cert.pem")
1084
+ private_key_path = File.join(@certs_dir, "server.key.pem")
1085
+ create_server_pair_signed_by_self(cert_path, private_key_path, private_key_passphrase)
1086
+
1087
+ transport_opts = {
1088
+ 'cert_path' => cert_path,
1089
+ 'private_key_path' => private_key_path,
1090
+ }
1091
+ transport_opts['private_key_passphrase'] = private_key_passphrase if private_key_passphrase
1092
+ transport_conf = config_element('transport', 'tls', transport_opts)
1093
+ conf = config_element('match', 'tag.*', {}, [transport_conf])
1094
+
1095
+ @d.configure(conf); @d.start; @d.after_start
1096
+
1097
+ received = ""
1098
+ @d.server_create_tls(:s, PORT) do |data, conn|
1099
+ received << data
1100
+ end
1101
+ assert_raise "" do
1102
+ open_tls_session('127.0.0.1', PORT) do |sock|
1103
+ sock.post_connection_check('server.testing.fluentd.org')
1104
+ # cannot connect by failing verification without server cert
1105
+ end
1106
+ end
1107
+ open_tls_session('127.0.0.1', PORT, cert_path: cert_path) do |sock|
1108
+ sock.puts "yay"
1109
+ sock.puts "foo"
1110
+ end
1111
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1112
+ assert_equal "yay\nfoo\n", received
1113
+ end
1114
+
1115
+ data('with passphrase' => "fooooooooooooooooooooooooo",
1116
+ 'without passphrase' => nil)
1117
+ test 'create dynamic server cert by private CA cert file, verified from clients using CA cert file' do |ca_key_passphrase|
1118
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
1119
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
1120
+ create_ca_pair_signed_by_self(ca_cert_path, ca_key_path, ca_key_passphrase)
1121
+
1122
+ transport_opts = {
1123
+ 'ca_cert_path' => ca_cert_path,
1124
+ 'ca_private_key_path' => ca_key_path,
1125
+ }
1126
+ transport_opts['ca_private_key_passphrase'] = ca_key_passphrase if ca_key_passphrase
1127
+ transport_conf = config_element('transport', 'tls', transport_opts)
1128
+ conf = config_element('match', 'tag.*', {}, [transport_conf])
1129
+
1130
+ @d.configure(conf); @d.start; @d.after_start
1131
+
1132
+ received = ""
1133
+ @d.server_create_tls(:s, PORT) do |data, conn|
1134
+ received << data
1135
+ end
1136
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
1137
+ sock.puts "yay"
1138
+ sock.puts "foo"
1139
+ end
1140
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1141
+ assert_equal "yay\nfoo\n", received
1142
+ end
1143
+
1144
+ data('with passphrase' => ["foooooooo", "yaaaaaaaaaaaaaaaaaaay"],
1145
+ 'without passphrase' => [nil, nil])
1146
+ test 'load static server cert by private CA cert file, verified from clients using CA cert file' do |(ca_key_passphrase, private_key_passphrase)|
1147
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
1148
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
1149
+ create_ca_pair_signed_by_self(ca_cert_path, ca_key_path, ca_key_passphrase)
1150
+
1151
+ cert_path = File.join(@server_cert_dir, "cert.pem")
1152
+ private_key_path = File.join(@certs_dir, "server.key.pem")
1153
+ create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)
1154
+
1155
+ transport_opts = {
1156
+ 'cert_path' => cert_path,
1157
+ 'private_key_path' => private_key_path,
1158
+ }
1159
+ transport_opts['private_key_passphrase'] = private_key_passphrase if private_key_passphrase
1160
+ transport_conf = config_element('transport', 'tls', transport_opts)
1161
+ conf = config_element('match', 'tag.*', {}, [transport_conf])
1162
+
1163
+ @d.configure(conf); @d.start; @d.after_start
1164
+
1165
+ received = ""
1166
+ @d.server_create_tls(:s, PORT) do |data, conn|
1167
+ received << data
1168
+ end
1169
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
1170
+ sock.puts "yay"
1171
+ sock.puts "foo"
1172
+ end
1173
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1174
+ assert_equal "yay\nfoo\n", received
1175
+ end
1176
+
1177
+ data('with passphrase' => ["foooooooo", "yaaaaaaaaaaaaaaaaaaay"],
1178
+ 'without passphrase' => [nil, nil])
1179
+ test 'load chained server cert by private CA cert file, verified from clients using CA cert file as root' do |(ca_key_passphrase, private_key_passphrase)|
1180
+ ca_cert_path = File.join(@certs_dir, "ca_cert.pem")
1181
+ ca_key_path = File.join(@certs_dir, "ca.key.pem")
1182
+ cert_path = File.join(@server_cert_dir, "cert.pem")
1183
+ private_key_path = File.join(@certs_dir, "server.key.pem")
1184
+ create_server_pair_chained_with_root_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)
1185
+
1186
+ transport_opts = {
1187
+ 'cert_path' => cert_path,
1188
+ 'private_key_path' => private_key_path,
1189
+ }
1190
+ transport_opts['private_key_passphrase'] = private_key_passphrase if private_key_passphrase
1191
+ transport_conf = config_element('transport', 'tls', transport_opts)
1192
+ conf = config_element('match', 'tag.*', {}, [transport_conf])
1193
+
1194
+ @d.configure(conf); @d.start; @d.after_start
1195
+
1196
+ received = ""
1197
+ @d.server_create_tls(:s, PORT) do |data, conn|
1198
+ received << data
1199
+ end
1200
+ open_tls_session('127.0.0.1', PORT, cert_path: ca_cert_path) do |sock|
1201
+ sock.puts "yay"
1202
+ sock.puts "foo"
1203
+ end
1204
+ waiting(10){ sleep 0.1 until received.bytesize == 8 }
1205
+ assert_equal "yay\nfoo\n", received
1206
+ end
1207
+ end
1208
+ end
1209
+
1210
+ sub_test_case '#server_create_tls' do
1211
+ setup do
1212
+ @certs_dir = File.join(TMP_DIR, "tls_certs")
1213
+ FileUtils.rm_rf @certs_dir
1214
+ FileUtils.mkdir_p @certs_dir
1215
+
1216
+ @server_cert_dir = File.join(@certs_dir, "server")
1217
+ FileUtils.mkdir_p @server_cert_dir
1218
+
1219
+ @cert_path = File.join(@server_cert_dir, "cert.pem")
1220
+ private_key_path = File.join(@certs_dir, "server.key.pem")
1221
+ private_key_passphrase = "yaaaaaaaaaaaaaaaaaaay"
1222
+ create_server_pair_signed_by_self(@cert_path, private_key_path, private_key_passphrase)
1223
+
1224
+ @default_hostname = ::Socket.gethostname
1225
+
1226
+ @tls_options = {
1227
+ protocol: :tls,
1228
+ version: 'TLSv1_2',
1229
+ ciphers: 'ALL:!aNULL:!eNULL:!SSLv2',
1230
+ insecure: false,
1231
+ cert_path: @cert_path,
1232
+ private_key_path: private_key_path,
1233
+ private_key_passphrase: private_key_passphrase,
1234
+ }
1235
+ end
1236
+
1237
+ test 'can accept all keyword arguments valid for tcp/tls server' do
1238
+ assert_nothing_raised do
1239
+ @d.server_create_tls(:s, PORT, bind: '127.0.0.1', shared: false, resolve_name: true, linger_timeout: 10, backlog: 500, tls_options: @tls_options) do |data, conn|
1240
+ # ...
1241
+ end
1242
+ end
1243
+ end
1244
+
1245
+ test 'creates a tls server just to read data' do
1246
+ received = ""
1247
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1248
+ received << data
1249
+ end
1250
+ 3.times do
1251
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1252
+ sock.puts "yay"
1253
+ sock.puts "foo"
1254
+ end
1255
+ end
1256
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
1257
+ assert_equal 3, received.scan("yay\n").size
1258
+ assert_equal 3, received.scan("foo\n").size
1259
+ end
1260
+
1261
+ test 'creates a tls server to read and write data' do
1262
+ received = ""
1263
+ responses = []
1264
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1265
+ received << data
1266
+ conn.write "ack\n"
1267
+ end
1268
+ 3.times do
1269
+ # open_tls_session('127.0.0.1', PORT, cert_path: @cert_path, hostname: @default_hostname) do |sock|
1270
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1271
+ sock.puts "yay"
1272
+ sock.puts "foo"
1273
+ responses << sock.readline
1274
+ end
1275
+ end
1276
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
1277
+ assert_equal 3, received.scan("yay\n").size
1278
+ assert_equal 3, received.scan("foo\n").size
1279
+ assert_equal ["ack\n","ack\n","ack\n"], responses
1280
+ end
1281
+
1282
+ test 'creates a tls server to read and write data using IPv6' do
1283
+ omit "IPv6 unavailable here" unless ipv6_enabled?
1284
+
1285
+ received = ""
1286
+ responses = []
1287
+ @d.server_create_tls(:s, PORT, bind: "::1", tls_options: @tls_options) do |data, conn|
1288
+ received << data
1289
+ conn.write "ack\n"
1290
+ end
1291
+ 3.times do
1292
+ # open_tls_session('::1', PORT, cert_path: @cert_path, hostname: @default_hostname) do |sock|
1293
+ open_tls_session('::1', PORT, cert_path: @cert_path) do |sock|
1294
+ sock.puts "yay"
1295
+ sock.puts "foo"
1296
+ responses << sock.readline
1297
+ end
1298
+ end
1299
+ waiting(10){ sleep 0.1 until received.bytesize == 24 }
1300
+ assert_equal 3, received.scan("yay\n").size
1301
+ assert_equal 3, received.scan("foo\n").size
1302
+ assert_equal ["ack\n","ack\n","ack\n"], responses
1303
+ end
1304
+
1305
+ test 'does not resolve name of client address in default' do
1306
+ received = ""
1307
+ sources = []
1308
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1309
+ received << data
1310
+ sources << conn.remote_host
1311
+ end
1312
+ 3.times do
1313
+ # open_tls_session('127.0.0.1', PORT, cert_path: @cert_path, hostname: @default_hostname) do |sock|
1314
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1315
+ sock.puts "yay"
1316
+ end
1317
+ end
1318
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
1319
+ assert_equal 3, received.scan("yay\n").size
1320
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
1321
+ end
1322
+
1323
+ test 'does resolve name of client address if resolve_name is true' do
1324
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
1325
+
1326
+ received = ""
1327
+ sources = []
1328
+ @d.server_create_tls(:s, PORT, resolve_name: true, tls_options: @tls_options) do |data, conn|
1329
+ received << data
1330
+ sources << conn.remote_host
1331
+ end
1332
+ 3.times do
1333
+ # open_tls_session('127.0.0.1', PORT, cert_path: @cert_path, hostname: @default_hostname) do |sock|
1334
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1335
+ sock.puts "yay"
1336
+ end
1337
+ end
1338
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
1339
+ assert_equal 3, received.scan("yay\n").size
1340
+ assert{ sources.all?{|s| s == hostname } }
1341
+ end
1342
+
1343
+ test 'can keep connections alive for tls if keepalive specified' do
1344
+ # pend "not implemented yet"
1345
+ end
1346
+
1347
+ test 'raises error if plugin registers data callback for connection object from #server_create' do
1348
+ received = ""
1349
+ errors = []
1350
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1351
+ received << data
1352
+ begin
1353
+ conn.data{|d| received << d.upcase }
1354
+ rescue => e
1355
+ errors << e
1356
+ end
1357
+ end
1358
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1359
+ sock.puts "foo"
1360
+ end
1361
+ waiting(10){ sleep 0.1 until received.bytesize == 4 || errors.size == 1 }
1362
+ assert_equal "foo\n", received
1363
+ assert_equal 1, errors.size
1364
+ assert_equal "data callback can be registered just once, but registered twice", errors.first.message
1365
+ end
1366
+
1367
+ test 'can call write_complete callback if registered' do
1368
+ buffer = ""
1369
+ lines = []
1370
+ responses = []
1371
+ response_completes = []
1372
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1373
+ conn.on(:write_complete){|c| response_completes << true }
1374
+ buffer << data
1375
+ if idx = buffer.index("\n")
1376
+ lines << buffer.slice!(0,idx+1)
1377
+ conn.write "ack\n"
1378
+ end
1379
+ end
1380
+ 3.times do
1381
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1382
+ sock.write "yay"
1383
+ sock.write "foo\n"
1384
+ begin
1385
+ responses << sock.readline
1386
+ rescue EOFError, IOError, Errno::ECONNRESET
1387
+ # ignore
1388
+ end
1389
+ sock.close
1390
+ end
1391
+ end
1392
+ waiting(10){ sleep 0.1 until lines.size == 3 && response_completes.size == 3 }
1393
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
1394
+ assert_equal ["ack\n","ack\n","ack\n"], responses
1395
+ assert_equal [true, true, true], response_completes
1396
+ end
1397
+
1398
+ test 'can call close callback if registered' do
1399
+ buffer = ""
1400
+ lines = []
1401
+ callback_results = []
1402
+ @d.server_create_tls(:s, PORT, tls_options: @tls_options) do |data, conn|
1403
+ conn.on(:close){|c| callback_results << "closed" }
1404
+ buffer << data
1405
+ if idx = buffer.index("\n")
1406
+ lines << buffer.slice!(0,idx+1)
1407
+ conn.write "ack\n"
1408
+ end
1409
+ end
1410
+ 3.times do
1411
+ open_tls_session('127.0.0.1', PORT, cert_path: @cert_path) do |sock|
1412
+ sock.write "yay"
1413
+ sock.write "foo\n"
1414
+ begin
1415
+ while line = sock.readline
1416
+ if line == "ack\n"
1417
+ sock.close
1418
+ end
1419
+ end
1420
+ rescue EOFError, IOError, Errno::ECONNRESET
1421
+ # ignore
1422
+ end
1423
+ end
1424
+ end
1425
+ waiting(10){ sleep 0.1 until lines.size == 3 && callback_results.size == 3 }
1426
+ assert_equal ["yayfoo\n", "yayfoo\n", "yayfoo\n"], lines
1427
+ assert_equal ["closed", "closed", "closed"], callback_results
1428
+ end
1429
+ end
1430
+
1431
+ sub_test_case '#server_create_unix' do
1432
+ # not implemented yet
1433
+
1434
+ # test 'can accept all keyword arguments valid for unix server'
1435
+ # test 'creates a unix server just to read data'
1436
+ # test 'creates a unix server to read and write data'
1437
+
1438
+ # test 'raises error if plugin registers data callback for connection object from #server_create'
1439
+ # test 'can call write_complete callback if registered'
1440
+ # test 'can call close callback if registered'
1441
+ end
1442
+
1443
+ def open_client(proto, addr, port)
1444
+ client = case proto
1445
+ when :tcp
1446
+ TCPSocket.open(addr, port)
1447
+ when :tls
1448
+ c = OpenSSL::SSL::SSLSocket.new(TCPSocket.open(addr, port))
1449
+ c.sync_close = true
1450
+ c.connect
1451
+ else
1452
+ raise ArgumentError, "unknown proto:#{proto}"
1453
+ end
1454
+ yield client
1455
+ ensure
1456
+ client.close rescue nil
1457
+ end
1458
+
1459
+ # run tests for tcp, tls and unix
1460
+ sub_test_case '#server_create_connection' do
1461
+ test 'raise error if udp is specified in proto' do
1462
+ assert_raise(ArgumentError.new("BUG: cannot create connection for UDP")) do
1463
+ @d.server_create_connection(:myserver, PORT, proto: :udp){|c| c }
1464
+ end
1465
+ end
1466
+
1467
+ # def server_create_connection(title, port, proto: :tcp, bind: '0.0.0.0', shared: true, tls_options: nil, resolve_name: false, linger_timeout: 0, backlog: nil, &block)
1468
+ protocols = {
1469
+ 'tcp' => [:tcp, {}],
1470
+ 'tls' => [:tls, {tls_options: {insecure: true}}],
1471
+ # 'unix' => [:unix, {path: ""}],
1472
+ }
1473
+
1474
+ data(protocols)
1475
+ test 'raise error if block argument is not specified or too many' do |(proto, kwargs)|
1476
+ empty_block = ->(){}
1477
+ assert_raise(ArgumentError.new("BUG: block must have just one argument")) do
1478
+ @d.server_create_connection(:myserver, PORT, proto: proto, **kwargs, &empty_block)
1479
+ end
1480
+ assert_raise(ArgumentError.new("BUG: block must have just one argument")) do
1481
+ @d.server_create_connection(:myserver, PORT, proto: proto, **kwargs){|conn, what_is_this| [conn, what_is_this] }
1482
+ end
1483
+ end
1484
+
1485
+ data(protocols)
1486
+ test 'does not resolve name of client address in default' do |(proto, kwargs)|
1487
+ received = ""
1488
+ sources = []
1489
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
1490
+ sources << conn.remote_host
1491
+ conn.data do |d|
1492
+ received << d
1493
+ end
1494
+ end
1495
+ 3.times do
1496
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1497
+ sock.puts "yay"
1498
+ end
1499
+ end
1500
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
1501
+ assert_equal "yay\nyay\nyay\n", received
1502
+ assert{ sources.all?{|s| s == "127.0.0.1" } }
1503
+ end
1504
+
1505
+ data(protocols)
1506
+ test 'does resolve name of client address if resolve_name is true' do |(proto, kwargs)|
1507
+ hostname = Socket.getnameinfo([nil, nil, nil, "127.0.0.1"])[0]
1508
+
1509
+ received = ""
1510
+ sources = []
1511
+ @d.server_create_connection(:s, PORT, proto: proto, resolve_name: true, **kwargs) do |conn|
1512
+ sources << conn.remote_host
1513
+ conn.data do |d|
1514
+ received << d
1515
+ end
1516
+ end
1517
+ 3.times do
1518
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1519
+ sock.puts "yay"
1520
+ end
1521
+ end
1522
+ waiting(10){ sleep 0.1 until received.bytesize == 12 }
1523
+ assert_equal "yay\nyay\nyay\n", received
1524
+ assert{ sources.all?{|s| s == hostname } }
1525
+ end
1526
+
1527
+ data(protocols)
1528
+ test 'creates a server to provide connection, which can read, write and close' do |(proto, kwargs)|
1529
+ lines = []
1530
+ buffer = ""
1531
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
1532
+ conn.data do |d|
1533
+ buffer << d
1534
+ if buffer == "x"
1535
+ buffer.slice!(0, 1)
1536
+ conn.close
1537
+ end
1538
+ if idx = buffer.index("\n")
1539
+ lines << buffer.slice!(0, idx + 1)
1540
+ conn.write "foo!\n"
1541
+ end
1542
+ end
1543
+ end
1544
+ replied = []
1545
+ disconnecteds = []
1546
+ 3.times do |i|
1547
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1548
+ sock.puts "yay"
1549
+ while line = sock.readline
1550
+ replied << line
1551
+ break
1552
+ end
1553
+ sock.write "x"
1554
+ connection_closed = false
1555
+ begin
1556
+ data = sock.read
1557
+ if data.empty?
1558
+ connection_closed = true
1559
+ end
1560
+ rescue => e
1561
+ if e.is_a?(Errno::ECONNRESET)
1562
+ connection_closed = true
1563
+ end
1564
+ ensure
1565
+ disconnecteds << connection_closed
1566
+ end
1567
+ end
1568
+ end
1569
+ waiting(10){ sleep 0.1 until lines.size == 3 }
1570
+ waiting(10){ sleep 0.1 until replied.size == 3 }
1571
+ waiting(10){ sleep 0.1 until disconnecteds.size == 3 }
1572
+ assert_equal ["yay\n", "yay\n", "yay\n"], lines
1573
+ assert_equal ["foo!\n", "foo!\n", "foo!\n"], replied
1574
+ assert_equal [true, true, true], disconnecteds
1575
+ end
1576
+
1577
+ data(protocols)
1578
+ test 'creates a server to provide connection, which accepts callbacks for data, write_complete, and close' do |(proto, kwargs)|
1579
+ lines = []
1580
+ buffer = ""
1581
+ written = 0
1582
+ closed = 0
1583
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
1584
+ conn.on(:write_complete){|_conn| written += 1 }
1585
+ conn.on(:close){|_conn| closed += 1 }
1586
+ conn.on(:data) do |d|
1587
+ buffer << d
1588
+ if idx = buffer.index("\n")
1589
+ lines << buffer.slice!(0, idx + 1)
1590
+ conn.write "foo!\n"
1591
+ end
1592
+ end
1593
+ end
1594
+ replied = []
1595
+ 3.times do
1596
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1597
+ sock.puts "yay"
1598
+ while line = sock.readline
1599
+ replied << line
1600
+ break
1601
+ end
1602
+ end # TCP socket is closed here
1603
+ end
1604
+ waiting(10){ sleep 0.1 until lines.size == 3 }
1605
+ waiting(10){ sleep 0.1 until replied.size == 3 }
1606
+ waiting(10){ sleep 0.1 until closed == 3 }
1607
+ assert_equal ["yay\n", "yay\n", "yay\n"], lines
1608
+ assert_equal 3, written
1609
+ assert_equal 3, closed
1610
+ assert_equal ["foo!\n", "foo!\n", "foo!\n"], replied
1611
+ end
1612
+
1613
+ data(protocols)
1614
+ test 'creates a server, and does not leak connections' do |(proto, kwargs)|
1615
+ buffer = ""
1616
+ closed = 0
1617
+ @d.server_create_connection(:s, PORT, proto: proto, **kwargs) do |conn|
1618
+ conn.on(:close){|_c| closed += 1 }
1619
+ conn.on(:data) do |d|
1620
+ buffer << d
1621
+ end
1622
+ end
1623
+ 3.times do
1624
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1625
+ sock.puts "yay"
1626
+ end
1627
+ end
1628
+ waiting(10){ sleep 0.1 until buffer.bytesize == 12 }
1629
+ waiting(10){ sleep 0.1 until closed == 3 }
1630
+ assert_equal 0, @d.instance_eval{ @_server_connections.size }
1631
+ end
1632
+
1633
+ data(protocols)
1634
+ test 'will refuse more connect requests after stop, but read data from sockets already connected, in non-shared server' do |(proto, kwargs)|
1635
+ connected = false
1636
+ begin
1637
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1638
+ # expected behavior is connection refused...
1639
+ connected = true
1640
+ end
1641
+ rescue
1642
+ end
1643
+
1644
+ assert_false connected
1645
+
1646
+ received = ""
1647
+ @d.server_create_connection(:s, PORT, proto: proto, shared: false, **kwargs) do |conn|
1648
+ conn.on(:data) do |data|
1649
+ received << data
1650
+ conn.write "ack\n"
1651
+ end
1652
+ end
1653
+
1654
+ th0 = Thread.new do
1655
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1656
+ sock.puts "yay"
1657
+ sock.readline
1658
+ end
1659
+ end
1660
+
1661
+ value0 = waiting(5){ th0.value }
1662
+ assert_equal "ack\n", value0
1663
+
1664
+ stopped = false
1665
+ sleeping = false
1666
+ ending = false
1667
+
1668
+ th1 = Thread.new do
1669
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1670
+ sleeping = true
1671
+ sleep 0.1 until stopped
1672
+ sock.puts "yay"
1673
+ res = sock.readline
1674
+ ending = true
1675
+ res
1676
+ end
1677
+ end
1678
+
1679
+ sleep 0.1 until sleeping
1680
+
1681
+ @d.stop
1682
+ assert @d.stopped?
1683
+ stopped = true
1684
+
1685
+ sleep 0.1 until ending
1686
+
1687
+ @d.before_shutdown
1688
+ @d.shutdown
1689
+
1690
+ th2 = Thread.new do
1691
+ begin
1692
+ open_client(proto, "127.0.0.1", PORT) do |sock|
1693
+ sock.puts "foo"
1694
+ end
1695
+ false # failed
1696
+ rescue
1697
+ true # success
1698
+ end
1699
+ end
1700
+
1701
+ value1 = waiting(5){ th1.value }
1702
+ value2 = waiting(5){ th2.value }
1703
+
1704
+ assert_equal "yay\nyay\n", received
1705
+ assert_equal "ack\n", value1
1706
+ assert value2, "should be truthy value to show connection was correctly refused"
1707
+ end
1708
+
1709
+ test 'can keep connections alive for tcp/tls if keepalive specified' do
1710
+ # pend "not implemented yet"
1711
+ end
1712
+ end
1713
+
1714
+ end