client_for_poslynx 0.9.0 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,313 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module ClientForPoslynx
6
+
7
+ describe Net::EM_Session do
8
+ subject {
9
+ described_class.new( connector, em_system: em_system )
10
+ }
11
+ let( :connector ) { double(
12
+ :connector,
13
+ request_pending?: false,
14
+ latest_request: nil,
15
+ ) }
16
+ let( :em_system ) { double(:em_system) }
17
+
18
+ it "allows making a request and returning the response" do
19
+ expect( connector ).to receive( :connect ) do |opts|
20
+ opts[:on_success].call
21
+ end
22
+ allow( connector ).to receive( :send_request ) do |data, opts|
23
+ opts[:on_response].call :the_response
24
+ end
25
+
26
+ response = nil
27
+ subject.execute do |s|
28
+ response = s.request( :the_request_data )
29
+ end
30
+
31
+ expect( response ).to eq( :the_response )
32
+ end
33
+
34
+ it "raises an exception when making a request with an initial connection failure" do
35
+ expect( connector ).to receive( :connect ) do |opts|
36
+ opts[:on_failure].call
37
+ end
38
+
39
+ exception = nil
40
+ subject.execute do |s|
41
+ begin
42
+ s.request( :the_request_data )
43
+ rescue => ex
44
+ exception = ex
45
+ end
46
+ end
47
+
48
+ expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
49
+ end
50
+
51
+ it "raises an exception when making a request that fails" do
52
+ expect( connector ).to receive( :connect ) do |opts|
53
+ opts[:on_success].call
54
+ end
55
+ allow( connector ).to receive( :send_request ) do |data, opts|
56
+ opts[:on_failure].call
57
+ end
58
+
59
+ exception = nil
60
+ subject.execute do |s|
61
+ begin
62
+ s.request( :the_request_data )
63
+ rescue => ex
64
+ exception = ex
65
+ end
66
+ end
67
+
68
+ expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
69
+ end
70
+
71
+ context "when an existing pin pad reset request is pending" do
72
+ before do
73
+ allow( connector ).to receive( :request_pending? ).and_return( true )
74
+ allow( connector ).to receive( :latest_request ).and_return(
75
+ Net::EMC.RequestCall(
76
+ prev_request_data, { on_failure: prev_on_failure}
77
+ )
78
+ )
79
+ end
80
+
81
+ let( :prev_request_data ) {
82
+ Data::Requests::PinPadReset.new
83
+ }
84
+ let( :prev_on_failure ) { double(:prev_on_failure, call: nil) }
85
+
86
+ it "usurps the pending request when making a new pin pad reset request" do
87
+ allow( connector ).to receive( :get_response ) do |opts|
88
+ opts[:on_response].call :the_response
89
+ end
90
+
91
+ response = nil
92
+ subject.execute do |s|
93
+ response = s.request( Data::Requests::PinPadReset.new )
94
+ end
95
+
96
+ expect( prev_on_failure ).to have_received( :call )
97
+ expect( response ).to eq( :the_response )
98
+ end
99
+ end
100
+
101
+ context "when a request is pending" do
102
+ before do
103
+ allow( connector ).to receive( :connection_status ).and_return( :connected )
104
+ allow( connector ).to receive( :request_pending? ).and_return( true )
105
+ allow( connector ).to receive( :latest_request ).and_return(
106
+ Net::EMC.RequestCall(
107
+ prev_request_data,
108
+ {
109
+ on_response: prev_on_response,
110
+ on_failure: prev_on_failure,
111
+ on_detached: prev_on_detached,
112
+ }
113
+ )
114
+ )
115
+ end
116
+ let( :prev_request_data ) { Data::Requests::PinPadInitialize.new }
117
+ let( :prev_on_response ) { double(:prev_on_response, call: nil) }
118
+ let( :prev_on_failure ) { double(:prev_on_failure, call: nil) }
119
+ let( :prev_on_detached ) { double(:prev_on_detached, call: nil) }
120
+
121
+ context "making a new request of the same type" do
122
+ it "raises an appropriate exception" do
123
+ request_data = Data::Requests::PinPadInitialize.new
124
+
125
+ exception = nil
126
+ subject.execute do |s|
127
+ begin
128
+ s.request( request_data )
129
+ rescue => ex
130
+ exception = ex
131
+ end
132
+ end
133
+
134
+ expect( exception ).to be_kind_of( Net::EM_Session::ConflictingRequestError )
135
+ end
136
+ end
137
+
138
+ context "making a new request of a different type" do
139
+ it "supplants the pending request if possible" do
140
+ request_data = Data::Requests::PinPadDisplayMessage.new
141
+ response_data = Data::Responses::PinPadDisplayMessage.new
142
+ allow( connector ).to receive( :connect ) do |opts|
143
+ opts[:on_success].call
144
+ end
145
+ allow( connector ).to receive( :send_request ).with( request_data, anything ) do |data, opts|
146
+ opts[:on_response].call response_data
147
+ end
148
+
149
+ response = nil
150
+ subject.execute do |s|
151
+ response = s.request( request_data )
152
+ end
153
+
154
+ expect( prev_on_failure ).to have_received( :call )
155
+ expect( response ).to eq( response_data )
156
+ end
157
+
158
+ it "detaches the other event chain if supplanting the pending request is unsuccessful" do
159
+ # FIXME: This is awfully convoluted, even by comparison
160
+ # with other examples in this spec file.
161
+ allow( connector ).to receive( :connect ) do |opts|
162
+ opts[:on_success].call
163
+ end
164
+
165
+ request_data = Data::Requests::PinPadDisplayMessage.new
166
+ first_response_data = Data::Responses::PinPadInitialize.new
167
+ second_response_data = Data::Responses::PinPadDisplayMessage.new
168
+
169
+ expect( connector ).to receive( :send_request ).ordered.with( request_data, anything ) do |data, opts|
170
+ opts[:on_response].call first_response_data
171
+ end
172
+ expect( prev_on_detached ).to receive( :call ).ordered
173
+ expect( prev_on_response ).to receive( :call ).ordered.with( first_response_data )
174
+ expect( connector ).to receive( :get_response ).ordered do |opts|
175
+ opts[:on_response].call second_response_data
176
+ end
177
+
178
+ response = nil
179
+ subject.execute do |s|
180
+ response = s.request( request_data )
181
+ end
182
+
183
+ expect( prev_on_failure ).not_to have_received( :call )
184
+ expect( response ).to eq( second_response_data )
185
+ end
186
+
187
+ it "fails both the new and previously pending requests on request failure without response" do
188
+ request_data = Data::Requests::PinPadDisplayMessage.new
189
+ response_data = Data::Responses::PinPadInitialize.new
190
+ allow( connector ).to receive( :connect ) do |opts|
191
+ opts[:on_success].call
192
+ end
193
+ allow( connector ).to receive( :send_request ).with( request_data, anything ) do |data, opts|
194
+ opts[:on_failure].call
195
+ end
196
+
197
+ exception = nil
198
+ subject.execute do |s|
199
+ begin
200
+ s.request( request_data )
201
+ rescue => ex
202
+ exception = ex
203
+ end
204
+ end
205
+
206
+ expect( prev_on_failure ).to have_received( :call )
207
+ expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
208
+ end
209
+
210
+ end
211
+
212
+ context "when its event chain is detached during successful receipt of response" do
213
+ it "continues to run and receives the returned response" do
214
+ expect( connector ).to receive( :connect ) do |opts|
215
+ opts[:on_success].call
216
+ end
217
+ allow( connector ).to receive( :send_request ) do |data, opts|
218
+ opts[:on_detached].call
219
+ opts[:on_response].call :the_response
220
+ end
221
+
222
+ response = nil
223
+ subject.execute do |s|
224
+ response = s.request( :the_request_data )
225
+ end
226
+
227
+ expect( response ).to eq( :the_response )
228
+ end
229
+
230
+ it "is blocked from making additional requests" do
231
+ expect( connector ).to receive( :connect ) do |opts|
232
+ opts[:on_success].call
233
+ end
234
+ allow( connector ).to receive( :send_request ) do |data, opts|
235
+ opts[:on_detached].call
236
+ opts[:on_response].call :the_response
237
+ end
238
+
239
+ exception = nil
240
+ subject.execute do |s|
241
+ s.request( :the_request_data )
242
+ begin
243
+ s.request( :the_request_data )
244
+ rescue Net::EM_Session::RequestError => ex
245
+ exception = ex
246
+ end
247
+ end
248
+
249
+ expect( prev_on_failure ).to have_received( :call )
250
+ expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
251
+ end
252
+ end
253
+ end
254
+
255
+ context "executing a dissociated code" do
256
+ before do
257
+ allow( em_system ).to receive( :defer ) do |block, callback|
258
+ result = block.call
259
+ callback.call result
260
+ end
261
+ end
262
+
263
+ it "gets the value returned from the code execution" do
264
+ exec_result = nil
265
+ subject.execute do |s|
266
+ exec_result = subject.exec_dissociated {
267
+ :the_result
268
+ }
269
+ end
270
+ expect( exec_result ).to eq( :the_result )
271
+ end
272
+
273
+ it "gets the exception raised during the code execution" do
274
+ exception = nil
275
+ subject.execute do |s|
276
+ begin
277
+ subject.exec_dissociated do
278
+ raise 'the error'
279
+ end
280
+ rescue => e
281
+ exception = e
282
+ end
283
+ end
284
+ expect( exception ).to be_kind_of( StandardError )
285
+ expect( exception.message ).to eq( 'the error' )
286
+ end
287
+ end
288
+
289
+ context "sleeping" do
290
+ before do
291
+ @run_sequence = []
292
+ allow( em_system ).to receive( :add_timer ) do |delay_time, callback|
293
+ @run_sequence << [:add_timer, delay_time]
294
+ callback.call
295
+ end
296
+ end
297
+
298
+ it "adds an EM timer, and resumes after the timer callback fires" do
299
+ subject.execute do |s|
300
+ s.sleep 5.5
301
+ @run_sequence << :after_timer
302
+ end
303
+
304
+ expect( @run_sequence ).to eq( [
305
+ [:add_timer, 5.5],
306
+ :after_timer
307
+ ] )
308
+ end
309
+ end
310
+
311
+ end
312
+
313
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: client_for_poslynx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 1.0.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jorgensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-03 00:00:00.000000000 Z
11
+ date: 2015-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -113,6 +113,9 @@ files:
113
113
  - TODO.txt
