lita 3.3.1 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +3 -0
  4. data/lib/lita.rb +45 -97
  5. data/lib/lita/adapter.rb +38 -17
  6. data/lib/lita/adapters/shell.rb +5 -3
  7. data/lib/lita/authorization.rb +109 -60
  8. data/lib/lita/builder.rb +38 -0
  9. data/lib/lita/callback.rb +37 -0
  10. data/lib/lita/cli.rb +2 -0
  11. data/lib/lita/config.rb +1 -18
  12. data/lib/lita/configurable.rb +29 -0
  13. data/lib/lita/configuration.rb +179 -0
  14. data/lib/lita/configuration_validator.rb +66 -0
  15. data/lib/lita/daemon.rb +4 -11
  16. data/lib/lita/default_configuration.rb +146 -0
  17. data/lib/lita/errors.rb +9 -0
  18. data/lib/lita/handler.rb +5 -264
  19. data/lib/lita/handler/chat_router.rb +130 -0
  20. data/lib/lita/handler/common.rb +114 -0
  21. data/lib/lita/handler/event_router.rb +77 -0
  22. data/lib/lita/handler/http_router.rb +26 -0
  23. data/lib/lita/handlers/authorization.rb +13 -18
  24. data/lib/lita/handlers/deprecation_check.rb +24 -0
  25. data/lib/lita/handlers/help.rb +5 -3
  26. data/lib/lita/handlers/info.rb +2 -2
  27. data/lib/lita/http_callback.rb +29 -0
  28. data/lib/lita/http_route.rb +41 -26
  29. data/lib/lita/namespace.rb +23 -0
  30. data/lib/lita/rack_app.rb +29 -2
  31. data/lib/lita/registry.rb +133 -0
  32. data/lib/lita/robot.rb +58 -20
  33. data/lib/lita/route_validator.rb +12 -4
  34. data/lib/lita/rspec.rb +23 -14
  35. data/lib/lita/rspec/handler.rb +93 -23
  36. data/lib/lita/rspec/matchers/chat_route_matcher.rb +48 -0
  37. data/lib/lita/rspec/matchers/deprecated.rb +36 -0
  38. data/lib/lita/rspec/matchers/event_route_matcher.rb +27 -0
  39. data/lib/lita/rspec/matchers/http_route_matcher.rb +18 -60
  40. data/lib/lita/user.rb +0 -6
  41. data/lib/lita/util.rb +1 -8
  42. data/lib/lita/version.rb +1 -1
  43. data/lita.gemspec +1 -0
  44. data/spec/lita/adapter_spec.rb +25 -7
  45. data/spec/lita/adapters/shell_spec.rb +24 -4
  46. data/spec/lita/authorization_spec.rb +57 -38
  47. data/spec/lita/builder_spec.rb +39 -0
  48. data/spec/lita/config_spec.rb +0 -24
  49. data/spec/lita/configuration_spec.rb +222 -0
  50. data/spec/lita/configuration_validator_spec.rb +112 -0
  51. data/spec/lita/daemon_spec.rb +2 -2
  52. data/spec/lita/default_configuration_spec.rb +254 -0
  53. data/spec/lita/handler/chat_router_spec.rb +192 -0
  54. data/spec/lita/handler/common_spec.rb +272 -0
  55. data/spec/lita/handler/event_router_spec.rb +54 -0
  56. data/spec/lita/handler/http_router_spec.rb +106 -0
  57. data/spec/lita/handler_spec.rb +20 -291
  58. data/spec/lita/handlers/authorization_spec.rb +9 -11
  59. data/spec/lita/handlers/deprecation_check_spec.rb +21 -0
  60. data/spec/lita/handlers/help_spec.rb +31 -9
  61. data/spec/lita/handlers/info_spec.rb +2 -2
  62. data/spec/lita/handlers/room_spec.rb +5 -3
  63. data/spec/lita/robot_spec.rb +30 -11
  64. data/spec/lita/rspec_spec.rb +71 -31
  65. data/spec/lita/user_spec.rb +2 -2
  66. data/spec/lita_spec.rb +62 -4
  67. data/spec/spec_helper.rb +7 -0
  68. data/templates/locales/en.yml +56 -4
  69. data/templates/plugin/gemspec.tt +1 -0
  70. data/templates/plugin/spec/spec_helper.tt +4 -0
  71. metadata +54 -8
  72. data/lib/lita/rspec/matchers/event_subscription_matcher.rb +0 -67
  73. data/lib/lita/rspec/matchers/route_matcher.rb +0 -69
  74. data/spec/lita/rack_app_spec.rb +0 -92
