stealth 1.1.2 → 2.0.0.beta1
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/.circleci/config.yml +18 -8
- data/CHANGELOG.md +100 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +49 -43
- data/LICENSE +4 -17
- data/README.md +9 -17
- data/VERSION +1 -1
- data/lib/stealth/base.rb +62 -13
- data/lib/stealth/cli.rb +1 -2
- data/lib/stealth/commands/console.rb +1 -1
- data/lib/stealth/configuration.rb +0 -3
- data/lib/stealth/controller/callbacks.rb +1 -1
- data/lib/stealth/controller/catch_all.rb +27 -4
- data/lib/stealth/controller/controller.rb +168 -49
- data/lib/stealth/controller/dev_jumps.rb +41 -0
- data/lib/stealth/controller/dynamic_delay.rb +4 -6
- data/lib/stealth/controller/interrupt_detect.rb +100 -0
- data/lib/stealth/controller/messages.rb +283 -0
- data/lib/stealth/controller/nlp.rb +50 -0
- data/lib/stealth/controller/replies.rb +179 -41
- data/lib/stealth/controller/unrecognized_message.rb +62 -0
- data/lib/stealth/core_ext.rb +5 -0
- data/lib/stealth/{flow/core_ext.rb → core_ext/numeric.rb} +0 -1
- data/lib/stealth/core_ext/string.rb +18 -0
- data/lib/stealth/dispatcher.rb +21 -0
- data/lib/stealth/errors.rb +12 -0
- data/lib/stealth/flow/base.rb +1 -2
- data/lib/stealth/flow/specification.rb +3 -2
- data/lib/stealth/flow/state.rb +3 -3
- data/lib/stealth/generators/builder/Gemfile +4 -3
- data/lib/stealth/generators/builder/bot/controllers/bot_controller.rb +42 -0
- data/lib/stealth/generators/builder/bot/controllers/catch_alls_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/goodbyes_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/hellos_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
- data/lib/stealth/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
- data/lib/stealth/generators/builder/config/flow_map.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/autoload.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/inflections.rb +16 -0
- data/lib/stealth/generators/builder/config/puma.rb +15 -0
- data/lib/stealth/helpers/redis.rb +40 -0
- data/lib/stealth/lock.rb +83 -0
- data/lib/stealth/logger.rb +27 -18
- data/lib/stealth/nlp/client.rb +22 -0
- data/lib/stealth/nlp/result.rb +57 -0
- data/lib/stealth/reloader.rb +90 -0
- data/lib/stealth/reply.rb +17 -0
- data/lib/stealth/scheduled_reply.rb +3 -3
- data/lib/stealth/server.rb +4 -4
- data/lib/stealth/service_message.rb +3 -2
- data/lib/stealth/service_reply.rb +5 -1
- data/lib/stealth/services/base_reply_handler.rb +2 -2
- data/lib/stealth/session.rb +106 -53
- data/spec/configuration_spec.rb +9 -2
- data/spec/controller/callbacks_spec.rb +23 -28
- data/spec/controller/catch_all_spec.rb +81 -29
- data/spec/controller/controller_spec.rb +444 -43
- data/spec/controller/dynamic_delay_spec.rb +16 -18
- data/spec/controller/helpers_spec.rb +1 -2
- data/spec/controller/interrupt_detect_spec.rb +171 -0
- data/spec/controller/messages_spec.rb +744 -0
- data/spec/controller/nlp_spec.rb +93 -0
- data/spec/controller/replies_spec.rb +446 -11
- data/spec/controller/unrecognized_message_spec.rb +168 -0
- data/spec/dispatcher_spec.rb +79 -0
- data/spec/flow/flow_spec.rb +1 -2
- data/spec/flow/state_spec.rb +14 -3
- data/spec/helpers/redis_spec.rb +77 -0
- data/spec/lock_spec.rb +100 -0
- data/spec/nlp/client_spec.rb +23 -0
- data/spec/nlp/result_spec.rb +57 -0
- data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
- data/spec/replies/messages/say_randomize_speech.yml +10 -0
- data/spec/replies/messages/say_randomize_text.yml +10 -0
- data/spec/replies/messages/sub1/sub2/say_nested.yml +10 -0
- data/spec/reply_spec.rb +61 -0
- data/spec/scheduled_reply_spec.rb +23 -0
- data/spec/service_reply_spec.rb +1 -2
- data/spec/session_spec.rb +251 -12
- data/spec/spec_helper.rb +21 -0
- data/spec/support/controllers/vaders_controller.rb +24 -0
- data/spec/support/nlp_clients/dialogflow.rb +9 -0
- data/spec/support/nlp_clients/luis.rb +9 -0
- data/spec/support/nlp_results/luis_result.rb +163 -0
- data/spec/version_spec.rb +1 -2
- data/stealth.gemspec +6 -6
- metadata +83 -39
- data/docs/00-introduction.md +0 -37
- data/docs/01-getting-started.md +0 -21
- data/docs/02-local-development.md +0 -40
- data/docs/03-basics.md +0 -171
- data/docs/04-sessions.md +0 -29
- data/docs/05-controllers.md +0 -179
- data/docs/06-models.md +0 -39
- data/docs/07-replies.md +0 -114
- data/docs/08-catchalls.md +0 -49
- data/docs/09-messaging-integrations.md +0 -80
- data/docs/10-nlp-integrations.md +0 -13
- data/docs/11-analytics.md +0 -13
- data/docs/12-commands.md +0 -62
- data/docs/13-deployment.md +0 -50
- data/lib/stealth/generators/builder/config/initializers/.keep +0 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Stealth::Controller::Nlp do
|
6
|
+
|
7
|
+
let(:fb_message) { SampleMessage.new(service: 'facebook') }
|
8
|
+
let(:controller) { VadersController.new(service_message: fb_message.message_with_text) }
|
9
|
+
|
10
|
+
describe 'nlp_client_klass' do
|
11
|
+
it 'should return the correct class for LUIS' do
|
12
|
+
config_dbl = double('Stealth Config', nlp_integration: :luis).as_null_object
|
13
|
+
allow(Stealth).to receive(:config).and_return(config_dbl)
|
14
|
+
expect(controller.send(:nlp_client_klass)).to eq Stealth::Nlp::Luis::Client
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return the correct class for Dialogflow' do
|
18
|
+
config_dbl = double('Stealth Config', nlp_integration: :dialogflow).as_null_object
|
19
|
+
allow(Stealth).to receive(:config).and_return(config_dbl)
|
20
|
+
expect(controller.send(:nlp_client_klass)).to eq Stealth::Nlp::Dialogflow::Client
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should raise an error if it cannot locate a class' do
|
24
|
+
config_dbl = double('Stealth Config', nlp_integration: :unknown).as_null_object
|
25
|
+
allow(Stealth).to receive(:config).and_return(config_dbl)
|
26
|
+
expect {
|
27
|
+
controller.send(:nlp_client_klass)
|
28
|
+
}.to raise_error(NameError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'perform_nlp!' do
|
33
|
+
|
34
|
+
describe 'NLP has not yet been configured' do
|
35
|
+
it 'should raise Stealth::Errors::ConfigurationError' do
|
36
|
+
config_dbl = double('Stealth Config', nlp_integration: nil).as_null_object
|
37
|
+
allow(Stealth).to receive(:config).and_return(config_dbl)
|
38
|
+
|
39
|
+
expect {
|
40
|
+
controller.perform_nlp!
|
41
|
+
}.to raise_error(Stealth::Errors::ConfigurationError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'NLP has been configured' do
|
46
|
+
before(:each) do
|
47
|
+
config_dbl = double('Stealth Config', nlp_integration: :luis).as_null_object
|
48
|
+
@luis_client_dbl = double('LUIS Client')
|
49
|
+
allow(Stealth).to receive(:config).and_return(config_dbl)
|
50
|
+
allow(Stealth::Nlp::Luis::Client).to receive(:new).and_return(@luis_client_dbl)
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:nlp_result) { Stealth::Nlp::Result.new(result: {}) }
|
54
|
+
|
55
|
+
it 'should call understand on the NLP client' do
|
56
|
+
expect(@luis_client_dbl).to receive(:understand).with(query: 'Hello World!').and_return(nlp_result)
|
57
|
+
controller.perform_nlp!
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return an Nlp::Result object' do
|
61
|
+
expect(@luis_client_dbl).to receive(:understand).with(query: 'Hello World!').and_return(nlp_result)
|
62
|
+
expect(controller.perform_nlp!).to eq nlp_result
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should memoize the understand call' do
|
66
|
+
expect(@luis_client_dbl).to receive(:understand).once.with(query: 'Hello World!').and_return(nlp_result)
|
67
|
+
controller.perform_nlp!
|
68
|
+
controller.perform_nlp!
|
69
|
+
controller.perform_nlp!
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should store the nlp_result for the current controller' do
|
73
|
+
expect(@luis_client_dbl).to receive(:understand).once.with(query: 'Hello World!').and_return(nlp_result)
|
74
|
+
controller.perform_nlp!
|
75
|
+
expect(controller.nlp_result).to eq nlp_result
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should store the nlp_result for the current service_message' do
|
79
|
+
expect(@luis_client_dbl).to receive(:understand).once.with(query: 'Hello World!').and_return(nlp_result)
|
80
|
+
controller.perform_nlp!
|
81
|
+
expect(controller.current_message.nlp_result).to eq nlp_result
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should perform the NLP query if it has been cleared out' do
|
85
|
+
expect(@luis_client_dbl).to receive(:understand).exactly(2).times.with(query: 'Hello World!').and_return(nlp_result)
|
86
|
+
controller.perform_nlp!
|
87
|
+
controller.nlp_result = nil
|
88
|
+
controller.perform_nlp!
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
3
|
+
require 'spec_helper'
|
5
4
|
|
6
5
|
describe "Stealth::Controller replies" do
|
7
6
|
|
@@ -39,9 +38,43 @@ describe "Stealth::Controller replies" do
|
|
39
38
|
send_replies
|
40
39
|
end
|
41
40
|
|
41
|
+
def say_msgs_without_breaks
|
42
|
+
send_replies
|
43
|
+
end
|
44
|
+
|
42
45
|
def say_uh_oh
|
43
46
|
send_replies
|
44
47
|
end
|
48
|
+
|
49
|
+
def say_randomize_text
|
50
|
+
send_replies
|
51
|
+
end
|
52
|
+
|
53
|
+
def say_randomize_speech
|
54
|
+
send_replies
|
55
|
+
end
|
56
|
+
|
57
|
+
def say_custom_reply
|
58
|
+
send_replies custom_reply: 'messages/say_offer'
|
59
|
+
end
|
60
|
+
|
61
|
+
def say_howdy_with_dynamic
|
62
|
+
send_replies
|
63
|
+
end
|
64
|
+
|
65
|
+
def say_nested_custom_reply
|
66
|
+
send_replies custom_reply: 'messages/sub1/sub2/say_nested'
|
67
|
+
end
|
68
|
+
|
69
|
+
def say_inline_reply
|
70
|
+
reply = [
|
71
|
+
{ 'reply_type' => 'text', 'text' => 'Hi, Morty. Welcome to Stealth bot...' },
|
72
|
+
{ 'reply_type' => 'delay', 'duration' => 2 },
|
73
|
+
{ 'reply_type' => 'text', 'text' => 'We offer users an awesome Ruby framework for building chat bots.' }
|
74
|
+
]
|
75
|
+
|
76
|
+
send_replies inline: reply
|
77
|
+
end
|
45
78
|
end
|
46
79
|
|
47
80
|
describe "missing reply" do
|
@@ -100,6 +133,11 @@ describe "Stealth::Controller replies" do
|
|
100
133
|
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
101
134
|
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
102
135
|
allow(controller.current_session).to receive(:state_string).and_return("say_oi")
|
136
|
+
Stealth.config.auto_insert_delays = false
|
137
|
+
end
|
138
|
+
|
139
|
+
after(:each) do
|
140
|
+
Stealth.config.auto_insert_delays = true
|
103
141
|
end
|
104
142
|
|
105
143
|
it "should translate each reply_type in the reply" do
|
@@ -139,6 +177,11 @@ describe "Stealth::Controller replies" do
|
|
139
177
|
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
140
178
|
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
141
179
|
allow(controller.current_session).to receive(:state_string).and_return("say_offer")
|
180
|
+
Stealth.config.auto_insert_delays = false
|
181
|
+
end
|
182
|
+
|
183
|
+
after(:each) do
|
184
|
+
Stealth.config.auto_insert_delays = true
|
142
185
|
end
|
143
186
|
|
144
187
|
it "should translate each reply_type in the reply" do
|
@@ -169,6 +212,243 @@ describe "Stealth::Controller replies" do
|
|
169
212
|
end
|
170
213
|
end
|
171
214
|
|
215
|
+
describe "custom_reply" do
|
216
|
+
let(:stubbed_handler) { double("handler") }
|
217
|
+
let(:stubbed_client) { double("client") }
|
218
|
+
|
219
|
+
before(:each) do
|
220
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
221
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
222
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
223
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_custom_reply")
|
224
|
+
Stealth.config.auto_insert_delays = false
|
225
|
+
end
|
226
|
+
|
227
|
+
after(:each) do
|
228
|
+
Stealth.config.auto_insert_delays = true
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should translate each reply_type in the reply" do
|
232
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
233
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
234
|
+
|
235
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
236
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).times
|
237
|
+
controller.say_custom_reply
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should transmit each reply_type in the reply" do
|
241
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
242
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
243
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
244
|
+
|
245
|
+
expect(stubbed_client).to receive(:transmit).exactly(3).times
|
246
|
+
controller.say_custom_reply
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should sleep on delays" do
|
250
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
251
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
252
|
+
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
253
|
+
|
254
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(2.0)
|
255
|
+
controller.say_custom_reply
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should correctly load from sub-dirs" do
|
259
|
+
expect(stubbed_handler).to receive(:text).exactly(3).times
|
260
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
261
|
+
expect(stubbed_client).to receive(:transmit).exactly(5).times
|
262
|
+
|
263
|
+
expect(controller).to receive(:sleep).exactly(2).times.with(2.0)
|
264
|
+
controller.say_nested_custom_reply
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "inline replies" do
|
269
|
+
let(:stubbed_handler) { double("handler") }
|
270
|
+
let(:stubbed_client) { double("client") }
|
271
|
+
|
272
|
+
before(:each) do
|
273
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
274
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
275
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
276
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_inline_reply")
|
277
|
+
Stealth.config.auto_insert_delays = false
|
278
|
+
end
|
279
|
+
|
280
|
+
after(:each) do
|
281
|
+
Stealth.config.auto_insert_delays = true
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should translate each reply_type in the reply" do
|
285
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
286
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
287
|
+
|
288
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
289
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).times
|
290
|
+
controller.say_inline_reply
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should transmit each reply_type in the reply" do
|
294
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
295
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
296
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
297
|
+
|
298
|
+
expect(stubbed_client).to receive(:transmit).exactly(3).times
|
299
|
+
controller.say_inline_reply
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should sleep on delays" do
|
303
|
+
allow(stubbed_handler).to receive(:text).exactly(2).times
|
304
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).times
|
305
|
+
allow(stubbed_client).to receive(:transmit).exactly(3).times
|
306
|
+
|
307
|
+
expect(controller).to receive(:sleep).exactly(1).times.with(2.0)
|
308
|
+
controller.say_inline_reply
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "auto delays" do
|
313
|
+
let(:stubbed_handler) { double("handler") }
|
314
|
+
let(:stubbed_client) { double("client") }
|
315
|
+
|
316
|
+
before(:each) do
|
317
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
318
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
319
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
320
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_msgs_without_breaks")
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should add two additional delays to a reply without delays" do
|
324
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
325
|
+
allow(controller).to receive(:sleep).and_return(true)
|
326
|
+
|
327
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
328
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
329
|
+
controller.say_msgs_without_breaks
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should only add a single delay to a reply that already contains a delay" do
|
333
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
334
|
+
allow(controller).to receive(:sleep).and_return(true)
|
335
|
+
|
336
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
337
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
338
|
+
controller.say_offer
|
339
|
+
end
|
340
|
+
|
341
|
+
it "should not add delays if auto_insert_delays = false" do
|
342
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
343
|
+
allow(controller).to receive(:sleep).and_return(true)
|
344
|
+
|
345
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
346
|
+
expect(stubbed_handler).to_not receive(:delay)
|
347
|
+
|
348
|
+
Stealth.config.auto_insert_delays = false
|
349
|
+
controller.say_msgs_without_breaks
|
350
|
+
Stealth.config.auto_insert_delays = true
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "session locking" do
|
355
|
+
let(:stubbed_handler) { double("handler") }
|
356
|
+
let(:stubbed_client) { double("client") }
|
357
|
+
|
358
|
+
before(:each) do
|
359
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
360
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
361
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
362
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_offer")
|
363
|
+
Stealth.config.auto_insert_delays = false
|
364
|
+
end
|
365
|
+
|
366
|
+
after(:each) do
|
367
|
+
Stealth.config.auto_insert_delays = true
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should update the lock for each reply_type in the reply" do
|
371
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
372
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
373
|
+
|
374
|
+
expect(controller).to receive(:lock_session!).exactly(3).times
|
375
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
376
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).times
|
377
|
+
controller.say_offer
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should update the lock position for each reply_type in the reply" do
|
381
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
382
|
+
allow(controller).to receive(:sleep).and_return(true).with(2.0)
|
383
|
+
|
384
|
+
expect(controller).to receive(
|
385
|
+
:lock_session!
|
386
|
+
).with(
|
387
|
+
session_slug: controller.current_session.get_session,
|
388
|
+
position: 0
|
389
|
+
).exactly(1).times
|
390
|
+
|
391
|
+
expect(controller).to receive(
|
392
|
+
:lock_session!
|
393
|
+
).with(
|
394
|
+
session_slug: controller.current_session.get_session,
|
395
|
+
position: 1
|
396
|
+
).exactly(1).times
|
397
|
+
|
398
|
+
expect(controller).to receive(
|
399
|
+
:lock_session!
|
400
|
+
).with(
|
401
|
+
session_slug: controller.current_session.get_session,
|
402
|
+
position: 2
|
403
|
+
).exactly(1).times
|
404
|
+
|
405
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
406
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).times
|
407
|
+
controller.say_offer
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should update the lock position with an offset for each reply_type in the reply" do
|
411
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
412
|
+
allow(controller).to receive(:sleep).and_return(true)
|
413
|
+
|
414
|
+
controller.pos = 17 # set the offset
|
415
|
+
|
416
|
+
expect(controller).to receive(
|
417
|
+
:lock_session!
|
418
|
+
).with(
|
419
|
+
session_slug: controller.current_session.get_session,
|
420
|
+
position: 17
|
421
|
+
).exactly(1).times
|
422
|
+
|
423
|
+
expect(controller).to receive(
|
424
|
+
:lock_session!
|
425
|
+
).with(
|
426
|
+
session_slug: controller.current_session.get_session,
|
427
|
+
position: 18
|
428
|
+
).exactly(1).times
|
429
|
+
|
430
|
+
expect(controller).to receive(
|
431
|
+
:lock_session!
|
432
|
+
).with(
|
433
|
+
session_slug: controller.current_session.get_session,
|
434
|
+
position: 19
|
435
|
+
).exactly(1).times
|
436
|
+
|
437
|
+
expect(controller).to receive(
|
438
|
+
:lock_session!
|
439
|
+
).with(
|
440
|
+
session_slug: controller.current_session.get_session,
|
441
|
+
position: 20
|
442
|
+
).exactly(1).times
|
443
|
+
|
444
|
+
expect(stubbed_handler).to receive(:cards).exactly(1).time
|
445
|
+
expect(stubbed_handler).to receive(:list).exactly(1).time
|
446
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
447
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_howdy_with_dynamic")
|
448
|
+
controller.say_howdy_with_dynamic
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
172
452
|
describe "dynamic delays" do
|
173
453
|
let(:stubbed_handler) { double("handler") }
|
174
454
|
let(:stubbed_client) { double("client") }
|
@@ -182,33 +462,33 @@ describe "Stealth::Controller replies" do
|
|
182
462
|
|
183
463
|
it "should use the default multiplier if none is set" do
|
184
464
|
allow(stubbed_handler).to receive(:text).exactly(2).times
|
185
|
-
allow(stubbed_handler).to receive(:delay).exactly(
|
186
|
-
allow(stubbed_client).to receive(:transmit).exactly(
|
465
|
+
allow(stubbed_handler).to receive(:delay).exactly(2).times
|
466
|
+
allow(stubbed_client).to receive(:transmit).exactly(4).times
|
187
467
|
|
188
468
|
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
189
|
-
expect(controller).to receive(:sleep).exactly(
|
469
|
+
expect(controller).to receive(:sleep).exactly(2).times.with(delay)
|
190
470
|
controller.say_offer_with_dynamic
|
191
471
|
end
|
192
472
|
|
193
473
|
it "should slow down SHORT_DELAY if dynamic_delay_muliplier > 1" do
|
194
474
|
allow(stubbed_handler).to receive(:text).exactly(2).times
|
195
|
-
allow(stubbed_handler).to receive(:delay).exactly(
|
196
|
-
allow(stubbed_client).to receive(:transmit).exactly(
|
475
|
+
allow(stubbed_handler).to receive(:delay).exactly(2).times
|
476
|
+
allow(stubbed_client).to receive(:transmit).exactly(4).times
|
197
477
|
|
198
478
|
Stealth.config.dynamic_delay_muliplier = 5
|
199
479
|
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
200
|
-
expect(controller).to receive(:sleep).exactly(
|
480
|
+
expect(controller).to receive(:sleep).exactly(2).times.with(delay)
|
201
481
|
controller.say_offer_with_dynamic
|
202
482
|
end
|
203
483
|
|
204
484
|
it "should speed up SHORT_DELAY if dynamic_delay_muliplier < 1" do
|
205
485
|
allow(stubbed_handler).to receive(:text).exactly(2).times
|
206
|
-
allow(stubbed_handler).to receive(:delay).exactly(
|
207
|
-
allow(stubbed_client).to receive(:transmit).exactly(
|
486
|
+
allow(stubbed_handler).to receive(:delay).exactly(2).times
|
487
|
+
allow(stubbed_client).to receive(:transmit).exactly(4).times
|
208
488
|
|
209
489
|
Stealth.config.dynamic_delay_muliplier = 0.1
|
210
490
|
delay = Stealth.config.dynamic_delay_muliplier * Stealth::Controller::DynamicDelay::SHORT_DELAY
|
211
|
-
expect(controller).to receive(:sleep).exactly(
|
491
|
+
expect(controller).to receive(:sleep).exactly(2).times.with(delay)
|
212
492
|
controller.say_offer_with_dynamic
|
213
493
|
end
|
214
494
|
end
|
@@ -256,4 +536,159 @@ describe "Stealth::Controller replies" do
|
|
256
536
|
end
|
257
537
|
end
|
258
538
|
|
539
|
+
describe "randomized replies" do
|
540
|
+
let(:stubbed_handler) { double("handler") }
|
541
|
+
let(:stubbed_client) { double("client") }
|
542
|
+
|
543
|
+
before(:each) do
|
544
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
545
|
+
end
|
546
|
+
|
547
|
+
describe "text replies" do
|
548
|
+
before(:each) do
|
549
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
550
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_randomize_text")
|
551
|
+
Stealth.config.auto_insert_delays = false
|
552
|
+
end
|
553
|
+
|
554
|
+
after(:each) do
|
555
|
+
Stealth.config.auto_insert_delays = true
|
556
|
+
end
|
557
|
+
|
558
|
+
it "should receive a single text string" do
|
559
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new) do |*args|
|
560
|
+
expect(args.first[:reply]['text']).to be_a(String)
|
561
|
+
stubbed_handler
|
562
|
+
end
|
563
|
+
allow(stubbed_handler).to receive(:text).exactly(1).time
|
564
|
+
expect(stubbed_client).to receive(:transmit).exactly(1).time
|
565
|
+
controller.say_randomize_text
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
describe "sub-state replies" do
|
571
|
+
let(:stubbed_handler) { double("handler") }
|
572
|
+
let(:stubbed_client) { double("client") }
|
573
|
+
|
574
|
+
before(:each) do
|
575
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
576
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
577
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
578
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_offer")
|
579
|
+
allow(stubbed_client).to receive(:transmit).and_return(true)
|
580
|
+
allow(controller).to receive(:sleep).and_return(true)
|
581
|
+
end
|
582
|
+
|
583
|
+
it "should transmit only the last reply in the file when @pos = -1" do
|
584
|
+
expect(stubbed_handler).to receive(:text).exactly(1).time
|
585
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).time # auto-delay
|
586
|
+
controller.pos = -1
|
587
|
+
controller.say_offer
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should transmit the last two replies in the file when @pos = -2" do
|
591
|
+
expect(stubbed_handler).to receive(:text).exactly(1).time
|
592
|
+
expect(stubbed_handler).to receive(:delay).exactly(1).time
|
593
|
+
controller.pos = -2
|
594
|
+
controller.say_offer
|
595
|
+
end
|
596
|
+
|
597
|
+
it "should transmit all the replies in the file when @pos = 0" do
|
598
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
599
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
600
|
+
controller.pos = 0
|
601
|
+
controller.say_offer
|
602
|
+
end
|
603
|
+
|
604
|
+
it "should transmit all the replies in the file when @pos = nil" do
|
605
|
+
expect(stubbed_handler).to receive(:text).exactly(2).times
|
606
|
+
expect(stubbed_handler).to receive(:delay).exactly(2).times
|
607
|
+
expect(controller.pos).to be_nil
|
608
|
+
controller.say_offer
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
describe "client errors" do
|
613
|
+
let(:stubbed_handler) { double("handler") }
|
614
|
+
let(:stubbed_client) { double("client") }
|
615
|
+
|
616
|
+
before(:each) do
|
617
|
+
allow(Stealth::Services::Facebook::ReplyHandler).to receive(:new).and_return(stubbed_handler)
|
618
|
+
allow(Stealth::Services::Facebook::Client).to receive(:new).and_return(stubbed_client)
|
619
|
+
allow(controller.current_session).to receive(:flow_string).and_return("message")
|
620
|
+
allow(controller.current_session).to receive(:state_string).and_return("say_offer")
|
621
|
+
allow(stubbed_handler).to receive(:delay).exactly(1).time
|
622
|
+
allow(stubbed_handler).to receive(:text).exactly(1).time
|
623
|
+
end
|
624
|
+
|
625
|
+
describe "Stealth::Errors::UserOptOut" do
|
626
|
+
before(:each) do
|
627
|
+
expect(stubbed_client).to receive(:transmit).and_raise(
|
628
|
+
Stealth::Errors::UserOptOut.new('boom')
|
629
|
+
).once # Retuns early; doesn't send the remaining replies in the file
|
630
|
+
end
|
631
|
+
|
632
|
+
it "should log the unhandled exception if the controller does not have a handle_opt_out method" do
|
633
|
+
expect(Stealth::Logger).to receive(:l).with(
|
634
|
+
topic: :err,
|
635
|
+
message: "User #{facebook_message.sender_id} unhandled exception due to opt-out."
|
636
|
+
)
|
637
|
+
expect(controller).to receive(:do_nothing)
|
638
|
+
controller.say_offer
|
639
|
+
end
|
640
|
+
|
641
|
+
it "should call handle_opt_out method" do
|
642
|
+
expect(controller).to receive(:handle_opt_out)
|
643
|
+
expect(Stealth::Logger).to receive(:l).with(
|
644
|
+
topic: 'facebook',
|
645
|
+
message: "User #{facebook_message.sender_id} opted out. [boom]"
|
646
|
+
)
|
647
|
+
expect(controller).to receive(:do_nothing)
|
648
|
+
controller.say_offer
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
describe "Stealth::Errors::InvalidSessionID" do
|
653
|
+
before(:each) do
|
654
|
+
expect(stubbed_client).to receive(:transmit).and_raise(
|
655
|
+
Stealth::Errors::InvalidSessionID.new('boom')
|
656
|
+
).once # Retuns early; doesn't send the remaining replies in the file
|
657
|
+
end
|
658
|
+
|
659
|
+
it "should log the unhandled exception if the controller does not have a handle_invalid_session_id method" do
|
660
|
+
expect(Stealth::Logger).to receive(:l).with(
|
661
|
+
topic: :err,
|
662
|
+
message: "User #{facebook_message.sender_id} unhandled exception due to invalid session_id."
|
663
|
+
)
|
664
|
+
expect(controller).to receive(:do_nothing)
|
665
|
+
controller.say_offer
|
666
|
+
end
|
667
|
+
|
668
|
+
it "should call handle_invalid_session_id method" do
|
669
|
+
expect(controller).to receive(:handle_invalid_session_id)
|
670
|
+
expect(Stealth::Logger).to receive(:l).with(
|
671
|
+
topic: 'facebook',
|
672
|
+
message: "User #{facebook_message.sender_id} has an invalid session_id. [boom]"
|
673
|
+
)
|
674
|
+
expect(controller).to receive(:do_nothing)
|
675
|
+
controller.say_offer
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
describe 'an unknown client error' do
|
680
|
+
before(:each) do
|
681
|
+
allow(stubbed_client).to receive(:transmit).and_raise(
|
682
|
+
StandardError
|
683
|
+
)
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'should raise the error' do
|
687
|
+
expect {
|
688
|
+
controller.say_offer
|
689
|
+
}.to raise_error(StandardError)
|
690
|
+
end
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
259
694
|
end
|