xip 0.0.1 → 2.0.0.beta2
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 +116 -0
- data/.gitignore +12 -0
- data/CHANGELOG.md +135 -0
- data/Gemfile +4 -1
- data/Gemfile.lock +65 -15
- data/LICENSE +6 -4
- data/README.md +51 -1
- data/VERSION +1 -0
- data/bin/xip +3 -11
- data/lib/xip.rb +1 -3
- data/lib/xip/base.rb +189 -0
- data/lib/xip/cli.rb +273 -0
- data/lib/xip/cli_base.rb +24 -0
- data/lib/xip/commands/command.rb +13 -0
- data/lib/xip/commands/console.rb +74 -0
- data/lib/xip/commands/server.rb +63 -0
- data/lib/xip/configuration.rb +56 -0
- data/lib/xip/controller/callbacks.rb +63 -0
- data/lib/xip/controller/catch_all.rb +84 -0
- data/lib/xip/controller/controller.rb +274 -0
- data/lib/xip/controller/dev_jumps.rb +40 -0
- data/lib/xip/controller/dynamic_delay.rb +61 -0
- data/lib/xip/controller/helpers.rb +128 -0
- data/lib/xip/controller/interrupt_detect.rb +99 -0
- data/lib/xip/controller/messages.rb +283 -0
- data/lib/xip/controller/nlp.rb +49 -0
- data/lib/xip/controller/replies.rb +281 -0
- data/lib/xip/controller/unrecognized_message.rb +61 -0
- data/lib/xip/core_ext.rb +5 -0
- data/lib/xip/core_ext/numeric.rb +10 -0
- data/lib/xip/core_ext/string.rb +18 -0
- data/lib/xip/dispatcher.rb +68 -0
- data/lib/xip/errors.rb +55 -0
- data/lib/xip/flow/base.rb +69 -0
- data/lib/xip/flow/specification.rb +56 -0
- data/lib/xip/flow/state.rb +82 -0
- data/lib/xip/generators/builder.rb +41 -0
- data/lib/xip/generators/builder/.gitignore +30 -0
- data/lib/xip/generators/builder/Gemfile +19 -0
- data/lib/xip/generators/builder/Procfile.dev +2 -0
- data/lib/xip/generators/builder/README.md +9 -0
- data/lib/xip/generators/builder/Rakefile +2 -0
- data/lib/xip/generators/builder/bot/controllers/bot_controller.rb +55 -0
- data/lib/xip/generators/builder/bot/controllers/catch_alls_controller.rb +21 -0
- data/lib/xip/generators/builder/bot/controllers/concerns/.keep +0 -0
- data/lib/xip/generators/builder/bot/controllers/goodbyes_controller.rb +9 -0
- data/lib/xip/generators/builder/bot/controllers/hellos_controller.rb +9 -0
- data/lib/xip/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
- data/lib/xip/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
- data/lib/xip/generators/builder/bot/helpers/bot_helper.rb +2 -0
- data/lib/xip/generators/builder/bot/models/bot_record.rb +3 -0
- data/lib/xip/generators/builder/bot/models/concerns/.keep +0 -0
- data/lib/xip/generators/builder/bot/replies/catch_alls/level1.yml +2 -0
- data/lib/xip/generators/builder/bot/replies/goodbyes/say_goodbye.yml +2 -0
- data/lib/xip/generators/builder/bot/replies/hellos/say_hello.yml +2 -0
- data/lib/xip/generators/builder/config.ru +4 -0
- data/lib/xip/generators/builder/config/boot.rb +6 -0
- data/lib/xip/generators/builder/config/database.yml +25 -0
- data/lib/xip/generators/builder/config/environment.rb +2 -0
- data/lib/xip/generators/builder/config/flow_map.rb +25 -0
- data/lib/xip/generators/builder/config/initializers/autoload.rb +8 -0
- data/lib/xip/generators/builder/config/initializers/inflections.rb +16 -0
- data/lib/xip/generators/builder/config/puma.rb +25 -0
- data/lib/xip/generators/builder/config/services.yml +35 -0
- data/lib/xip/generators/builder/config/sidekiq.yml +3 -0
- data/lib/xip/generators/builder/db/seeds.rb +7 -0
- data/lib/xip/generators/generate.rb +39 -0
- data/lib/xip/generators/generate/flow/controllers/controller.tt +7 -0
- data/lib/xip/generators/generate/flow/helpers/helper.tt +3 -0
- data/lib/xip/generators/generate/flow/replies/ask_example.tt +9 -0
- data/lib/xip/helpers/redis.rb +40 -0
- data/lib/xip/jobs.rb +9 -0
- data/lib/xip/lock.rb +82 -0
- data/lib/xip/logger.rb +9 -3
- data/lib/xip/migrations/configurator.rb +73 -0
- data/lib/xip/migrations/generators.rb +16 -0
- data/lib/xip/migrations/railtie_config.rb +14 -0
- data/lib/xip/migrations/tasks.rb +43 -0
- data/lib/xip/nlp/client.rb +21 -0
- data/lib/xip/nlp/result.rb +56 -0
- data/lib/xip/reloader.rb +89 -0
- data/lib/xip/reply.rb +36 -0
- data/lib/xip/scheduled_reply.rb +18 -0
- data/lib/xip/server.rb +63 -0
- data/lib/xip/service_message.rb +17 -0
- data/lib/xip/service_reply.rb +44 -0
- data/lib/xip/services/base_client.rb +24 -0
- data/lib/xip/services/base_message_handler.rb +27 -0
- data/lib/xip/services/base_reply_handler.rb +72 -0
- data/lib/xip/services/jobs/handle_message_job.rb +21 -0
- data/lib/xip/session.rb +203 -0
- data/lib/xip/version.rb +7 -1
- data/logo.svg +17 -0
- data/spec/configuration_spec.rb +93 -0
- data/spec/controller/callbacks_spec.rb +217 -0
- data/spec/controller/catch_all_spec.rb +154 -0
- data/spec/controller/controller_spec.rb +889 -0
- data/spec/controller/dynamic_delay_spec.rb +70 -0
- data/spec/controller/helpers_spec.rb +119 -0
- 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 +694 -0
- data/spec/controller/unrecognized_message_spec.rb +168 -0
- data/spec/dispatcher_spec.rb +79 -0
- data/spec/flow/flow_spec.rb +82 -0
- data/spec/flow/state_spec.rb +109 -0
- 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/hello.yml.erb +15 -0
- data/spec/replies/messages/say_hola.yml+facebook.erb +6 -0
- data/spec/replies/messages/say_hola.yml+twilio.erb +6 -0
- data/spec/replies/messages/say_hola.yml.erb +6 -0
- data/spec/replies/messages/say_howdy_with_dynamic.yml +79 -0
- data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
- data/spec/replies/messages/say_offer.yml +6 -0
- data/spec/replies/messages/say_offer_with_dynamic.yml +6 -0
- data/spec/replies/messages/say_oi.yml.erb +15 -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/say_yo.yml +6 -0
- data/spec/replies/messages/say_yo.yml+twitter +6 -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 +92 -0
- data/spec/session_spec.rb +366 -0
- data/spec/spec_helper.rb +22 -66
- data/spec/support/alternate_helpers/foo_helper.rb +5 -0
- data/spec/support/controllers/vaders_controller.rb +24 -0
- data/spec/support/helpers/fun/games_helper.rb +7 -0
- data/spec/support/helpers/fun/pdf_helper.rb +7 -0
- data/spec/support/helpers/standalone_helper.rb +5 -0
- data/spec/support/helpers_typo/users_helper.rb +2 -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/support/sample_messages.rb +66 -0
- data/spec/support/services.yml +31 -0
- data/spec/support/services_with_erb.yml +31 -0
- data/spec/version_spec.rb +16 -0
- data/xip.gemspec +25 -14
- metadata +320 -18
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe "Xip::Controller::UnrecognizedMessage" 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 'run_unrecognized_message' do
|
|
11
|
+
let(:e) {
|
|
12
|
+
e = OpenStruct.new
|
|
13
|
+
e.class = RuntimeError
|
|
14
|
+
e.message = 'oops'
|
|
15
|
+
e.backtrace = [
|
|
16
|
+
'/xip/lib/xip/controller/controller.rb',
|
|
17
|
+
'/xip/lib/xip/controller/catch_all.rb',
|
|
18
|
+
]
|
|
19
|
+
e
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe 'when UnrecognizedMessagesController is not defined' do
|
|
23
|
+
before(:each) do
|
|
24
|
+
Object.send(:remove_const, :UnrecognizedMessagesController)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should log and run catch_all" do
|
|
28
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
29
|
+
topic: 'unrecognized_message',
|
|
30
|
+
message: "The message \"Hello World!\" was not recognized in the original context."
|
|
31
|
+
).ordered
|
|
32
|
+
|
|
33
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
34
|
+
topic: 'unrecognized_message',
|
|
35
|
+
message: 'Running catch_all; UnrecognizedMessagesController not defined.'
|
|
36
|
+
).ordered
|
|
37
|
+
|
|
38
|
+
expect(controller).to receive(:run_catch_all).with(err: e)
|
|
39
|
+
controller.run_unrecognized_message(err: e)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should call handle_unrecognized_message on the UnrecognizedMessagesController" do
|
|
44
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
45
|
+
def handle_unrecognized_message
|
|
46
|
+
do_nothing
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
51
|
+
topic: 'unrecognized_message',
|
|
52
|
+
message: "The message \"Hello World!\" was not recognized in the original context."
|
|
53
|
+
).ordered
|
|
54
|
+
|
|
55
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
56
|
+
topic: 'unrecognized_message',
|
|
57
|
+
message: 'A match was detected. Skipping catch-all.'
|
|
58
|
+
).ordered
|
|
59
|
+
|
|
60
|
+
controller.run_unrecognized_message(err: e)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should log if the UnrecognizedMessagesController#handle_unrecognized_message does not progress the session" do
|
|
64
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
65
|
+
def handle_unrecognized_message
|
|
66
|
+
# Oops
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
71
|
+
topic: 'unrecognized_message',
|
|
72
|
+
message: "The message \"Hello World!\" was not recognized in the original context."
|
|
73
|
+
).ordered
|
|
74
|
+
|
|
75
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
76
|
+
topic: 'unrecognized_message',
|
|
77
|
+
message: 'Did not send replies, update session, or step'
|
|
78
|
+
).ordered
|
|
79
|
+
|
|
80
|
+
expect(controller).to_not receive(:run_catch_all)
|
|
81
|
+
|
|
82
|
+
controller.run_unrecognized_message(err: e)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe 'handoff to catch_all' do
|
|
86
|
+
before(:each) do
|
|
87
|
+
@session = Xip::Session.new(id: controller.current_session_id)
|
|
88
|
+
@session.set_session(new_flow: 'vader', new_state: 'action_with_unrecognized_msg')
|
|
89
|
+
|
|
90
|
+
@error_slug = [
|
|
91
|
+
'error',
|
|
92
|
+
controller.current_session_id,
|
|
93
|
+
'vader',
|
|
94
|
+
'action_with_unrecognized_msg'
|
|
95
|
+
].join('-')
|
|
96
|
+
|
|
97
|
+
$redis.del(@error_slug)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should catch StandardError within UnrecognizedMessagesController and run catch_all" do
|
|
101
|
+
$err = Xip::Errors::ReplyNotFound.new('oops')
|
|
102
|
+
|
|
103
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
104
|
+
def handle_unrecognized_message
|
|
105
|
+
raise $err
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
expect(Xip::Logger).to receive(:l).with(
|
|
110
|
+
topic: 'unrecognized_message',
|
|
111
|
+
message: "The message \"Hello World!\" was not recognized in the original context."
|
|
112
|
+
).ordered
|
|
113
|
+
|
|
114
|
+
expect(controller).to receive(:run_catch_all).with(err: $err)
|
|
115
|
+
|
|
116
|
+
controller.run_unrecognized_message(err: e)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should track the catch_all level against the original session during exceptions" do
|
|
120
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
121
|
+
def handle_unrecognized_message
|
|
122
|
+
raise 'oops'
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
expect($redis.get(@error_slug)).to be_nil
|
|
127
|
+
controller.run_unrecognized_message(err: e)
|
|
128
|
+
expect($redis.get(@error_slug)).to eq '1'
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "should track the catch_all level against the original session for UnrecognizedMessage errors" do
|
|
132
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
133
|
+
def handle_unrecognized_message
|
|
134
|
+
handle_message(
|
|
135
|
+
'x' => proc { do_nothing },
|
|
136
|
+
'y' => proc { do_nothing }
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
expect($redis.get(@error_slug)).to be_nil
|
|
142
|
+
controller.action(action: :action_with_unrecognized_msg)
|
|
143
|
+
expect($redis.get(@error_slug)).to eq '1'
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "should NOT run catch_all if UnrecognizedMessagesController handles the message" do
|
|
147
|
+
$x = 0
|
|
148
|
+
class UnrecognizedMessagesController < Xip::Controller
|
|
149
|
+
def handle_unrecognized_message
|
|
150
|
+
handle_message(
|
|
151
|
+
'Hello World!' => proc {
|
|
152
|
+
$x = 1
|
|
153
|
+
do_nothing
|
|
154
|
+
},
|
|
155
|
+
'y' => proc { do_nothing }
|
|
156
|
+
)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
expect($redis.get(@error_slug)).to be_nil
|
|
161
|
+
controller.action(action: :action_with_unrecognized_msg)
|
|
162
|
+
expect($redis.get(@error_slug)).to be_nil
|
|
163
|
+
expect($x).to eq 1
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe "Xip::Dispatcher" do
|
|
6
|
+
|
|
7
|
+
class Xip::Services::Facebook::MessageHandler
|
|
8
|
+
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe 'coordinate' do
|
|
12
|
+
let(:dispatcher) {
|
|
13
|
+
Xip::Dispatcher.new(
|
|
14
|
+
service: 'facebook',
|
|
15
|
+
params: {},
|
|
16
|
+
headers: {}
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
it 'should call coordinate on the message handler' do
|
|
21
|
+
message_handler = double
|
|
22
|
+
expect(Xip::Services::Facebook::MessageHandler).to receive(:new).and_return(message_handler)
|
|
23
|
+
expect(message_handler).to receive(:coordinate)
|
|
24
|
+
|
|
25
|
+
dispatcher.coordinate
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe 'process' do
|
|
30
|
+
class StubbedBotController < Xip::Controller
|
|
31
|
+
def route
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
let(:dispatcher) {
|
|
37
|
+
Xip::Dispatcher.new(
|
|
38
|
+
service: 'facebook',
|
|
39
|
+
params: {},
|
|
40
|
+
headers: {}
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
let(:fb_message) { SampleMessage.new(service: 'facebook') }
|
|
44
|
+
let(:stubbed_controller) {
|
|
45
|
+
StubbedBotController.new(service_message: fb_message.message_with_text)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
it 'should call process on the message handler' do
|
|
49
|
+
message_handler = double
|
|
50
|
+
|
|
51
|
+
# Stub out the message handler to return a service_message
|
|
52
|
+
expect(Xip::Services::Facebook::MessageHandler).to receive(:new).and_return(message_handler)
|
|
53
|
+
expect(message_handler).to receive(:process).and_return(fb_message.message_with_text)
|
|
54
|
+
|
|
55
|
+
# Stub out BotController and set session
|
|
56
|
+
expect(BotController).to receive(:new).and_return(stubbed_controller)
|
|
57
|
+
stubbed_controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
|
58
|
+
|
|
59
|
+
dispatcher.process
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should log the incoming message if transcript_logging is enabled' do
|
|
63
|
+
message_handler = double
|
|
64
|
+
|
|
65
|
+
# Stub out the message handler to return a service_message
|
|
66
|
+
expect(Xip::Services::Facebook::MessageHandler).to receive(:new).and_return(message_handler)
|
|
67
|
+
expect(message_handler).to receive(:process).and_return(fb_message.message_with_text)
|
|
68
|
+
|
|
69
|
+
# Stub out BotController and set session
|
|
70
|
+
expect(BotController).to receive(:new).and_return(stubbed_controller)
|
|
71
|
+
stubbed_controller.current_session.set_session(new_flow: 'mr_tron', new_state: 'other_action')
|
|
72
|
+
|
|
73
|
+
Xip.config.transcript_logging = true
|
|
74
|
+
expect(dispatcher).to receive(:log_incoming_message).with(fb_message.message_with_text)
|
|
75
|
+
dispatcher.process
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Xip::Flow do
|
|
6
|
+
|
|
7
|
+
class CustomFlowMap
|
|
8
|
+
include Xip::Flow
|
|
9
|
+
|
|
10
|
+
flow :new_todo do
|
|
11
|
+
state :new
|
|
12
|
+
state :get_due_date
|
|
13
|
+
state :created
|
|
14
|
+
state :error
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
flow :hello do
|
|
18
|
+
state :say_hello
|
|
19
|
+
state :say_oi
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
flow "howdy" do
|
|
23
|
+
state :say_howdy
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
let(:flow_map) { CustomFlowMap.new }
|
|
28
|
+
|
|
29
|
+
describe "inititating with states" do
|
|
30
|
+
it "should init a state given a state name" do
|
|
31
|
+
flow_map.init(flow: 'new_todo', state: 'created')
|
|
32
|
+
expect(flow_map.current_state).to eq :created
|
|
33
|
+
|
|
34
|
+
flow_map.init(flow: 'new_todo', state: 'error')
|
|
35
|
+
expect(flow_map.current_state).to eq :error
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should raise an error if an invalid state is specified" do
|
|
39
|
+
expect {
|
|
40
|
+
flow_map.init(flow: 'new_todo', state: 'invalid')
|
|
41
|
+
}.to raise_error(Xip::Errors::InvalidStateTransition)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "accessing states" do
|
|
46
|
+
it "should default to the first flow and state" do
|
|
47
|
+
expect(flow_map.current_flow).to eq(:new_todo)
|
|
48
|
+
expect(flow_map.current_state).to eq(:new)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should support comparing states" do
|
|
52
|
+
first_state = CustomFlowMap.flow_spec[:new_todo].states[:new]
|
|
53
|
+
last_state = CustomFlowMap.flow_spec[:new_todo].states[:error]
|
|
54
|
+
expect(first_state < last_state).to be true
|
|
55
|
+
expect(last_state > first_state).to be true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should allow every state to be fetched for a flow" do
|
|
59
|
+
expect(CustomFlowMap.flow_spec[:new_todo].states.length).to eq 4
|
|
60
|
+
expect(CustomFlowMap.flow_spec[:hello].states.length).to eq 2
|
|
61
|
+
expect(CustomFlowMap.flow_spec[:new_todo].states.keys).to eq([:new, :get_due_date, :created, :error])
|
|
62
|
+
expect(CustomFlowMap.flow_spec[:hello].states.keys).to eq([:say_hello, :say_oi])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should return the states in an array for a given FlowMap instance" do
|
|
66
|
+
expect(flow_map.states).to eq [:new, :get_due_date, :created, :error]
|
|
67
|
+
flow_map.init(flow: :hello, state: :say_oi)
|
|
68
|
+
expect(flow_map.states).to eq [:say_hello, :say_oi]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should allow flows to be specified with strings" do
|
|
72
|
+
expect(CustomFlowMap.flow_spec[:howdy].states.length).to eq 1
|
|
73
|
+
expect(CustomFlowMap.flow_spec[:howdy].states.keys).to eq([:say_howdy])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should allow FlowMaps to be intialized with strings" do
|
|
77
|
+
flow_map.init(flow: "hello", state: "say_oi")
|
|
78
|
+
expect(flow_map.states).to eq [:say_hello, :say_oi]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Xip::Flow::State do
|
|
6
|
+
|
|
7
|
+
class SuperFlowMap
|
|
8
|
+
include Xip::Flow
|
|
9
|
+
|
|
10
|
+
flow :new_todo do
|
|
11
|
+
state :new
|
|
12
|
+
state :get_due_date
|
|
13
|
+
state :created, fails_to: :new
|
|
14
|
+
state :created2, fails_to: 'new_todo->new'
|
|
15
|
+
state :deprecated, redirects_to: 'new'
|
|
16
|
+
state :deprecated2, redirects_to: 'other_flow->say_hi'
|
|
17
|
+
state :new_opts, opt1: 'hello', opt2: 1
|
|
18
|
+
state :error
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:flow_map) { SuperFlowMap.new }
|
|
23
|
+
|
|
24
|
+
describe "flow states" do
|
|
25
|
+
it "should convert itself to a string" do
|
|
26
|
+
expect(flow_map.current_state.to_s).to be_a(String)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should convert itself to a symbol" do
|
|
30
|
+
expect(flow_map.current_state.to_sym).to be_a(Symbol)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "fails_to" do
|
|
35
|
+
it "should be nil for a state that has not specified a fails_to" do
|
|
36
|
+
expect(flow_map.current_state.fails_to).to be_nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should return the fail_state if a fails_to was specified" do
|
|
40
|
+
flow_map.init(flow: :new_todo, state: :created)
|
|
41
|
+
expect(flow_map.current_state.fails_to).to be_a(Xip::Session)
|
|
42
|
+
expect(flow_map.current_state.fails_to.state_string).to eq 'new'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should return the fail_state if a fails_to was specified as a session" do
|
|
46
|
+
flow_map.init(flow: :new_todo, state: :created2)
|
|
47
|
+
expect(flow_map.current_state.fails_to).to be_a(Xip::Session)
|
|
48
|
+
expect(flow_map.current_state.fails_to.state_string).to eq 'new'
|
|
49
|
+
expect(flow_map.current_state.fails_to.flow_string).to eq 'new_todo'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "redirects_to" do
|
|
54
|
+
it "should be nil for a state that has not specified a fails_to" do
|
|
55
|
+
expect(flow_map.current_state.redirects_to).to be_nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should return the redirects_to state if a redirects_to was specified" do
|
|
59
|
+
flow_map.init(flow: :new_todo, state: :deprecated)
|
|
60
|
+
expect(flow_map.current_state.redirects_to).to be_a(Xip::Session)
|
|
61
|
+
expect(flow_map.current_state.redirects_to.state_string).to eq 'new'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should return the redirects_to state if a redirects_to was specified as a session" do
|
|
65
|
+
flow_map.init(flow: :new_todo, state: :deprecated2)
|
|
66
|
+
expect(flow_map.current_state.redirects_to).to be_a(Xip::Session)
|
|
67
|
+
expect(flow_map.current_state.redirects_to.state_string).to eq 'say_hi'
|
|
68
|
+
expect(flow_map.current_state.redirects_to.flow_string).to eq 'other_flow'
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "opts" do
|
|
73
|
+
it "should return {} for a state that has not specified any opts" do
|
|
74
|
+
expect(flow_map.current_state.opts).to eq({})
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should return the opts if they were specified" do
|
|
78
|
+
flow_map.init(flow: :new_todo, state: :new_opts)
|
|
79
|
+
expect(flow_map.current_state.opts).to eq({ opt1: 'hello', opt2: 1 })
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "state incrementing and decrementing" do
|
|
84
|
+
it "should increment the state" do
|
|
85
|
+
flow_map.init(flow: :new_todo, state: :get_due_date)
|
|
86
|
+
new_state = flow_map.current_state + 1.state
|
|
87
|
+
expect(new_state).to eq(:created)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should decrement the state" do
|
|
91
|
+
flow_map.init(flow: :new_todo, state: :error)
|
|
92
|
+
new_state = flow_map.current_state - 6.states
|
|
93
|
+
expect(new_state).to eq(:get_due_date)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should return the first state if the decrement is out of bounds" do
|
|
97
|
+
flow_map.init(flow: :new_todo, state: :get_due_date)
|
|
98
|
+
new_state = flow_map.current_state - 5.states
|
|
99
|
+
expect(new_state).to eq(:new)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should return the last state if the increment is out of bounds" do
|
|
103
|
+
flow_map.init(flow: :new_todo, state: :created)
|
|
104
|
+
new_state = flow_map.current_state + 10.states
|
|
105
|
+
expect(new_state).to eq(:error)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe "Xip::Redis" do
|
|
6
|
+
|
|
7
|
+
class RedisTester
|
|
8
|
+
include Xip::Redis
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
let(:redis_tester) { RedisTester.new }
|
|
12
|
+
let(:key) { 'xyz' }
|
|
13
|
+
|
|
14
|
+
describe "get_key" do
|
|
15
|
+
it "should return the key from Redis if an expiration is not set" do
|
|
16
|
+
$redis.set(key, 'abc')
|
|
17
|
+
expect(redis_tester.send(:get_key, key)).to eq 'abc'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should call getex if an expiration is set" do
|
|
21
|
+
expect(redis_tester).to receive(:getex).with(key, 30)
|
|
22
|
+
redis_tester.send(:get_key, key, expiration: 30)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "delete_key" do
|
|
27
|
+
it 'should delete the key from Redis' do
|
|
28
|
+
$redis.set(key, 'abc')
|
|
29
|
+
expect(redis_tester.send(:get_key, key)).to eq 'abc'
|
|
30
|
+
redis_tester.send(:delete_key, key)
|
|
31
|
+
expect(redis_tester.send(:get_key, key)).to be_nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "getex" do
|
|
36
|
+
it "should return the key from Redis" do
|
|
37
|
+
Xip.config.session_ttl = 50
|
|
38
|
+
$redis.set(key, 'abc')
|
|
39
|
+
expect(redis_tester.send(:getex, key)).to eq 'abc'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should set the expiration of a key in Redis" do
|
|
43
|
+
Xip.config.session_ttl = 50
|
|
44
|
+
$redis.set(key, 'abc')
|
|
45
|
+
redis_tester.send(:getex, key)
|
|
46
|
+
expect($redis.ttl(key)).to be_between(0, 50).inclusive
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should update the expiration of a key in Redis" do
|
|
50
|
+
Xip.config.session_ttl = 500
|
|
51
|
+
$redis.setex(key, 50, 'abc')
|
|
52
|
+
redis_tester.send(:getex, key)
|
|
53
|
+
expect($redis.ttl(key)).to be_between(400, 500).inclusive
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "persist_key" do
|
|
58
|
+
it "should set the key in Redis" do
|
|
59
|
+
Xip.config.session_ttl = 50
|
|
60
|
+
redis_tester.send(:persist_key, key: key, value: 'zzz')
|
|
61
|
+
expect($redis.get(key)).to eq 'zzz'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should set the expiration to session_ttl if none specified" do
|
|
65
|
+
Xip.config.session_ttl = 50
|
|
66
|
+
redis_tester.send(:persist_key, key: key, value: 'zzz')
|
|
67
|
+
expect($redis.ttl(key)).to be_between(0, 50).inclusive
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should set the expiration to the specified value when provided" do
|
|
71
|
+
Xip.config.session_ttl = 50
|
|
72
|
+
redis_tester.send(:persist_key, key: key, value: 'zzz', expiration: 500)
|
|
73
|
+
expect($redis.ttl(key)).to be_between(400, 500).inclusive
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|