fluent-plugin-elasticsearch 1.9.4 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  4. data/.github/workflows/issue-auto-closer.yml +12 -0
  5. data/.github/workflows/linux.yml +26 -0
  6. data/.github/workflows/macos.yml +26 -0
  7. data/.github/workflows/windows.yml +26 -0
  8. data/.travis.yml +33 -6
  9. data/CONTRIBUTING.md +24 -0
  10. data/Gemfile +4 -1
  11. data/History.md +445 -1
  12. data/ISSUE_TEMPLATE.md +19 -0
  13. data/README.ElasticsearchGenID.md +116 -0
  14. data/README.ElasticsearchInput.md +293 -0
  15. data/README.Troubleshooting.md +692 -0
  16. data/README.md +1013 -38
  17. data/appveyor.yml +20 -0
  18. data/fluent-plugin-elasticsearch.gemspec +15 -9
  19. data/{Gemfile.v0.12 → gemfiles/Gemfile.elasticsearch.v6} +6 -5
  20. data/lib/fluent/log-ext.rb +38 -0
  21. data/lib/fluent/plugin/default-ilm-policy.json +14 -0
  22. data/lib/fluent/plugin/elasticsearch_constants.rb +13 -0
  23. data/lib/fluent/plugin/elasticsearch_error.rb +5 -0
  24. data/lib/fluent/plugin/elasticsearch_error_handler.rb +129 -0
  25. data/lib/fluent/plugin/elasticsearch_fallback_selector.rb +9 -0
  26. data/lib/fluent/plugin/elasticsearch_index_lifecycle_management.rb +67 -0
  27. data/lib/fluent/plugin/elasticsearch_index_template.rb +186 -12
  28. data/lib/fluent/plugin/elasticsearch_simple_sniffer.rb +10 -0
  29. data/lib/fluent/plugin/elasticsearch_tls.rb +70 -0
  30. data/lib/fluent/plugin/filter_elasticsearch_genid.rb +77 -0
  31. data/lib/fluent/plugin/in_elasticsearch.rb +325 -0
  32. data/lib/fluent/plugin/oj_serializer.rb +22 -0
  33. data/lib/fluent/plugin/out_elasticsearch.rb +1008 -267
  34. data/lib/fluent/plugin/out_elasticsearch_data_stream.rb +218 -0
  35. data/lib/fluent/plugin/out_elasticsearch_dynamic.rb +232 -214
  36. data/test/plugin/test_alias_template.json +9 -0
  37. data/test/plugin/test_elasticsearch_error_handler.rb +646 -0
  38. data/test/plugin/test_elasticsearch_fallback_selector.rb +74 -0
  39. data/test/plugin/test_elasticsearch_index_lifecycle_management.rb +66 -0
  40. data/test/plugin/test_elasticsearch_tls.rb +145 -0
  41. data/test/plugin/test_filter_elasticsearch_genid.rb +215 -0
  42. data/test/plugin/test_in_elasticsearch.rb +459 -0
  43. data/test/plugin/test_index_alias_template.json +11 -0
  44. data/test/plugin/test_index_template.json +25 -0
  45. data/test/plugin/test_oj_serializer.rb +19 -0
  46. data/test/plugin/test_out_elasticsearch.rb +5029 -387
  47. data/test/plugin/test_out_elasticsearch_data_stream.rb +337 -0
  48. data/test/plugin/test_out_elasticsearch_dynamic.rb +681 -208
  49. data/test/test_log-ext.rb +35 -0
  50. metadata +97 -19
