slack-messenger 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/lib/slack-messenger.rb +59 -0
  3. data/lib/slack-messenger/config.rb +43 -0
  4. data/lib/slack-messenger/payload_middleware.rb +24 -0
  5. data/lib/slack-messenger/payload_middleware/at.rb +36 -0
  6. data/lib/slack-messenger/payload_middleware/base.rb +34 -0
  7. data/lib/slack-messenger/payload_middleware/channels.rb +21 -0
  8. data/lib/slack-messenger/payload_middleware/format_attachments.rb +44 -0
  9. data/lib/slack-messenger/payload_middleware/format_message.rb +20 -0
  10. data/lib/slack-messenger/payload_middleware/stack.rb +50 -0
  11. data/lib/slack-messenger/util/escape.rb +16 -0
  12. data/lib/slack-messenger/util/http_client.rb +64 -0
  13. data/lib/slack-messenger/util/link_formatter.rb +81 -0
  14. data/lib/slack-messenger/version.rb +7 -0
  15. data/spec/end_to_end_spec.rb +95 -0
  16. data/spec/integration/ping_integration_test.rb +16 -0
  17. data/spec/lib/slack-messenger/config_spec.rb +71 -0
  18. data/spec/lib/slack-messenger/payload_middleware/at_spec.rb +25 -0
  19. data/spec/lib/slack-messenger/payload_middleware/base_spec.rb +76 -0
  20. data/spec/lib/slack-messenger/payload_middleware/channels_spec.rb +20 -0
  21. data/spec/lib/slack-messenger/payload_middleware/format_attachments_spec.rb +48 -0
  22. data/spec/lib/slack-messenger/payload_middleware/format_message_spec.rb +27 -0
  23. data/spec/lib/slack-messenger/payload_middleware/stack_spec.rb +119 -0
  24. data/spec/lib/slack-messenger/payload_middleware_spec.rb +33 -0
  25. data/spec/lib/slack-messenger/util/http_client_spec.rb +55 -0
  26. data/spec/lib/slack-messenger/util/link_formatter_spec.rb +155 -0
  27. data/spec/lib/slack-messenger_spec.rb +98 -0
  28. data/spec/spec_helper.rb +28 -0
  29. metadata +84 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ class Messenger