@@ -0,0 +1,192 @@
1
+ require "spec_helper"
2
+
3
+ handler = Class.new do
4
+ extend Lita::Handler::ChatRouter
5
+
6
+ def self.name
7
+ "Test"
8
+ end
9
+
10
+ route(/message/, :message)
11
+ route(/command/, :command, command: true)
12
+ route(/admin/, :admin, restrict_to: :admins)
13
+ route(/error/, :error)
14
+ route(/validate route hook/, :validate_route_hook, code_word: true)
15
+ route(/trigger route hook/, :trigger_route_hook, custom_data: "trigger route hook")
16
+
17
+ def message(response)
18
+ response.reply("message")
19
+ end
20
+
21
+ def command(response)
22
+ response.reply("command")
23
+ end
24
+
25
+ def admin(response)
26
+ response.reply("admin")
27
+ end
28
+
29
+ def error(_response)
30
+ raise
31
+ end
32
+
33
+ def validate_route_hook(response)
34
+ response.reply("validate route hook")
35
+ end
36
+
37
+ def trigger_route_hook(response)
38
+ response.reply(response.extensions[:custom_data])
39
+ end
40
+
41
+ route(/block/) do |response|
42
+ response.reply("block")
43
+ end
44
+ end
45
+
46
+ describe handler, lita_handler: true do
47
+ describe ".dispatch" do
48
+ it "routes a matching message to the supplied method" do
49
+ send_message("message")
50
+ expect(replies.last).to eq("message")
51
+ end
52
+
53
+ it "routes a matching message even if addressed to the robot" do
54
+ send_command("message")
55
+ expect(replies.last).to eq("message")
56
+ end
57
+
58
+ it "routes a command message to the supplied method" do
59
+ send_command("command")
60
+ expect(replies.last).to eq("command")
61
+ end
62
+
63
+ it "requires command routes to be addressed to the robot" do
64
+ send_message("command")
65
+ expect(replies).to be_empty
66
+ end
67
+
68
+ it "doesn't route messages that don't match anything" do
69
+ send_message("nothing")
70
+ expect(replies).to be_empty
71
+ end
72
+
73
+ it "dispatches to restricted routes if the user is in the auth group" do
74
+ allow(robot.auth).to receive(:user_is_admin?).with(user).and_return(true)
75
+ send_message("admin")
76
+ expect(replies.last).to eq("admin")
77
+ end
78
+
79
+ it "doesn't route unauthorized users' messages to restricted routes" do
80
+ send_message("admin")
81
+ expect(replies).to be_empty
82
+ end
83
+
84
+ it "ignores messages from itself" do
85
+ allow(user).to receive(:name).and_return(robot.name)
86
+ send_message("message")
87
+ expect(replies).to be_empty
88
+ end
89
+
90
+ it "allows route callbacks to be provided as blocks" do
91
+ send_message("block")
92
+ expect(replies.last).to eq("block")
93
+ end
94
+
95
+ it "logs exceptions without crashing" do
96
+ test_mode = Lita.test_mode?
97
+
98
+ begin
99
+ Lita.test_mode = false
100
+ expect(Lita.logger).to receive(:error).with(/Test crashed/)
101
+ send_message("error")
102
+ ensure
103
+ Lita.test_mode = test_mode
104
+ end
105
+ end
106
+
107
+ it "raises exceptions in test mode" do
108
+ expect { send_message("error") }.to raise_error(RuntimeError)
109
+ end
110
+
111
+ context "with a custom validate_route hook" do
112
+ let(:hook) do
113
+ proc do |payload|
114
+ if payload[:route].extensions[:code_word]
115
+ payload[:message].body.include?("code word")
116
+ else
117
+ true
118
+ end
119
+ end
120
+ end
121
+
122
+ before { registry.register_hook(:validate_route, hook) }
123
+
124
+ it "matches if the hook returns true" do
125
+ send_message("validate route hook - code word")
126
+ expect(replies.last).to eq("validate route hook")
127
+ end
128
+
129
+ it "does not match if the hook returns false" do
130
+ send_message("validate route hook")
131
+ expect(replies).to be_empty
132
+ end
133
+ end
134
+
135
+ context "with a custom trigger_route hook" do
136
+ let(:hook) do
137
+ proc do |payload|
138
+ payload[:response].extensions[:custom_data] = payload[:route].extensions[:custom_data]
139
+ end
140
+ end
141
+
142
+ before { registry.register_hook(:trigger_route, hook) }
143
+
144
+ it "adds data to the response's extensions" do
145
+ send_message("trigger route hook")
146
+ expect(replies.last).to eq("trigger route hook")
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ handler = Class.new do
153
+ extend Lita::Handler::ChatRouter
154
+ extend Lita::Handler::EventRouter
155
+
156
+ def self.name
157
+ "Test"
158
+ end
159
+
160
+ route(/one/) { |response| response.reply "got one" }
161
+ route(/two/) { |response| response.reply "got two" }
162
+
163
+ on :unhandled_message do |payload|
164
+ message = payload[:message]
165
+ robot.send_message(message.source, message.body)
166
+ end
167
+ end
168
+
169
+ describe handler, lita_handler: true do
170
+ it "triggers the unhandled message event if no route matches" do
171
+ send_message("this won't match any routes")
172
+ expect(replies.last).to eq("this won't match any routes")
173
+ end
174
+
175
+ it "doesn't stop checking routes when the first one matches" do
176
+ send_message("one two")
177
+ expect(replies.last).to eq("got two")
178
+ end
179
+
180
+ context "with another handler registered" do
181
+ before do
182
+ registry.register_handler(:test_2) do
183
+ route(/three/) { |response| response.reply "got three" }
184
+ end
185
+ end
186
+
187
+ it "doesn't stop dispatching to handlers when there is a matching route in one" do
188
+ send_message("two three")
189
+ expect(replies.last).to eq("got three")
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,272 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handler::Common, lita: true do
4
+ let(:robot) { Lita::Robot.new(registry) }
5
+
6
+ let(:handler) do
7
+ Class.new do
8
+ include Lita::Handler::Common
9
+
10
+ namespace "foo"
11
+ end
12
+ end
13
+
14
+ subject { handler.new(robot) }
15
+
16
+ describe ".config" do
17
+ it "sets configuration attributes" do
18
+ handler.config :foo
19
+
20
+ config = handler.configuration.finalize
21
+
22
+ expect(config.foo).to be_nil
23
+ config.foo = :bar
24
+ expect(config.foo).to eq(:bar)
25
+ end
26
+ end
27
+
28
+ describe ".configuration" do
29
+ it "returns a Configuration object" do
30
+ expect(handler.configuration).to be_a(Lita::Configuration)
31
+ end
32
+
33
+ it "is memoized" do
34
+ expect(handler.configuration).to equal(handler.configuration)
35
+ end
36
+ end
37
+
38
+ describe ".namespace" do
39
+ it "returns a snake cased namesapce for the handler based on class name" do
40
+ handler = Class.new do
41
+ include Lita::Handler::Common
42
+
43
+ def self.name
44
+ "Lita::Handlers::FooBarBaz"
45
+ end
46
+ end
47
+
48
+ expect(handler.namespace).to eq("foo_bar_baz")
49
+ end
50
+
51
+ it "allows the namespace to be set with a simple string" do
52
+ handler = Class.new do
53
+ include Lita::Handler::Common
54
+
55
+ namespace "common"
56
+ end
57
+
58
+ expect(handler.namespace).to eq("common")
59
+ end
60
+
61
+ it "allows the namespace to be set with the full path to an object as a string" do
62
+ handler = Class.new do
63
+ include Lita::Handler::Common
64
+
65
+ namespace "Lita::Handler::Common"
66
+ end
67
+
68
+ expect(handler.namespace).to eq("common")
69
+ end
70
+
71
+ it "allows the namespace to be set with an object" do
72
+ handler = Class.new do
73
+ include Lita::Handler::Common
74
+
75
+ namespace Lita::Handler::Common
76
+ end
77
+
78
+ expect(handler.namespace).to eq("common")
79
+ end
80
+
81
+ it "raises an exception if the handler doesn't have a name to derive the namespace from" do
82
+ handler = Class.new { include Lita::Handler::Common }
83
+ expect { handler.namespace }.to raise_error
84
+ end
85
+ end
86
+
87
+ describe "#config" do
88
+ before { registry.register_handler(handler) }
89
+
90
+ context "with old-style config" do
91
+ let(:handler) do
92
+ Class.new do
93
+ include Lita::Handler::Common
94
+
95
+ namespace "foo_bar_baz"
96
+
97
+ def self.default_config(config)
98
+ config.style = :old
99
+ end
100
+ end
101
+ end
102
+
103
+ it "returns the handler's config settings" do
104
+ expect(subject.config.style).to eq(:old)
105
+ end
106
+ end
107
+
108
+ context "with new-style config" do
109
+ let(:handler) do
110
+ Class.new do
111
+ include Lita::Handler::Common
112
+
113
+ namespace "foo_bar_baz"
114
+
115
+ config :style, default: :new
116
+ end
117
+ end
118
+
119
+ it "returns the handler's config settings" do
120
+ expect(subject.config.style).to eq(:new)
121
+ end
122
+ end
123
+
124
+ context "with both types of configuration" do
125
+ let(:handler) do
126
+ Class.new do
127
+ include Lita::Handler::Common
128
+
129
+ namespace "foo_bar_baz"
130
+
131
+ config :style, default: :new
132
+
133
+ def self.default_config(config)
134
+ config.style = :old
135
+ end
136
+ end
137
+ end
138
+
139
+ it "gives precedence to the new style" do
140
+ expect(subject.config.style).to eq(:new)
141
+ end
142
+ end
143
+
144
+ context "with no configuration" do
145
+ let(:handler) do
146
+ Class.new do
147
+ include Lita::Handler::Common
148
+
149
+ namespace "foo_bar_baz"
150
+ end
151
+ end
152
+
153
+ it "uses an old-style config object" do
154
+ subject.config.style = :old
155
+ expect(subject.config.style).to eq(:old)
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "#http" do
161
+ it "returns a Faraday connection" do
162
+ expect(subject.http).to be_a(Faraday::Connection)
163
+ end
164
+
165
+ it "sets a default user agent" do
166
+ expect(subject.http.headers["User-Agent"]).to eq("Lita v#{Lita::VERSION}")
167
+ end
168
+
169
+ it "merges in user-supplied options" do
170
+ connection = subject.http(headers: {
171
+ "User-Agent" => "Foo", "X-Bar" => "Baz"
172
+ })
173
+ expect(connection.headers["User-Agent"]).to eq("Foo")
174
+ expect(connection.headers["X-Bar"]).to eq("Baz")
175
+ end
176
+
177
+ it "passes blocks on to Faraday" do
178
+ connection = subject.http { |builder| builder.response :logger }
179
+ expect(connection.builder.handlers).to include(Faraday::Response::Logger)
180
+ end
181
+ end
182
+
183
+ describe "#log" do
184
+ it "returns the Lita logger" do
185
+ expect(subject.log).to eq(Lita.logger)
186
+ end
187
+ end
188
+
189
+ describe "timer methods" do
190
+ let(:queue) { Queue.new }
191
+
192
+ subject { handler.new(robot) }
193
+
194
+ before { allow_any_instance_of(Lita::Timer).to receive(:sleep) }
195
+
196
+ describe "#after" do
197
+ let(:handler) do
198
+ Class.new do
199
+ include Lita::Handler::Common
200
+
201
+ namespace "foo"
202
+
203
+ def after_test(queue)
204
+ after(2) { queue.push("Waited 2 seconds!") }
205
+ end
206
+ end
207
+ end
208
+
209
+ it "triggers the block after the given number of seconds" do
210
+ subject.after_test(queue)
211
+ expect(queue.pop).to eq("Waited 2 seconds!")
212
+ expect { queue.pop(true) }.to raise_error(ThreadError)
213
+ end
214
+ end
215
+
216
+ describe "#every" do
217
+ let(:handler) do
218
+ Class.new do
219
+ include Lita::Handler::Common
220
+
221
+ namespace "foo"
222
+
223
+ def every_test(queue)
224
+ array = [1, 2, 3]
225
+
226
+ every(2) do |timer|
227
+ value = array.shift
228
+
229
+ if value
230
+ queue.push(value)
231
+ else
232
+ timer.stop
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ it "triggers the block until the timer is stopped" do
240
+ subject.every_test(queue)
241
+ expect(queue.pop).to eq(1)
242
+ expect(queue.pop).to eq(2)
243
+ expect(queue.pop).to eq(3)
244
+ expect { queue.pop(true) }.to raise_error(ThreadError)
245
+ end
246
+ end
247
+
248
+ context "with an infinite timer" do
249
+ let(:response) { instance_double("Lita::Response") }
250
+
251
+ let(:handler) do
252
+ Class.new do
253
+ include Lita::Handler::Common
254
+
255
+ namespace "foo"
256
+
257
+ def infinite_every_test(response)
258
+ thread = every(5) { "Looping forever!" }
259
+ response.reply("Replying after timer!")
260
+ thread
261
+ end
262
+ end
263
+ end
264
+
265
+ it "doesn't block the handler's thread" do
266
+ expect(response).to receive(:reply)
267
+ thread = subject.infinite_every_test(response)
268
+ thread.kill
269
+ end
270
+ end
271
+ end
272
+ end