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,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe "Xip::ScheduledReplyJob" do
|
|
6
|
+
|
|
7
|
+
let(:scheduled_reply_job) { Xip::ScheduledReplyJob.new }
|
|
8
|
+
|
|
9
|
+
it "should instantiate BotController with service_message, set flow and state, and route" do
|
|
10
|
+
service_msg_double = double('service_message')
|
|
11
|
+
expect(Xip::ServiceMessage).to receive(:new).with(service: 'twilio').and_return(service_msg_double)
|
|
12
|
+
expect(service_msg_double).to receive(:sender_id=).with('+18885551212')
|
|
13
|
+
expect(service_msg_double).to receive(:target_id=).with('33322')
|
|
14
|
+
|
|
15
|
+
bot_controller_double = double('bot_controller')
|
|
16
|
+
expect(BotController).to receive(:new).with(service_message: service_msg_double).and_return(bot_controller_double)
|
|
17
|
+
expect(bot_controller_double).to receive(:step_to).with(flow: 'my_flow', state: 'say_hi')
|
|
18
|
+
|
|
19
|
+
scheduled_reply_job = Xip::ScheduledReplyJob.new
|
|
20
|
+
scheduled_reply_job.perform('twilio', '+18885551212', 'my_flow', 'say_hi', '33322')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe "Xip::ServiceReply" do
|
|
6
|
+
|
|
7
|
+
let(:recipient_id) { "8b3e0a3c-62f1-401e-8b0f-615c9d256b1f" }
|
|
8
|
+
let(:yaml_reply) { File.read(File.join(File.dirname(__FILE__), 'replies', 'hello.yml.erb')) }
|
|
9
|
+
|
|
10
|
+
describe "nested reply with ERB" do
|
|
11
|
+
it "should load all the replies" do
|
|
12
|
+
first_name = "Presley"
|
|
13
|
+
|
|
14
|
+
service_reply = Xip::ServiceReply.new(
|
|
15
|
+
recipient_id: recipient_id,
|
|
16
|
+
yaml_reply: yaml_reply,
|
|
17
|
+
context: binding,
|
|
18
|
+
preprocessor: :erb
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
expect(service_reply.replies.size).to eq 5
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should load all replies as Xip::Reply objects" do
|
|
25
|
+
first_name = "Presley"
|
|
26
|
+
|
|
27
|
+
service_reply = Xip::ServiceReply.new(
|
|
28
|
+
recipient_id: recipient_id,
|
|
29
|
+
yaml_reply: yaml_reply,
|
|
30
|
+
context: binding,
|
|
31
|
+
preprocessor: :erb
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
expect(service_reply.replies).to all(be_an(Xip::Reply))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should replace the ERB tag" do
|
|
38
|
+
first_name = "Presley"
|
|
39
|
+
|
|
40
|
+
service_reply = Xip::ServiceReply.new(
|
|
41
|
+
recipient_id: recipient_id,
|
|
42
|
+
yaml_reply: yaml_reply,
|
|
43
|
+
context: binding,
|
|
44
|
+
preprocessor: :erb
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
phrase_in_reply = service_reply.replies.first['text']
|
|
48
|
+
expect(phrase_in_reply).to eq "Hi, Presley. Welcome to Xip bot..."
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should raise Xip::Errors::UndefinedVariable when local variable is not available" do
|
|
52
|
+
expect {
|
|
53
|
+
service_reply = Xip::ServiceReply.new(
|
|
54
|
+
recipient_id: recipient_id,
|
|
55
|
+
yaml_reply: yaml_reply,
|
|
56
|
+
context: binding,
|
|
57
|
+
preprocessor: :erb
|
|
58
|
+
)
|
|
59
|
+
}.to raise_error(Xip::Errors::UndefinedVariable)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "processing a reply without a preprocessor specified" do
|
|
64
|
+
it "should not replace the ERB tag when no preprocessor is specified" do
|
|
65
|
+
first_name = "Gisele"
|
|
66
|
+
|
|
67
|
+
service_reply = Xip::ServiceReply.new(
|
|
68
|
+
recipient_id: recipient_id,
|
|
69
|
+
yaml_reply: yaml_reply,
|
|
70
|
+
context: binding
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
phrase_in_reply = service_reply.replies.first['text']
|
|
74
|
+
expect(phrase_in_reply).to eq "Hi, <%= first_name %>. Welcome to Xip bot..."
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should not replace the ERB tag when :none is specified as the preprocessor" do
|
|
78
|
+
first_name = "Gisele"
|
|
79
|
+
|
|
80
|
+
service_reply = Xip::ServiceReply.new(
|
|
81
|
+
recipient_id: recipient_id,
|
|
82
|
+
yaml_reply: yaml_reply,
|
|
83
|
+
context: binding,
|
|
84
|
+
preprocessor: :none
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
phrase_in_reply = service_reply.replies.first['text']
|
|
88
|
+
expect(phrase_in_reply).to eq "Hi, <%= first_name %>. Welcome to Xip bot..."
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
class FlowMap
|
|
6
|
+
include Xip::Flow
|
|
7
|
+
|
|
8
|
+
flow :new_todo do
|
|
9
|
+
state :new
|
|
10
|
+
state :get_due_date
|
|
11
|
+
state :created, fails_to: :new
|
|
12
|
+
state :error
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
flow :marco do
|
|
16
|
+
state :polo
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "Xip::Session" do
|
|
21
|
+
let(:id) { '0xDEADBEEF' }
|
|
22
|
+
|
|
23
|
+
it "should raise an error if $redis is not set" do
|
|
24
|
+
$redis = nil
|
|
25
|
+
|
|
26
|
+
expect {
|
|
27
|
+
Xip::Session.new(id: id)
|
|
28
|
+
}.to raise_error(Xip::Errors::RedisNotConfigured)
|
|
29
|
+
|
|
30
|
+
$redis = MockRedis.new
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "without a session" do
|
|
34
|
+
let(:session) { Xip::Session.new(id: id) }
|
|
35
|
+
|
|
36
|
+
it "should have nil flow and state" do
|
|
37
|
+
expect(session.flow).to be_nil
|
|
38
|
+
expect(session.state).to be_nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should have nil flow_string and state_string" do
|
|
42
|
+
expect(session.flow_string).to be_nil
|
|
43
|
+
expect(session.state_string).to be_nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should respond to present? and blank?" do
|
|
47
|
+
expect(session.present?).to be false
|
|
48
|
+
expect(session.blank?).to be true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "with a session" do
|
|
53
|
+
let(:session) do
|
|
54
|
+
session = Xip::Session.new(id: id)
|
|
55
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
56
|
+
session
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should return the FlowMap" do
|
|
60
|
+
expect(session.flow).to be_a(FlowMap)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should return the state" do
|
|
64
|
+
expect(session.state).to be_a(Xip::Flow::State)
|
|
65
|
+
expect(session.state).to eq :polo
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should return the flow_string" do
|
|
69
|
+
expect(session.flow_string).to eq "marco"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should return the state_string" do
|
|
73
|
+
expect(session.state_string).to eq "polo"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should respond to present? and blank?" do
|
|
77
|
+
expect(session.present?).to be true
|
|
78
|
+
expect(session.blank?).to be false
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe "incrementing and decrementing" do
|
|
83
|
+
let(:session) { Xip::Session.new(id: id) }
|
|
84
|
+
|
|
85
|
+
it "should increment the state" do
|
|
86
|
+
session.set_session(new_flow: 'new_todo', new_state: 'get_due_date')
|
|
87
|
+
new_session = session + 1.state
|
|
88
|
+
expect(new_session.state_string).to eq('created')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should decrement the state" do
|
|
92
|
+
session.set_session(new_flow: 'new_todo', new_state: 'error')
|
|
93
|
+
new_session = session - 2.states
|
|
94
|
+
expect(new_session.state_string).to eq('get_due_date')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should return the first state if the decrement is out of bounds" do
|
|
98
|
+
session.set_session(new_flow: 'new_todo', new_state: 'get_due_date')
|
|
99
|
+
new_session = session - 5.states
|
|
100
|
+
expect(new_session.state_string).to eq('new')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should return the last state if the increment is out of bounds" do
|
|
104
|
+
session.set_session(new_flow: 'new_todo', new_state: 'created')
|
|
105
|
+
new_session = session + 5.states
|
|
106
|
+
expect(new_session.state_string).to eq('error')
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe "==" do
|
|
111
|
+
let(:session) {
|
|
112
|
+
_session = Xip::Session.new(id: id, type: :primary)
|
|
113
|
+
_session.set_session(new_flow: 'hello', new_state: 'say_hola')
|
|
114
|
+
_session
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
it "should return false if the session ids do not" do
|
|
118
|
+
other_session = Xip::Session.new(id: 'xyz123', type: :primary)
|
|
119
|
+
other_session.set_session(new_flow: 'hello', new_state: 'say_hola')
|
|
120
|
+
expect(session == other_session).to be false
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "should return false if the states do not" do
|
|
124
|
+
other_session = Xip::Session.new(id: id, type: :primary)
|
|
125
|
+
other_session.set_session(new_flow: 'hello', new_state: 'say_hola2')
|
|
126
|
+
expect(session == other_session).to be false
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "should return false if flows do not match" do
|
|
130
|
+
other_session = Xip::Session.new(id: id, type: :primary)
|
|
131
|
+
other_session.set_session(new_flow: 'hello2', new_state: 'say_hola')
|
|
132
|
+
expect(session == other_session).to be false
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it 'should return false if the session type does not match' do
|
|
136
|
+
other_session = Xip::Session.new(id: id, type: :back_to)
|
|
137
|
+
other_session.set_session(new_flow: 'hello', new_state: 'say_hola')
|
|
138
|
+
expect(session == other_session).to be false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'should return true if the session id, flow, state, and session types match' do
|
|
142
|
+
other_session = Xip::Session.new(id: id, type: :primary)
|
|
143
|
+
other_session.set_session(new_flow: 'hello', new_state: 'say_hola')
|
|
144
|
+
expect(session == other_session).to be true
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe "self.is_a_session_string?" do
|
|
149
|
+
it "should return false for state strings" do
|
|
150
|
+
session_string = 'say_hello'
|
|
151
|
+
expect(Xip::Session.is_a_session_string?(session_string)).to be false
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "should return false for an incomplete session string" do
|
|
155
|
+
session_string = 'hello->'
|
|
156
|
+
expect(Xip::Session.is_a_session_string?(session_string)).to be false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "should return true for a complete session string" do
|
|
160
|
+
session_string = 'hello->say_hello'
|
|
161
|
+
expect(Xip::Session.is_a_session_string?(session_string)).to be true
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe "self.canonical_session_slug" do
|
|
166
|
+
it "should generate a canonical session slug given a flow and state as symbols" do
|
|
167
|
+
expect(
|
|
168
|
+
Xip::Session.canonical_session_slug(flow: :hello, state: :say_hello)
|
|
169
|
+
).to eq 'hello->say_hello'
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should generate a canonical session slug given a flow and state as strings" do
|
|
173
|
+
expect(
|
|
174
|
+
Xip::Session.canonical_session_slug(flow: 'hello', state: 'say_hello')
|
|
175
|
+
).to eq 'hello->say_hello'
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
describe "self.flow_and_state_from_session_slug" do
|
|
180
|
+
it "should return the flow and string as a hash with symbolized keys" do
|
|
181
|
+
slug = 'hello->say_hello'
|
|
182
|
+
expect(
|
|
183
|
+
Xip::Session.flow_and_state_from_session_slug(slug: slug)
|
|
184
|
+
).to eq({ flow: 'hello', state: 'say_hello' })
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "should not raise if slug is nil" do
|
|
188
|
+
slug = nil
|
|
189
|
+
expect(
|
|
190
|
+
Xip::Session.flow_and_state_from_session_slug(slug: slug)
|
|
191
|
+
).to eq({ flow: nil, state: nil })
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe "setting sessions" do
|
|
196
|
+
let(:session) { Xip::Session.new(id: id) }
|
|
197
|
+
let(:previous_session) { Xip::Session.new(id: id, type: :previous) }
|
|
198
|
+
let(:back_to_session) { Xip::Session.new(id: id, type: :back_to) }
|
|
199
|
+
|
|
200
|
+
before(:each) do
|
|
201
|
+
$redis.del(id)
|
|
202
|
+
$redis.del([id, 'previous'].join('-'))
|
|
203
|
+
$redis.del([id, 'back_to'].join('-'))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "should store the new session" do
|
|
207
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
208
|
+
expect($redis.get(id)).to eq 'marco->polo'
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should store the current_session to previous_session" do
|
|
212
|
+
$redis.set(id, 'new_todo->new')
|
|
213
|
+
$redis.set([id, 'previous'].join('-'), 'new_todo->error')
|
|
214
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
215
|
+
expect(previous_session.get_session).to eq 'new_todo->new'
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it "should not update previous_session if it matches current_session" do
|
|
219
|
+
$redis.set(id, 'marco->polo')
|
|
220
|
+
$redis.set([id, 'previous'].join('-'), 'new_todo->new')
|
|
221
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
222
|
+
expect(previous_session.get_session).to eq 'new_todo->new'
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "should set an expiration for current_session if session_ttl is specified" do
|
|
226
|
+
Xip.config.session_ttl = 500
|
|
227
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
228
|
+
expect($redis.ttl(id)).to be > 0
|
|
229
|
+
Xip.config.session_ttl = 0
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "should set an expiration for previous_session if session_ttl is specified" do
|
|
233
|
+
Xip.config.session_ttl = 500
|
|
234
|
+
$redis.set(id, 'new_todo->new')
|
|
235
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
236
|
+
expect($redis.ttl([id, 'previous'].join('-'))).to be > 0
|
|
237
|
+
Xip.config.session_ttl = 0
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "should NOT set an expiration if session_ttl is not specified" do
|
|
241
|
+
Xip.config.session_ttl = 0
|
|
242
|
+
session.set_session(new_flow: 'new_todo', new_state: 'get_due_date')
|
|
243
|
+
expect($redis.ttl(id)).to eq -1 # Does not expire
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "should set the session for back_to" do
|
|
247
|
+
back_to_session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
248
|
+
expect($redis.get([id, 'back_to'].join('-'))).to eq 'marco->polo'
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "should set an expiration for back_to if session_ttl is specified" do
|
|
252
|
+
Xip.config.session_ttl = 500
|
|
253
|
+
back_to_session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
254
|
+
expect($redis.ttl([id, 'back_to'].join('-'))).to be > 0
|
|
255
|
+
Xip.config.session_ttl = 0
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe "getting sessions" do
|
|
260
|
+
let(:session) { Xip::Session.new(id: id) }
|
|
261
|
+
let(:previous_session) { Xip::Session.new(id: id, type: :previous) }
|
|
262
|
+
let(:back_to_session) { Xip::Session.new(id: id, type: :back_to) }
|
|
263
|
+
|
|
264
|
+
before(:each) do
|
|
265
|
+
$redis.del(id)
|
|
266
|
+
$redis.del([id, 'previous'].join('-'))
|
|
267
|
+
$redis.del([id, 'back_to'].join('-'))
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it "should return the stored current_session" do
|
|
271
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
272
|
+
expect(session.get_session).to eq 'marco->polo'
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it "should return the stored previous_session if previous is requested" do
|
|
276
|
+
$redis.set(id, 'new_todo->new')
|
|
277
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
278
|
+
expect(previous_session.get_session).to eq 'new_todo->new'
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "should update the expiration of current_session if session_ttl is set" do
|
|
282
|
+
Xip.config.session_ttl = 50
|
|
283
|
+
session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
284
|
+
expect($redis.ttl(id)).to be_between(0, 50).inclusive
|
|
285
|
+
|
|
286
|
+
Xip.config.session_ttl = 500
|
|
287
|
+
session.session = nil # reset memoization
|
|
288
|
+
session.get_session
|
|
289
|
+
expect($redis.ttl(id)).to be > 100
|
|
290
|
+
|
|
291
|
+
Xip.config.session_ttl = 0
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it "should return the stored back_to_session" do
|
|
295
|
+
back_to_session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
296
|
+
expect(back_to_session.get_session).to eq 'marco->polo'
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "should update the expiration of back_to_session if session_ttl is set" do
|
|
300
|
+
Xip.config.session_ttl = 50
|
|
301
|
+
back_to_session.set_session(new_flow: 'marco', new_state: 'polo')
|
|
302
|
+
expect($redis.ttl([id, 'back_to'].join('-'))).to be_between(0, 50).inclusive
|
|
303
|
+
|
|
304
|
+
Xip.config.session_ttl = 500
|
|
305
|
+
back_to_session.session = nil # reset memoization
|
|
306
|
+
back_to_session.get_session
|
|
307
|
+
expect($redis.ttl([id, 'back_to'].join('-'))).to be > 100
|
|
308
|
+
|
|
309
|
+
Xip.config.session_ttl = 0
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
describe "clearing sessions" do
|
|
314
|
+
let(:session) { Xip::Session.new(id: id) }
|
|
315
|
+
let(:previous_session) { Xip::Session.new(id: id, type: :previous) }
|
|
316
|
+
let(:back_to_session) { Xip::Session.new(id: id, type: :back_to) }
|
|
317
|
+
|
|
318
|
+
before(:each) do
|
|
319
|
+
session.send(:persist_key, key: session.session_key, value: '1')
|
|
320
|
+
previous_session.send(:persist_key, key: previous_session.session_key, value: '1')
|
|
321
|
+
back_to_session.send(:persist_key, key: back_to_session.session_key, value: '1')
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "should remove a default session from Redis" do
|
|
325
|
+
expect($redis.get(session.session_key)).to eq '1'
|
|
326
|
+
session.clear_session
|
|
327
|
+
expect($redis.get(session.session_key)).to be_nil
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it "should remove a previous session from Redis" do
|
|
331
|
+
expect($redis.get(previous_session.session_key)).to eq '1'
|
|
332
|
+
previous_session.clear_session
|
|
333
|
+
expect($redis.get(previous_session.session_key)).to be_nil
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it "should remove a back_to session from Redis" do
|
|
337
|
+
expect($redis.get(back_to_session.session_key)).to eq '1'
|
|
338
|
+
back_to_session.clear_session
|
|
339
|
+
expect($redis.get(back_to_session.session_key)).to be_nil
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
describe "self.slugify" do
|
|
344
|
+
it "should return a session slug given a flow and state" do
|
|
345
|
+
expect(Xip::Session.slugify(flow: 'hello', state: 'world')).to eq 'hello->world'
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
it "should raise an ArgumentError if flow is blank" do
|
|
349
|
+
expect {
|
|
350
|
+
Xip::Session.slugify(flow: '', state: 'world')
|
|
351
|
+
}.to raise_error(ArgumentError)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it "should raise an ArgumentError if state is blank" do
|
|
355
|
+
expect {
|
|
356
|
+
Xip::Session.slugify(flow: 'hello', state: nil)
|
|
357
|
+
}.to raise_error(ArgumentError)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it "should raise an ArgumentError if flow and state are blank" do
|
|
361
|
+
expect {
|
|
362
|
+
Xip::Session.slugify(flow: nil, state: nil)
|
|
363
|
+
}.to raise_error(ArgumentError)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|