114
114
  - bin/fake_pos_terminal
115
115
  - client_for_poslynx.gemspec
116
+ - examples/em_protocol_example.rb
117
+ - examples/em_session_basic_example.rb
118
+ - examples/em_session_interrupt_example.rb
116
119
  - lib/client_for_poslynx.rb
117
120
  - lib/client_for_poslynx/bit_sequence.rb
118
121
  - lib/client_for_poslynx/data.rb
@@ -176,9 +179,15 @@ files:
176
179
  - lib/client_for_poslynx/message_handling/xml_extractor.rb
177
180
  - lib/client_for_poslynx/message_handling/xml_lines_buffer.rb
178
181
  - lib/client_for_poslynx/net.rb
182
+ - lib/client_for_poslynx/net/em_connector.rb
183
+ - lib/client_for_poslynx/net/em_connector/callback_map.rb
184
+ - lib/client_for_poslynx/net/em_connector/connection_handler.rb
185
+ - lib/client_for_poslynx/net/em_connector/connector_state.rb
186
+ - lib/client_for_poslynx/net/em_connector/event_dispatcher.rb
187
+ - lib/client_for_poslynx/net/em_connector/handles_connection.rb
188
+ - lib/client_for_poslynx/net/em_connector/request_call.rb
179
189
  - lib/client_for_poslynx/net/em_protocol.rb