@@ -0,0 +1,459 @@
1
+ require_relative '../helper'
2
+ require 'date'
3
+ require 'fluent/test/helpers'
4
+ require 'json'
5
+ require 'fluent/test/driver/input'
6
+ require 'flexmock/test_unit'
7
+ require 'fluent/plugin/in_elasticsearch'
8
+
9
+ class ElasticsearchInputTest < Test::Unit::TestCase
10
+ include FlexMock::TestCase
11
+ include Fluent::Test::Helpers
12
+
13
+ CONFIG = %[
14
+ tag raw.elasticsearch
15
+ interval 2
16
+ ]
17
+
18
+ def setup
19
+ Fluent::Test.setup
20
+ @driver = nil
21
+ log = Fluent::Engine.log
22
+ log.out.logs.slice!(0, log.out.logs.length)
23
+ @http_method = if Gem::Version.new(Elasticsearch::VERSION) >= Gem::Version.new("7.9.0")
24
+ :post
25
+ else
26
+ :get
27
+ end
28
+ end
29
+
30
+ def driver(conf='')
31
+ @driver ||= Fluent::Test::Driver::Input.new(Fluent::Plugin::ElasticsearchInput).configure(conf)
32
+ end
33
+
34
+ def sample_response(index_name="fluentd")
35
+ {
36
+ "took"=>4,
37
+ "timed_out"=>false,
38
+ "_shards"=>{
39
+ "total"=>2,
40
+ "successful"=>2,
41
+ "skipped"=>0,
42
+ "failed"=>0
43
+ },
44
+ "hits"=>{
45
+ "total"=>{
46
+ "value"=>1,
47
+ "relation"=>"eq"
48
+ },
49
+ "max_score"=>1,
50
+ "hits"=>[
51
+ {
52
+ "_index"=>"#{index_name}-2019.11.14",
53
+ "_type"=>"_doc",
54
+ "_id"=>"MJ_faG4B16RqUMOji_nH",
55
+ "_score"=>1,
56
+ "_source"=>{
57
+ "message"=>"Hi from Fluentd!",
58
+ "@timestamp"=>"2019-11-14T16:45:10.559841000+09:00"
59
+ }
60
+ }
61
+ ]
62
+ }
63
+ }.to_json
64
+ end
65
+
66
+ def sample_scroll_response
67
+ {
68
+ "_scroll_id"=>"WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz",
69
+ "took"=>0,
70
+ "timed_out"=>false,
71
+ "_shards"=>{
72
+ "total"=>1,
73
+ "successful"=>1,
74
+ "skipped"=>0,
75
+ "failed"=>0
76
+ },
77
+ "hits"=>{
78
+ "total"=>{
79
+ "value"=>7,
80
+ "relation"=>"eq"
81
+ },
82
+ "max_score"=>nil,
83
+ "hits"=>[
84
+ {
85
+ "_index"=>"fluentd-2019.11.14",
86
+ "_type"=>"_doc",
87
+ "_id"=>"MJ_faG4B16RqUMOji_nH",
88
+ "_score"=>1,
89
+ "_source"=>{
90
+ "message"=>"Hi from Fluentd!",
91
+ "@timestamp"=>"2019-11-14T16:45:10.559841000+09:00"
92
+ },
93
+ "sort"=>[0]
94
+ }
95
+ ]
96
+ }
97
+ }.to_json
98
+ end
99
+
100
+ def sample_scroll_response_2
101
+ {
102
+ "_scroll_id"=>"WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz",
103
+ "took"=>0,
104
+ "timed_out"=>false,
105
+ "_shards"=>{
106
+ "total"=>1,
107
+ "successful"=>1,
108
+ "skipped"=>0,
109
+ "failed"=>0
110
+ },
111
+ "hits"=>{
112
+ "total"=>{
113
+ "value"=>7,
114
+ "relation"=>"eq"
115
+ },
116
+ "max_score"=>nil,
117
+ "hits"=>[
118
+ {
119
+ "_index"=>"fluentd-2019.11.14",
120
+ "_type"=>"_doc",
121
+ "_id"=>"L5-saG4B16RqUMOjw_kb",
122
+ "_score"=>1,
123
+ "_source"=>{
124
+ "message"=>"Yaaaaaaay from Fluentd!",
125
+ "@timestamp"=>"2019-11-14T15:49:41.112023000+09:00"
126
+ },
127
+ "sort"=>[1]
128
+ }
129
+ ]
130
+ }
131
+ }.to_json
132
+ end
133
+
134
+ def sample_scroll_response_terminate
135
+ {
136
+ "_scroll_id"=>"WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz",
137
+ "took"=>1,
138
+ "timed_out"=>false,
139
+ "terminated_early"=>true,
140
+ "_shards"=>{
141
+ "total"=>1,
142
+ "successful"=>1,
143
+ "skipped"=>0,
144
+ "failed"=>0
145
+ },
146
+ "hits"=>{
147
+ "total"=>{
148
+ "value"=>7,
149
+ "relation"=>"eq"
150
+ },
151
+ "max_score"=>nil,
152
+ "hits"=>[]
153
+ }
154
+ }.to_json
155
+ end
156
+
157
+ def test_configure
158
+ config = %{
159
+ host logs.google.com
160
+ port 777
161
+ scheme https
162
+ path /es/
163
+ user john
164
+ password doe
165
+ tag raw.elasticsearch
166
+ }
167
+ instance = driver(config).instance
168
+
169
+ expected_query = { "sort" => [ "_doc" ]}
170
+ assert_equal 'logs.google.com', instance.host
171
+ assert_equal 777, instance.port
172
+ assert_equal :https, instance.scheme
173
+ assert_equal '/es/', instance.path
174
+ assert_equal 'john', instance.user
175
+ assert_equal 'doe', instance.password
176
+ assert_equal 'raw.elasticsearch', instance.tag
177
+ assert_equal :TLSv1_2, instance.ssl_version
178
+ assert_equal 'fluentd', instance.index_name
179
+ assert_equal expected_query, instance.query
180
+ assert_equal '1m', instance.scroll
181
+ assert_equal 1000, instance.size
182
+ assert_equal 1, instance.num_slices
183
+ assert_equal 5, instance.interval
184
+ assert_true instance.repeat
185
+ assert_nil instance.client_key
186
+ assert_nil instance.client_cert
187
+ assert_nil instance.client_key_pass
188
+ assert_nil instance.ca_file
189
+ assert_false instance.with_transporter_log
190
+ assert_equal :excon, instance.http_backend
191
+ assert_nil instance.sniffer_class_name
192
+ assert_true instance.custom_headers.empty?
193
+ assert_equal ['_index', '_type', '_id'], instance.docinfo_fields
194
+ assert_equal '@metadata', instance.docinfo_target
195
+ assert_false instance.docinfo
196
+ end
197
+
198
+ def test_single_host_params_and_defaults
199
+ config = %{
200
+ host logs.google.com
201
+ user john
202
+ password doe
203
+ tag raw.elasticsearch
204
+ }
205
+ instance = driver(config).instance
206
+
207
+ assert_equal 1, instance.get_connection_options[:hosts].length
208
+ host1 = instance.get_connection_options[:hosts][0]
209
+
210
+ assert_equal 'logs.google.com', host1[:host]
211
+ assert_equal 9200, host1[:port]
212
+ assert_equal 'http', host1[:scheme]
213
+ assert_equal 'john', host1[:user]
214
+ assert_equal 'doe', host1[:password]
215
+ assert_equal nil, host1[:path]
216
+ assert_equal 'raw.elasticsearch', instance.tag
217
+ end
218
+
219
+ def test_single_host_params_and_defaults_with_escape_placeholders
220
+ config = %{
221
+ host logs.google.com
222
+ user %{j+hn}
223
+ password %{d@e}
224
+ tag raw.elasticsearch
225
+ }
226
+ instance = driver(config).instance
227
+
228
+ assert_equal 1, instance.get_connection_options[:hosts].length
229
+ host1 = instance.get_connection_options[:hosts][0]
230
+
231
+ assert_equal 'logs.google.com', host1[:host]
232
+ assert_equal 9200, host1[:port]
233
+ assert_equal 'http', host1[:scheme]
234
+ assert_equal 'j%2Bhn', host1[:user]
235
+ assert_equal 'd%40e', host1[:password]
236
+ assert_equal nil, host1[:path]
237
+ assert_equal 'raw.elasticsearch', instance.tag
238
+ end
239
+
240
+ def test_legacy_hosts_list
241
+ config = %{
242
+ hosts host1:50,host2:100,host3
243
+ scheme https
244
+ path /es/
245
+ port 123
246
+ tag raw.elasticsearch
247
+ }
248
+ instance = driver(config).instance
249
+
250
+ assert_equal 3, instance.get_connection_options[:hosts].length
251
+ host1, host2, host3 = instance.get_connection_options[:hosts]
252
+
253
+ assert_equal 'host1', host1[:host]
254
+ assert_equal 50, host1[:port]
255
+ assert_equal 'https', host1[:scheme]
256
+ assert_equal '/es/', host2[:path]
257
+ assert_equal 'host3', host3[:host]
258
+ assert_equal 123, host3[:port]
259
+ assert_equal 'https', host3[:scheme]
260
+ assert_equal '/es/', host3[:path]
261
+ assert_equal 'raw.elasticsearch', instance.tag
262
+ end
263
+
264
+ def test_hosts_list
265
+ config = %{
266
+ hosts https://john:password@host1:443/elastic/,http://host2
267
+ path /default_path
268
+ user default_user
269
+ password default_password
270
+ tag raw.elasticsearch
271
+ }
272
+ instance = driver(config).instance
273
+
274
+ assert_equal 2, instance.get_connection_options[:hosts].length
275
+ host1, host2 = instance.get_connection_options[:hosts]
276
+
277
+ assert_equal 'host1', host1[:host]
278
+ assert_equal 443, host1[:port]
279
+ assert_equal 'https', host1[:scheme]
280
+ assert_equal 'john', host1[:user]
281
+ assert_equal 'password', host1[:password]
282
+ assert_equal '/elastic/', host1[:path]
283
+
284
+ assert_equal 'host2', host2[:host]
285
+ assert_equal 'http', host2[:scheme]
286
+ assert_equal 'default_user', host2[:user]
287
+ assert_equal 'default_password', host2[:password]
288
+ assert_equal '/default_path', host2[:path]
289
+ assert_equal 'raw.elasticsearch', instance.tag
290
+ end
291
+
292
+ def test_hosts_list_with_escape_placeholders
293
+ config = %{
294
+ hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
295
+ path /default_path
296
+ user default_user
297
+ password default_password
298
+ tag raw.elasticsearch
299
+ }
300
+ instance = driver(config).instance
301
+
302
+ assert_equal 2, instance.get_connection_options[:hosts].length
303
+ host1, host2 = instance.get_connection_options[:hosts]
304
+
305
+ assert_equal 'host1', host1[:host]
306
+ assert_equal 443, host1[:port]
307
+ assert_equal 'https', host1[:scheme]
308
+ assert_equal 'j%2Bhn', host1[:user]
309
+ assert_equal 'passw%40rd', host1[:password]
310
+ assert_equal '/elastic/', host1[:path]
311
+
312
+ assert_equal 'host2', host2[:host]
313
+ assert_equal 'http', host2[:scheme]
314
+ assert_equal 'default_user', host2[:user]
315
+ assert_equal 'default_password', host2[:password]
316
+ assert_equal '/default_path', host2[:path]
317
+ assert_equal 'raw.elasticsearch', instance.tag
318
+ end
319
+
320
+ def test_emit
321
+ stub_request(@http_method, "http://localhost:9200/fluentd/_search?scroll=1m&size=1000").
322
+ with(body: "{\"sort\":[\"_doc\"]}").
323
+ to_return(status: 200, body: sample_response.to_s,
324
+ headers: {'Content-Type' => 'application/json'})
325
+
326
+ driver(CONFIG)
327
+ driver.run(expect_emits: 1, timeout: 10)
328
+ expected = {"message" => "Hi from Fluentd!",
329
+ "@timestamp" => "2019-11-14T16:45:10.559841000+09:00"}
330
+ event = driver.events.map {|e| e.last}.last
331
+ assert_equal expected, event
332
+ end
333
+
334
+ def test_emit_with_custom_index_name
335
+ index_name = "logstash"
336
+ stub_request(@http_method, "http://localhost:9200/#{index_name}/_search?scroll=1m&size=1000").
337
+ with(body: "{\"sort\":[\"_doc\"]}").
338
+ to_return(status: 200, body: sample_response(index_name).to_s,
339
+ headers: {'Content-Type' => 'application/json'})
340
+
341
+ driver(CONFIG + %[index_name #{index_name}])
342
+ driver.run(expect_emits: 1, timeout: 10)
343
+ expected = {"message" => "Hi from Fluentd!",
344
+ "@timestamp" => "2019-11-14T16:45:10.559841000+09:00"}
345
+ event = driver.events.map {|e| e.last}.last
346
+ assert_equal expected, event
347
+ end
348
+
349
+ def test_emit_with_parse_timestamp
350
+ index_name = "fluentd"
351
+ stub_request(@http_method, "http://localhost:9200/#{index_name}/_search?scroll=1m&size=1000").
352
+ with(body: "{\"sort\":[\"_doc\"]}").
353
+ to_return(status: 200, body: sample_response(index_name).to_s,
354
+ headers: {'Content-Type' => 'application/json'})
355
+
356
+ driver(CONFIG + %[parse_timestamp])
357
+ driver.run(expect_emits: 1, timeout: 10)
358
+ expected = {"message" => "Hi from Fluentd!",
359
+ "@timestamp" => "2019-11-14T16:45:10.559841000+09:00"}
360
+ event = driver.events.map {|e| e.last}.last
361
+ time = driver.events.map {|e| e[1]}.last
362
+ expected_time = event_time("2019-11-14T16:45:10.559841000+09:00")
363
+ assert_equal expected_time.to_time, time.to_time
364
+ assert_equal expected, event
365
+ end
366
+
367
+ def test_emit_with_parse_timestamp_and_timstamp_format
368
+ index_name = "fluentd"
369
+ stub_request(@http_method, "http://localhost:9200/#{index_name}/_search?scroll=1m&size=1000").
370
+ with(body: "{\"sort\":[\"_doc\"]}").
371
+ to_return(status: 200, body: sample_response(index_name).to_s,
372
+ headers: {'Content-Type' => 'application/json'})
373
+
374
+ driver(CONFIG + %[parse_timestamp true
375
+ timestamp_key_format %Y-%m-%dT%H:%M:%S.%N%z
376
+ ])
377
+ driver.run(expect_emits: 1, timeout: 10)
378
+ expected = {"message" => "Hi from Fluentd!",
379
+ "@timestamp" => "2019-11-14T16:45:10.559841000+09:00"}
380
+ event = driver.events.map {|e| e.last}.last
381
+ time = driver.events.map {|e| e[1]}.last
382
+ expected_time = event_time("2019-11-14T16:45:10.559841000+09:00")
383
+ assert_equal expected_time.to_time, time.to_time
384
+ assert_equal expected, event
385
+ end
386
+
387
+ def test_emit_with_docinfo
388
+ stub_request(@http_method, "http://localhost:9200/fluentd/_search?scroll=1m&size=1000").
389
+ with(body: "{\"sort\":[\"_doc\"]}").
390
+ to_return(status: 200, body: sample_response.to_s,
391
+ headers: {'Content-Type' => 'application/json'})
392
+
393
+ driver(CONFIG + %[docinfo true])
394
+ driver.run(expect_emits: 1, timeout: 10)
395
+ expected = {"message" => "Hi from Fluentd!",
396
+ "@timestamp" => "2019-11-14T16:45:10.559841000+09:00"}
397
+ expected.merge!({"@metadata"=>
398
+ {"_id"=>"MJ_faG4B16RqUMOji_nH",
399
+ "_index"=>"fluentd-2019.11.14",
400
+ "_type"=>"_doc"}
401
+ })
402
+ event = driver.events.map {|e| e.last}.last
403
+ assert_equal expected, event
404
+ end
405
+
406
+ def test_emit_with_slices
407
+ stub_request(@http_method, "http://localhost:9200/fluentd/_search?scroll=1m&size=1000").
408
+ with(body: "{\"sort\":[\"_doc\"],\"slice\":{\"id\":0,\"max\":2}}").
409
+ to_return(status: 200, body: sample_response.to_s,
410
+ headers: {'Content-Type' => 'application/json'})
411
+ stub_request(@http_method, "http://localhost:9200/fluentd/_search?scroll=1m&size=1000").
412
+ with(body: "{\"sort\":[\"_doc\"],\"slice\":{\"id\":1,\"max\":2}}").
413
+ to_return(status: 200, body: sample_response.to_s,
414
+ headers: {'Content-Type' => 'application/json'})
415
+
416
+ driver(CONFIG + %[num_slices 2])
417
+ driver.run(expect_emits: 1, timeout: 10)
418
+ expected = [
419
+ {"message"=>"Hi from Fluentd!", "@timestamp"=>"2019-11-14T16:45:10.559841000+09:00"},
420
+ {"message"=>"Hi from Fluentd!", "@timestamp"=>"2019-11-14T16:45:10.559841000+09:00"},
421
+ ]
422
+ events = driver.events.map {|e| e.last}
423
+ assert_equal expected, events
424
+ end
425
+
426
+ def test_emit_with_size
427
+ stub_request(@http_method, "http://localhost:9200/fluentd/_search?scroll=1m&size=1").
428
+ with(body: "{\"sort\":[\"_doc\"]}").
429
+ to_return(status: 200, body: sample_scroll_response.to_s,
430
+ headers: {'Content-Type' => 'application/json'})
431
+ connection = 0
432
+ scroll_request = stub_request(@http_method, "http://localhost:9200/_search/scroll?scroll=1m").
433
+ with(
434
+ body: "{\"scroll_id\":\"WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz\"}") do
435
+ connection += 1
436
+ end
437
+ scroll_request.to_return(lambda do |req|
438
+ if connection <= 1
439
+ {status: 200, body: sample_scroll_response_2.to_s,
440
+ headers: {'Content-Type' => 'application/json'}}
441
+ else
442
+ {status: 200, body: sample_scroll_response_terminate.to_s,
443
+ headers: {'Content-Type' => 'application/json'}}
444
+ end
445
+ end)
446
+ stub_request(:delete, "http://localhost:9200/_search/scroll/WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz").
447
+ to_return(status: 200, body: "", headers: {})
448
+
449
+ driver(CONFIG + %[size 1])
450
+ driver.run(expect_emits: 1, timeout: 10)
451
+ expected = [
452
+ {"message"=>"Hi from Fluentd!", "@timestamp"=>"2019-11-14T16:45:10.559841000+09:00"},
453
+ {"message"=>"Yaaaaaaay from Fluentd!", "@timestamp"=>"2019-11-14T15:49:41.112023000+09:00"}
454
+ ]
455
+ events = driver.events.map{|e| e.last}
456
+ assert_equal expected, events
457
+ end
458
+
459
+ end
@@ -0,0 +1,11 @@
1
+ {
2
+ "priority": 105,
3
+ "index_patterns": "--index_prefix-----appid---*",
4
+ "template" : {
5
+ "settings": {},
6
+ "mappings": {},
7
+ "aliases": {
8
+ "--appid---alias": {}
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "index_patterns": "te*",
3
+ "template": {
4
+ "settings": {
5
+ "number_of_shards": 1
6
+ },
7
+ "mappings": {
8
+ "type1": {
9
+ "_source": {
10
+ "enabled": false
11
+ },
12
+ "properties": {
13
+ "host_name": {
14
+ "type": "string",
15
+ "index": "not_analyzed"
16
+ },
17
+ "created_at": {
18
+ "type": "date",
19
+ "format": "EEE MMM dd HH:mm:ss Z YYYY"
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,19 @@
1
+ require_relative '../helper'
2
+ require 'elasticsearch'
3
+
4
+ class OjSerializerTest < Test::Unit::TestCase
5
+ def setup
6
+ begin
7
+ require 'fluent/plugin/oj_serializer'
8
+ rescue LoadError
9
+ omit "OjSerializer testcase needs oj gem."
10
+ end
11
+ @serializer = Fluent::Plugin::Serializer::Oj.new
12
+ end
13
+
14
+ def test_serializer
15
+ data = {"message" => "Hi"}
16
+ assert_equal data.to_json, @serializer.dump(data)
17
+ assert_equal data, @serializer.load(data.to_json)
18
+ end
19
+ end