lita 3.3.1 → 4.0.0.rc1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +3 -0
- data/lib/lita.rb +45 -97
- data/lib/lita/adapter.rb +38 -17
- data/lib/lita/adapters/shell.rb +5 -3
- data/lib/lita/authorization.rb +109 -60
- data/lib/lita/builder.rb +38 -0
- data/lib/lita/callback.rb +37 -0
- data/lib/lita/cli.rb +2 -0
- data/lib/lita/config.rb +1 -18
- data/lib/lita/configurable.rb +29 -0
- data/lib/lita/configuration.rb +179 -0
- data/lib/lita/configuration_validator.rb +66 -0
- data/lib/lita/daemon.rb +4 -11
- data/lib/lita/default_configuration.rb +146 -0
- data/lib/lita/errors.rb +9 -0
- data/lib/lita/handler.rb +5 -264
- data/lib/lita/handler/chat_router.rb +130 -0
- data/lib/lita/handler/common.rb +114 -0
- data/lib/lita/handler/event_router.rb +77 -0
- data/lib/lita/handler/http_router.rb +26 -0
- data/lib/lita/handlers/authorization.rb +13 -18
- data/lib/lita/handlers/deprecation_check.rb +24 -0
- data/lib/lita/handlers/help.rb +5 -3
- data/lib/lita/handlers/info.rb +2 -2
- data/lib/lita/http_callback.rb +29 -0
- data/lib/lita/http_route.rb +41 -26
- data/lib/lita/namespace.rb +23 -0
- data/lib/lita/rack_app.rb +29 -2
- data/lib/lita/registry.rb +133 -0
- data/lib/lita/robot.rb +58 -20
- data/lib/lita/route_validator.rb +12 -4
- data/lib/lita/rspec.rb +23 -14
- data/lib/lita/rspec/handler.rb +93 -23
- data/lib/lita/rspec/matchers/chat_route_matcher.rb +48 -0
- data/lib/lita/rspec/matchers/deprecated.rb +36 -0
- data/lib/lita/rspec/matchers/event_route_matcher.rb +27 -0
- data/lib/lita/rspec/matchers/http_route_matcher.rb +18 -60
- data/lib/lita/user.rb +0 -6
- data/lib/lita/util.rb +1 -8
- data/lib/lita/version.rb +1 -1
- data/lita.gemspec +1 -0
- data/spec/lita/adapter_spec.rb +25 -7
- data/spec/lita/adapters/shell_spec.rb +24 -4
- data/spec/lita/authorization_spec.rb +57 -38
- data/spec/lita/builder_spec.rb +39 -0
- data/spec/lita/config_spec.rb +0 -24
- data/spec/lita/configuration_spec.rb +222 -0
- data/spec/lita/configuration_validator_spec.rb +112 -0
- data/spec/lita/daemon_spec.rb +2 -2
- data/spec/lita/default_configuration_spec.rb +254 -0
- data/spec/lita/handler/chat_router_spec.rb +192 -0
- data/spec/lita/handler/common_spec.rb +272 -0
- data/spec/lita/handler/event_router_spec.rb +54 -0
- data/spec/lita/handler/http_router_spec.rb +106 -0
- data/spec/lita/handler_spec.rb +20 -291
- data/spec/lita/handlers/authorization_spec.rb +9 -11
- data/spec/lita/handlers/deprecation_check_spec.rb +21 -0
- data/spec/lita/handlers/help_spec.rb +31 -9
- data/spec/lita/handlers/info_spec.rb +2 -2
- data/spec/lita/handlers/room_spec.rb +5 -3
- data/spec/lita/robot_spec.rb +30 -11
- data/spec/lita/rspec_spec.rb +71 -31
- data/spec/lita/user_spec.rb +2 -2
- data/spec/lita_spec.rb +62 -4
- data/spec/spec_helper.rb +7 -0
- data/templates/locales/en.yml +56 -4
- data/templates/plugin/gemspec.tt +1 -0
- data/templates/plugin/spec/spec_helper.tt +4 -0
- metadata +54 -8
- data/lib/lita/rspec/matchers/event_subscription_matcher.rb +0 -67
- data/lib/lita/rspec/matchers/route_matcher.rb +0 -69
- 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
|