180
- - lib/client_for_poslynx/net/structured_client.rb
181
- - lib/client_for_poslynx/net/structured_client/em_connection.rb
190
+ - lib/client_for_poslynx/net/em_session.rb
182
191
  - lib/client_for_poslynx/signature_image.rb
183
192
  - lib/client_for_poslynx/signature_image/draw.rb
184
193
  - lib/client_for_poslynx/signature_image/metrics.rb
@@ -207,8 +216,9 @@ files:
207
216
  - spec/client_for_poslynx/message_handling/data_extractor_spec.rb
208
217
  - spec/client_for_poslynx/message_handling/xml_extractor_spec.rb
209
218
  - spec/client_for_poslynx/message_handling_spec.rb
219
+ - spec/client_for_poslynx/net/em_connector_spec.rb
210
220
  - spec/client_for_poslynx/net/em_protocol_spec.rb
211
- - spec/client_for_poslynx/net/structured_client_spec.rb
221
+ - spec/client_for_poslynx/net/em_session_spec.rb
212
222
  - spec/client_for_poslynx/signature_image/to_svg_converter_spec.rb
213
223
  - spec/client_for_poslynx/signature_image_spec.rb
214
224
  - spec/client_for_poslynx_spec.rb
@@ -230,9 +240,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
230
240
  version: 1.9.3
