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
data/spec/configuration_spec.rb
CHANGED
@@ -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::Configuration" do
|
7
6
|
|
@@ -29,6 +28,14 @@ describe "Stealth::Configuration" do
|
|
29
28
|
it "should handle multiple keys at the root level" do
|
30
29
|
expect(config.twilio_sms.account_sid).to eq parsed_config['twilio_sms']['account_sid']
|
31
30
|
end
|
31
|
+
|
32
|
+
it "should return nil if the key is not present at the node" do
|
33
|
+
expect(config.twilio_sms.api_key).to be nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise a NoMethodError when accessing multi-levels of missing nodes" do
|
37
|
+
expect { config.slack.api_key }.to raise_error(NoMethodError)
|
38
|
+
end
|
32
39
|
end
|
33
40
|
|
34
41
|
describe "config files with ERB" do
|
@@ -1,57 +1,48 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
$history = []
|
5
6
|
|
6
7
|
class BotController < Stealth::Controller
|
7
8
|
before_action :fetch_user_name
|
8
9
|
|
9
|
-
attr_accessor :record
|
10
|
-
|
11
10
|
def some_action
|
12
|
-
@record = []
|
13
11
|
step_to flow: 'flow_tester', state: 'my_action'
|
14
12
|
end
|
15
13
|
|
16
14
|
def other_action
|
17
|
-
@record = []
|
18
15
|
step_to flow: 'other_flow_tester', state: 'other_action'
|
19
16
|
end
|
20
17
|
|
21
18
|
def halted_action
|
22
|
-
@record = []
|
23
19
|
step_to flow: 'flow_tester', state: 'my_action2'
|
24
20
|
end
|
25
21
|
|
26
22
|
def filtered_action
|
27
|
-
@record = []
|
28
23
|
step_to flow: 'flow_tester', state: 'my_action3'
|
29
24
|
end
|
30
25
|
|
31
26
|
def some_other_action2
|
32
|
-
@record = []
|
33
27
|
step_to flow: 'other_flow_tester', state: 'other_action2'
|
34
28
|
end
|
35
29
|
|
36
30
|
def some_other_action3
|
37
|
-
@record = []
|
38
31
|
step_to flow: 'other_flow_tester', state: 'other_action3'
|
39
32
|
end
|
40
33
|
|
41
34
|
def some_other_action4
|
42
|
-
@record = []
|
43
35
|
step_to flow: 'other_flow_tester', state: 'other_action4'
|
44
36
|
end
|
45
37
|
|
46
38
|
def some_other_action5
|
47
|
-
@record = []
|
48
39
|
step_to flow: 'other_flow_tester', state: 'other_action5'
|
49
40
|
end
|
50
41
|
|
51
42
|
private
|
52
43
|
|
53
44
|
def fetch_user_name
|
54
|
-
|
45
|
+
$history << "fetched user name"
|
55
46
|
end
|
56
47
|
end
|
57
48
|
|
@@ -77,7 +68,7 @@ class FlowTestersController < BotController
|
|
77
68
|
protected
|
78
69
|
|
79
70
|
def test_action
|
80
|
-
|
71
|
+
$history << "tested action"
|
81
72
|
end
|
82
73
|
|
83
74
|
def test_before_halting
|
@@ -85,11 +76,11 @@ class FlowTestersController < BotController
|
|
85
76
|
end
|
86
77
|
|
87
78
|
def test_filtering
|
88
|
-
|
79
|
+
$history << "filtered"
|
89
80
|
end
|
90
81
|
|
91
82
|
def test_after_halting
|
92
|
-
|
83
|
+
$history << "after action ran"
|
93
84
|
end
|
94
85
|
end
|
95
86
|
|
@@ -125,11 +116,11 @@ class OtherFlowTestersController < BotController
|
|
125
116
|
private
|
126
117
|
|
127
118
|
def after_action1
|
128
|
-
|
119
|
+
$history << "after action 1"
|
129
120
|
end
|
130
121
|
|
131
122
|
def after_action2
|
132
|
-
|
123
|
+
$history << "after action 2"
|
133
124
|
end
|
134
125
|
|
135
126
|
def run_halt
|
@@ -137,9 +128,9 @@ class OtherFlowTestersController < BotController
|
|
137
128
|
end
|
138
129
|
|
139
130
|
def run_around_filter
|
140
|
-
|
131
|
+
$history << "around before"
|
141
132
|
yield
|
142
|
-
|
133
|
+
$history << "around after"
|
143
134
|
end
|
144
135
|
end
|
145
136
|
|
@@ -165,29 +156,33 @@ describe "Stealth::Controller callbacks" do
|
|
165
156
|
|
166
157
|
let(:facebook_message) { SampleMessage.new(service: 'facebook') }
|
167
158
|
|
159
|
+
before(:each) do
|
160
|
+
$history = []
|
161
|
+
end
|
162
|
+
|
168
163
|
describe "before_action" do
|
169
164
|
it "should fire the callback on the parent class" do
|
170
165
|
controller = BotController.new(service_message: facebook_message.message_with_text)
|
171
166
|
controller.other_action
|
172
|
-
expect(
|
167
|
+
expect($history).to eq ["fetched user name"]
|
173
168
|
end
|
174
169
|
|
175
170
|
it "should fire the callback on a child class" do
|
176
171
|
controller = FlowTestersController.new(service_message: facebook_message.message_with_text)
|
177
172
|
controller.some_action
|
178
|
-
expect(
|
173
|
+
expect($history).to eq ["fetched user name", "tested action"]
|
179
174
|
end
|
180
175
|
|
181
176
|
it "should halt the callback chain when :abort is thrown" do
|
182
177
|
controller = FlowTestersController.new(service_message: facebook_message.message_with_text)
|
183
178
|
controller.halted_action
|
184
|
-
expect(
|
179
|
+
expect($history).to eq ["fetched user name"]
|
185
180
|
end
|
186
181
|
|
187
182
|
it "should respect 'unless' filter" do
|
188
183
|
controller = FlowTestersController.new(service_message: facebook_message.message_with_text)
|
189
184
|
controller.filtered_action
|
190
|
-
expect(
|
185
|
+
expect($history).to eq ["fetched user name", "tested action", "filtered"]
|
191
186
|
end
|
192
187
|
end
|
193
188
|
|
@@ -195,13 +190,13 @@ describe "Stealth::Controller callbacks" do
|
|
195
190
|
it "should fire the after callbacks in reverse order" do
|
196
191
|
controller = OtherFlowTestersController.new(service_message: facebook_message.message_with_text)
|
197
192
|
controller.some_other_action2
|
198
|
-
expect(
|
193
|
+
expect($history).to eq ["fetched user name", "after action 2", "after action 1"]
|
199
194
|
end
|
200
195
|
|
201
196
|
it "should not fire after callbacks if a before callback throws an :abort" do
|
202
197
|
controller = OtherFlowTestersController.new(service_message: facebook_message.message_with_text)
|
203
198
|
controller.some_other_action3
|
204
|
-
expect(
|
199
|
+
expect($history).to eq ["fetched user name"]
|
205
200
|
end
|
206
201
|
end
|
207
202
|
|
@@ -209,13 +204,13 @@ describe "Stealth::Controller callbacks" do
|
|
209
204
|
it "should fire the around callback before and after" do
|
210
205
|
controller = OtherFlowTestersController.new(service_message: facebook_message.message_with_text)
|
211
206
|
controller.some_other_action4
|
212
|
-
expect(
|
207
|
+
expect($history).to eq ["fetched user name", "around before", "around after"]
|
213
208
|
end
|
214
209
|
|
215
210
|
it "should not fire the around callback if a before callback throws abort" do
|
216
211
|
controller = OtherFlowTestersController.new(service_message: facebook_message.message_with_text)
|
217
212
|
controller.some_other_action5
|
218
|
-
expect(
|
213
|
+
expect($history).to eq ["fetched user name"]
|
219
214
|
end
|
220
215
|
end
|
221
216
|
|
@@ -1,35 +1,22 @@
|
|
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::CatchAll" do
|
7
|
-
|
8
|
-
class VadersController < Stealth::Controller
|
9
|
-
def my_action
|
10
|
-
raise "oops"
|
11
|
-
end
|
12
|
-
|
13
|
-
def my_action2
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def my_action3
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
6
|
+
$msg = nil
|
21
7
|
|
22
8
|
class StubbedCatchAllsController < Stealth::Controller
|
23
9
|
def level1
|
24
|
-
|
10
|
+
$msg = current_message
|
11
|
+
do_nothing
|
25
12
|
end
|
26
13
|
|
27
14
|
def level2
|
28
|
-
|
15
|
+
do_nothing
|
29
16
|
end
|
30
17
|
|
31
18
|
def level3
|
32
|
-
|
19
|
+
do_nothing
|
33
20
|
end
|
34
21
|
end
|
35
22
|
|
@@ -40,6 +27,8 @@ describe "Stealth::Controller::CatchAll" do
|
|
40
27
|
state :my_action
|
41
28
|
state :my_action2
|
42
29
|
state :my_action3
|
30
|
+
state :action_with_unrecognized_msg
|
31
|
+
state :action_with_unrecognized_match
|
43
32
|
end
|
44
33
|
|
45
34
|
flow :catch_all do
|
@@ -64,30 +53,26 @@ describe "Stealth::Controller::CatchAll" do
|
|
64
53
|
it "should step_to catch_all->level1 when a StandardError is raised" do
|
65
54
|
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'vader', state: 'my_action')
|
66
55
|
controller.action(action: :my_action)
|
67
|
-
expect(controller.current_session.
|
68
|
-
expect(controller.current_session.state_string).to eq("level1")
|
56
|
+
expect($redis.get(controller.current_session.session_key)).to eq('catch_all->level1')
|
69
57
|
end
|
70
58
|
|
71
59
|
it "should step_to catch_all->level1 when an action doesn't progress the flow" do
|
72
60
|
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'vader', state: 'my_action2')
|
73
61
|
controller.action(action: :my_action2)
|
74
|
-
expect(controller.current_session.
|
75
|
-
expect(controller.current_session.state_string).to eq("level1")
|
62
|
+
expect($redis.get(controller.current_session.session_key)).to eq('catch_all->level1')
|
76
63
|
end
|
77
64
|
|
78
65
|
it "should step_to catch_all->level2 when an action raises back to back" do
|
79
66
|
controller.step_to flow: :vader, state: :my_action
|
80
67
|
controller.step_to flow: :vader, state: :my_action
|
81
|
-
expect(controller.current_session.
|
82
|
-
expect(controller.current_session.state_string).to eq("level2")
|
68
|
+
expect($redis.get(controller.current_session.session_key)).to eq('catch_all->level2')
|
83
69
|
end
|
84
70
|
|
85
71
|
it "should step_to catch_all->level3 when an action raises back to back to back" do
|
86
72
|
controller.step_to flow: :vader, state: :my_action
|
87
73
|
controller.step_to flow: :vader, state: :my_action
|
88
74
|
controller.step_to flow: :vader, state: :my_action
|
89
|
-
expect(controller.current_session.
|
90
|
-
expect(controller.current_session.state_string).to eq("level3")
|
75
|
+
expect($redis.get(controller.current_session.session_key)).to eq('catch_all->level3')
|
91
76
|
end
|
92
77
|
|
93
78
|
it "should just stop after the maximum number of catch_all levels have been reached" do
|
@@ -95,8 +80,75 @@ describe "Stealth::Controller::CatchAll" do
|
|
95
80
|
controller.step_to flow: :vader, state: :my_action
|
96
81
|
controller.step_to flow: :vader, state: :my_action
|
97
82
|
controller.step_to flow: :vader, state: :my_action
|
98
|
-
expect(controller.current_session.
|
99
|
-
|
83
|
+
expect($redis.get(controller.current_session.session_key)).to eq('vader->my_action')
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should NOT run the catch_all if do_nothing is called" do
|
87
|
+
controller.current_session.set_session(new_flow: 'vader', new_state: 'my_action3')
|
88
|
+
controller.action(action: :my_action3)
|
89
|
+
expect($redis.get(controller.current_session.session_key)).to eq('vader->my_action3')
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "catch_alls from within catch_all flow" do
|
93
|
+
let(:e) {
|
94
|
+
e = OpenStruct.new
|
95
|
+
e.class = RuntimeError
|
96
|
+
e.message = 'oops'
|
97
|
+
e.backtrace = [
|
98
|
+
'/stealth/lib/stealth/controller/controller.rb',
|
99
|
+
'/stealth/lib/stealth/controller/catch_all.rb',
|
100
|
+
]
|
101
|
+
e
|
102
|
+
}
|
103
|
+
|
104
|
+
before(:each) do
|
105
|
+
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'catch_all', state: 'level1')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not step_to to catch_all" do
|
109
|
+
expect(controller).to_not receive(:step_to)
|
110
|
+
controller.run_catch_all(err: e)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should return false" do
|
114
|
+
expect(controller.run_catch_all(err: e)).to be false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should log the error message" do
|
118
|
+
expect(Stealth::Logger).to receive(:l).with(topic: 'catch_all', message: "[Level 1] for user #{facebook_message.sender_id} OpenStruct\noops\n/stealth/lib/stealth/controller/controller.rb\n/stealth/lib/stealth/controller/catch_all.rb")
|
119
|
+
expect(Stealth::Logger).to receive(:l).with(topic: 'catch_all', message: "CatchAll triggered for user #{facebook_message.sender_id} from within CatchAll; ignoring.")
|
120
|
+
controller.run_catch_all(err: e)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "catch_all_reason" do
|
125
|
+
before(:each) do
|
126
|
+
@session = Stealth::Session.new(id: controller.current_session_id)
|
127
|
+
@session.set_session(new_flow: 'vader', new_state: 'my_action2')
|
128
|
+
end
|
129
|
+
|
130
|
+
after(:each) do
|
131
|
+
$msg = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should have access to the error raised in current_message.catch_all_reason' do
|
135
|
+
controller.action(action: :my_action)
|
136
|
+
expect($msg.catch_all_reason).to be_a(Hash)
|
137
|
+
expect($msg.catch_all_reason[:err]).to eq(RuntimeError)
|
138
|
+
expect($msg.catch_all_reason[:err_msg]).to eq('oops')
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should have the correct error when handle_message fails to recognize a message' do
|
142
|
+
controller.action(action: :action_with_unrecognized_msg)
|
143
|
+
expect($msg.catch_all_reason[:err]).to eq(Stealth::Errors::UnrecognizedMessage)
|
144
|
+
expect($msg.catch_all_reason[:err_msg]).to eq("The reply '#{facebook_message.message_with_text.message}' was not recognized.")
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should have the correct error when get_match fails to recognize a message' do
|
148
|
+
controller.action(action: :action_with_unrecognized_match)
|
149
|
+
expect($msg.catch_all_reason[:err]).to eq(Stealth::Errors::UnrecognizedMessage)
|
150
|
+
expect($msg.catch_all_reason[:err_msg]).to eq("The reply '#{facebook_message.message_with_text.message}' was not recognized.")
|
151
|
+
end
|
100
152
|
end
|
101
153
|
end
|
102
154
|
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" do
|
7
6
|
|
@@ -25,12 +24,24 @@ describe "Stealth::Controller" do
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def other_action2
|
28
|
-
|
27
|
+
step_to state: :other_action4
|
29
28
|
end
|
30
29
|
|
31
30
|
def other_action3
|
32
31
|
|
33
32
|
end
|
33
|
+
|
34
|
+
def other_action4
|
35
|
+
do_nothing
|
36
|
+
end
|
37
|
+
|
38
|
+
def broken_action
|
39
|
+
raise StandardError
|
40
|
+
end
|
41
|
+
|
42
|
+
def parts_unknown
|
43
|
+
step_to flow: :parts, state: :unknown
|
44
|
+
end
|
34
45
|
end
|
35
46
|
|
36
47
|
class FlowMap
|
@@ -46,27 +57,26 @@ describe "Stealth::Controller" do
|
|
46
57
|
state :other_action
|
47
58
|
state :other_action2
|
48
59
|
state :other_action3
|
60
|
+
state :other_action4
|
61
|
+
state :broken_action
|
62
|
+
state :part_unknown
|
49
63
|
state :deprecated_action, redirects_to: :other_action
|
50
64
|
state :deprecated_action2, redirects_to: 'mr_robot->my_action'
|
51
65
|
end
|
52
66
|
end
|
53
67
|
|
54
68
|
let(:facebook_message) { SampleMessage.new(service: 'facebook') }
|
55
|
-
let(:controller) {
|
69
|
+
let(:controller) {
|
70
|
+
MrTronsController.new(service_message: facebook_message.message_with_text)
|
71
|
+
}
|
56
72
|
|
57
73
|
describe "convenience methods" do
|
58
74
|
it "should make the session ID accessible via current_session_id" do
|
59
|
-
controller.current_session.
|
75
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
60
76
|
|
61
77
|
expect(controller.current_session_id).to eq(facebook_message.sender_id)
|
62
78
|
end
|
63
79
|
|
64
|
-
it "should make the session ID accessible via current_user_id" do
|
65
|
-
controller.current_session.set(flow: 'mr_tron', state: 'other_action')
|
66
|
-
|
67
|
-
expect(controller.current_user_id).to eq(facebook_message.sender_id)
|
68
|
-
end
|
69
|
-
|
70
80
|
it "should make the message available in current_message.message" do
|
71
81
|
expect(controller.current_message.message).to eq(facebook_message.message)
|
72
82
|
end
|
@@ -126,9 +136,9 @@ describe "Stealth::Controller" do
|
|
126
136
|
|
127
137
|
it "should step_to the specified redirect flow and state when a session is specified" do
|
128
138
|
controller.current_session.session = Stealth::Session.canonical_session_slug(flow: 'mr_tron', state: 'deprecated_action2')
|
129
|
-
mr_robot_controller =
|
139
|
+
mr_robot_controller = MrRobotsController.new(service_message: facebook_message.message_with_text)
|
130
140
|
|
131
|
-
|
141
|
+
allow(MrRobotsController).to receive(:new).and_return(mr_robot_controller)
|
132
142
|
expect(mr_robot_controller).to receive(:my_action)
|
133
143
|
controller.action(action: :deprecated_action2)
|
134
144
|
end
|
@@ -156,7 +166,7 @@ describe "Stealth::Controller" do
|
|
156
166
|
it "should call a controller's corresponding action when only a state is provided" do
|
157
167
|
expect_any_instance_of(MrTronsController).to receive(:other_action3)
|
158
168
|
|
159
|
-
controller.current_session.
|
169
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
160
170
|
|
161
171
|
controller.step_to state: "other_action3"
|
162
172
|
end
|
@@ -175,10 +185,44 @@ describe "Stealth::Controller" do
|
|
175
185
|
controller.step_to session: controller.current_session
|
176
186
|
end
|
177
187
|
|
188
|
+
it "should call a controller's corresponding action when a session slug is provided" do
|
189
|
+
expect_any_instance_of(MrRobotsController).to receive(:my_action3)
|
190
|
+
controller.step_to slug: 'mr_robot->my_action3'
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should pass along the service_message" do
|
194
|
+
robot_controller_dbl = double('MrRobotsController').as_null_object
|
195
|
+
expect(MrRobotsController).to receive(:new).with(service_message: controller.current_message, pos: nil).and_return(robot_controller_dbl)
|
196
|
+
controller.step_to flow: :mr_robot, state: :my_action3
|
197
|
+
end
|
198
|
+
|
178
199
|
it "should accept flow and string specified as symbols" do
|
179
200
|
expect_any_instance_of(MrRobotsController).to receive(:my_action3)
|
180
201
|
controller.step_to flow: :mr_robot, state: :my_action3
|
181
202
|
end
|
203
|
+
|
204
|
+
it "should check if an interruption occured" do
|
205
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
206
|
+
controller.step_to flow: :mr_robot, state: :my_action3
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
210
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
211
|
+
expect(controller).to receive(:run_interrupt_action)
|
212
|
+
expect(controller.step_to(flow: :mr_robot, state: :my_action3)).to eq :interrupted
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should set @pos if it is specified in the arguments" do
|
216
|
+
expect_any_instance_of(MrRobotsController).to receive(:my_action3)
|
217
|
+
controller.step_to flow: :mr_robot, state: :my_action3, pos: -1
|
218
|
+
expect(controller.pos).to eq -1
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should leave @pos as nil if the pos argument is not specified" do
|
222
|
+
expect_any_instance_of(MrRobotsController).to receive(:my_action3)
|
223
|
+
controller.step_to flow: :mr_robot, state: :my_action3
|
224
|
+
expect(controller.pos).to be_nil
|
225
|
+
end
|
182
226
|
end
|
183
227
|
|
184
228
|
describe "update_session_to" do
|
@@ -199,7 +243,7 @@ describe "Stealth::Controller" do
|
|
199
243
|
it "should update session to controller's corresponding action when only a state is provided" do
|
200
244
|
expect_any_instance_of(MrTronsController).to_not receive(:other_action3)
|
201
245
|
|
202
|
-
controller.current_session.
|
246
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
203
247
|
|
204
248
|
controller.update_session_to state: "other_action3"
|
205
249
|
expect(controller.current_session.flow_string).to eq('mr_tron')
|
@@ -217,14 +261,22 @@ describe "Stealth::Controller" do
|
|
217
261
|
it "should update session to controller's corresponding action when a session is provided" do
|
218
262
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action3)
|
219
263
|
|
220
|
-
session = Stealth::Session.new(
|
221
|
-
session.
|
264
|
+
session = Stealth::Session.new(id: controller.current_session_id)
|
265
|
+
session.set_session(new_flow: 'mr_robot', new_state: 'my_action3')
|
222
266
|
|
223
267
|
controller.update_session_to session: session
|
224
268
|
expect(controller.current_session.flow_string).to eq('mr_robot')
|
225
269
|
expect(controller.current_session.state_string).to eq('my_action3')
|
226
270
|
end
|
227
271
|
|
272
|
+
it "should update session to controller's corresponding action when a session slug is provided" do
|
273
|
+
expect_any_instance_of(MrRobotsController).to_not receive(:my_action3)
|
274
|
+
expect(controller.current_session.flow_string).to eq('mr_robot')
|
275
|
+
expect(controller.current_session.state_string).to eq('my_action3')
|
276
|
+
|
277
|
+
controller.update_session_to slug: 'mr_robot->my_action3'
|
278
|
+
end
|
279
|
+
|
228
280
|
it "should accept flow and string specified as symbols" do
|
229
281
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action3)
|
230
282
|
|
@@ -232,6 +284,17 @@ describe "Stealth::Controller" do
|
|
232
284
|
expect(controller.current_session.flow_string).to eq('mr_robot')
|
233
285
|
expect(controller.current_session.state_string).to eq('my_action3')
|
234
286
|
end
|
287
|
+
|
288
|
+
it "should check if an interruption occured" do
|
289
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
290
|
+
controller.update_session_to flow: :mr_robot, state: :my_action3
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
294
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
295
|
+
expect(controller).to receive(:run_interrupt_action)
|
296
|
+
expect(controller.update_session_to(flow: :mr_robot, state: :my_action3)).to eq :interrupted
|
297
|
+
end
|
235
298
|
end
|
236
299
|
|
237
300
|
describe "step_to_in" do
|
@@ -255,30 +318,32 @@ describe "Stealth::Controller" do
|
|
255
318
|
controller.current_service,
|
256
319
|
controller.current_session_id,
|
257
320
|
'mr_robot',
|
258
|
-
'my_action'
|
321
|
+
'my_action',
|
322
|
+
nil
|
259
323
|
)
|
260
324
|
|
261
325
|
expect {
|
262
326
|
controller.step_to_in 100.seconds, flow: "mr_robot"
|
263
|
-
}.to_not change(controller.current_session, :
|
327
|
+
}.to_not change(controller.current_session, :get_session)
|
264
328
|
end
|
265
329
|
|
266
330
|
it "should schedule a transition to controller's corresponding action when only a state is provided" do
|
267
331
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
268
332
|
|
269
|
-
controller.current_session.
|
333
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
270
334
|
|
271
335
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
272
336
|
100.seconds,
|
273
337
|
controller.current_service,
|
274
338
|
controller.current_session_id,
|
275
339
|
'mr_tron',
|
276
|
-
'other_action3'
|
340
|
+
'other_action3',
|
341
|
+
nil
|
277
342
|
)
|
278
343
|
|
279
344
|
expect {
|
280
345
|
controller.step_to_in 100.seconds, state: "other_action3"
|
281
|
-
}.to_not change(controller.current_session, :
|
346
|
+
}.to_not change(controller.current_session, :get_session)
|
282
347
|
end
|
283
348
|
|
284
349
|
it "should update session to controller's corresponding action when a state and flow is provided" do
|
@@ -289,31 +354,50 @@ describe "Stealth::Controller" do
|
|
289
354
|
controller.current_service,
|
290
355
|
controller.current_session_id,
|
291
356
|
'mr_robot',
|
292
|
-
'my_action3'
|
357
|
+
'my_action3',
|
358
|
+
nil
|
293
359
|
)
|
294
360
|
|
295
361
|
expect {
|
296
362
|
controller.step_to_in 100.seconds, flow: 'mr_robot', state: "my_action3"
|
297
|
-
}.to_not change(controller.current_session, :
|
363
|
+
}.to_not change(controller.current_session, :get_session)
|
298
364
|
end
|
299
365
|
|
300
366
|
it "should update session to controller's corresponding action when a session is provided" do
|
301
367
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
302
368
|
|
303
|
-
session = Stealth::Session.new(
|
304
|
-
session.
|
369
|
+
session = Stealth::Session.new(id: controller.current_session_id)
|
370
|
+
session.set_session(new_flow: 'mr_robot', new_state: 'my_action3')
|
305
371
|
|
306
372
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
307
373
|
100.seconds,
|
308
374
|
controller.current_service,
|
309
375
|
controller.current_session_id,
|
310
376
|
'mr_robot',
|
311
|
-
'my_action3'
|
377
|
+
'my_action3',
|
378
|
+
nil
|
312
379
|
)
|
313
380
|
|
314
381
|
expect {
|
315
382
|
controller.step_to_in 100.seconds, session: session
|
316
|
-
}.to_not change(controller.current_session, :
|
383
|
+
}.to_not change(controller.current_session, :get_session)
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should update session to controller's corresponding action when a session slug is provided" do
|
387
|
+
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
388
|
+
|
389
|
+
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
390
|
+
100.seconds,
|
391
|
+
controller.current_service,
|
392
|
+
controller.current_session_id,
|
393
|
+
'mr_robot',
|
394
|
+
'my_action3',
|
395
|
+
nil
|
396
|
+
)
|
397
|
+
|
398
|
+
expect {
|
399
|
+
controller.step_to_in 100.seconds, slug: 'mr_robot->my_action3'
|
400
|
+
}.to_not change(controller.current_session, :get_session)
|
317
401
|
end
|
318
402
|
|
319
403
|
it "should accept flow and string specified as symbols" do
|
@@ -324,12 +408,38 @@ describe "Stealth::Controller" do
|
|
324
408
|
controller.current_service,
|
325
409
|
controller.current_session_id,
|
326
410
|
'mr_robot',
|
327
|
-
'my_action3'
|
411
|
+
'my_action3',
|
412
|
+
nil
|
328
413
|
)
|
329
414
|
|
330
415
|
expect {
|
331
416
|
controller.step_to_in 100.seconds, flow: :mr_robot, state: :my_action3
|
332
|
-
}.to_not change(controller.current_session, :
|
417
|
+
}.to_not change(controller.current_session, :get_session)
|
418
|
+
end
|
419
|
+
|
420
|
+
it "should pass along the target_id if set on the message" do
|
421
|
+
expect(Stealth::ScheduledReplyJob).to receive(:perform_in).with(
|
422
|
+
100.seconds,
|
423
|
+
controller.current_service,
|
424
|
+
controller.current_session_id,
|
425
|
+
'mr_robot',
|
426
|
+
'my_action3',
|
427
|
+
'+18885551212'
|
428
|
+
)
|
429
|
+
|
430
|
+
controller.current_message.target_id = '+18885551212'
|
431
|
+
controller.step_to_in 100.seconds, flow: :mr_robot, state: :my_action3
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should check if an interruption occured" do
|
435
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
436
|
+
controller.step_to_in 100.seconds, flow: :mr_robot, state: :my_action3
|
437
|
+
end
|
438
|
+
|
439
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
440
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
441
|
+
expect(controller).to receive(:run_interrupt_action)
|
442
|
+
expect(controller.step_to_in(100.seconds, flow: :mr_robot, state: :my_action3)).to eq :interrupted
|
333
443
|
end
|
334
444
|
end
|
335
445
|
|
@@ -356,30 +466,32 @@ describe "Stealth::Controller" do
|
|
356
466
|
controller.current_service,
|
357
467
|
controller.current_session_id,
|
358
468
|
'mr_robot',
|
359
|
-
'my_action'
|
469
|
+
'my_action',
|
470
|
+
nil
|
360
471
|
)
|
361
472
|
|
362
473
|
expect {
|
363
474
|
controller.step_to_at future_timestamp, flow: "mr_robot"
|
364
|
-
}.to_not change(controller.current_session, :
|
475
|
+
}.to_not change(controller.current_session, :get_session)
|
365
476
|
end
|
366
477
|
|
367
478
|
it "should schedule a transition to controller's corresponding action when only a state is provided" do
|
368
479
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
369
480
|
|
370
|
-
controller.current_session.
|
481
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
371
482
|
|
372
483
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
373
484
|
future_timestamp,
|
374
485
|
controller.current_service,
|
375
486
|
controller.current_session_id,
|
376
487
|
'mr_tron',
|
377
|
-
'other_action3'
|
488
|
+
'other_action3',
|
489
|
+
nil
|
378
490
|
)
|
379
491
|
|
380
492
|
expect {
|
381
493
|
controller.step_to_at future_timestamp, state: "other_action3"
|
382
|
-
}.to_not change(controller.current_session, :
|
494
|
+
}.to_not change(controller.current_session, :get_session)
|
383
495
|
end
|
384
496
|
|
385
497
|
it "should update session to controller's corresponding action when a state and flow is provided" do
|
@@ -390,31 +502,50 @@ describe "Stealth::Controller" do
|
|
390
502
|
controller.current_service,
|
391
503
|
controller.current_session_id,
|
392
504
|
'mr_robot',
|
393
|
-
'my_action3'
|
505
|
+
'my_action3',
|
506
|
+
nil
|
394
507
|
)
|
395
508
|
|
396
509
|
expect {
|
397
510
|
controller.step_to_at future_timestamp, flow: 'mr_robot', state: "my_action3"
|
398
|
-
}.to_not change(controller.current_session, :
|
511
|
+
}.to_not change(controller.current_session, :get_session)
|
399
512
|
end
|
400
513
|
|
401
514
|
it "should update session to controller's corresponding action when a session is provided" do
|
402
515
|
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
403
516
|
|
404
|
-
session = Stealth::Session.new(
|
405
|
-
session.
|
517
|
+
session = Stealth::Session.new(id: controller.current_session_id)
|
518
|
+
session.set_session(new_flow: 'mr_robot', new_state: 'my_action3')
|
406
519
|
|
407
520
|
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
408
521
|
future_timestamp,
|
409
522
|
controller.current_service,
|
410
523
|
controller.current_session_id,
|
411
524
|
'mr_robot',
|
412
|
-
'my_action3'
|
525
|
+
'my_action3',
|
526
|
+
nil
|
413
527
|
)
|
414
528
|
|
415
529
|
expect {
|
416
530
|
controller.step_to_at future_timestamp, session: session
|
417
|
-
}.to_not change(controller.current_session, :
|
531
|
+
}.to_not change(controller.current_session, :get_session)
|
532
|
+
end
|
533
|
+
|
534
|
+
it "should update session to controller's corresponding action when a session slug is provided" do
|
535
|
+
expect_any_instance_of(MrRobotsController).to_not receive(:my_action)
|
536
|
+
|
537
|
+
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
538
|
+
future_timestamp,
|
539
|
+
controller.current_service,
|
540
|
+
controller.current_session_id,
|
541
|
+
'mr_robot',
|
542
|
+
'my_action3',
|
543
|
+
nil
|
544
|
+
)
|
545
|
+
|
546
|
+
expect {
|
547
|
+
controller.step_to_at future_timestamp, slug: 'mr_robot->my_action3'
|
548
|
+
}.to_not change(controller.current_session, :get_session)
|
418
549
|
end
|
419
550
|
|
420
551
|
it "should accept flow and string specified as symbols" do
|
@@ -425,12 +556,148 @@ describe "Stealth::Controller" do
|
|
425
556
|
controller.current_service,
|
426
557
|
controller.current_session_id,
|
427
558
|
'mr_robot',
|
428
|
-
'my_action3'
|
559
|
+
'my_action3',
|
560
|
+
nil
|
429
561
|
)
|
430
562
|
|
431
563
|
expect {
|
432
564
|
controller.step_to_at future_timestamp, flow: :mr_robot, state: :my_action3
|
433
|
-
}.to_not change(controller.current_session, :
|
565
|
+
}.to_not change(controller.current_session, :get_session)
|
566
|
+
end
|
567
|
+
|
568
|
+
it "should pass along the target_id if set on the message" do
|
569
|
+
expect(Stealth::ScheduledReplyJob).to receive(:perform_at).with(
|
570
|
+
future_timestamp,
|
571
|
+
controller.current_service,
|
572
|
+
controller.current_session_id,
|
573
|
+
'mr_robot',
|
574
|
+
'my_action3',
|
575
|
+
'+18885551212'
|
576
|
+
)
|
577
|
+
|
578
|
+
controller.current_message.target_id = '+18885551212'
|
579
|
+
controller.step_to_at future_timestamp, flow: :mr_robot, state: :my_action3
|
580
|
+
end
|
581
|
+
|
582
|
+
it "should check if an interruption occured" do
|
583
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
584
|
+
controller.step_to_at future_timestamp, flow: :mr_robot, state: :my_action3
|
585
|
+
end
|
586
|
+
|
587
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
588
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
589
|
+
expect(controller).to receive(:run_interrupt_action)
|
590
|
+
expect(controller.step_to_at(future_timestamp, flow: :mr_robot, state: :my_action3)).to eq :interrupted
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
describe "set_back_to" do
|
595
|
+
it "should raise an ArgumentError if a session, flow, or state is not specified" do
|
596
|
+
expect {
|
597
|
+
controller.set_back_to
|
598
|
+
}.to raise_error(ArgumentError)
|
599
|
+
end
|
600
|
+
|
601
|
+
it "should call the flow's first state's controller action when only a flow is provided" do
|
602
|
+
expect {
|
603
|
+
controller.set_back_to(flow: :mr_robot)
|
604
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('mr_robot->my_action')
|
605
|
+
end
|
606
|
+
|
607
|
+
it "should call a controller's corresponding action when only a state is provided" do
|
608
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
609
|
+
|
610
|
+
expect {
|
611
|
+
controller.set_back_to(state: :other_action3)
|
612
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('mr_tron->other_action3')
|
613
|
+
end
|
614
|
+
|
615
|
+
it "should call a controller's corresponding action when a state and flow is provided" do
|
616
|
+
expect {
|
617
|
+
controller.set_back_to(flow: 'marco', state: 'polo')
|
618
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('marco->polo')
|
619
|
+
end
|
620
|
+
|
621
|
+
it "should call a controller's corresponding action when a session is provided" do
|
622
|
+
allow(controller.current_session).to receive(:flow_string).and_return("mr_robot")
|
623
|
+
allow(controller.current_session).to receive(:state_string).and_return("my_action3")
|
624
|
+
|
625
|
+
expect {
|
626
|
+
controller.set_back_to(session: controller.current_session)
|
627
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('mr_robot->my_action3')
|
628
|
+
end
|
629
|
+
|
630
|
+
it "should call a controller's corresponding action when a session slug is provided" do
|
631
|
+
expect {
|
632
|
+
controller.set_back_to(slug: 'marco->polo')
|
633
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('marco->polo')
|
634
|
+
end
|
635
|
+
|
636
|
+
it "should default to the scoped flow if one is not specified" do
|
637
|
+
controller.current_session.set_session(new_flow: :mr_tron, new_state: :other_action)
|
638
|
+
expect {
|
639
|
+
controller.set_back_to(state: 'polo')
|
640
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.to('mr_tron->polo')
|
641
|
+
end
|
642
|
+
|
643
|
+
it "should overwrite the existing back_to_session if one is already present" do
|
644
|
+
$redis.set([controller.current_session_id, 'back_to'].join('-'), 'marco->polo')
|
645
|
+
controller.current_session.set_session(new_flow: :mr_tron, new_state: :other_action)
|
646
|
+
expect {
|
647
|
+
controller.set_back_to(state: 'other_action')
|
648
|
+
}.to change{ $redis.get([controller.current_session_id, 'back_to'].join('-')) }.from('marco->polo').to('mr_tron->other_action')
|
649
|
+
end
|
650
|
+
|
651
|
+
it "should check if an interruption occured" do
|
652
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
653
|
+
controller.set_back_to flow: :mr_robot, state: :my_action3
|
654
|
+
end
|
655
|
+
|
656
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
657
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
658
|
+
expect(controller).to receive(:run_interrupt_action)
|
659
|
+
expect(controller.set_back_to(flow: :mr_robot, state: :my_action3)).to eq :interrupted
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
describe "step_back" do
|
664
|
+
let(:back_to_slug) { [controller.current_session_id, 'back_to'].join('-') }
|
665
|
+
|
666
|
+
it "should raise Stealth::Errors::InvalidStateTransition if back_to_session is not set" do
|
667
|
+
$redis.del(back_to_slug)
|
668
|
+
expect {
|
669
|
+
controller.step_back
|
670
|
+
}.to raise_error(Stealth::Errors::InvalidStateTransition)
|
671
|
+
end
|
672
|
+
|
673
|
+
it "should step_to the stored back_to_session" do
|
674
|
+
controller.set_back_to(flow: 'marco', state: 'polo')
|
675
|
+
back_to_session = Stealth::Session.new(
|
676
|
+
id: controller.current_session_id,
|
677
|
+
type: :back_to
|
678
|
+
)
|
679
|
+
|
680
|
+
# We need to control the returned session object so the IDs match
|
681
|
+
expect(Stealth::Session).to receive(:new).with(
|
682
|
+
id: controller.current_session_id,
|
683
|
+
type: :back_to
|
684
|
+
).and_return(back_to_session)
|
685
|
+
expect(controller).to receive(:step_to).with(session: back_to_session)
|
686
|
+
|
687
|
+
controller.step_back
|
688
|
+
end
|
689
|
+
|
690
|
+
it "should check if an interruption occured" do
|
691
|
+
controller.set_back_to(flow: :mr_robot, state: :my_action3)
|
692
|
+
expect(controller).to receive(:interrupt_detected?).and_return(false)
|
693
|
+
controller.step_back
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should call run_interrupt_action if an interruption occured and return" do
|
697
|
+
controller.set_back_to(flow: :mr_robot, state: :my_action3)
|
698
|
+
expect(controller).to receive(:interrupt_detected?).and_return(true)
|
699
|
+
expect(controller).to receive(:run_interrupt_action)
|
700
|
+
expect(controller.step_back).to eq :interrupted
|
434
701
|
end
|
435
702
|
end
|
436
703
|
|
@@ -479,10 +746,144 @@ describe "Stealth::Controller" do
|
|
479
746
|
end
|
480
747
|
|
481
748
|
it "should be falsey otherwise" do
|
749
|
+
allow(controller).to receive(:flow_controller).and_return(controller)
|
482
750
|
expect(controller.progressed?).to be_falsey
|
483
751
|
controller.action(action: :other_action)
|
484
752
|
expect(controller.progressed?).to be_falsey
|
485
753
|
end
|
486
754
|
end
|
487
755
|
|
756
|
+
describe "do_nothing" do
|
757
|
+
it "should set progressed to truthy when called" do
|
758
|
+
allow(controller).to receive(:flow_controller).and_return(controller)
|
759
|
+
expect(controller.progressed?).to be_falsey
|
760
|
+
controller.action(action: :other_action4)
|
761
|
+
expect(controller.progressed?).to be_truthy
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
describe "update_session" do
|
766
|
+
before(:each) do
|
767
|
+
controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
768
|
+
end
|
769
|
+
|
770
|
+
it "should set progressed to :updated_session" do
|
771
|
+
controller.send(:update_session, flow: :mr_tron, state: :other_action)
|
772
|
+
expect(controller.progressed?).to eq :updated_session
|
773
|
+
end
|
774
|
+
|
775
|
+
it "call set_session on the current_session with the new flow and state" do
|
776
|
+
controller.send(:update_session, flow: :mr_robot, state: :my_action)
|
777
|
+
expect(controller.current_session.flow_string).to eq 'mr_robot'
|
778
|
+
expect(controller.current_session.state_string).to eq 'my_action'
|
779
|
+
end
|
780
|
+
|
781
|
+
it "should not call set_session on current_session if the flow and state match" do
|
782
|
+
expect_any_instance_of(Stealth::Session).to_not receive(:set_session)
|
783
|
+
controller.send(:update_session, flow: :mr_tron, state: :other_action)
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
describe "dev jumps" do
|
788
|
+
let!(:dev_env) { ActiveSupport::StringInquirer.new('development') }
|
789
|
+
|
790
|
+
describe "dev_jump_detected?" do
|
791
|
+
it "should return false if the enviornment is not 'development'" do
|
792
|
+
expect(Stealth.env).to eq 'test'
|
793
|
+
expect(controller.send(:dev_jump_detected?)).to be false
|
794
|
+
end
|
795
|
+
|
796
|
+
it "should return false if the message does not match the jump format" do
|
797
|
+
allow(Stealth).to receive(:env).and_return(dev_env)
|
798
|
+
controller.current_message.message = 'hello world'
|
799
|
+
expect(Stealth.env.development?).to be true
|
800
|
+
expect(controller.send(:dev_jump_detected?)).to be false
|
801
|
+
end
|
802
|
+
|
803
|
+
it "should return false if the message looks like an American date" do
|
804
|
+
allow(Stealth).to receive(:env).and_return(dev_env)
|
805
|
+
controller.current_message.message = '1/23/84'
|
806
|
+
expect(Stealth.env.development?).to be true
|
807
|
+
expect(controller.send(:dev_jump_detected?)).to be false
|
808
|
+
end
|
809
|
+
|
810
|
+
it "should return false if the message looks like an American date that is zero padded" do
|
811
|
+
allow(Stealth).to receive(:env).and_return(dev_env)
|
812
|
+
controller.current_message.message = '01/23/1984'
|
813
|
+
expect(Stealth.env.development?).to be true
|
814
|
+
expect(controller.send(:dev_jump_detected?)).to be false
|
815
|
+
end
|
816
|
+
|
817
|
+
describe "with a dev jump message" do
|
818
|
+
before(:each) do
|
819
|
+
expect(controller).to receive(:handle_dev_jump).and_return(true)
|
820
|
+
expect(Stealth).to receive(:env).and_return(dev_env)
|
821
|
+
end
|
822
|
+
|
823
|
+
it "should return true if the message is in the format /flow/state" do
|
824
|
+
controller.current_message.message = '/mr_robot/my_action'
|
825
|
+
expect(controller.send(:dev_jump_detected?)).to be true
|
826
|
+
end
|
827
|
+
|
828
|
+
it "should return true if the message is in the format /flow" do
|
829
|
+
controller.current_message.message = '/mr_robot'
|
830
|
+
expect(controller.send(:dev_jump_detected?)).to be true
|
831
|
+
end
|
832
|
+
|
833
|
+
it "should return true if the message is in the format //state" do
|
834
|
+
controller.current_message.message = '//my_action'
|
835
|
+
expect(controller.send(:dev_jump_detected?)).to be true
|
836
|
+
end
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
describe "handle_dev_jump" do
|
841
|
+
it "should handle messages in the format /flow/state" do
|
842
|
+
controller.current_message.message = '/mr_robot/my_action'
|
843
|
+
expect(controller).to receive(:step_to).with(flow: 'mr_robot', state: 'my_action')
|
844
|
+
controller.send(:handle_dev_jump)
|
845
|
+
end
|
846
|
+
|
847
|
+
it "should handle messages in the format /flow" do
|
848
|
+
controller.current_message.message = '/mr_robot'
|
849
|
+
expect(controller).to receive(:step_to).with(flow: 'mr_robot', state: nil)
|
850
|
+
controller.send(:handle_dev_jump)
|
851
|
+
end
|
852
|
+
|
853
|
+
it "should handle messages in the format //state" do
|
854
|
+
controller.current_message.message = '//my_action'
|
855
|
+
expect(controller).to receive(:step_to).with(flow: nil, state: 'my_action')
|
856
|
+
controller.send(:handle_dev_jump)
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
describe "session locking" do
|
861
|
+
before(:each) do
|
862
|
+
allow(MrTronsController).to receive(:new).and_return(controller)
|
863
|
+
end
|
864
|
+
|
865
|
+
it "should lock and then unlock a session when a do_nothing action is called" do
|
866
|
+
expect(controller).to receive(:lock_session!).once
|
867
|
+
expect(controller).to receive(:release_lock!).once
|
868
|
+
controller.action(action: :other_action4)
|
869
|
+
end
|
870
|
+
|
871
|
+
it "should lock and then unlock a session twice when an action steps to another" do
|
872
|
+
expect(controller).to receive(:lock_session!).twice
|
873
|
+
expect(controller).to receive(:release_lock!).twice
|
874
|
+
controller.action(action: :other_action2)
|
875
|
+
end
|
876
|
+
|
877
|
+
it 'should still release the lock even if an action raises' do
|
878
|
+
expect(controller).to receive(:release_lock!).once
|
879
|
+
controller.action(action: :broken_action)
|
880
|
+
end
|
881
|
+
|
882
|
+
it 'should still release the lock if an action steps to an unknown flow->state' do
|
883
|
+
expect(controller).to receive(:release_lock!).once
|
884
|
+
controller.action(action: :parts_unknown)
|
885
|
+
end
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
488
889
|
end
|