client_for_poslynx 0.9.0 → 1.0.0.pre

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.
@@ -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