fluent-plugin-s3-file-inclusion 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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