fluent-plugin-slack-stakater 0.6.8

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,289 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'logger'
5
+ require_relative 'slack_client/error'
6
+
7
+ module Fluent
8
+ module SlackClient
9
+ # The base framework of slack client
10
+ class Base
11
+ attr_accessor :log, :debug_dev
12
+ attr_reader :endpoint, :https_proxy
13
+
14
+ # @param [String] endpoint
15
+ #
16
+ # (Incoming Webhook) required
17
+ # https://hooks.slack.com/services/XXX/XXX/XXX
18
+ #
19
+ # (Slackbot) required
20
+ # https://xxxx.slack.com/services/hooks/slackbot?token=XXXXX
21
+ #
22
+ # (Web API) optional and default to be
23
+ # https://slack.com/api/
24
+ #
25
+ # @param [String] https_proxy (optional)
26
+ #
27
+ # https://proxy.foo.bar:port
28
+ #
29
+ def initialize(endpoint = nil, https_proxy = nil)
30
+ self.endpoint = endpoint if endpoint
31
+ self.https_proxy = https_proxy if https_proxy
32
+ @log = Logger.new('/dev/null')
33
+ end
34
+
35
+ def endpoint=(endpoint)
36
+ @endpoint = URI.parse(endpoint)
37
+ end
38
+
39
+ def https_proxy=(https_proxy)
40
+ @https_proxy = URI.parse(https_proxy)
41
+ @proxy_class = Net::HTTP.Proxy(@https_proxy.host, @https_proxy.port)
42
+ end
43
+
44
+ def proxy_class
45
+ @proxy_class ||= Net::HTTP
46
+ end
47
+
48
+ def post(endpoint, params)
49
+ http = proxy_class.new(endpoint.host, endpoint.port)
50
+ http.use_ssl = (endpoint.scheme == 'https')
51
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
52
+ http.set_debug_output(debug_dev) if debug_dev
53
+
54
+ req = Net::HTTP::Post.new(endpoint.request_uri)
55
+ req['Host'] = endpoint.host
56
+ req['Accept'] = 'application/json; charset=utf-8'
57
+ req['User-Agent'] = 'fluent-plugin-slack'
58
+ req.body = encode_body(params)
59
+
60
+ res = http.request(req)
61
+ response_check(res, params)
62
+ end
63
+
64
+ private
65
+
66
+ def encode_body(params)
67
+ raise NotImplementedError
68
+ end
69
+
70
+ def response_check(res, params)
71
+ if res.code != "200"
72
+ raise Error.new(res, params)
73
+ end
74
+ end
75
+
76
+ def filter_params(params)
77
+ params.dup.tap {|p| p[:token] = '[FILTERED]' if p[:token] }
78
+ end
79
+
80
+ # Required to implement to use #with_channels_create
81
+ # channels.create API is available from only Slack Web API
82
+ def api
83
+ raise NotImplementedError
84
+ end
85
+
86
+ def with_channels_create(params = {}, opts = {})
87
+ retries = 1
88
+ begin
89
+ yield
90
+ rescue ChannelNotFoundError => e
91
+ if params[:token] and opts[:auto_channels_create]
92
+ log.warn "out_slack: channel \"#{params[:channel]}\" is not found. try to create the channel, and then retry to post the message."
93
+ api.channels_create({name: params[:channel], token: params[:token]})
94
+ retry if (retries -= 1) >= 0 # one time retry
95
+ else
96
+ raise e
97
+ end
98
+ end
99
+ end
100
+
101
+ def to_json_with_scrub!(params)
102
+ retries = 1
103
+ begin
104
+ params.to_json
105
+ rescue Encoding::UndefinedConversionError => e
106
+ recursive_scrub!(params)
107
+ if (retries -= 1) >= 0 # one time retry
108
+ log.warn "out_slack: to_json `#{params}` failed. retry after scrub!. #{e.message}"
109
+ retry
110
+ else
111
+ raise e
112
+ end
113
+ end
114
+ end
115
+
116
+ def recursive_scrub!(params)
117
+ case params
118
+ when Hash
119
+ params.each {|k, v| recursive_scrub!(v)}
120
+ when Array
121
+ params.each {|elm| recursive_scrub!(elm)}
122
+ when String
123
+ params.force_encoding(Encoding::UTF_8) if params.encoding == Encoding::ASCII_8BIT
124
+ params.scrub!('?') if params.respond_to?(:scrub!)
125
+ else
126
+ params
127
+ end
128
+ end
129
+ end
130
+
131
+ # Slack client for Incoming Webhook
132
+ # https://api.slack.com/incoming-webhooks
133
+ class IncomingWebhook < Base
134
+ def initialize(endpoint, https_proxy = nil)
135
+ super
136
+ end
137
+
138
+ def post_message(params = {}, opts = {})
139
+ log.info { "out_slack: post_message #{params}" }
140
+ post(endpoint, params)
141
+ end
142
+
143
+ private
144
+
145
+ def encode_body(params = {})
146
+ # https://api.slack.com/docs/formatting
147
+ to_json_with_scrub!(params).gsub(/&/, '&amp;').gsub(/</, '&lt;').gsub(/>/, '&gt;')
148
+ end
149
+
150
+ def response_check(res, params)
151
+ super
152
+ unless res.body == 'ok'
153
+ raise Error.new(res, params)
154
+ end
155
+ end
156
+ end
157
+
158
+ # Slack client for Slackbot Remote Control
159
+ # https://api.slack.com/slackbot
160
+ class Slackbot < Base
161
+ def initialize(endpoint, https_proxy = nil)
162
+ super
163
+ end
164
+
165
+ def api
166
+ @api ||= WebApi.new(nil, https_proxy)
167
+ end
168
+
169
+ def post_message(params = {}, opts = {})
170
+ raise ArgumentError, "channel parameter is required" unless params[:channel]
171
+ with_channels_create(params, opts) do
172
+ log.info { "out_slack: post_message #{filter_params(params)}" }
173
+ post(slackbot_endpoint(params), params)
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def slackbot_endpoint(params)
180
+ endpoint.dup.tap {|e| e.query += "&channel=#{URI.encode(params[:channel])}" }
181
+ end
182
+
183
+ def encode_body(params = {})
184
+ return params[:text]if params[:text]
185
+ unless params[:attachments]
186
+ raise ArgumentError, 'params[:text] or params[:attachments] is required'
187
+ end
188
+ # handle params[:attachments]
189
+ attachment = Array(params[:attachments]).first # see only the first for now
190
+ # {
191
+ # attachments: [{
192
+ # text: "HERE",
193
+ # }]
194
+ # }
195
+ text = attachment[:text]
196
+ # {
197
+ # attachments: [{
198
+ # fields: [{
199
+ # title: "title",
200
+ # value: "HERE",
201
+ # }]
202
+ # }]
203
+ # }
204
+ if text.nil? and attachment[:fields]
205
+ text = Array(attachment[:fields]).first[:value] # see only the first for now
206
+ end
207
+ text
208
+ end
209
+
210
+ def response_check(res, params)
211
+ if res.body == 'channel_not_found'
212
+ raise ChannelNotFoundError.new(res, params)
213
+ elsif res.body != 'ok'
214
+ raise Error.new(res, params)
215
+ end
216
+ end
217
+ end
218
+
219
+ # Slack client for Web API
220
+ class WebApi < Base
221
+ DEFAULT_ENDPOINT = "https://slack.com/api/".freeze
222
+
223
+ def api
224
+ self
225
+ end
226
+
227
+ def endpoint
228
+ @endpoint ||= URI.parse(DEFAULT_ENDPOINT)
229
+ end
230
+
231
+ def post_message_endpoint
232
+ @post_message_endpoint ||= URI.join(endpoint, "chat.postMessage")
233
+ end
234
+
235
+ def channels_create_endpoint
236
+ @channels_create_endpoint ||= URI.join(endpoint, "channels.create")
237
+ end
238
+
239
+ # Sends a message to a channel.
240
+ #
241
+ # @see https://api.slack.com/methods/chat.postMessage
242
+ # @see https://github.com/slackhq/slack-api-docs/blob/master/methods/chat.postMessage.md
243
+ # @see https://github.com/slackhq/slack-api-docs/blob/master/methods/chat.postMessage.json
244
+ def post_message(params = {}, opts = {})
245
+ with_channels_create(params, opts) do
246
+ log.info { "out_slack: post_message #{filter_params(params)}" }
247
+ post(post_message_endpoint, params)
248
+ end
249
+ end
250
+
251
+ # Creates a channel.
252
+ #
253
+ # NOTE: Bot user can not create a channel. Token must be issued by Normal User Account
254
+ # @see https://api.slack.com/bot-users
255
+ #
256
+ # @see https://api.slack.com/methods/channels.create
257
+ # @see https://github.com/slackhq/slack-api-docs/blob/master/methods/channels.create.md
258
+ # @see https://github.com/slackhq/slack-api-docs/blob/master/methods/channels.create.json
259
+ def channels_create(params = {}, opts = {})
260
+ log.info { "out_slack: channels_create #{filter_params(params)}" }
261
+ post(channels_create_endpoint, params)
262
+ end
263
+
264
+ private
265
+
266
+ def encode_body(params = {})
267
+ body = params.dup
268
+ if params[:attachments]
269
+ body[:attachments] = to_json_with_scrub!(params[:attachments])
270
+ end
271
+ URI.encode_www_form(body)
272
+ end
273
+
274
+ def response_check(res, params)
275
+ super
276
+ res_params = JSON.parse(res.body)
277
+ return if res_params['ok']
278
+ case res_params['error']
279
+ when 'channel_not_found'
280
+ raise ChannelNotFoundError.new(res, params)
281
+ when 'name_taken'
282
+ raise NameTakenError.new(res, params)
283
+ else
284
+ raise Error.new(res, params)
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,24 @@
1
+ require 'net/http'
2
+
3
+ module Fluent
4
+ module SlackClient
5
+ class Error < StandardError
6
+ attr_reader :res, :req_params
7
+
8
+ def initialize(res, req_params = {})
9
+ @res = res
10
+ @req_params = req_params.dup
11
+ end
12
+
13
+ def message
14
+ @req_params[:token] = '[FILTERED]' if @req_params[:token]
15
+ "res.code:#{@res.code}, res.body:#{@res.body}, req_params:#{@req_params}"
16
+ end
17
+
18
+ alias :to_s :message
19
+ end
20
+
21
+ class ChannelNotFoundError < Error; end
22
+ class NameTakenError < Error; end
23
+ end
24
+ end
data/test.sh ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ echo '{"message":"message"}' | bundle exec fluent-cat tag
@@ -0,0 +1,566 @@
1
+ require_relative '../test_helper'
2
+ require 'fluent/plugin/out_slack'
3
+ require 'time'
4
+
5
+ class SlackOutputTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ super
9
+ Fluent::Test.setup
10
+ @icon_url = 'http://www.google.com/s2/favicons?domain=www.google.de'
11
+ end
12
+
13
+ CONFIG = %[
14
+ channel channel
15
+ webhook_url https://hooks.slack.com/services/XXXX/XXXX/XXX
16
+ ]
17
+
18
+ def default_payload
19
+ {
20
+ channel: '#channel',
21
+ mrkdwn: true,
22
+ link_names: true,
23
+ }
24
+ end
25
+
26
+ def default_attachment
27
+ {
28
+ mrkdwn_in: %w[text fields],
29
+ }
30
+ end
31
+
32
+ def create_driver(conf = CONFIG)
33
+ Fluent::Test::BufferedOutputTestDriver.new(Fluent::SlackOutput).configure(conf)
34
+ end
35
+
36
+ # old version compatibility with v0.4.0"
37
+ def test_old_config
38
+ # default check
39
+ d = create_driver
40
+ assert_equal true, d.instance.localtime
41
+ assert_equal nil, d.instance.username # 'fluentd' break lower version compatibility
42
+ assert_equal nil, d.instance.color # 'good' break lower version compatibility
43
+ assert_equal nil, d.instance.icon_emoji # ':question:' break lower version compatibility
44
+ assert_equal nil, d.instance.icon_url
45
+ assert_equal true, d.instance.mrkdwn
46
+ assert_equal true, d.instance.link_names
47
+ assert_equal nil, d.instance.parse
48
+
49
+ assert_nothing_raised do
50
+ create_driver(CONFIG + %[api_key testtoken])
51
+ end
52
+
53
+ # incoming webhook endpoint was changed. team option should be ignored
54
+ assert_nothing_raised do
55
+ create_driver(CONFIG + %[team sowasowa])
56
+ end
57
+
58
+ # rtm? it was not calling `rtm.start`. rtm option was removed and should be ignored
59
+ assert_nothing_raised do
60
+ create_driver(CONFIG + %[rtm true])
61
+ end
62
+
63
+ # channel should be URI.unescape-ed
64
+ d = create_driver(CONFIG + %[channel %23test])
65
+ assert_equal '#test', d.instance.channel
66
+
67
+ # timezone should work
68
+ d = create_driver(CONFIG + %[timezone Asia/Tokyo])
69
+ assert_equal 'Asia/Tokyo', d.instance.timezone
70
+ end
71
+
72
+ def test_configure
73
+ d = create_driver(%[
74
+ channel channel
75
+ time_format %Y/%m/%d %H:%M:%S
76
+ username username
77
+ color bad
78
+ icon_emoji :ghost:
79
+ token XX-XX-XX
80
+ title slack notice!
81
+ message %s
82
+ message_keys message
83
+ ])
84
+ assert_equal '#channel', d.instance.channel
85
+ assert_equal '%Y/%m/%d %H:%M:%S', d.instance.time_format
86
+ assert_equal 'username', d.instance.username
87
+ assert_equal 'bad', d.instance.color
88
+ assert_equal ':ghost:', d.instance.icon_emoji
89
+ assert_equal 'XX-XX-XX', d.instance.token
90
+ assert_equal '%s', d.instance.message
91
+ assert_equal ['message'], d.instance.message_keys
92
+
93
+ # Allow DM
94
+ d = create_driver(CONFIG + %[channel @test])
95
+ assert_equal '@test', d.instance.channel
96
+
97
+ assert_raise(Fluent::ConfigError) do
98
+ create_driver(CONFIG + %[title %s %s\ntitle_keys foo])
99
+ end
100
+
101
+ assert_raise(Fluent::ConfigError) do
102
+ create_driver(CONFIG + %[message %s %s\nmessage_keys foo])
103
+ end
104
+
105
+ assert_raise(Fluent::ConfigError) do
106
+ create_driver(CONFIG + %[channel %s %s\nchannel_keys foo])
107
+ end
108
+ end
109
+
110
+ def test_slack_configure
111
+ # One of webhook_url or slackbot_url, or token is required
112
+ assert_raise(Fluent::ConfigError) do
113
+ create_driver(%[channel foo])
114
+ end
115
+
116
+ # webhook_url is an empty string
117
+ assert_raise(Fluent::ConfigError) do
118
+ create_driver(%[channel foo\nwebhook_url])
119
+ end
120
+
121
+ # webhook without channel (it works because webhook has a default channel)
122
+ assert_nothing_raised do
123
+ create_driver(%[webhook_url https://example.com/path/to/webhook])
124
+ end
125
+
126
+ # slackbot_url is an empty string
127
+ assert_raise(Fluent::ConfigError) do
128
+ create_driver(%[channel foo\nslackbot_url])
129
+ end
130
+
131
+ # slackbot without channel
132
+ assert_raise(Fluent::ConfigError) do
133
+ create_driver(%[slackbot_url https://example.com/path/to/slackbot])
134
+ end
135
+
136
+ # token is an empty string
137
+ assert_raise(Fluent::ConfigError) do
138
+ create_driver(%[channel foo\ntoken])
139
+ end
140
+
141
+ # slack webapi token without channel
142
+ assert_raise(Fluent::ConfigError) do
143
+ create_driver(%[token some_token])
144
+ end
145
+ end
146
+
147
+ def test_timezone_configure
148
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
149
+
150
+ d = create_driver(CONFIG + %[localtime])
151
+ with_timezone('Asia/Tokyo') do
152
+ assert_equal true, d.instance.localtime
153
+ assert_equal "07:00:00", d.instance.timef.format(time)
154
+ end
155
+
156
+ d = create_driver(CONFIG + %[utc])
157
+ with_timezone('Asia/Tokyo') do
158
+ assert_equal false, d.instance.localtime
159
+ assert_equal "22:00:00", d.instance.timef.format(time)
160
+ end
161
+
162
+ d = create_driver(CONFIG + %[timezone Asia/Taipei])
163
+ with_timezone('Asia/Tokyo') do
164
+ assert_equal "Asia/Taipei", d.instance.timezone
165
+ assert_equal "06:00:00", d.instance.timef.format(time)
166
+ end
167
+ end
168
+
169
+ def test_time_format_configure
170
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
171
+
172
+ d = create_driver(CONFIG + %[time_format %Y/%m/%d %H:%M:%S])
173
+ with_timezone('Asia/Tokyo') do
174
+ assert_equal "2014/01/02 07:00:00", d.instance.timef.format(time)
175
+ end
176
+ end
177
+
178
+ def test_buffer_configure
179
+ assert_nothing_raised do
180
+ create_driver(CONFIG + %[buffer_type file\nbuffer_path tmp/])
181
+ end
182
+ end
183
+
184
+ def test_icon_configure
185
+ # default
186
+ d = create_driver(CONFIG)
187
+ assert_equal nil, d.instance.icon_emoji
188
+ assert_equal nil, d.instance.icon_url
189
+
190
+ # either of icon_emoji or icon_url can be specified
191
+ assert_raise(Fluent::ConfigError) do
192
+ d = create_driver(CONFIG + %[icon_emoji :ghost:\nicon_url #{@icon_url}])
193
+ end
194
+
195
+ # icon_emoji
196
+ d = create_driver(CONFIG + %[icon_emoji :ghost:])
197
+ assert_equal ':ghost:', d.instance.icon_emoji
198
+ assert_equal nil, d.instance.icon_url
199
+
200
+ # icon_url
201
+ d = create_driver(CONFIG + %[icon_url #{@icon_url}])
202
+ assert_equal nil, d.instance.icon_emoji
203
+ assert_equal @icon_url, d.instance.icon_url
204
+ end
205
+
206
+ def test_link_names_configure
207
+ # default
208
+ d = create_driver(CONFIG)
209
+ assert_equal true, d.instance.link_names
210
+
211
+ # true
212
+ d = create_driver(CONFIG + %[link_names true])
213
+ assert_equal true, d.instance.link_names
214
+
215
+ # false
216
+ d = create_driver(CONFIG + %[link_names false])
217
+ assert_equal false, d.instance.link_names
218
+ end
219
+
220
+ def test_parse_configure
221
+ # default
222
+ d = create_driver(CONFIG)
223
+ assert_equal nil, d.instance.parse
224
+
225
+ # none
226
+ d = create_driver(CONFIG + %[parse none])
227
+ assert_equal 'none', d.instance.parse
228
+
229
+ # full
230
+ d = create_driver(CONFIG + %[parse full])
231
+ assert_equal 'full', d.instance.parse
232
+
233
+ # invalid
234
+ assert_raise(Fluent::ConfigError) do
235
+ d = create_driver(CONFIG + %[parse invalid])
236
+ end
237
+ end
238
+
239
+ def test_mrkwn_configure
240
+ # default
241
+ d = create_driver(CONFIG)
242
+ assert_equal true, d.instance.mrkdwn
243
+ assert_equal %w[text fields], d.instance.mrkdwn_in
244
+
245
+ # true
246
+ d = create_driver(CONFIG + %[mrkdwn true])
247
+ assert_equal true, d.instance.mrkdwn
248
+ assert_equal %w[text fields], d.instance.mrkdwn_in
249
+
250
+ # false
251
+ d = create_driver(CONFIG + %[mrkdwn false])
252
+ assert_equal false, d.instance.mrkdwn
253
+ assert_equal nil, d.instance.mrkdwn_in
254
+ end
255
+
256
+ def test_https_proxy_configure
257
+ # default
258
+ d = create_driver(CONFIG)
259
+ assert_equal nil, d.instance.slack.https_proxy
260
+ assert_equal Net::HTTP, d.instance.slack.proxy_class
261
+
262
+ # https_proxy
263
+ d = create_driver(CONFIG + %[https_proxy https://proxy.foo.bar:443])
264
+ assert_equal URI.parse('https://proxy.foo.bar:443'), d.instance.slack.https_proxy
265
+ assert_not_equal Net::HTTP, d.instance.slack.proxy_class # Net::HTTP.Proxy
266
+ end
267
+
268
+ def test_auto_channels_create_configure
269
+ # default
270
+ d = create_driver(CONFIG)
271
+ assert_equal false, d.instance.auto_channels_create
272
+ assert_equal({}, d.instance.post_message_opts)
273
+
274
+ # require `token`
275
+ assert_raise(Fluent::ConfigError) do
276
+ d = create_driver(CONFIG + %[auto_channels_create true])
277
+ end
278
+
279
+ # auto_channels_create
280
+ d = create_driver(CONFIG + %[auto_channels_create true\ntoken XXX-XX-XXX])
281
+ assert_equal true, d.instance.auto_channels_create
282
+ assert_equal({auto_channels_create: true}, d.instance.post_message_opts)
283
+ end
284
+
285
+ def test_default_incoming_webhook
286
+ d = create_driver(%[
287
+ channel channel
288
+ webhook_url https://hooks.slack.com/services/XXX/XXX/XXX
289
+ ])
290
+ assert_equal Fluent::SlackClient::IncomingWebhook, d.instance.slack.class
291
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
292
+ d.tag = 'test'
293
+ mock(d.instance.slack).post_message(default_payload.merge({
294
+ text: "sowawa1\nsowawa2\n",
295
+ }), {})
296
+ with_timezone('Asia/Tokyo') do
297
+ d.emit({message: 'sowawa1'}, time)
298
+ d.emit({message: 'sowawa2'}, time)
299
+ d.run
300
+ end
301
+ end
302
+
303
+ def test_default_slackbot
304
+ d = create_driver(%[
305
+ channel channel
306
+ slackbot_url https://xxxxx.slack.com/services/hooks/slackbot?token=XXXXXXX
307
+ ])
308
+ assert_equal Fluent::SlackClient::Slackbot, d.instance.slack.class
309
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
310
+ d.tag = 'test'
311
+ mock(d.instance.slack).post_message(default_payload.merge({
312
+ text: "sowawa1\nsowawa2\n",
313
+ }), {})
314
+ with_timezone('Asia/Tokyo') do
315
+ d.emit({message: 'sowawa1'}, time)
316
+ d.emit({message: 'sowawa2'}, time)
317
+ d.run
318
+ end
319
+ end
320
+
321
+ def test_default_slack_api
322
+ d = create_driver(%[
323
+ channel channel
324
+ token XX-XX-XX
325
+ ])
326
+ assert_equal Fluent::SlackClient::WebApi, d.instance.slack.class
327
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
328
+ d.tag = 'test'
329
+ mock(d.instance.slack).post_message(default_payload.merge({
330
+ token: 'XX-XX-XX',
331
+ text: "sowawa1\nsowawa2\n",
332
+ }), {})
333
+ with_timezone('Asia/Tokyo') do
334
+ d.emit({message: 'sowawa1'}, time)
335
+ d.emit({message: 'sowawa2'}, time)
336
+ d.run
337
+ end
338
+ end
339
+
340
+ def test_title_payload
341
+ title = "mytitle"
342
+ d = create_driver(CONFIG + %[title #{title}])
343
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
344
+ d.tag = 'test'
345
+ # attachments field should be changed to show the title
346
+ mock(d.instance.slack).post_message(default_payload.merge({
347
+ attachments: [default_attachment.merge({
348
+ fallback: title,
349
+ fields: [
350
+ {
351
+ title: title,
352
+ value: "sowawa1\nsowawa2\n",
353
+ }
354
+ ],
355
+ })]
356
+ }), {})
357
+ with_timezone('Asia/Tokyo') do
358
+ d.emit({message: 'sowawa1'}, time)
359
+ d.emit({message: 'sowawa2'}, time)
360
+ d.run
361
+ end
362
+ end
363
+
364
+ def test_title_payload_with_verbose_fallback_option
365
+ title = "mytitle"
366
+ d = create_driver(CONFIG + %[title #{title}\nverbose_fallback true])
367
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
368
+ d.tag = 'test'
369
+ # attachments field should be changed to show the title
370
+ mock(d.instance.slack).post_message(default_payload.merge({
371
+ attachments: [default_attachment.merge({
372
+ fallback: "#{title} sowawa1\nsowawa2\n",
373
+ fields: [
374
+ {
375
+ title: title,
376
+ value: "sowawa1\nsowawa2\n",
377
+ }
378
+ ],
379
+ })]
380
+ }), {})
381
+ with_timezone('Asia/Tokyo') do
382
+ d.emit({message: 'sowawa1'}, time)
383
+ d.emit({message: 'sowawa2'}, time)
384
+ d.run
385
+ end
386
+ end
387
+
388
+ def test_color_payload
389
+ color = 'good'
390
+ d = create_driver(CONFIG + %[color #{color}])
391
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
392
+ d.tag = 'test'
393
+ # attachments field should be changed to show the title
394
+ mock(d.instance.slack).post_message(default_payload.merge({
395
+ attachments: [default_attachment.merge({
396
+ color: color,
397
+ fallback: "sowawa1\nsowawa2\n",
398
+ text: "sowawa1\nsowawa2\n",
399
+ })]
400
+ }), {})
401
+ with_timezone('Asia/Tokyo') do
402
+ d.emit({message: 'sowawa1'}, time)
403
+ d.emit({message: 'sowawa2'}, time)
404
+ d.run
405
+ end
406
+ end
407
+
408
+ def test_plain_payload
409
+ d = create_driver(CONFIG)
410
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
411
+ d.tag = 'test'
412
+ # attachments field should be changed to show the title
413
+ mock(d.instance.slack).post_message(default_payload.merge({
414
+ text: "sowawa1\nsowawa2\n",
415
+ }), {})
416
+ with_timezone('Asia/Tokyo') do
417
+ d.emit({message: 'sowawa1'}, time)
418
+ d.emit({message: 'sowawa2'}, time)
419
+ d.run
420
+ end
421
+ end
422
+
423
+ def test_title_keys
424
+ d = create_driver(CONFIG + %[title [%s] %s\ntitle_keys time,tag])
425
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
426
+ d.tag = 'test'
427
+ # attachments field should be changed to show the title
428
+ mock(d.instance.slack).post_message(default_payload.merge({
429
+ attachments: [default_attachment.merge({
430
+ fallback: "[07:00:00] #{d.tag}",
431
+ fields: [
432
+ {
433
+ title: "[07:00:00] #{d.tag}",
434
+ value: "sowawa1\nsowawa2\n",
435
+ }
436
+ ],
437
+ })]
438
+ }), {})
439
+ with_timezone('Asia/Tokyo') do
440
+ d.emit({message: 'sowawa1'}, time)
441
+ d.emit({message: 'sowawa2'}, time)
442
+ d.run
443
+ end
444
+ end
445
+
446
+ def test_message_keys
447
+ d = create_driver(CONFIG + %[message [%s] %s %s\nmessage_keys time,tag,message])
448
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
449
+ d.tag = 'test'
450
+ mock(d.instance.slack).post_message(default_payload.merge({
451
+ text: "[07:00:00] test sowawa1\n[07:00:00] test sowawa2\n",
452
+ }), {})
453
+ with_timezone('Asia/Tokyo') do
454
+ d.emit({message: 'sowawa1'}, time)
455
+ d.emit({message: 'sowawa2'}, time)
456
+ d.run
457
+ end
458
+ end
459
+
460
+ def test_channel_keys
461
+ d = create_driver(CONFIG + %[channel %s\nchannel_keys channel])
462
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
463
+ d.tag = 'test'
464
+ mock(d.instance.slack).post_message(default_payload.merge({
465
+ channel: '#channel1',
466
+ text: "sowawa1\n",
467
+ }), {})
468
+ mock(d.instance.slack).post_message(default_payload.merge({
469
+ channel: '#channel2',
470
+ text: "sowawa2\n",
471
+ }), {})
472
+ with_timezone('Asia/Tokyo') do
473
+ d.emit({message: 'sowawa1', channel: 'channel1'}, time)
474
+ d.emit({message: 'sowawa2', channel: 'channel2'}, time)
475
+ d.run
476
+ end
477
+ end
478
+
479
+ def test_icon_emoji
480
+ d = create_driver(CONFIG + %[icon_emoji :ghost:])
481
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
482
+ d.tag = 'test'
483
+ mock(d.instance.slack).post_message(default_payload.merge({
484
+ icon_emoji: ':ghost:',
485
+ text: "foo\n",
486
+ }), {})
487
+ with_timezone('Asia/Tokyo') do
488
+ d.emit({message: 'foo'}, time)
489
+ d.run
490
+ end
491
+ end
492
+
493
+ def test_icon_url
494
+ d = create_driver(CONFIG + %[icon_url #{@icon_url}])
495
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
496
+ d.tag = 'test'
497
+ mock(d.instance.slack).post_message(default_payload.merge({
498
+ icon_url: @icon_url,
499
+ text: "foo\n",
500
+ }), {})
501
+ with_timezone('Asia/Tokyo') do
502
+ d.emit({message: 'foo'}, time)
503
+ d.run
504
+ end
505
+ end
506
+
507
+ def test_mrkdwn
508
+ d = create_driver(CONFIG + %[mrkdwn true])
509
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
510
+ d.tag = 'test'
511
+ mock(d.instance.slack).post_message(default_payload.merge({
512
+ mrkdwn: true,
513
+ text: "foo\n",
514
+ }), {})
515
+ with_timezone('Asia/Tokyo') do
516
+ d.emit({message: 'foo'}, time)
517
+ d.run
518
+ end
519
+ end
520
+
521
+ def test_mrkdwn_in
522
+ d = create_driver(CONFIG + %[mrkdwn true\ncolor good])
523
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
524
+ d.tag = 'test'
525
+ mock(d.instance.slack).post_message(default_payload.merge({
526
+ attachments: [default_attachment.merge({
527
+ color: "good",
528
+ fallback: "foo\n",
529
+ text: "foo\n",
530
+ mrkdwn_in: ["text", "fields"],
531
+ })]
532
+ }), {})
533
+ with_timezone('Asia/Tokyo') do
534
+ d.emit({message: 'foo'}, time)
535
+ d.run
536
+ end
537
+ end
538
+
539
+ def test_link_names
540
+ d = create_driver(CONFIG + %[link_names true])
541
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
542
+ d.tag = 'test'
543
+ mock(d.instance.slack).post_message(default_payload.merge({
544
+ link_names: true,
545
+ text: "foo\n",
546
+ }), {})
547
+ with_timezone('Asia/Tokyo') do
548
+ d.emit({message: 'foo'}, time)
549
+ d.run
550
+ end
551
+ end
552
+
553
+ def test_parse
554
+ d = create_driver(CONFIG + %[parse full])
555
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
556
+ d.tag = 'test'
557
+ mock(d.instance.slack).post_message(default_payload.merge({
558
+ parse: "full",
559
+ text: "foo\n",
560
+ }), {})
561
+ with_timezone('Asia/Tokyo') do
562
+ d.emit({message: 'foo'}, time)
563
+ d.run
564
+ end
565
+ end
566
+ end