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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +116 -0
  3. data/.gitignore +12 -0
  4. data/CHANGELOG.md +135 -0
  5. data/Gemfile +4 -1
  6. data/Gemfile.lock +65 -15
  7. data/LICENSE +6 -4
  8. data/README.md +51 -1
  9. data/VERSION +1 -0
  10. data/bin/xip +3 -11
  11. data/lib/xip.rb +1 -3
  12. data/lib/xip/base.rb +189 -0
  13. data/lib/xip/cli.rb +273 -0
  14. data/lib/xip/cli_base.rb +24 -0
  15. data/lib/xip/commands/command.rb +13 -0
  16. data/lib/xip/commands/console.rb +74 -0
  17. data/lib/xip/commands/server.rb +63 -0
  18. data/lib/xip/configuration.rb +56 -0
  19. data/lib/xip/controller/callbacks.rb +63 -0
  20. data/lib/xip/controller/catch_all.rb +84 -0
  21. data/lib/xip/controller/controller.rb +274 -0
  22. data/lib/xip/controller/dev_jumps.rb +40 -0
  23. data/lib/xip/controller/dynamic_delay.rb +61 -0
  24. data/lib/xip/controller/helpers.rb +128 -0
  25. data/lib/xip/controller/interrupt_detect.rb +99 -0
  26. data/lib/xip/controller/messages.rb +283 -0
  27. data/lib/xip/controller/nlp.rb +49 -0
  28. data/lib/xip/controller/replies.rb +281 -0
  29. data/lib/xip/controller/unrecognized_message.rb +61 -0
  30. data/lib/xip/core_ext.rb +5 -0
  31. data/lib/xip/core_ext/numeric.rb +10 -0
  32. data/lib/xip/core_ext/string.rb +18 -0
  33. data/lib/xip/dispatcher.rb +68 -0
  34. data/lib/xip/errors.rb +55 -0
  35. data/lib/xip/flow/base.rb +69 -0
  36. data/lib/xip/flow/specification.rb +56 -0
  37. data/lib/xip/flow/state.rb +82 -0
  38. data/lib/xip/generators/builder.rb +41 -0
  39. data/lib/xip/generators/builder/.gitignore +30 -0
  40. data/lib/xip/generators/builder/Gemfile +19 -0
  41. data/lib/xip/generators/builder/Procfile.dev +2 -0
  42. data/lib/xip/generators/builder/README.md +9 -0
  43. data/lib/xip/generators/builder/Rakefile +2 -0
  44. data/lib/xip/generators/builder/bot/controllers/bot_controller.rb +55 -0
  45. data/lib/xip/generators/builder/bot/controllers/catch_alls_controller.rb +21 -0
  46. data/lib/xip/generators/builder/bot/controllers/concerns/.keep +0 -0
  47. data/lib/xip/generators/builder/bot/controllers/goodbyes_controller.rb +9 -0
  48. data/lib/xip/generators/builder/bot/controllers/hellos_controller.rb +9 -0
  49. data/lib/xip/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
  50. data/lib/xip/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
  51. data/lib/xip/generators/builder/bot/helpers/bot_helper.rb +2 -0
  52. data/lib/xip/generators/builder/bot/models/bot_record.rb +3 -0
  53. data/lib/xip/generators/builder/bot/models/concerns/.keep +0 -0
  54. data/lib/xip/generators/builder/bot/replies/catch_alls/level1.yml +2 -0
  55. data/lib/xip/generators/builder/bot/replies/goodbyes/say_goodbye.yml +2 -0
  56. data/lib/xip/generators/builder/bot/replies/hellos/say_hello.yml +2 -0
  57. data/lib/xip/generators/builder/config.ru +4 -0
  58. data/lib/xip/generators/builder/config/boot.rb +6 -0
  59. data/lib/xip/generators/builder/config/database.yml +25 -0
  60. data/lib/xip/generators/builder/config/environment.rb +2 -0
  61. data/lib/xip/generators/builder/config/flow_map.rb +25 -0
  62. data/lib/xip/generators/builder/config/initializers/autoload.rb +8 -0
  63. data/lib/xip/generators/builder/config/initializers/inflections.rb +16 -0
  64. data/lib/xip/generators/builder/config/puma.rb +25 -0
  65. data/lib/xip/generators/builder/config/services.yml +35 -0
  66. data/lib/xip/generators/builder/config/sidekiq.yml +3 -0
  67. data/lib/xip/generators/builder/db/seeds.rb +7 -0
  68. data/lib/xip/generators/generate.rb +39 -0
  69. data/lib/xip/generators/generate/flow/controllers/controller.tt +7 -0
  70. data/lib/xip/generators/generate/flow/helpers/helper.tt +3 -0
  71. data/lib/xip/generators/generate/flow/replies/ask_example.tt +9 -0
  72. data/lib/xip/helpers/redis.rb +40 -0
  73. data/lib/xip/jobs.rb +9 -0
  74. data/lib/xip/lock.rb +82 -0
  75. data/lib/xip/logger.rb +9 -3
  76. data/lib/xip/migrations/configurator.rb +73 -0
  77. data/lib/xip/migrations/generators.rb +16 -0
  78. data/lib/xip/migrations/railtie_config.rb +14 -0
  79. data/lib/xip/migrations/tasks.rb +43 -0
  80. data/lib/xip/nlp/client.rb +21 -0
  81. data/lib/xip/nlp/result.rb +56 -0
  82. data/lib/xip/reloader.rb +89 -0
  83. data/lib/xip/reply.rb +36 -0
  84. data/lib/xip/scheduled_reply.rb +18 -0
  85. data/lib/xip/server.rb +63 -0
  86. data/lib/xip/service_message.rb +17 -0
  87. data/lib/xip/service_reply.rb +44 -0
  88. data/lib/xip/services/base_client.rb +24 -0
  89. data/lib/xip/services/base_message_handler.rb +27 -0
  90. data/lib/xip/services/base_reply_handler.rb +72 -0
  91. data/lib/xip/services/jobs/handle_message_job.rb +21 -0
  92. data/lib/xip/session.rb +203 -0
  93. data/lib/xip/version.rb +7 -1
  94. data/logo.svg +17 -0
  95. data/spec/configuration_spec.rb +93 -0
  96. data/spec/controller/callbacks_spec.rb +217 -0
  97. data/spec/controller/catch_all_spec.rb +154 -0
  98. data/spec/controller/controller_spec.rb +889 -0
  99. data/spec/controller/dynamic_delay_spec.rb +70 -0
  100. data/spec/controller/helpers_spec.rb +119 -0
  101. data/spec/controller/interrupt_detect_spec.rb +171 -0
  102. data/spec/controller/messages_spec.rb +744 -0
  103. data/spec/controller/nlp_spec.rb +93 -0
  104. data/spec/controller/replies_spec.rb +694 -0
  105. data/spec/controller/unrecognized_message_spec.rb +168 -0
  106. data/spec/dispatcher_spec.rb +79 -0
  107. data/spec/flow/flow_spec.rb +82 -0
  108. data/spec/flow/state_spec.rb +109 -0
  109. data/spec/helpers/redis_spec.rb +77 -0
  110. data/spec/lock_spec.rb +100 -0
  111. data/spec/nlp/client_spec.rb +23 -0
  112. data/spec/nlp/result_spec.rb +57 -0
  113. data/spec/replies/hello.yml.erb +15 -0
  114. data/spec/replies/messages/say_hola.yml+facebook.erb +6 -0
  115. data/spec/replies/messages/say_hola.yml+twilio.erb +6 -0
  116. data/spec/replies/messages/say_hola.yml.erb +6 -0
  117. data/spec/replies/messages/say_howdy_with_dynamic.yml +79 -0
  118. data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
  119. data/spec/replies/messages/say_offer.yml +6 -0
  120. data/spec/replies/messages/say_offer_with_dynamic.yml +6 -0
  121. data/spec/replies/messages/say_oi.yml.erb +15 -0
  122. data/spec/replies/messages/say_randomize_speech.yml +10 -0
  123. data/spec/replies/messages/say_randomize_text.yml +10 -0
  124. data/spec/replies/messages/say_yo.yml +6 -0
  125. data/spec/replies/messages/say_yo.yml+twitter +6 -0
  126. data/spec/replies/messages/sub1/sub2/say_nested.yml +10 -0
  127. data/spec/reply_spec.rb +61 -0
  128. data/spec/scheduled_reply_spec.rb +23 -0
  129. data/spec/service_reply_spec.rb +92 -0
  130. data/spec/session_spec.rb +366 -0
  131. data/spec/spec_helper.rb +22 -66
  132. data/spec/support/alternate_helpers/foo_helper.rb +5 -0
  133. data/spec/support/controllers/vaders_controller.rb +24 -0
  134. data/spec/support/helpers/fun/games_helper.rb +7 -0
  135. data/spec/support/helpers/fun/pdf_helper.rb +7 -0
  136. data/spec/support/helpers/standalone_helper.rb +5 -0
  137. data/spec/support/helpers_typo/users_helper.rb +2 -0
  138. data/spec/support/nlp_clients/dialogflow.rb +9 -0
  139. data/spec/support/nlp_clients/luis.rb +9 -0
  140. data/spec/support/nlp_results/luis_result.rb +163 -0
  141. data/spec/support/sample_messages.rb +66 -0
  142. data/spec/support/services.yml +31 -0
  143. data/spec/support/services_with_erb.yml +31 -0
  144. data/spec/version_spec.rb +16 -0
  145. data/xip.gemspec +25 -14
  146. 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