fluent-plugin-s3-file-inclusion 1.4.1

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.
@@ -0,0 +1,52 @@
1
+ module Fluent::Plugin
2
+ class S3Output
3
+ class GzipCommandCompressor < Compressor
4
+ S3Output.register_compressor('gzip_command', self)
5
+
6
+ config_param :command_parameter, :string, default: ''
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('gzip')
11
+ end
12
+
13
+ def ext
14
+ 'gz'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-gzip'.freeze
19
+ end
20
+
21
+ def compress(chunk, tmp)
22
+ chunk_is_file = @buffer_type == 'file'
23
+ path = if chunk_is_file
24
+ chunk.path
25
+ else
26
+ w = Tempfile.new("chunk-gzip-tmp")
27
+ w.binmode
28
+ chunk.write_to(w)
29
+ w.close
30
+ w.path
31
+ end
32
+
33
+ res = system "gzip #{@command_parameter} -c #{path} > #{tmp.path}"
34
+ unless res
35
+ log.warn "failed to execute gzip command. Fallback to GzipWriter. status = #{$?}"
36
+ begin
37
+ tmp.truncate(0)
38
+ gw = Zlib::GzipWriter.new(tmp)
39
+ chunk.write_to(gw)
40
+ gw.close
41
+ ensure
42
+ gw.close rescue nil
43
+ end
44
+ end
45
+ ensure
46
+ unless chunk_is_file
47
+ w.close(true) rescue nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,35 @@
1
+ module Fluent::Plugin
2
+ class S3Output
3
+ class LZMA2Compressor < Compressor
4
+ S3Output.register_compressor('lzma2', self)
5
+
6
+ config_param :command_parameter, :string, default: '-qf0'
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('xz', 'LZMA2')
11
+ end
12
+
13
+ def ext
14
+ 'xz'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-xz'.freeze
19
+ end
20
+
21
+ def compress(chunk, tmp)
22
+ w = Tempfile.new("chunk-xz-tmp")
23
+ w.binmode
24
+ chunk.write_to(w)
25
+ w.close
26
+
27
+ # We don't check the return code because we can't recover lzop failure.
28
+ system "xz #{@command_parameter} -c #{w.path} > #{tmp.path}"
29
+ ensure
30
+ w.close rescue nil
31
+ w.unlink rescue nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module Fluent::Plugin
2
+ class S3Output
3
+ class LZOCompressor < Compressor
4
+ S3Output.register_compressor('lzo', self)
5
+
6
+ config_param :command_parameter, :string, default: '-qf1'
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('lzop', 'LZO')
11
+ end
12
+
13
+ def ext
14
+ 'lzo'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-lzop'.freeze
19
+ end
20
+
21
+ def compress(chunk, tmp)
22
+ w = Tempfile.new("chunk-tmp")
23
+ w.binmode
24
+ chunk.write_to(w)
25
+ w.close
26
+
27
+ # We don't check the return code because we can't recover lzop failure.
28
+ system "lzop #{@command_parameter} -o #{tmp.path} #{w.path}"
29
+ ensure
30
+ w.close rescue nil
31
+ w.unlink rescue nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ module Fluent::Plugin
2
+ class S3Input
3
+ class GzipCommandExtractor < Extractor
4
+ S3Input.register_extractor('gzip_command', self)
5
+
6
+ config_param :command_parameter, :string, default: '-dc'
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('gzip')
11
+ end
12
+
13
+ def ext
14
+ 'gz'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-gzip'.freeze
19
+ end
20
+
21
+ def extract(io)
22
+ path = if io.respond_to?(:path)
23
+ io.path
24
+ else
25
+ temp = Tempfile.new("gzip-temp")
26
+ temp.write(io.read)
27
+ temp.close
28
+ temp.path
29
+ end
30
+
31
+ stdout, succeeded = Open3.capture2("gzip #{@command_parameter} #{path}")
32
+ if succeeded
33
+ stdout
34
+ else
35
+ log.warn "failed to execute gzip command. Fallback to GzipReader. status = #{succeeded}"
36
+ begin
37
+ io.rewind
38
+ Zlib::GzipReader.wrap(io) do |gz|
39
+ gz.read
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module Fluent::Plugin
2
+ class S3Input
3
+ class LZMA2Extractor < Extractor
4
+ S3Input.register_extractor('lzma2', self)
5
+
6
+ config_param :command_parameter, :string, default: '-qdc'
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('xz', 'LZMA')
11
+ end
12
+
13
+ def ext
14
+ 'xz'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-xz'.freeze
19
+ end
20
+
21
+ def extract(io)
22
+ path = if io.respond_to?(path)
23
+ io.path
24
+ else
25
+ temp = Tempfile.new("xz-temp")
26
+ temp.write(io.read)
27
+ temp.close
28
+ temp.path
29
+ end
30
+
31
+ stdout, succeeded = Open3.capture2("xz #{@command_parameter} #{path}")
32
+ if succeeded
33
+ stdout
34
+ else
35
+ raise "Failed to extract #{path} with xz command."
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module Fluent::Plugin
2
+ class S3Input
3
+ class LZOExtractor < Extractor
4
+ S3Input.register_extractor('lzo', self)
5
+
6
+ config_param :command_parameter, :string, default: '-qdc'
7
+
8
+ def configure(conf)
9
+ super
10
+ check_command('lzop', 'LZO')
11
+ end
12
+
13
+ def ext
14
+ 'lzo'.freeze
15
+ end
16
+
17
+ def content_type
18
+ 'application/x-lzop'.freeze
19
+ end
20
+
21
+ def extract(io)
22
+ path = if io.respond_to?(path)
23
+ io.path
24
+ else
25
+ temp = Tempfile.new("lzop-temp")
26
+ temp.write(io.read)
27
+ temp.close
28
+ temp.path
29
+ end
30
+
31
+ stdout, succeeded = Open3.capture2("lzop #{@command_parameter} #{path}")
32
+ if succeeded
33
+ stdout
34
+ else
35
+ raise "Failed to extract #{path} with lzop command."
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,513 @@
1
+ require 'aws-sdk-s3'
2
+ require 'aws-sdk-sqs'
3
+ require 'aws-sdk-sqs/queue_poller'
4
+
5
+ require 'fluent/test'
6
+ require 'fluent/test/helpers'
7
+ require 'fluent/test/log'
8
+ require 'fluent/test/driver/input'
9
+ require 'fluent/plugin/in_s3'
10
+
11
+ require 'test/unit/rr'
12
+ require 'zlib'
13
+ require 'fileutils'
14
+ require 'ostruct'
15
+
16
+ include Fluent::Test::Helpers
17
+
18
+ class S3InputTest < Test::Unit::TestCase
19
+ def setup
20
+ Fluent::Test.setup
21
+ @time = event_time("2015-09-30 13:14:15 UTC")
22
+ Fluent::Engine.now = @time
23
+ if Fluent.const_defined?(:EventTime)
24
+ stub(Fluent::EventTime).now { @time }
25
+ end
26
+ end
27
+
28
+ CONFIG = %[
29
+ aws_key_id test_key_id
30
+ aws_sec_key test_sec_key
31
+ s3_bucket test_bucket
32
+ buffer_type memory
33
+ <sqs>
34
+ queue_name test_queue
35
+ queue_owner_aws_account_id 123456789123
36
+ </sqs>
37
+ ]
38
+
39
+ def create_driver(conf = CONFIG)
40
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::S3Input).configure(conf)
41
+ end
42
+
43
+ class ConfigTest < self
44
+ def test_default
45
+ d = create_driver
46
+ extractor = d.instance.instance_variable_get(:@extractor)
47
+ actual = {
48
+ aws_key_id: d.instance.aws_key_id,
49
+ aws_sec_key: d.instance.aws_sec_key,
50
+ s3_bucket: d.instance.s3_bucket,
51
+ s3_region: d.instance.s3_region,
52
+ sqs_queue_name: d.instance.sqs.queue_name,
53
+ extractor_ext: extractor.ext,
54
+ extractor_content_type: extractor.content_type
55
+ }
56
+ expected = {
57
+ aws_key_id: "test_key_id",
58
+ aws_sec_key: "test_sec_key",
59
+ s3_bucket: "test_bucket",
60
+ s3_region: "us-east-1",
61
+ sqs_queue_name: "test_queue",
62
+ extractor_ext: "gz",
63
+ extractor_content_type: "application/x-gzip"
64
+ }
65
+ assert_equal(expected, actual)
66
+ end
67
+
68
+ def test_empty
69
+ assert_raise(Fluent::ConfigError) do
70
+ create_driver("")
71
+ end
72
+ end
73
+
74
+ def test_without_sqs_section
75
+ conf = %[
76
+ aws_key_id test_key_id
77
+ aws_sec_key test_sec_key
78
+ s3_bucket test_bucket
79
+ ]
80
+ assert_raise_message("'<sqs>' sections are required") do
81
+ create_driver(conf)
82
+ end
83
+ end
84
+
85
+ def test_unknown_store_as
86
+ config = CONFIG + "\nstore_as unknown"
87
+ assert_raise(Fluent::ConfigError) do
88
+ create_driver(config)
89
+ end
90
+ end
91
+
92
+ data("json" => ["json", "json", "application/json"],
93
+ "text" => ["text", "txt", "text/plain"],
94
+ "gzip" => ["gzip", "gz", "application/x-gzip"],
95
+ "gzip_command" => ["gzip_command", "gz", "application/x-gzip"],
96
+ "lzo" => ["lzo", "lzo", "application/x-lzop"],
97
+ "lzma2" => ["lzma2", "xz", "application/x-xz"])
98
+ def test_extractor(data)
99
+ store_type, ext, content_type = data
100
+ config = CONFIG + "\nstore_as #{store_type}\n"
101
+ d = create_driver(config)
102
+ extractor = d.instance.instance_variable_get(:@extractor)
103
+ expected = {
104
+ ext: ext,
105
+ content_type: content_type
106
+ }
107
+ actual = {
108
+ ext: extractor.ext,
109
+ content_type: extractor.content_type
110
+ }
111
+ assert_equal(expected, actual)
112
+ rescue Fluent::ConfigError => e
113
+ pend(e.message)
114
+ end
115
+ end
116
+
117
+
118
+ def test_s3_endpoint_with_valid_endpoint
119
+ d = create_driver(CONFIG + 's3_endpoint riak-cs.example.com')
120
+ assert_equal 'riak-cs.example.com', d.instance.s3_endpoint
121
+ end
122
+
123
+ data('US West (Oregon)' => 's3-us-west-2.amazonaws.com',
124
+ 'EU (Frankfurt)' => 's3.eu-central-1.amazonaws.com',
125
+ 'Asia Pacific (Tokyo)' => 's3-ap-northeast-1.amazonaws.com')
126
+ def test_s3_endpoint_with_invalid_endpoint(endpoint)
127
+ assert_raise(Fluent::ConfigError, "s3_endpoint parameter is not supported, use s3_region instead. This parameter is for S3 compatible services") {
128
+ create_driver(CONFIG + "s3_endpoint #{endpoint}")
129
+ }
130
+ end
131
+
132
+ data('US West (Oregon)' => 's3-us-west-2.amazonaws.com',
133
+ 'EU (Frankfurt)' => 's3.eu-central-1.amazonaws.com',
134
+ 'Asia Pacific (Tokyo)' => 's3-ap-northeast-1.amazonaws.com')
135
+ def test_sqs_endpoint_with_invalid_endpoint(endpoint)
136
+ assert_raise(Fluent::ConfigError, "sqs.endpoint parameter is not supported, use s3_region instead. This parameter is for SQS compatible services") {
137
+ conf = <<"EOS"
138
+ aws_key_id test_key_id
139
+ aws_sec_key test_sec_key
140
+ s3_bucket test_bucket
141
+ buffer_type memory
142
+ <sqs>
143
+ queue_name test_queue
144
+ endpoint #{endpoint}
145
+ </sqs>
146
+ EOS
147
+ create_driver(conf)
148
+ }
149
+ end
150
+
151
+ Struct.new("StubResponse", :queue_url)
152
+ Struct.new("StubMessage", :message_id, :receipt_handle, :body)
153
+
154
+ def setup_mocks
155
+ @s3_client = stub(Aws::S3::Client.new(stub_responses: true))
156
+ stub(@s3_client).config { OpenStruct.new({region: "us-east-1"}) }
157
+ mock(Aws::S3::Client).new(anything).at_least(0) { @s3_client }
158
+ @s3_resource = mock(Aws::S3::Resource.new(client: @s3_client))
159
+ mock(Aws::S3::Resource).new(client: @s3_client) { @s3_resource }
160
+ @s3_bucket = mock(Aws::S3::Bucket.new(name: "test",
161
+ client: @s3_client))
162
+ @s3_bucket.exists? { true }
163
+ @s3_resource.bucket(anything) { @s3_bucket }
164
+
165
+ test_queue_url = "http://example.com/test_queue"
166
+ @sqs_client = stub(Aws::SQS::Client.new(stub_responses: true))
167
+ @sqs_response = stub(Struct::StubResponse.new(test_queue_url))
168
+ @sqs_client.get_queue_url(queue_name: "test_queue", queue_owner_aws_account_id: "123456789123"){ @sqs_response }
169
+ mock(Aws::SQS::Client).new(anything).once { @sqs_client }
170
+ @real_poller = Aws::SQS::QueuePoller.new(test_queue_url, client: @sqs_client)
171
+ @sqs_poller = stub(@real_poller)
172
+ mock(Aws::SQS::QueuePoller).new(anything, client: @sqs_client) { @sqs_poller }
173
+ end
174
+
175
+ def test_no_records
176
+ setup_mocks
177
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\n")
178
+ mock(d.instance).process(anything).never
179
+
180
+ message = Struct::StubMessage.new(1, 1, "{}")
181
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
182
+ config.before_request.call(stats) if config.before_request
183
+ stats.request_count += 1
184
+ if stats.request_count > 1
185
+ d.instance.instance_variable_set(:@running, false)
186
+ end
187
+ [message]
188
+ end
189
+ assert_nothing_raised do
190
+ d.run {}
191
+ end
192
+ end
193
+
194
+ def test_one_record
195
+ setup_mocks
196
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\n")
197
+
198
+ s3_object = stub(Object.new)
199
+ s3_response = stub(Object.new)
200
+ s3_response.body { StringIO.new("aaa") }
201
+ s3_object.get { s3_response }
202
+ @s3_bucket.object(anything).at_least(1) { s3_object }
203
+
204
+ body = {
205
+ "Records" => [
206
+ {
207
+ "s3" => {
208
+ "object" => {
209
+ "key" => "test_key"
210
+ }
211
+ }
212
+ }
213
+ ]
214
+ }
215
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
216
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
217
+ config.before_request.call(stats) if config.before_request
218
+ stats.request_count += 1
219
+ if stats.request_count >= 1
220
+ d.instance.instance_variable_set(:@running, false)
221
+ end
222
+ [message]
223
+ end
224
+ d.run(expect_emits: 1)
225
+ events = d.events
226
+ assert_equal({ "message" => "aaa" }, events.first[2])
227
+ end
228
+
229
+ def test_one_record_with_metadata
230
+ setup_mocks
231
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\nadd_object_metadata true\n")
232
+
233
+ s3_object = stub(Object.new)
234
+ s3_response = stub(Object.new)
235
+ s3_response.body { StringIO.new("aaa") }
236
+ s3_object.get { s3_response }
237
+ @s3_bucket.object(anything).at_least(1) { s3_object }
238
+
239
+ body = {
240
+ "Records" => [
241
+ {
242
+ "s3" => {
243
+ "object" => {
244
+ "key" => "test_key"
245
+ }
246
+ }
247
+ }
248
+ ]
249
+ }
250
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
251
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
252
+ config.before_request.call(stats) if config.before_request
253
+ stats.request_count += 1
254
+ if stats.request_count >= 1
255
+ d.instance.instance_variable_set(:@running, false)
256
+ end
257
+ [message]
258
+ end
259
+ d.run(expect_emits: 1)
260
+ events = d.events
261
+ assert_equal({ "s3_bucket" => "test_bucket", "s3_key" => "test_key", "message" => "aaa" }, events.first[2])
262
+ end
263
+
264
+ def test_one_record_url_encoded
265
+ setup_mocks
266
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\n")
267
+
268
+ s3_object = stub(Object.new)
269
+ s3_response = stub(Object.new)
270
+ s3_response.body { StringIO.new("aaa") }
271
+ s3_object.get { s3_response }
272
+ @s3_bucket.object('test key').at_least(1) { s3_object }
273
+
274
+ body = {
275
+ "Records" => [
276
+ {
277
+ "s3" => {
278
+ "object" => {
279
+ "key" => "test+key"
280
+ }
281
+ }
282
+ }
283
+ ]
284
+ }
285
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
286
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
287
+ config.before_request.call(stats) if config.before_request
288
+ stats.request_count += 1
289
+ if stats.request_count >= 1
290
+ d.instance.instance_variable_set(:@running, false)
291
+ end
292
+ [message]
293
+ end
294
+ d.run(expect_emits: 1)
295
+ events = d.events
296
+ assert_equal({ "message" => "aaa" }, events.first[2])
297
+ end
298
+
299
+ def test_one_record_url_encoded_with_metadata
300
+ setup_mocks
301
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\nadd_object_metadata true")
302
+
303
+ s3_object = stub(Object.new)
304
+ s3_response = stub(Object.new)
305
+ s3_response.body { StringIO.new("aaa") }
306
+ s3_object.get { s3_response }
307
+ @s3_bucket.object('test key').at_least(1) { s3_object }
308
+
309
+ body = {
310
+ "Records" => [
311
+ {
312
+ "s3" => {
313
+ "object" => {
314
+ "key" => "test+key"
315
+ }
316
+ }
317
+ }
318
+ ]
319
+ }
320
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
321
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
322
+ config.before_request.call(stats) if config.before_request
323
+ stats.request_count += 1
324
+ if stats.request_count >= 1
325
+ d.instance.instance_variable_set(:@running, false)
326
+ end
327
+ [message]
328
+ end
329
+ d.run(expect_emits: 1)
330
+ events = d.events
331
+ assert_equal({ "s3_bucket" => "test_bucket", "s3_key" => "test+key", "message" => "aaa" }, events.first[2])
332
+ end
333
+
334
+ def test_one_record_multi_line
335
+ setup_mocks
336
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\n")
337
+
338
+ s3_object = stub(Object.new)
339
+ s3_response = stub(Object.new)
340
+ s3_response.body { StringIO.new("aaa\nbbb\nccc\n") }
341
+ s3_object.get { s3_response }
342
+ @s3_bucket.object(anything).at_least(1) { s3_object }
343
+
344
+ body = {
345
+ "Records" => [
346
+ {
347
+ "s3" => {
348
+ "object" => {
349
+ "key" => "test_key"
350
+ }
351
+ }
352
+ }
353
+ ]
354
+ }
355
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
356
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
357
+ config.before_request.call(stats) if config.before_request
358
+ stats.request_count += 1
359
+ if stats.request_count >= 1
360
+ d.instance.instance_variable_set(:@running, false)
361
+ end
362
+ [message]
363
+ end
364
+ d.run(expect_emits: 1)
365
+ events = d.events
366
+ expected_records = [
367
+ { "message" => "aaa\n" },
368
+ { "message" => "bbb\n" },
369
+ { "message" => "ccc\n" }
370
+ ]
371
+ assert_equal(expected_records, events.map {|_tag, _time, record| record })
372
+ end
373
+
374
+ def test_one_record_multi_line_with_metadata
375
+ setup_mocks
376
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as text\nformat none\nadd_object_metadata true")
377
+
378
+ s3_object = stub(Object.new)
379
+ s3_response = stub(Object.new)
380
+ s3_response.body { StringIO.new("aaa\nbbb\nccc\n") }
381
+ s3_object.get { s3_response }
382
+ @s3_bucket.object(anything).at_least(1) { s3_object }
383
+
384
+ body = {
385
+ "Records" => [
386
+ {
387
+ "s3" => {
388
+ "object" => {
389
+ "key" => "test_key"
390
+ }
391
+ }
392
+ }
393
+ ]
394
+ }
395
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
396
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
397
+ config.before_request.call(stats) if config.before_request
398
+ stats.request_count += 1
399
+ if stats.request_count >= 1
400
+ d.instance.instance_variable_set(:@running, false)
401
+ end
402
+ [message]
403
+ end
404
+ d.run(expect_emits: 1)
405
+ events = d.events
406
+ expected_records = [
407
+ { "s3_bucket" => "test_bucket", "s3_key" => "test_key", "message" => "aaa\n" },
408
+ { "s3_bucket" => "test_bucket", "s3_key" => "test_key", "message" => "bbb\n" },
409
+ { "s3_bucket" => "test_bucket", "s3_key" => "test_key", "message" => "ccc\n" }
410
+ ]
411
+ assert_equal(expected_records, events.map {|_tag, _time, record| record })
412
+ end
413
+
414
+ def test_gzip_single_stream
415
+ setup_mocks
416
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as gzip\nformat none\n")
417
+
418
+ s3_object = stub(Object.new)
419
+ s3_response = stub(Object.new)
420
+ s3_response.body {
421
+ io = StringIO.new
422
+ Zlib::GzipWriter.wrap(io) do |gz|
423
+ gz.write "aaa\nbbb\n"
424
+ gz.finish
425
+ end
426
+ io.rewind
427
+ io
428
+ }
429
+ s3_object.get { s3_response }
430
+ @s3_bucket.object(anything).at_least(1) { s3_object }
431
+
432
+ body = {
433
+ "Records" => [
434
+ {
435
+ "s3" => {
436
+ "object" => {
437
+ "key" => "test_key"
438
+ }
439
+ }
440
+ }
441
+ ]
442
+ }
443
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
444
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
445
+ config.before_request.call(stats) if config.before_request
446
+ stats.request_count += 1
447
+ if stats.request_count >= 1
448
+ d.instance.instance_variable_set(:@running, false)
449
+ end
450
+ [message]
451
+ end
452
+ d.run(expect_emits: 1)
453
+ events = d.events
454
+ expected_records = [
455
+ { "message" => "aaa\n" },
456
+ { "message" => "bbb\n" }
457
+ ]
458
+ assert_equal(expected_records, events.map {|_tag, _time, record| record })
459
+ end
460
+
461
+ def test_gzip_multiple_steams
462
+ setup_mocks
463
+ d = create_driver(CONFIG + "\ncheck_apikey_on_start false\nstore_as gzip\nformat none\n")
464
+
465
+ s3_object = stub(Object.new)
466
+ s3_response = stub(Object.new)
467
+ s3_response.body {
468
+ io = StringIO.new
469
+ Zlib::GzipWriter.wrap(io) do |gz|
470
+ gz.write "aaa\nbbb\n"
471
+ gz.finish
472
+ end
473
+ Zlib::GzipWriter.wrap(io) do |gz|
474
+ gz.write "ccc\nddd\n"
475
+ gz.finish
476
+ end
477
+ io.rewind
478
+ io
479
+ }
480
+ s3_object.get { s3_response }
481
+ @s3_bucket.object(anything).at_least(1) { s3_object }
482
+
483
+ body = {
484
+ "Records" => [
485
+ {
486
+ "s3" => {
487
+ "object" => {
488
+ "key" => "test_key"
489
+ }
490
+ }
491
+ }
492
+ ]
493
+ }
494
+ message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
495
+ @sqs_poller.get_messages(anything, anything) do |config, stats|
496
+ config.before_request.call(stats) if config.before_request
497
+ stats.request_count += 1
498
+ if stats.request_count >= 1
499
+ d.instance.instance_variable_set(:@running, false)
500
+ end
501
+ [message]
502
+ end
503
+ d.run(expect_emits: 1)
504
+ events = d.events
505
+ expected_records = [
506
+ { "message" => "aaa\n" },
507
+ { "message" => "bbb\n" },
508
+ { "message" => "ccc\n" },
509
+ { "message" => "ddd\n" }
510
+ ]
511
+ assert_equal(expected_records, events.map {|_tag, _time, record| record })
512
+ end
513
+ end