231
241
  required_rubygems_version: !ruby/object:Gem::Requirement
232
242
  requirements:
233
- - - ! '>='
243
+ - - ! '>'
234
244
  - !ruby/object:Gem::Version
235
- version: '0'
245
+ version: 1.3.1
236
246
  requirements: []
237
247
  rubyforge_project:
238
248
  rubygems_version: 2.2.2
@@ -262,8 +272,9 @@ test_files:
262
272
  - spec/client_for_poslynx/message_handling/data_extractor_spec.rb
263
273
  - spec/client_for_poslynx/message_handling/xml_extractor_spec.rb
264
274
  - spec/client_for_poslynx/message_handling_spec.rb
275
+ - spec/client_for_poslynx/net/em_connector_spec.rb
265
276
  - spec/client_for_poslynx/net/em_protocol_spec.rb
266
- - spec/client_for_poslynx/net/structured_client_spec.rb
277
+ - spec/client_for_poslynx/net/em_session_spec.rb
267
278
  - spec/client_for_poslynx/signature_image/to_svg_converter_spec.rb
268
279
  - spec/client_for_poslynx/signature_image_spec.rb
269
280
  - spec/client_for_poslynx_spec.rb
@@ -1,104 +0,0 @@
1
- # coding: utf-8
2
-
3
- require_relative 'structured_client/em_connection'
4
-
5
- module ClientForPoslynx
6
- module Net
7
-
8
- # A network client API suitable for use in a Structured (as
9
- # oppoesed to Event-Driven) context such as from within an
10
- # irb console session.
11
- class StructuredClient
12
-
13
- class SessionEndedError < StandardError ; end
14
- class SessionEndingError < StandardError ; end
15
-
16
- # Initializes a new instance, given a host name or address
17
- # and a host IP port number. If an SSL connection is
18
- # required, then supply true for the use_ssl argument.
19
- def initialize(host, port, use_ssl = false)
20
- @directive_queue = Queue.new
21
- @activity_queue = Queue.new
22
- @em_thread = Thread.new do
23
- EM.run do
24
- EM.connect host, port, EM_Connection, use_ssl, directive_queue, activity_queue
25
- EM.error_handler do |e|
26
- raise e
27
- end
28
- end
29
- end
30
- end
31
-
32
- # Close the server connection if it is open and end the
33
- # session managed by the receiving instance.
34
- def end_session
35
- return unless em_thread.status
36
- directive_queue << :end_session
37
- self.session_end_initiated = true
38
- em_thread.join
39
- nil
40
- end
41
-
42
- # Sends a request to the POSLynx system and returns
43
- # immediately.
44
- # The request object is expected to behave like an
45
- # instance of a descendant class of
46
- # ClientForPoslynx::Data::Requests::AbstractRequest.
47
- def send_request(request_data)
48
- if session_ended?
49
- raise SessionEndedError, "The session has been closed and cannot be used to send requests"
50
- elsif session_ending?
51
- raise SessionEndingError, "The session is ending and cannot be used to send requests"
52
- end
53
- directive_queue << [ :send_request, request_data ]
54
- nil
55
- end
56
-
57
- # Returns the next available received response, if any.
58
- # Returns nil is there are no remaining received responses
59
- # to get.
60
- # Each response will be an instance of a descendent class
61
- # of
62
- # ClientForPoslynx::Data::Responses::AbstractResponse.
63
- def get_response
64
- process_new_activity
65
- received_responses.shift
66
- end
67
-
68
- # Returns true if the managed session has ended, either
69
- # as a result of a call to #end_session or because the
70
- # connection was closed by the server or otherwise lost.
71
- def session_ended?
72
- ! em_thread.status
73
- end
74
-
75
- private
76
-
77
- attr_reader :em_thread, :directive_queue, :activity_queue
78
- attr_accessor :session_end_initiated
79
-
80
- def session_ending?
81
- session_end_initiated && ! session_ended?
82
- end
83
-
84
- def process_new_activity
85
- until activity_queue.empty?
86
- process_activity_entry *activity_queue.shift
87
- end
88
- end
89
-
90
- def process_activity_entry(kind, data=nil)
91
- case kind
92
- when :received_response
93
- received_responses << data
94
- end
95
- end
96
-
97
- def received_responses
98
- @received_responses ||= []
99
- end
100
-
101
- end
102
-
103
- end
104
- end