5
+ VERSION = "2.3.3".freeze # rubocop:disable Style/RedundantFreeze
6
+ end
7
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require "spec_helper"
5
+
6
+ RSpec.describe Slack::Messenger do
7
+ {
8
+ { text: "hello" } =>
9
+ { payload: { text: "hello" } },
10
+
11
+ { text: "[hello](http://example.com/world)" } =>
12
+ { payload: { text: "<http://example.com/world|hello>" } },
13
+
14
+ { text: '<a href="http://example.com">example</a>' } =>
15
+ { payload: { text: "<http://example.com|example>" } },
16
+
17
+ { text: "hello/こんにちは from messenger test" } =>
18
+ { payload: { text: "hello/こんにちは from messenger test" } },
19
+
20
+ { text: "Hello World, enjoy [](http://example.com)." } =>
21
+ { payload: { text: "Hello World, enjoy <http://example.com>." } },
22
+
23
+ { text: "Hello World, enjoy [this](http://example.com)[this2](http://example2.com)" } =>
24
+ { payload: { text: "Hello World, enjoy <http://example.com|this><http://example2.com|this2>" } },
25
+
26
+ { text: "[John](mailto:john@example.com)" } =>
27
+ { payload: { text: "<mailto:john@example.com|John>" } },
28
+
29
+ { text: '<a href="mailto:john@example.com">John</a>' } =>
30
+ { payload: { text: "<mailto:john@example.com|John>" } },
31
+
32
+ { text: "hello", channel: "hodor" } =>
33
+ { payload: { text: "hello", channel: "hodor" } },
34
+
35
+ { text: nil, attachments: [{ text: "attachment message" }] } =>
36
+ { payload: { text: nil, attachments: [{ text: "attachment message" }] } },
37
+
38
+ { text: "the message", channel: "foo", attachments: [{ color: "#000",
39
+ text: "attachment message",
40
+ fallback: "fallback message" }] } =>
41
+ { payload: { text: "the message",
42
+ channel: "foo",
43
+ attachments: [{ color: "#000",
44
+ text: "attachment message",
45
+ fallback: "fallback message" }] } },
46
+
47
+ { attachments: [{ color: "#000",
48
+ text: "attachment message",
49
+ fallback: "fallback message" }] } =>
50
+ { payload: { attachments: [{ color: "#000",
51
+ text: "attachment message",
52
+ fallback: "fallback message" }] } },
53
+
54
+ { attachments: { color: "#000",
55
+ text: "attachment message [hodor](http://winterfell.com)",
56
+ fallback: "fallback message" } } =>
57
+ { payload: { attachments: [{ color: "#000",
58
+ text: "attachment message <http://winterfell.com|hodor>",
59
+ fallback: "fallback message" }] } },
60
+
61
+ { attachments: { color: "#000",
62
+ text: nil,
63
+ fallback: "fallback message" } } =>
64
+ { payload: { attachments: [{ color: "#000",
65
+ text: nil,
66
+ fallback: "fallback message" }] } },
67
+
68
+ { text: "hello", http_options: { timeout: 5 } } =>
69
+ { http_options: { timeout: 5 }, payload: { text: "hello" } }
70
+ }.each do |args, payload|
71
+ it "sends correct payload for #post(#{args})" do
72
+ http_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
73
+ messenger = Slack::Messenger.new "http://example.com", http_client: http_client
74
+ payload[:payload] = payload[:payload].to_json
75
+
76
+ expect(http_client).to receive(:post)
77
+ .with(URI.parse("http://example.com"), payload)
78
+
79
+ messenger.post(args)
80
+ end
81
+ end
82
+
83
+ it "applies options given to middleware" do
84
+ client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
85
+ messenger = Slack::Messenger.new "http://example.com" do
86
+ http_client client
87
+ middleware format_message: { formats: [] }
88
+ end
89
+
90
+ expect(client).to receive(:post)
91
+ .with(URI.parse("http://example.com"), payload: { text: "Hello [world](http://example.com)!" }.to_json)
92
+
93
+ messenger.post text: "Hello [world](http://example.com)!"
94
+ end
95
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require_relative "../../lib/slack-messenger"
5
+
6
+ ruby = if defined?(JRUBY_VERSION)
7
+ "jruby #{JRUBY_VERSION}"
8
+ else
9
+ "ruby #{RUBY_VERSION}"
10
+ end
11
+ puts "testing with #{ruby}"
12
+
13
+ messenger = Slack::Messenger.new ENV["SLACK_WEBHOOK_URL"], username: "messenger"
14
+ messenger.ping "hello", channel: ["#general", "#random"]
15
+ messenger.ping "hello/こんにちは from messenger test script on #{ruby}\225"
16
+ messenger.ping attachments: [{ color: "#1BF5AF", fallback: "fallback", text: "attachment" }]
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::Config do
4
+ describe "#http_client" do
5
+ it "is Util::HTTPClient if not set" do
6
+ subject = described_class.new
7
+ expect(subject.http_client).to eq Slack::Messenger::Util::HTTPClient
8
+ end
9
+
10
+ it "sets a new client class if given one" do
11
+ new_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
12
+ subject = described_class.new
13
+ subject.http_client new_client
14
+ expect(subject.http_client).to eq new_client
15
+ end
16
+
17
+ it "raises an ArgumentError if given class does not respond to ::post" do
18
+ subject = described_class.new
19
+ expect do
20
+ subject.http_client :nope
21
+ end.to raise_error ArgumentError
22
+ end
23
+ end
24
+
25
+ describe "#defaults" do
26
+ it "is an empty hash by default" do
27
+ subject = described_class.new
28
+ expect(subject.defaults).to eq({})
29
+ end
30
+
31
+ it "sets a hash to default if given" do
32
+ subject = described_class.new
33
+ subject.defaults foo: :bar
34
+ expect(subject.defaults).to eq foo: :bar
35
+ end
36
+
37
+ it "raises ArgumentError if not given a hash" do
38
+ subject = described_class.new
39
+ expect do
40
+ subject.defaults :nope
41
+ end.to raise_error ArgumentError
42
+ end
43
+ end
44
+
45
+ describe "#middleware" do
46
+ it "is [:format_message, :format_attachments, :at] if not set" do
47
+ subject = described_class.new
48
+
49
+ expect(subject.middleware).to eq %i[format_message format_attachments at channels]
50
+ end
51
+
52
+ it "takes an array or a splat of args" do
53
+ subject = described_class.new
54
+
55
+ subject.middleware :layer, :two
56
+ expect(subject.middleware).to eq %i[layer two]
57
+
58
+ subject.middleware %i[one layer]
59
+ expect(subject.middleware).to eq %i[one layer]
60
+ end
61
+
62
+ it "allows passing options to middleware stack" do
63
+ subject = described_class.new
64
+ subject.middleware one: { opts: :for_one },
65
+ two: { opts: :for_two }
66
+
67
+ expect(subject.middleware).to eq one: { opts: :for_one },
68
+ two: { opts: :for_two }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::At do
4
+ it "can handle array at" do
5
+ subject = described_class.new(:messenger)
6
+ payload = { text: "hello", at: %i[john ken here] }
7
+
8
+ expect(subject.call(payload)).to eq text: "<@john> <@ken> <!here> hello"
9
+ end
10
+
11
+ it "can handle single at option" do
12
+ subject = described_class.new(:messenger)
13
+ payload = { text: "hello", at: :alice }
14
+
15
+ expect(subject.call(payload)).to eq text: "<@alice> hello"
16
+ end
17
+
18
+ it "generates :text in payload if given :at & no :text" do
19
+ subject = described_class.new(:messenger)
20
+ input_payload = { at: [:here], attachments: [{ text: "hello" }] }
21
+ output_payload = { text: "<!here> ", attachments: [{ text: "hello" }] }
22
+
23
+ expect(subject.call(input_payload)).to eq output_payload
24
+ end
25
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Base do
4
+ before(:each) do
5
+ @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup
6
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
7
+ end
8
+
9
+ after(:each) do
10
+ # cleanup middleware registry
11
+ Slack::Messenger::PayloadMiddleware.registry
12
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
13
+
14
+ # cleanup object constants
15
+ Object.send(:remove_const, :Subject) if Object.constants.include?(:Subject)
16
+ Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
17
+ end
18
+
19
+ describe "::middleware_name" do
20
+ it "registers class w/ given name" do
21
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
22
+ end
23
+
24
+ expect(Slack::Messenger::PayloadMiddleware)
25
+ .to receive(:register).with(Subject, :subject)
26
+
27
+ class Subject
28
+ middleware_name :subject
29
+ end
30
+ end
31
+
32
+ it "uses symbolized name to register" do
33
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
34
+ end
35
+
36
+ expect(Slack::Messenger::PayloadMiddleware)
37
+ .to receive(:register).with(Subject, :subject)
38
+
39
+ class Subject
40
+ middleware_name "subject"
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "::options" do
46
+ it "allows setting default options for a middleware" do
47
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
48
+ options foo: :bar
49
+ end
50
+
51
+ subject = Subject.new(:messenger)
52
+ expect(subject.options).to eq foo: :bar
53
+
54
+ subject = Subject.new(:messenger, foo: :baz)
55
+ expect(subject.options).to eq foo: :baz
56
+ end
57
+ end
58
+
59
+ describe "#initialize" do
60
+ it "sets given messenger as messenger" do
61
+ expect(described_class.new(:messenger).messenger).to eq :messenger
62
+ end
63
+
64
+ it "sets given options as opts" do
65
+ expect(described_class.new(:messenger, opts: :options).options).to eq opts: :options
66
+ end
67
+ end
68
+
69
+ describe "#call" do
70
+ it "raises NoMethodError (expects subclass to define)" do
71
+ expect do
72
+ described_class.new(:messenger).call
73
+ end.to raise_exception NoMethodError
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Channels do
4
+ it "leaves string channels alone" do
5
+ subject = described_class.new(:messenger)
6
+ payload = { text: "hello", channel: "hodor" }
7
+
8
+ expect(subject.call(payload)).to eq text: "hello", channel: "hodor"
9
+ end
10
+
11
+ it "splits payload into multiple if given an array of channels" do
12
+ subject = described_class.new(:messenger)
13
+ payload = { text: "hello", channel: %w[foo hodor] }
14
+
15
+ expect(subject.call(payload)).to eq [
16
+ { text: "hello", channel: "foo" },
17
+ { text: "hello", channel: "hodor" }
18
+ ]
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::FormatAttachments do
4
+ it "passes the text of attachments through linkformatter with options[:formats]" do
5
+ subject = described_class.new(:messenger, formats: [:html])
6
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
7
+ .with("hello", formats: [:html])
8
+ subject.call(attachments: [{ text: "hello" }])
9
+ end
10
+
11
+ it "searches through string or symbol keys" do
12
+ subject = described_class.new(:messenger)
13
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
14
+ .with("hello", formats: %i[html markdown])
15
+ subject.call("attachments" => [{ "text" => "hello" }])
16
+
17
+ subject = described_class.new(:messenger)
18
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
19
+ .with("hello", formats: %i[html markdown])
20
+ subject.call(attachments: [{ text: "hello" }])
21
+ end
22
+
23
+ it "can handle a single attachment" do
24
+ subject = described_class.new(:messenger)
25
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
26
+ .with("hello", formats: %i[html markdown])
27
+ subject.call(attachments: { text: "hello" })
28
+ end
29
+
30
+ it "wraps attachment into array if given as a single hash" do
31
+ params = {
32
+ attachments: { text: "hello" }
33
+ }
34
+ payload = {
35
+ attachments: [{ text: "hello" }]
36
+ }
37
+ subject = described_class.new(:messenger)
38
+
39
+ expect(subject.call(params)).to eq payload
40
+ end
41
+
42
+ it "returns the payload unmodified if not :attachments key" do
43
+ payload = { foo: :bar }
44
+ subject = described_class.new(:messenger)
45
+
46
+ expect(subject.call(payload)).to eq payload
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::FormatMessage do
4
+ it "passes the text through linkformatter with options[:formats]" do
5
+ subject = described_class.new(:messenger, formats: [:html])
6
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
7
+ .with("hello", formats: [:html])
8
+ subject.call(text: "hello")
9
+
10
+ subject = described_class.new(:messenger)
11
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
12
+ .with("hello", formats: %i[html markdown])
13
+ subject.call(text: "hello")
14
+
15
+ subject = described_class.new(:messenger, formats: [:markdown])
16
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
17
+ .with("hello", formats: [:markdown])
18
+ subject.call(text: "hello")
19
+ end
20
+
21
+ it "returns the payload unmodified if not :text key" do
22
+ payload = { foo: :bar }
23
+ subject = described_class.new(:messenger)
24
+
25
+ expect(subject.call(payload)).to eq payload
26
+ end
27
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Stack do
4
+ let(:return_one) do
5
+ double(call: 1)
6
+ end
7
+
8
+ let(:return_one_twice) do
9
+ double(call: [1, 1])
10
+ end
11
+
12
+ let(:return_two) do
13
+ double(call: 2)
14
+ end
15
+
16
+ let(:return_three) do
17
+ double(call: 3)
18
+ end
19
+
20
+ before(:each) do
21
+ # setup our middleware in the registry
22
+ @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup
23
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
24
+
25
+ Slack::Messenger::PayloadMiddleware.register return_one, :return_one
26
+ Slack::Messenger::PayloadMiddleware.register return_one_twice, :return_one_twice
27
+ Slack::Messenger::PayloadMiddleware.register return_two, :return_two
28
+ Slack::Messenger::PayloadMiddleware.register return_three, :return_three
29
+ end
30
+
31
+ after(:each) do
32
+ # cleanup middleware registry
33
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
34
+ Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
35
+ end
36
+
37
+ describe "::initialize" do
38
+ it "sets messenger to given messenger" do
39
+ expect(described_class.new(:messenger).messenger).to eq :messenger
40
+ end
41
+
42
+ it "has empty stack" do
43
+ expect(described_class.new(:messenger).stack).to match_array []
44
+ end
45
+ end
46
+
47
+ describe "#set" do
48
+ it "initializes each middleware w/ the messenger instance" do
49
+ expect(return_one).to receive(:new).with(:messenger)
50
+ expect(return_two).to receive(:new).with(:messenger)
51
+
52
+ described_class.new(:messenger).set(:return_one, :return_two)
53
+ end
54
+
55
+ it "creates the stack in an array" do
56
+ allow(return_one).to receive(:new).and_return(return_one)
57
+ allow(return_two).to receive(:new).and_return(return_two)
58
+
59
+ subject = described_class.new(:messenger)
60
+ subject.set(:return_one, :return_two)
61
+
62
+ expect(subject.stack).to be_a Array
63
+ expect(subject.stack.first.call).to eq 1
64
+ expect(subject.stack.last.call).to eq 2
65
+ end
66
+
67
+ it "creates a stack from hashes passing them as opts" do
68
+ expect(return_one).to receive(:new).with(:messenger, opts: :for_one)
69
+ expect(return_two).to receive(:new).with(:messenger, opts: :for_two)
70
+
71
+ subject = described_class.new(:messenger)
72
+ subject.set return_one: { opts: :for_one },
73
+ return_two: { opts: :for_two }
74
+ end
75
+
76
+ it "raises if a middleware is missing" do
77
+ expect do
78
+ described_class.new(:messenger).set(:missing)
79
+ end.to raise_exception KeyError
80
+ end
81
+ end
82
+
83
+ describe "#call" do
84
+ it "calls the middleware in order, passing return of each to the next" do
85
+ allow(return_one).to receive(:new).and_return(return_one)
86
+ allow(return_two).to receive(:new).and_return(return_two)
87
+ allow(return_three).to receive(:new).and_return(return_three)
88
+
89
+ subject = described_class.new(:messenger)
90
+ subject.set(:return_one, :return_three, :return_two)
91
+
92
+ expect(return_one).to receive(:call).with(5)
93
+ expect(return_three).to receive(:call).with(1)
94
+ expect(return_two).to receive(:call).with(3)
95
+
96
+ expect(subject.call(5)).to eq [2]
97
+ end
98
+
99
+ it "allows any middleware to return an array but other's don't need special behavior" do
100
+ allow(return_one_twice).to receive(:new).and_return(return_one_twice)
101
+ allow(return_two).to receive(:new).and_return(return_two)
102
+
103
+ subject = described_class.new(:messenger)
104
+ subject.set(:return_one_twice, :return_two)
105
+
106
+ expect(subject.call(5)).to eq [2, 2]
107
+ end
108
+
109
+ it "handles multiple middleware splitting payload" do
110
+ allow(return_one_twice).to receive(:new).and_return(return_one_twice)
111
+ allow(return_two).to receive(:new).and_return(return_two)
112
+
113
+ subject = described_class.new(:messenger)
114
+ subject.set(:return_one_twice, :return_one_twice, :return_two)
115
+
116
+ expect(subject.call(5)).to eq [2, 2, 2, 2]
117
+ end
118
+ end
119
+ end